1 /*
2  *  Driver entry points for p256-m
3  */
4 /*
5  *  Copyright The Mbed TLS Contributors
6  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
7  */
8 
9 #include "mbedtls/platform.h"
10 #include "p256-m_driver_entrypoints.h"
11 #include "p256-m/p256-m.h"
12 #include "psa/crypto.h"
13 #include <stddef.h>
14 #include <string.h>
15 #include "psa_crypto_driver_wrappers_no_static.h"
16 
17 #if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)
18 
19 /* INFORMATION ON PSA KEY EXPORT FORMATS:
20  *
21  * PSA exports SECP256R1 keys in two formats:
22  * 1. Keypair format: 32 byte string which is just the private key (public key
23  *                    can be calculated from the private key)
24  * 2. Public Key format: A leading byte 0x04 (indicating uncompressed format),
25  *                       followed by the 64 byte public key. This results in a
26  *                       total of 65 bytes.
27  *
28  * p256-m's internal format for private keys matches PSA. Its format for public
29  * keys is only 64 bytes: the same as PSA but without the leading byte (0x04).
30  * Hence, when passing public keys from PSA to p256-m, the leading byte is
31  * removed.
32  *
33  * Shared secret and signature have the same format between PSA and p256-m.
34  */
35 #define PSA_PUBKEY_SIZE         65
36 #define PSA_PUBKEY_HEADER_BYTE  0x04
37 #define P256_PUBKEY_SIZE        64
38 #define PRIVKEY_SIZE            32
39 #define SHARED_SECRET_SIZE      32
40 #define SIGNATURE_SIZE          64
41 
42 #define CURVE_BITS              256
43 
44 /* Convert between p256-m and PSA error codes */
p256_to_psa_error(int ret)45 static psa_status_t p256_to_psa_error(int ret)
46 {
47     switch (ret) {
48         case P256_SUCCESS:
49             return PSA_SUCCESS;
50         case P256_INVALID_PUBKEY:
51         case P256_INVALID_PRIVKEY:
52             return PSA_ERROR_INVALID_ARGUMENT;
53         case P256_INVALID_SIGNATURE:
54             return PSA_ERROR_INVALID_SIGNATURE;
55         case P256_RANDOM_FAILED:
56         default:
57             return PSA_ERROR_GENERIC_ERROR;
58     }
59 }
60 
p256_transparent_import_key(const psa_key_attributes_t * attributes,const uint8_t * data,size_t data_length,uint8_t * key_buffer,size_t key_buffer_size,size_t * key_buffer_length,size_t * bits)61 psa_status_t p256_transparent_import_key(const psa_key_attributes_t *attributes,
62                              const uint8_t *data,
63                              size_t data_length,
64                              uint8_t *key_buffer,
65                              size_t key_buffer_size,
66                              size_t *key_buffer_length,
67                              size_t *bits)
68 {
69     /* Check the key size */
70     if (*bits != 0 && *bits != CURVE_BITS) {
71         return PSA_ERROR_NOT_SUPPORTED;
72     }
73 
74     /* Validate the key (and its type and size) */
75     psa_key_type_t type = psa_get_key_type(attributes);
76     if (type == PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)) {
77         if (data_length != PSA_PUBKEY_SIZE) {
78             return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
79         }
80         /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
81         if (p256_validate_pubkey(data + 1) != P256_SUCCESS) {
82             return PSA_ERROR_INVALID_ARGUMENT;
83         }
84     } else if (type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
85         if (data_length != PRIVKEY_SIZE) {
86             return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
87         }
88         if (p256_validate_privkey(data) != P256_SUCCESS) {
89             return PSA_ERROR_INVALID_ARGUMENT;
90         }
91     } else {
92         return PSA_ERROR_NOT_SUPPORTED;
93     }
94     *bits = CURVE_BITS;
95 
96     /* We only support the export format for input, so just copy. */
97     if (key_buffer_size < data_length) {
98         return PSA_ERROR_BUFFER_TOO_SMALL;
99     }
100     memcpy(key_buffer, data, data_length);
101     *key_buffer_length = data_length;
102 
103     return PSA_SUCCESS;
104 }
105 
p256_transparent_export_public_key(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,uint8_t * data,size_t data_size,size_t * data_length)106 psa_status_t p256_transparent_export_public_key(const psa_key_attributes_t *attributes,
107                                     const uint8_t *key_buffer,
108                                     size_t key_buffer_size,
109                                     uint8_t *data,
110                                     size_t data_size,
111                                     size_t *data_length)
112 {
113     /* Is this the right curve? */
114     size_t bits = psa_get_key_bits(attributes);
115     psa_key_type_t type = psa_get_key_type(attributes);
116     if (bits != CURVE_BITS || type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
117         return PSA_ERROR_NOT_SUPPORTED;
118     }
119 
120     /* Validate sizes, as p256-m expects fixed-size buffers */
121     if (key_buffer_size != PRIVKEY_SIZE) {
122         return PSA_ERROR_INVALID_ARGUMENT;
123     }
124     if (data_size < PSA_PUBKEY_SIZE) {
125         return PSA_ERROR_BUFFER_TOO_SMALL;
126     }
127 
128     /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
129     data[0] = PSA_PUBKEY_HEADER_BYTE;
130     int ret = p256_public_from_private(data + 1, key_buffer);
131     if (ret == P256_SUCCESS) {
132         *data_length = PSA_PUBKEY_SIZE;
133     }
134 
135     return p256_to_psa_error(ret);
136 }
137 
p256_transparent_generate_key(const psa_key_attributes_t * attributes,uint8_t * key_buffer,size_t key_buffer_size,size_t * key_buffer_length)138 psa_status_t p256_transparent_generate_key(
139     const psa_key_attributes_t *attributes,
140     uint8_t *key_buffer,
141     size_t key_buffer_size,
142     size_t *key_buffer_length)
143 {
144     /* We don't use this argument, but the specification mandates the signature
145      * of driver entry-points. (void) used to avoid compiler warning. */
146     (void) attributes;
147 
148     /* Validate sizes, as p256-m expects fixed-size buffers */
149     if (key_buffer_size != PRIVKEY_SIZE) {
150         return PSA_ERROR_BUFFER_TOO_SMALL;
151     }
152 
153     /*
154      *  p256-m's keypair generation function outputs both public and private
155      *  keys. Allocate a buffer to which the public key will be written. The
156      *  private key will be written to key_buffer, which is passed to this
157      *  function as an argument. */
158     uint8_t public_key_buffer[P256_PUBKEY_SIZE];
159 
160     int ret = p256_gen_keypair(key_buffer, public_key_buffer);
161     if (ret == P256_SUCCESS) {
162         *key_buffer_length = PRIVKEY_SIZE;
163     }
164 
165     return p256_to_psa_error(ret);
166 }
167 
p256_transparent_key_agreement(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * peer_key,size_t peer_key_length,uint8_t * shared_secret,size_t shared_secret_size,size_t * shared_secret_length)168 psa_status_t p256_transparent_key_agreement(
169     const psa_key_attributes_t *attributes,
170     const uint8_t *key_buffer,
171     size_t key_buffer_size,
172     psa_algorithm_t alg,
173     const uint8_t *peer_key,
174     size_t peer_key_length,
175     uint8_t *shared_secret,
176     size_t shared_secret_size,
177     size_t *shared_secret_length)
178 {
179     /* We don't use these arguments, but the specification mandates the
180      * sginature of driver entry-points. (void) used to avoid compiler
181      * warning. */
182     (void) attributes;
183     (void) alg;
184 
185     /* Validate sizes, as p256-m expects fixed-size buffers */
186     if (key_buffer_size != PRIVKEY_SIZE || peer_key_length != PSA_PUBKEY_SIZE) {
187         return PSA_ERROR_INVALID_ARGUMENT;
188     }
189     if (shared_secret_size < SHARED_SECRET_SIZE) {
190         return PSA_ERROR_BUFFER_TOO_SMALL;
191     }
192 
193     /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
194     const uint8_t *peer_key_p256m = peer_key + 1;
195     int ret = p256_ecdh_shared_secret(shared_secret, key_buffer, peer_key_p256m);
196     if (ret == P256_SUCCESS) {
197         *shared_secret_length = SHARED_SECRET_SIZE;
198     }
199 
200     return p256_to_psa_error(ret);
201 }
202 
p256_transparent_sign_hash(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * hash,size_t hash_length,uint8_t * signature,size_t signature_size,size_t * signature_length)203 psa_status_t p256_transparent_sign_hash(
204     const psa_key_attributes_t *attributes,
205     const uint8_t *key_buffer,
206     size_t key_buffer_size,
207     psa_algorithm_t alg,
208     const uint8_t *hash,
209     size_t hash_length,
210     uint8_t *signature,
211     size_t signature_size,
212     size_t *signature_length)
213 {
214     /* We don't use these arguments, but the specification mandates the
215      * sginature of driver entry-points. (void) used to avoid compiler
216      * warning. */
217     (void) attributes;
218     (void) alg;
219 
220     /* Validate sizes, as p256-m expects fixed-size buffers */
221     if (key_buffer_size != PRIVKEY_SIZE) {
222         return PSA_ERROR_INVALID_ARGUMENT;
223     }
224     if (signature_size < SIGNATURE_SIZE) {
225         return PSA_ERROR_BUFFER_TOO_SMALL;
226     }
227 
228     int ret = p256_ecdsa_sign(signature, key_buffer, hash, hash_length);
229     if (ret == P256_SUCCESS) {
230         *signature_length = SIGNATURE_SIZE;
231     }
232 
233     return p256_to_psa_error(ret);
234 }
235 
236 /*  This function expects the key buffer to contain a PSA public key,
237  *  as exported by psa_export_public_key() */
p256_verify_hash_with_public_key(const uint8_t * key_buffer,size_t key_buffer_size,const uint8_t * hash,size_t hash_length,const uint8_t * signature,size_t signature_length)238 static psa_status_t p256_verify_hash_with_public_key(
239     const uint8_t *key_buffer,
240     size_t key_buffer_size,
241     const uint8_t *hash,
242     size_t hash_length,
243     const uint8_t *signature,
244     size_t signature_length)
245 {
246     /* Validate sizes, as p256-m expects fixed-size buffers */
247     if (key_buffer_size != PSA_PUBKEY_SIZE || *key_buffer != PSA_PUBKEY_HEADER_BYTE) {
248         return PSA_ERROR_INVALID_ARGUMENT;
249     }
250     if (signature_length != SIGNATURE_SIZE) {
251         return PSA_ERROR_INVALID_SIGNATURE;
252     }
253 
254     /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
255     const uint8_t *public_key_p256m = key_buffer + 1;
256     int ret = p256_ecdsa_verify(signature, public_key_p256m, hash, hash_length);
257 
258     return p256_to_psa_error(ret);
259 }
260 
p256_transparent_verify_hash(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * hash,size_t hash_length,const uint8_t * signature,size_t signature_length)261 psa_status_t p256_transparent_verify_hash(
262     const psa_key_attributes_t *attributes,
263     const uint8_t *key_buffer,
264     size_t key_buffer_size,
265     psa_algorithm_t alg,
266     const uint8_t *hash,
267     size_t hash_length,
268     const uint8_t *signature,
269     size_t signature_length)
270 {
271     /* We don't use this argument, but the specification mandates the signature
272      * of driver entry-points. (void) used to avoid compiler warning. */
273     (void) alg;
274 
275     psa_status_t status;
276     uint8_t public_key_buffer[PSA_PUBKEY_SIZE];
277     size_t public_key_buffer_size = PSA_PUBKEY_SIZE;
278 
279     size_t public_key_length = PSA_PUBKEY_SIZE;
280     /* As p256-m doesn't require dynamic allocation, we want to avoid it in
281      * the entrypoint functions as well. psa_driver_wrapper_export_public_key()
282      * requires size_t*, so we use a pointer to a stack variable. */
283     size_t *public_key_length_ptr = &public_key_length;
284 
285     /* The contents of key_buffer may either be the 32 byte private key
286      * (keypair format), or 0x04 followed by the 64 byte public key (public
287      * key format). To ensure the key is in the latter format, the public key
288      * is exported. */
289     status = psa_driver_wrapper_export_public_key(
290         attributes,
291         key_buffer,
292         key_buffer_size,
293         public_key_buffer,
294         public_key_buffer_size,
295         public_key_length_ptr);
296     if (status != PSA_SUCCESS) {
297         goto exit;
298     }
299 
300     status = p256_verify_hash_with_public_key(
301         public_key_buffer,
302         public_key_buffer_size,
303         hash,
304         hash_length,
305         signature,
306         signature_length);
307 
308 exit:
309     return status;
310 }
311 
312 #endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */
313