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