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  * This class 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      * This class 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          * This method 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      * This class 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          * This constructor initializes a `KeyPair` as empty (no key).
130          *
131          */
KeyPair(void)132         KeyPair(void) { mDerLength = 0; }
133 
134         /**
135          * This method 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          * This method 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          * This method 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          * This method 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          * This method gets the pointer to start of the key-pair buffer in DER format.
176          *
177          * This method 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          * This method 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          * This method calculates the ECDSA signature for a hashed message using the private key from `KeyPair`.
196          *
197          * This method 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      * This class represents a key pair (public and private keys) as a PSA KeyRef.
217      *
218      */
219     class KeyPairAsRef
220     {
221     public:
222         /**
223          * This constructor 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          * This method 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          * This method 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          * This method 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          * This method calculates the ECDSA signature for a hashed message using the private key from keypair
274          * referenced by mKeyRef.
275          *
276          * This method 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          * This method 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          * This method 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      * This class 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          * This method 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          * This method 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