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