1 /* 2 * Copyright (c) 2018, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for performing ECDSA signing. 32 */ 33 34 #ifndef ECDSA_HPP_ 35 #define ECDSA_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_ECDSA_ENABLE 40 41 #include <stdint.h> 42 #include <stdlib.h> 43 44 #include "common/error.hpp" 45 #include "crypto/sha256.hpp" 46 47 namespace ot { 48 namespace Crypto { 49 namespace Ecdsa { 50 51 /** 52 * @addtogroup core-security 53 * 54 * @{ 55 * 56 */ 57 58 /** 59 * This class implements ECDSA key-generation, signing, and verification for NIST P-256 curve using SHA-256 hash. 60 * 61 * NIST P-256 curve is also known as 256-bit Random ECP Group (RFC 5114 - 2.6), or secp256r1 (RFC 4492 - Appendix A). 62 * 63 */ 64 class P256 65 { 66 public: 67 static constexpr uint16_t kFieldBitLength = 256; ///< Prime field bit length used by the P-256 curve. 68 69 /** 70 * Max bytes in binary representation of an MPI (multi-precision int). 71 * 72 */ 73 static constexpr uint8_t kMpiSize = kFieldBitLength / 8; 74 75 class PublicKey; 76 class KeyPair; 77 78 /** 79 * This class represents an ECDSA signature. 80 * 81 * The signature is encoded as the concatenated binary representation of two MPIs `r` and `s` which are calculated 82 * during signing (RFC 6605 - section 4). 83 * 84 */ 85 OT_TOOL_PACKED_BEGIN 86 class Signature 87 { 88 friend class KeyPair; 89 friend class PublicKey; 90 91 public: 92 static constexpr uint8_t kSize = 2 * kMpiSize; ///< Signature size in bytes (two times the curve MPI size). 93 94 /** 95 * This method returns the signature as a byte array. 96 * 97 * @returns A pointer to the byte array containing the signature. 98 * 99 */ GetBytes(void) const100 const uint8_t *GetBytes(void) const { return mShared.mKey; } 101 102 private: 103 OT_TOOL_PACKED_BEGIN 104 struct Mpis 105 { 106 uint8_t mR[kMpiSize]; 107 uint8_t mS[kMpiSize]; 108 } OT_TOOL_PACKED_END; 109 110 union OT_TOOL_PACKED_FIELD 111 { 112 Mpis mMpis; 113 uint8_t mKey[kSize]; 114 } mShared; 115 } OT_TOOL_PACKED_END; 116 117 /** 118 * This class represents a key pair (public and private keys). 119 * 120 * The key pair is stored using Distinguished Encoding Rules (DER) format (per RFC 5915). 121 * 122 */ 123 class KeyPair 124 { 125 public: 126 /** 127 * Max buffer size (in bytes) for representing the key-pair in DER format. 128 * 129 */ 130 static constexpr uint8_t kMaxDerSize = 125; 131 132 /** 133 * This constructor initializes a `KeyPair` as empty (no key). 134 * 135 */ KeyPair(void)136 KeyPair(void) 137 : mDerLength(0) 138 { 139 } 140 141 /** 142 * This method generates and populates the `KeyPair` with a new public/private keys. 143 * 144 * @retval kErrorNone A new key pair was generated successfully. 145 * @retval kErrorNoBufs Failed to allocate buffer for key generation. 146 * @retval kErrorNotCapable Feature not supported. 147 * @retval kErrorFailed Failed to generate key. 148 * 149 */ 150 Error Generate(void); 151 152 /** 153 * This method gets the associated public key from the `KeyPair`. 154 * 155 * @param[out] aPublicKey A reference to a `PublicKey` to output the value. 156 * 157 * @retval kErrorNone Public key was retrieved successfully, and @p aPublicKey is updated. 158 * @retval kErrorParse The key-pair DER format could not be parsed (invalid format). 159 * 160 */ 161 Error GetPublicKey(PublicKey &aPublicKey) const; 162 163 /** 164 * This method gets the pointer to start of the buffer containing the key-pair info in DER format. 165 * 166 * The length (number of bytes) of DER format is given by `GetDerLength()`. 167 * 168 * @returns The pointer to the start of buffer containing the key-pair in DER format. 169 * 170 */ GetDerBytes(void) const171 const uint8_t *GetDerBytes(void) const { return mDerBytes; } 172 173 /** 174 * This method gets the length of the byte sequence representation of the key-pair in DER format. 175 * 176 * @returns The length of byte sequence representation of the key-pair in DER format. 177 * 178 */ GetDerLength(void) const179 uint8_t GetDerLength(void) const { return mDerLength; } 180 181 /** 182 * This method gets the pointer to start of the key-pair buffer in DER format. 183 * 184 * This method gives non-const pointer to the buffer and is intended for populating the buffer and setting 185 * the key-pair (e.g., reading the key-pair from non-volatile settings). The buffer contains `kMaxDerSize` 186 * bytes. After populating the buffer, `SetDerLength()` can be used to set the the number of bytes written. 187 * 188 * @returns The pointer to the start of key-pair buffer in DER format. 189 * 190 */ GetDerBytes(void)191 uint8_t *GetDerBytes(void) { return mDerBytes; } 192 193 /** 194 * This method sets the length of the byte sequence representation of the key-pair in DER format. 195 * 196 * @param[in] aDerLength The length (number of bytes). 197 * 198 */ SetDerLength(uint8_t aDerLength)199 void SetDerLength(uint8_t aDerLength) { mDerLength = aDerLength; } 200 201 /** 202 * This method calculates the ECDSA signature for a hashed message using the private key from `KeyPair`. 203 * 204 * This method uses the deterministic digital signature generation procedure from RFC 6979. 205 * 206 * @param[in] aHash The SHA-256 hash value of the message to use for signature calculation. 207 * @param[out] aSignature A reference to a `Signature` to output the calculated signature value. 208 * 209 * @retval kErrorNone The signature was calculated successfully and @p aSignature was updated. 210 * @retval kErrorParse The key-pair DER format could not be parsed (invalid format). 211 * @retval kErrorInvalidArgs The @p aHash is invalid. 212 * @retval kErrorNoBufs Failed to allocate buffer for signature calculation. 213 * 214 */ 215 Error Sign(const Sha256::Hash &aHash, Signature &aSignature) const; 216 217 private: 218 Error Parse(void *aContext) const; 219 220 uint8_t mDerBytes[kMaxDerSize]; 221 uint8_t mDerLength; 222 }; 223 224 /** 225 * This class represents a public key. 226 * 227 * The public key is stored as a byte sequence representation of an uncompressed curve point (RFC 6605 - sec 4). 228 * 229 */ 230 OT_TOOL_PACKED_BEGIN 231 class PublicKey 232 { 233 friend class KeyPair; 234 235 public: 236 static constexpr uint8_t kSize = kMpiSize * 2; ///< Size of the public key in bytes. 237 238 /** 239 * This method gets the pointer to the buffer containing the public key (as an uncompressed curve point). 240 * 241 * @return The pointer to the buffer containing the public key (with `kSize` bytes). 242 * 243 */ GetBytes(void) const244 const uint8_t *GetBytes(void) const { return mData; } 245 246 /** 247 * This method uses the `PublicKey` to verify the ECDSA signature of a hashed message. 248 * 249 * @param[in] aHash The SHA-256 hash value of a message to use for signature verification. 250 * @param[in] aSignature The signature value to verify. 251 * 252 * @retval kErrorNone The signature was verified successfully. 253 * @retval kErrorSecurity The signature is invalid. 254 * @retval kErrorInvalidArgs The key or has is invalid. 255 * @retval kErrorNoBufs Failed to allocate buffer for signature verification 256 * 257 */ 258 Error Verify(const Sha256::Hash &aHash, const Signature &aSignature) const; 259 260 private: 261 uint8_t mData[kSize]; 262 } OT_TOOL_PACKED_END; 263 }; 264 265 /** 266 * This function creates an ECDSA signature. 267 * 268 * @param[out] aOutput An output buffer where ECDSA sign should be stored. 269 * @param[inout] aOutputLength The length of the @p aOutput buffer. 270 * @param[in] aInputHash An input hash. 271 * @param[in] aInputHashLength The length of the @p aInputHash buffer. 272 * @param[in] aPrivateKey A private key in PEM format. 273 * @param[in] aPrivateKeyLength The length of the @p aPrivateKey buffer. 274 * 275 * @retval kErrorNone ECDSA sign has been created successfully. 276 * @retval kErrorNoBufs Output buffer is too small. 277 * @retval kErrorInvalidArgs Private key is not valid EC Private Key. 278 * @retval kErrorFailed Error during signing. 279 * 280 */ 281 Error Sign(uint8_t * aOutput, 282 uint16_t & aOutputLength, 283 const uint8_t *aInputHash, 284 uint16_t aInputHashLength, 285 const uint8_t *aPrivateKey, 286 uint16_t aPrivateKeyLength); 287 288 /** 289 * @} 290 * 291 */ 292 293 } // namespace Ecdsa 294 } // namespace Crypto 295 } // namespace ot 296 297 #endif // OPENTHREAD_CONFIG_ECDSA_ENABLE 298 299 #endif // ECDSA_HPP_ 300