• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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