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 <openthread/crypto.h> 45 #include <openthread/platform/crypto.h> 46 47 #include "common/error.hpp" 48 #include "crypto/sha256.hpp" 49 #include "crypto/storage.hpp" 50 51 namespace ot { 52 namespace Crypto { 53 namespace Ecdsa { 54 55 /** 56 * @addtogroup core-security 57 * 58 * @{ 59 * 60 */ 61 62 /** 63 * Implements ECDSA key-generation, signing, and verification for NIST P-256 curve using SHA-256 hash. 64 * 65 * NIST P-256 curve is also known as 256-bit Random ECP Group (RFC 5114 - 2.6), or secp256r1 (RFC 4492 - Appendix A). 66 * 67 */ 68 class P256 69 { 70 public: 71 static constexpr uint16_t kFieldBitLength = 256; ///< Prime field bit length used by the P-256 curve. 72 73 /** 74 * Max bytes in binary representation of an MPI (multi-precision int). 75 * 76 */ 77 static constexpr uint8_t kMpiSize = kFieldBitLength / 8; 78 79 class PublicKey; 80 class KeyPair; 81 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 82 class KeyPairAsRef; 83 #endif 84 85 /** 86 * Represents an ECDSA signature. 87 * 88 * The signature is encoded as the concatenated binary representation of two MPIs `r` and `s` which are calculated 89 * during signing (RFC 6605 - section 4). 90 * 91 */ 92 OT_TOOL_PACKED_BEGIN 93 class Signature : public otPlatCryptoEcdsaSignature 94 { 95 friend class KeyPair; 96 friend class PublicKey; 97 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 98 friend class KeyPairAsRef; 99 #endif 100 101 public: 102 static constexpr uint8_t kSize = OT_CRYPTO_ECDSA_SIGNATURE_SIZE; ///< Signature size in bytes. 103 104 /** 105 * Returns the signature as a byte array. 106 * 107 * @returns A pointer to the byte array containing the signature. 108 * 109 */ GetBytes(void) const110 const uint8_t *GetBytes(void) const { return m8; } 111 } OT_TOOL_PACKED_END; 112 113 /** 114 * Represents a key pair (public and private keys). 115 * 116 * The key pair is stored using Distinguished Encoding Rules (DER) format (per RFC 5915). 117 * 118 */ 119 class KeyPair : public otPlatCryptoEcdsaKeyPair 120 { 121 public: 122 /** 123 * Max buffer size (in bytes) for representing the key-pair in DER format. 124 * 125 */ 126 static constexpr uint8_t kMaxDerSize = OT_CRYPTO_ECDSA_MAX_DER_SIZE; 127 128 /** 129 * Initializes a `KeyPair` as empty (no key). 130 * 131 */ KeyPair(void)132 KeyPair(void) { mDerLength = 0; } 133 134 /** 135 * Generates and populates the `KeyPair` with a new public/private keys. 136 * 137 * @retval kErrorNone A new key pair was generated successfully. 138 * @retval kErrorNoBufs Failed to allocate buffer for key generation. 139 * @retval kErrorNotCapable Feature not supported. 140 * @retval kErrorFailed Failed to generate key. 141 * 142 */ Generate(void)143 Error Generate(void) { return otPlatCryptoEcdsaGenerateKey(this); } 144 145 /** 146 * Gets the associated public key from the `KeyPair`. 147 * 148 * @param[out] aPublicKey A reference to a `PublicKey` to output the value. 149 * 150 * @retval kErrorNone Public key was retrieved successfully, and @p aPublicKey is updated. 151 * @retval kErrorParse The key-pair DER format could not be parsed (invalid format). 152 * 153 */ GetPublicKey(PublicKey & aPublicKey) const154 Error GetPublicKey(PublicKey &aPublicKey) const { return otPlatCryptoEcdsaGetPublicKey(this, &aPublicKey); } 155 156 /** 157 * Gets the pointer to start of the buffer containing the key-pair info in DER format. 158 * 159 * The length (number of bytes) of DER format is given by `GetDerLength()`. 160 * 161 * @returns The pointer to the start of buffer containing the key-pair in DER format. 162 * 163 */ GetDerBytes(void) const164 const uint8_t *GetDerBytes(void) const { return mDerBytes; } 165 166 /** 167 * Gets the length of the byte sequence representation of the key-pair in DER format. 168 * 169 * @returns The length of byte sequence representation of the key-pair in DER format. 170 * 171 */ GetDerLength(void) const172 uint8_t GetDerLength(void) const { return mDerLength; } 173 174 /** 175 * Gets the pointer to start of the key-pair buffer in DER format. 176 * 177 * Gives non-const pointer to the buffer and is intended for populating the buffer and setting 178 * the key-pair (e.g., reading the key-pair from non-volatile settings). The buffer contains `kMaxDerSize` 179 * bytes. After populating the buffer, `SetDerLength()` can be used to set the the number of bytes written. 180 * 181 * @returns The pointer to the start of key-pair buffer in DER format. 182 * 183 */ GetDerBytes(void)184 uint8_t *GetDerBytes(void) { return mDerBytes; } 185 186 /** 187 * Sets the length of the byte sequence representation of the key-pair in DER format. 188 * 189 * @param[in] aDerLength The length (number of bytes). 190 * 191 */ SetDerLength(uint8_t aDerLength)192 void SetDerLength(uint8_t aDerLength) { mDerLength = aDerLength; } 193 194 /** 195 * Calculates the ECDSA signature for a hashed message using the private key from `KeyPair`. 196 * 197 * Uses the deterministic digital signature generation procedure from RFC 6979. 198 * 199 * @param[in] aHash The SHA-256 hash value of the message to use for signature calculation. 200 * @param[out] aSignature A reference to a `Signature` to output the calculated signature value. 201 * 202 * @retval kErrorNone The signature was calculated successfully and @p aSignature was updated. 203 * @retval kErrorParse The key-pair DER format could not be parsed (invalid format). 204 * @retval kErrorInvalidArgs The @p aHash is invalid. 205 * @retval kErrorNoBufs Failed to allocate buffer for signature calculation. 206 * 207 */ Sign(const Sha256::Hash & aHash,Signature & aSignature) const208 Error Sign(const Sha256::Hash &aHash, Signature &aSignature) const 209 { 210 return otPlatCryptoEcdsaSign(this, &aHash, &aSignature); 211 } 212 }; 213 214 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 215 /** 216 * Represents a key pair (public and private keys) as a PSA KeyRef. 217 * 218 */ 219 class KeyPairAsRef 220 { 221 public: 222 /** 223 * Initializes a `KeyPairAsRef`. 224 * 225 * @param[in] aKeyRef PSA key reference to use while using the keypair. 226 */ KeyPairAsRef(otCryptoKeyRef aKeyRef=0)227 explicit KeyPairAsRef(otCryptoKeyRef aKeyRef = 0) { mKeyRef = aKeyRef; } 228 229 /** 230 * Generates a new keypair and imports it into PSA ITS. 231 * 232 * @retval kErrorNone A new key pair was generated successfully. 233 * @retval kErrorNoBufs Failed to allocate buffer for key generation. 234 * @retval kErrorNotCapable Feature not supported. 235 * @retval kErrorFailed Failed to generate key. 236 * 237 */ Generate(void) const238 Error Generate(void) const { return otPlatCryptoEcdsaGenerateAndImportKey(mKeyRef); } 239 240 /** 241 * Imports a new keypair into PSA ITS. 242 * 243 * @param[in] aKeyPair KeyPair to be imported in DER format. 244 * 245 * @retval kErrorNone A key pair was imported successfully. 246 * @retval kErrorNotCapable Feature not supported. 247 * @retval kErrorFailed Failed to import the key. 248 * 249 */ ImportKeyPair(const KeyPair & aKeyPair)250 Error ImportKeyPair(const KeyPair &aKeyPair) 251 { 252 return Crypto::Storage::ImportKey(mKeyRef, Storage::kKeyTypeEcdsa, Storage::kKeyAlgorithmEcdsa, 253 (Storage::kUsageSignHash | Storage::kUsageVerifyHash), 254 Storage::kTypePersistent, aKeyPair.GetDerBytes(), 255 aKeyPair.GetDerLength()); 256 } 257 258 /** 259 * Gets the associated public key from the keypair referenced by mKeyRef. 260 * 261 * @param[out] aPublicKey A reference to a `PublicKey` to output the value. 262 * 263 * @retval kErrorNone Public key was retrieved successfully, and @p aPublicKey is updated. 264 * @retval kErrorFailed There was a error exporting the public key from PSA. 265 * 266 */ GetPublicKey(PublicKey & aPublicKey) const267 Error GetPublicKey(PublicKey &aPublicKey) const 268 { 269 return otPlatCryptoEcdsaExportPublicKey(mKeyRef, &aPublicKey); 270 } 271 272 /** 273 * Calculates the ECDSA signature for a hashed message using the private key from keypair 274 * referenced by mKeyRef. 275 * 276 * Uses the deterministic digital signature generation procedure from RFC 6979. 277 * 278 * @param[in] aHash The SHA-256 hash value of the message to use for signature calculation. 279 * @param[out] aSignature A reference to a `Signature` to output the calculated signature value. 280 * 281 * @retval kErrorNone The signature was calculated successfully and @p aSignature was updated. 282 * @retval kErrorParse The key-pair DER format could not be parsed (invalid format). 283 * @retval kErrorInvalidArgs The @p aHash is invalid. 284 * @retval kErrorNoBufs Failed to allocate buffer for signature calculation. 285 * 286 */ Sign(const Sha256::Hash & aHash,Signature & aSignature) const287 Error Sign(const Sha256::Hash &aHash, Signature &aSignature) const 288 { 289 return otPlatCryptoEcdsaSignUsingKeyRef(mKeyRef, &aHash, &aSignature); 290 } 291 292 /** 293 * Gets the Key reference for the keypair stored in the PSA. 294 * 295 * @returns The PSA key ref. 296 * 297 */ GetKeyRef(void) const298 otCryptoKeyRef GetKeyRef(void) const { return mKeyRef; } 299 300 /** 301 * Sets the Key reference. 302 * 303 * @param[in] aKeyRef PSA key reference to use while using the keypair. 304 * 305 */ SetKeyRef(otCryptoKeyRef aKeyRef)306 void SetKeyRef(otCryptoKeyRef aKeyRef) { mKeyRef = aKeyRef; } 307 308 private: 309 otCryptoKeyRef mKeyRef; 310 }; 311 #endif 312 313 /** 314 * Represents a public key. 315 * 316 * The public key is stored as a byte sequence representation of an uncompressed curve point (RFC 6605 - sec 4). 317 * 318 */ 319 OT_TOOL_PACKED_BEGIN 320 class PublicKey : public otPlatCryptoEcdsaPublicKey, public Equatable<PublicKey> 321 { 322 friend class KeyPair; 323 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 324 friend class KeyPairAsRef; 325 #endif 326 327 public: 328 static constexpr uint8_t kSize = OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE; ///< Size of the public key in bytes. 329 330 /** 331 * Gets the pointer to the buffer containing the public key (as an uncompressed curve point). 332 * 333 * @return The pointer to the buffer containing the public key (with `kSize` bytes). 334 * 335 */ GetBytes(void) const336 const uint8_t *GetBytes(void) const { return m8; } 337 338 /** 339 * Uses the `PublicKey` to verify the ECDSA signature of a hashed message. 340 * 341 * @param[in] aHash The SHA-256 hash value of a message to use for signature verification. 342 * @param[in] aSignature The signature value to verify. 343 * 344 * @retval kErrorNone The signature was verified successfully. 345 * @retval kErrorSecurity The signature is invalid. 346 * @retval kErrorInvalidArgs The key or has is invalid. 347 * @retval kErrorNoBufs Failed to allocate buffer for signature verification 348 * 349 */ Verify(const Sha256::Hash & aHash,const Signature & aSignature) const350 Error Verify(const Sha256::Hash &aHash, const Signature &aSignature) const 351 { 352 return otPlatCryptoEcdsaVerify(this, &aHash, &aSignature); 353 } 354 355 } OT_TOOL_PACKED_END; 356 }; 357 358 /** 359 * @} 360 * 361 */ 362 363 } // namespace Ecdsa 364 } // namespace Crypto 365 366 DefineCoreType(otPlatCryptoEcdsaSignature, Crypto::Ecdsa::P256::Signature); 367 DefineCoreType(otPlatCryptoEcdsaKeyPair, Crypto::Ecdsa::P256::KeyPair); 368 DefineCoreType(otPlatCryptoEcdsaPublicKey, Crypto::Ecdsa::P256::PublicKey); 369 370 } // namespace ot 371 372 #endif // OPENTHREAD_CONFIG_ECDSA_ENABLE 373 374 #endif // ECDSA_HPP_ 375