Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2022 DMTF. All rights reserved.
4 : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : **/
6 :
7 : /** @file
8 : * Elliptic Curve Wrapper Implementation.
9 : *
10 : * RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites
11 : * FIPS 186-4 - Digital signature Standard (DSS)
12 : **/
13 :
14 : #include "internal_crypt_lib.h"
15 : #include <mbedtls/ecp.h>
16 : #include <mbedtls/ecdh.h>
17 : #include <mbedtls/ecdsa.h>
18 : #include <mbedtls/bignum.h>
19 :
20 : /**
21 : * Allocates and Initializes one Elliptic Curve context for subsequent use
22 : * with the NID.
23 : *
24 : * @param nid cipher NID
25 : *
26 : * @return Pointer to the Elliptic Curve context that has been initialized.
27 : * If the allocations fails, libspdm_ec_new_by_nid() returns NULL.
28 : *
29 : **/
30 170 : void *libspdm_ec_new_by_nid(size_t nid)
31 : {
32 : mbedtls_ecdh_context *ctx;
33 : mbedtls_ecp_group_id grp_id;
34 : int ret;
35 :
36 170 : ctx = allocate_zero_pool(sizeof(mbedtls_ecdh_context));
37 170 : if (ctx == NULL) {
38 0 : return NULL;
39 : }
40 170 : switch (nid) {
41 170 : case LIBSPDM_CRYPTO_NID_SECP256R1:
42 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P256:
43 170 : grp_id = MBEDTLS_ECP_DP_SECP256R1;
44 170 : break;
45 0 : case LIBSPDM_CRYPTO_NID_SECP384R1:
46 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P384:
47 0 : grp_id = MBEDTLS_ECP_DP_SECP384R1;
48 0 : break;
49 0 : case LIBSPDM_CRYPTO_NID_SECP521R1:
50 : case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P521:
51 0 : grp_id = MBEDTLS_ECP_DP_SECP521R1;
52 0 : break;
53 0 : default:
54 0 : goto error;
55 : }
56 :
57 170 : mbedtls_ecdh_init(ctx);
58 170 : ret = mbedtls_ecdh_setup(ctx, grp_id);
59 170 : if (ret != 0) {
60 0 : goto error;
61 : }
62 170 : return ctx;
63 0 : error:
64 0 : free_pool(ctx);
65 0 : return NULL;
66 : }
67 :
68 : /**
69 : * Release the specified EC context.
70 : *
71 : * @param[in] ec_context Pointer to the EC context to be released.
72 : *
73 : **/
74 1026 : void libspdm_ec_free(void *ec_context)
75 : {
76 1026 : mbedtls_ecdh_free(ec_context);
77 1026 : free_pool(ec_context);
78 1026 : }
79 :
80 : /**
81 : * Sets the public key component into the established EC context.
82 : *
83 : * For P-256, the public_size is 64. first 32-byte is X, second 32-byte is Y.
84 : * For P-384, the public_size is 96. first 48-byte is X, second 48-byte is Y.
85 : * For P-521, the public_size is 132. first 66-byte is X, second 66-byte is Y.
86 : *
87 : * @param[in, out] ec_context Pointer to EC context being set.
88 : * @param[in] public Pointer to the buffer to receive generated public X,Y.
89 : * @param[in] public_size The size of public buffer in bytes.
90 : *
91 : * @retval true EC public key component was set successfully.
92 : * @retval false Invalid EC public key component.
93 : *
94 : **/
95 1 : bool libspdm_ec_set_pub_key(void *ec_context, const uint8_t *public_key,
96 : size_t public_key_size)
97 : {
98 : mbedtls_ecdh_context *ctx;
99 : int ret;
100 : size_t half_size;
101 :
102 1 : if (ec_context == NULL || public_key == NULL) {
103 0 : return false;
104 : }
105 :
106 1 : ctx = ec_context;
107 1 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
108 1 : case MBEDTLS_ECP_DP_SECP256R1:
109 1 : half_size = 32;
110 1 : break;
111 0 : case MBEDTLS_ECP_DP_SECP384R1:
112 0 : half_size = 48;
113 0 : break;
114 0 : case MBEDTLS_ECP_DP_SECP521R1:
115 0 : half_size = 66;
116 0 : break;
117 0 : default:
118 0 : return false;
119 : }
120 1 : if (public_key_size != half_size * 2) {
121 0 : return false;
122 : }
123 :
124 1 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X),
125 : public_key, half_size);
126 1 : if (ret != 0) {
127 0 : return false;
128 : }
129 1 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y),
130 1 : public_key + half_size, half_size);
131 1 : if (ret != 0) {
132 0 : return false;
133 : }
134 1 : ret = mbedtls_mpi_lset(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1);
135 1 : if (ret != 0) {
136 0 : return false;
137 : }
138 :
139 1 : return true;
140 : }
141 :
142 : /**
143 : * Sets the private key component into the established EC context.
144 : *
145 : * For P-256, the private_key_size is 32 byte.
146 : * For P-384, the private_key_size is 48 byte.
147 : * For P-521, the private_key_size is 66 byte.
148 : *
149 : * @param[in, out] ec_context Pointer to EC context being set.
150 : * @param[in] private_key Pointer to the private key buffer.
151 : * @param[in] private_key_size The size of private key buffer in bytes.
152 : *
153 : * @retval true EC private key component was set successfully.
154 : * @retval false Invalid EC private key component.
155 : *
156 : **/
157 2 : bool libspdm_ec_set_priv_key(void *ec_context, const uint8_t *private_key,
158 : size_t private_key_size)
159 : {
160 : mbedtls_ecdh_context *ctx;
161 : int ret;
162 : size_t half_size;
163 :
164 2 : if (ec_context == NULL || private_key == NULL) {
165 0 : return false;
166 : }
167 :
168 2 : ctx = ec_context;
169 2 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
170 2 : case MBEDTLS_ECP_DP_SECP256R1:
171 2 : half_size = 32;
172 2 : break;
173 0 : case MBEDTLS_ECP_DP_SECP384R1:
174 0 : half_size = 48;
175 0 : break;
176 0 : case MBEDTLS_ECP_DP_SECP521R1:
177 0 : half_size = 66;
178 0 : break;
179 0 : default:
180 0 : return false;
181 : }
182 2 : if (private_key_size != half_size) {
183 0 : return false;
184 : }
185 :
186 2 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(d), private_key,
187 : private_key_size);
188 2 : if (ret != 0) {
189 0 : return false;
190 : }
191 :
192 2 : return true;
193 : }
194 :
195 : /**
196 : * Gets the public key component from the established EC context.
197 : *
198 : * For P-256, the public_size is 64. first 32-byte is X, second 32-byte is Y.
199 : * For P-384, the public_size is 96. first 48-byte is X, second 48-byte is Y.
200 : * For P-521, the public_size is 132. first 66-byte is X, second 66-byte is Y.
201 : *
202 : * @param[in, out] ec_context Pointer to EC context being set.
203 : * @param[out] public Pointer to the buffer to receive generated public X,Y.
204 : * @param[in, out] public_size On input, the size of public buffer in bytes.
205 : * On output, the size of data returned in public buffer in bytes.
206 : *
207 : * @retval true EC key component was retrieved successfully.
208 : * @retval false Invalid EC key component.
209 : *
210 : **/
211 0 : bool libspdm_ec_get_pub_key(void *ec_context, uint8_t *public_key,
212 : size_t *public_key_size)
213 : {
214 : mbedtls_ecdh_context *ctx;
215 : int ret;
216 : size_t half_size;
217 : size_t x_size;
218 : size_t y_size;
219 :
220 0 : if (ec_context == NULL || public_key_size == NULL) {
221 0 : return false;
222 : }
223 :
224 0 : if (public_key == NULL && *public_key_size != 0) {
225 0 : return false;
226 : }
227 :
228 0 : ctx = ec_context;
229 0 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
230 0 : case MBEDTLS_ECP_DP_SECP256R1:
231 0 : half_size = 32;
232 0 : break;
233 0 : case MBEDTLS_ECP_DP_SECP384R1:
234 0 : half_size = 48;
235 0 : break;
236 0 : case MBEDTLS_ECP_DP_SECP521R1:
237 0 : half_size = 66;
238 0 : break;
239 0 : default:
240 0 : return false;
241 : }
242 0 : if (*public_key_size < half_size * 2) {
243 0 : *public_key_size = half_size * 2;
244 0 : return false;
245 : }
246 0 : *public_key_size = half_size * 2;
247 0 : libspdm_zero_mem(public_key, *public_key_size);
248 :
249 0 : x_size = mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X));
250 0 : y_size = mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y));
251 0 : LIBSPDM_ASSERT(x_size <= half_size && y_size <= half_size);
252 :
253 0 : ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X),
254 0 : &public_key[0 + half_size - x_size], x_size);
255 0 : if (ret != 0) {
256 0 : return false;
257 : }
258 0 : ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y),
259 0 : &public_key[half_size + half_size - y_size],
260 : y_size);
261 0 : if (ret != 0) {
262 0 : return false;
263 : }
264 :
265 0 : return true;
266 : }
267 :
268 : /**
269 : * Validates key components of EC context.
270 : * NOTE: This function performs integrity checks on all the EC key material, so
271 : * the EC key structure must contain all the private key data.
272 : *
273 : * If ec_context is NULL, then return false.
274 : *
275 : * @param[in] ec_context Pointer to EC context to check.
276 : *
277 : * @retval true EC key components are valid.
278 : * @retval false EC key components are not valid.
279 : *
280 : **/
281 0 : bool libspdm_ec_check_key(const void *ec_context)
282 : {
283 : /* TBD*/
284 0 : return true;
285 : }
286 :
287 : /**
288 : * Generates EC key and returns EC public key (X, Y).
289 : *
290 : * This function generates random secret, and computes the public key (X, Y), which is
291 : * returned via parameter public, public_size.
292 : * X is the first half of public with size being public_size / 2,
293 : * Y is the second half of public with size being public_size / 2.
294 : * EC context is updated accordingly.
295 : * If the public buffer is too small to hold the public X, Y, false is returned and
296 : * public_size is set to the required buffer size to obtain the public X, Y.
297 : *
298 : * For P-256, the public_size is 64. first 32-byte is X, second 32-byte is Y.
299 : * For P-384, the public_size is 96. first 48-byte is X, second 48-byte is Y.
300 : * For P-521, the public_size is 132. first 66-byte is X, second 66-byte is Y.
301 : *
302 : * If ec_context is NULL, then return false.
303 : * If public_size is NULL, then return false.
304 : * If public_size is large enough but public is NULL, then return false.
305 : *
306 : * @param[in, out] ec_context Pointer to the EC context.
307 : * @param[out] public_data Pointer to the buffer to receive generated public X,Y.
308 : * @param[in, out] public_size On input, the size of public buffer in bytes.
309 : * On output, the size of data returned in public buffer in bytes.
310 : *
311 : * @retval true EC public X,Y generation succeeded.
312 : * @retval false EC public X,Y generation failed.
313 : * @retval false public_size is not large enough.
314 : *
315 : **/
316 168 : bool libspdm_ec_generate_key(void *ec_context, uint8_t *public_data,
317 : size_t *public_size)
318 : {
319 : mbedtls_ecdh_context *ctx;
320 : int ret;
321 : size_t half_size;
322 : size_t x_size;
323 : size_t y_size;
324 :
325 168 : if (ec_context == NULL || public_size == NULL) {
326 0 : return false;
327 : }
328 :
329 168 : if (public_data == NULL && *public_size != 0) {
330 0 : return false;
331 : }
332 :
333 168 : ctx = ec_context;
334 168 : ret = mbedtls_ecdh_gen_public(&ctx->MBEDTLS_PRIVATE(grp),
335 : &ctx->MBEDTLS_PRIVATE(d),
336 : &ctx->MBEDTLS_PRIVATE(Q), libspdm_myrand,
337 : NULL);
338 168 : if (ret != 0) {
339 0 : return false;
340 : }
341 :
342 168 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
343 168 : case MBEDTLS_ECP_DP_SECP256R1:
344 168 : half_size = 32;
345 168 : break;
346 0 : case MBEDTLS_ECP_DP_SECP384R1:
347 0 : half_size = 48;
348 0 : break;
349 0 : case MBEDTLS_ECP_DP_SECP521R1:
350 0 : half_size = 66;
351 0 : break;
352 0 : default:
353 0 : return false;
354 : }
355 168 : if (*public_size < half_size * 2) {
356 0 : *public_size = half_size * 2;
357 0 : return false;
358 : }
359 168 : *public_size = half_size * 2;
360 168 : libspdm_zero_mem(public_data, *public_size);
361 :
362 168 : x_size = mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X));
363 168 : y_size = mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y));
364 168 : LIBSPDM_ASSERT(x_size <= half_size && y_size <= half_size);
365 :
366 168 : ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X),
367 168 : &public_data[0 + half_size - x_size], x_size);
368 168 : if (ret != 0) {
369 0 : return false;
370 : }
371 168 : ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y),
372 168 : &public_data[half_size + half_size - y_size],
373 : y_size);
374 168 : if (ret != 0) {
375 0 : return false;
376 : }
377 :
378 168 : return true;
379 : }
380 :
381 : /**
382 : * Computes exchanged common key.
383 : *
384 : * Given peer's public key (X, Y), this function computes the exchanged common key,
385 : * based on its own context including value of curve parameter and random secret.
386 : * X is the first half of peer_public with size being peer_public_size / 2,
387 : * Y is the second half of peer_public with size being peer_public_size / 2.
388 : *
389 : * If ec_context is NULL, then return false.
390 : * If peer_public is NULL, then return false.
391 : * If peer_public_size is 0, then return false.
392 : * If key is NULL, then return false.
393 : * If key_size is not large enough, then return false.
394 : *
395 : * For P-256, the peer_public_size is 64. first 32-byte is X, second 32-byte is Y. The key_size is 32.
396 : * For P-384, the peer_public_size is 96. first 48-byte is X, second 48-byte is Y. The key_size is 48.
397 : * For P-521, the peer_public_size is 132. first 66-byte is X, second 66-byte is Y. The key_size is 66.
398 : *
399 : * @param[in, out] ec_context Pointer to the EC context.
400 : * @param[in] peer_public Pointer to the peer's public X,Y.
401 : * @param[in] peer_public_size size of peer's public X,Y in bytes.
402 : * @param[out] key Pointer to the buffer to receive generated key.
403 : * @param[in, out] key_size On input, the size of key buffer in bytes.
404 : * On output, the size of data returned in key buffer in bytes.
405 : *
406 : * @retval true EC exchanged key generation succeeded.
407 : * @retval false EC exchanged key generation failed.
408 : * @retval false key_size is not large enough.
409 : *
410 : **/
411 75 : bool libspdm_ec_compute_key(void *ec_context, const uint8_t *peer_public,
412 : size_t peer_public_size, uint8_t *key,
413 : size_t *key_size)
414 : {
415 : mbedtls_ecdh_context *ctx;
416 : size_t half_size;
417 : int ret;
418 :
419 75 : if (ec_context == NULL || peer_public == NULL || key_size == NULL ||
420 : key == NULL) {
421 0 : return false;
422 : }
423 :
424 75 : if (peer_public_size > INT_MAX) {
425 0 : return false;
426 : }
427 :
428 75 : ctx = ec_context;
429 75 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
430 75 : case MBEDTLS_ECP_DP_SECP256R1:
431 75 : half_size = 32;
432 75 : break;
433 0 : case MBEDTLS_ECP_DP_SECP384R1:
434 0 : half_size = 48;
435 0 : break;
436 0 : case MBEDTLS_ECP_DP_SECP521R1:
437 0 : half_size = 66;
438 0 : break;
439 0 : default:
440 0 : return false;
441 : }
442 75 : if (peer_public_size != half_size * 2) {
443 0 : return false;
444 : }
445 :
446 75 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Qp).MBEDTLS_PRIVATE(X),
447 : peer_public, half_size);
448 75 : if (ret != 0) {
449 0 : return false;
450 : }
451 75 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Qp).MBEDTLS_PRIVATE(Y),
452 75 : peer_public + half_size, half_size);
453 75 : if (ret != 0) {
454 0 : return false;
455 : }
456 75 : ret = mbedtls_mpi_lset(&ctx->MBEDTLS_PRIVATE(Qp).MBEDTLS_PRIVATE(Z), 1);
457 75 : if (ret != 0) {
458 0 : return false;
459 : }
460 :
461 75 : ret = mbedtls_ecdh_compute_shared(&ctx->MBEDTLS_PRIVATE(grp),
462 : &ctx->MBEDTLS_PRIVATE(z),
463 75 : &ctx->MBEDTLS_PRIVATE(Qp),
464 75 : &ctx->MBEDTLS_PRIVATE(d),
465 : libspdm_myrand, NULL);
466 75 : if (ret != 0) {
467 0 : return false;
468 : }
469 :
470 75 : if (mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(z)) > *key_size) {
471 0 : return false;
472 : }
473 :
474 75 : *key_size = ctx->MBEDTLS_PRIVATE(grp).pbits / 8 +
475 75 : ((ctx->MBEDTLS_PRIVATE(grp).pbits % 8) != 0);
476 75 : ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(z), key, *key_size);
477 75 : if (ret != 0) {
478 0 : return false;
479 : }
480 :
481 75 : return true;
482 : }
483 :
484 : /**
485 : * Carries out the EC-DSA signature.
486 : *
487 : * This function carries out the EC-DSA signature.
488 : * If the signature buffer is too small to hold the contents of signature, false
489 : * is returned and sig_size is set to the required buffer size to obtain the signature.
490 : *
491 : * If ec_context is NULL, then return false.
492 : * If message_hash is NULL, then return false.
493 : * If hash_size need match the hash_nid. hash_nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
494 : * If sig_size is large enough but signature is NULL, then return false.
495 : *
496 : * For P-256, the sig_size is 64. first 32-byte is R, second 32-byte is S.
497 : * For P-384, the sig_size is 96. first 48-byte is R, second 48-byte is S.
498 : * For P-521, the sig_size is 132. first 66-byte is R, second 66-byte is S.
499 : *
500 : * @param[in] ec_context Pointer to EC context for signature generation.
501 : * @param[in] hash_nid hash NID
502 : * @param[in] message_hash Pointer to octet message hash to be signed.
503 : * @param[in] hash_size size of the message hash in bytes.
504 : * @param[out] signature Pointer to buffer to receive EC-DSA signature.
505 : * @param[in, out] sig_size On input, the size of signature buffer in bytes.
506 : * On output, the size of data returned in signature buffer in bytes.
507 : *
508 : * @retval true signature successfully generated in EC-DSA.
509 : * @retval false signature generation failed.
510 : * @retval false sig_size is too small.
511 : *
512 : **/
513 140 : bool libspdm_ecdsa_sign(void *ec_context, size_t hash_nid,
514 : const uint8_t *message_hash, size_t hash_size,
515 : uint8_t *signature, size_t *sig_size)
516 : {
517 : int ret;
518 : mbedtls_ecdh_context *ctx;
519 : mbedtls_mpi bn_r;
520 : mbedtls_mpi bn_s;
521 : size_t r_size;
522 : size_t s_size;
523 : size_t half_size;
524 :
525 140 : if (ec_context == NULL || message_hash == NULL) {
526 0 : return false;
527 : }
528 :
529 140 : if (signature == NULL) {
530 0 : return false;
531 : }
532 :
533 140 : ctx = ec_context;
534 140 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
535 140 : case MBEDTLS_ECP_DP_SECP256R1:
536 140 : half_size = 32;
537 140 : break;
538 0 : case MBEDTLS_ECP_DP_SECP384R1:
539 0 : half_size = 48;
540 0 : break;
541 0 : case MBEDTLS_ECP_DP_SECP521R1:
542 0 : half_size = 66;
543 0 : break;
544 0 : default:
545 0 : return false;
546 : }
547 140 : if (*sig_size < (size_t)(half_size * 2)) {
548 0 : *sig_size = half_size * 2;
549 0 : return false;
550 : }
551 140 : *sig_size = half_size * 2;
552 140 : libspdm_zero_mem(signature, *sig_size);
553 :
554 140 : switch (hash_nid) {
555 140 : case LIBSPDM_CRYPTO_NID_SHA256:
556 140 : if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) {
557 0 : return false;
558 : }
559 140 : break;
560 :
561 0 : case LIBSPDM_CRYPTO_NID_SHA384:
562 0 : if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) {
563 0 : return false;
564 : }
565 0 : break;
566 :
567 0 : case LIBSPDM_CRYPTO_NID_SHA512:
568 0 : if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) {
569 0 : return false;
570 : }
571 0 : break;
572 :
573 0 : case LIBSPDM_CRYPTO_NID_SHA3_256:
574 0 : if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) {
575 0 : return false;
576 : }
577 0 : break;
578 :
579 0 : case LIBSPDM_CRYPTO_NID_SHA3_384:
580 0 : if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) {
581 0 : return false;
582 : }
583 0 : break;
584 :
585 0 : case LIBSPDM_CRYPTO_NID_SHA3_512:
586 0 : if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) {
587 0 : return false;
588 : }
589 0 : break;
590 :
591 0 : default:
592 0 : return false;
593 : }
594 :
595 140 : mbedtls_mpi_init(&bn_r);
596 140 : mbedtls_mpi_init(&bn_s);
597 :
598 140 : ret = mbedtls_ecdsa_sign(&ctx->MBEDTLS_PRIVATE(grp), &bn_r, &bn_s,
599 140 : &ctx->MBEDTLS_PRIVATE(d), message_hash,
600 : hash_size, libspdm_myrand, NULL);
601 140 : if (ret != 0) {
602 0 : return false;
603 : }
604 :
605 140 : r_size = mbedtls_mpi_size(&bn_r);
606 140 : s_size = mbedtls_mpi_size(&bn_s);
607 140 : LIBSPDM_ASSERT(r_size <= half_size && s_size <= half_size);
608 :
609 140 : ret = mbedtls_mpi_write_binary(
610 140 : &bn_r, &signature[0 + half_size - r_size], r_size);
611 140 : if (ret != 0) {
612 0 : mbedtls_mpi_free(&bn_r);
613 0 : mbedtls_mpi_free(&bn_s);
614 0 : return false;
615 : }
616 140 : ret = mbedtls_mpi_write_binary(
617 140 : &bn_s, &signature[half_size + half_size - s_size], s_size);
618 140 : if (ret != 0) {
619 0 : mbedtls_mpi_free(&bn_r);
620 0 : mbedtls_mpi_free(&bn_s);
621 0 : return false;
622 : }
623 :
624 140 : mbedtls_mpi_free(&bn_r);
625 140 : mbedtls_mpi_free(&bn_s);
626 :
627 140 : return true;
628 : }
629 :
630 : /**
631 : * Verifies the EC-DSA signature.
632 : *
633 : * If ec_context is NULL, then return false.
634 : * If message_hash is NULL, then return false.
635 : * If signature is NULL, then return false.
636 : * If hash_size need match the hash_nid. hash_nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
637 : *
638 : * For P-256, the sig_size is 64. first 32-byte is R, second 32-byte is S.
639 : * For P-384, the sig_size is 96. first 48-byte is R, second 48-byte is S.
640 : * For P-521, the sig_size is 132. first 66-byte is R, second 66-byte is S.
641 : *
642 : * @param[in] ec_context Pointer to EC context for signature verification.
643 : * @param[in] hash_nid hash NID
644 : * @param[in] message_hash Pointer to octet message hash to be checked.
645 : * @param[in] hash_size size of the message hash in bytes.
646 : * @param[in] signature Pointer to EC-DSA signature to be verified.
647 : * @param[in] sig_size size of signature in bytes.
648 : *
649 : * @retval true Valid signature encoded in EC-DSA.
650 : * @retval false Invalid signature or invalid EC context.
651 : *
652 : **/
653 83 : bool libspdm_ecdsa_verify(void *ec_context, size_t hash_nid,
654 : const uint8_t *message_hash, size_t hash_size,
655 : const uint8_t *signature, size_t sig_size)
656 : {
657 : int ret;
658 : mbedtls_ecdh_context *ctx;
659 : mbedtls_mpi bn_r;
660 : mbedtls_mpi bn_s;
661 : size_t half_size;
662 :
663 83 : if (ec_context == NULL || message_hash == NULL || signature == NULL) {
664 0 : return false;
665 : }
666 :
667 83 : if (sig_size > INT_MAX || sig_size == 0) {
668 0 : return false;
669 : }
670 :
671 83 : ctx = ec_context;
672 83 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
673 83 : case MBEDTLS_ECP_DP_SECP256R1:
674 83 : half_size = 32;
675 83 : break;
676 0 : case MBEDTLS_ECP_DP_SECP384R1:
677 0 : half_size = 48;
678 0 : break;
679 0 : case MBEDTLS_ECP_DP_SECP521R1:
680 0 : half_size = 66;
681 0 : break;
682 0 : default:
683 0 : return false;
684 : }
685 83 : if (sig_size != (size_t)(half_size * 2)) {
686 0 : return false;
687 : }
688 :
689 83 : switch (hash_nid) {
690 83 : case LIBSPDM_CRYPTO_NID_SHA256:
691 83 : if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) {
692 0 : return false;
693 : }
694 83 : break;
695 :
696 0 : case LIBSPDM_CRYPTO_NID_SHA384:
697 0 : if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) {
698 0 : return false;
699 : }
700 0 : break;
701 :
702 0 : case LIBSPDM_CRYPTO_NID_SHA512:
703 0 : if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) {
704 0 : return false;
705 : }
706 0 : break;
707 :
708 0 : case LIBSPDM_CRYPTO_NID_SHA3_256:
709 0 : if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) {
710 0 : return false;
711 : }
712 0 : break;
713 :
714 0 : case LIBSPDM_CRYPTO_NID_SHA3_384:
715 0 : if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) {
716 0 : return false;
717 : }
718 0 : break;
719 :
720 0 : case LIBSPDM_CRYPTO_NID_SHA3_512:
721 0 : if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) {
722 0 : return false;
723 : }
724 0 : break;
725 :
726 0 : default:
727 0 : return false;
728 : }
729 :
730 83 : mbedtls_mpi_init(&bn_r);
731 83 : mbedtls_mpi_init(&bn_s);
732 :
733 83 : ret = mbedtls_mpi_read_binary(&bn_r, signature, half_size);
734 83 : if (ret != 0) {
735 0 : mbedtls_mpi_free(&bn_r);
736 0 : mbedtls_mpi_free(&bn_s);
737 0 : return false;
738 : }
739 83 : ret = mbedtls_mpi_read_binary(&bn_s, signature + half_size, half_size);
740 83 : if (ret != 0) {
741 0 : mbedtls_mpi_free(&bn_r);
742 0 : mbedtls_mpi_free(&bn_s);
743 0 : return false;
744 : }
745 :
746 83 : ret = mbedtls_ecdsa_verify(&ctx->MBEDTLS_PRIVATE(grp), message_hash,
747 83 : hash_size, &ctx->MBEDTLS_PRIVATE(Q),
748 : &bn_r, &bn_s);
749 83 : mbedtls_mpi_free(&bn_r);
750 83 : mbedtls_mpi_free(&bn_s);
751 :
752 83 : if (ret != 0) {
753 17 : return false;
754 : }
755 :
756 66 : return true;
757 : }
758 :
759 : #if LIBSPDM_FIPS_MODE
760 : /**
761 : * Carries out the EC-DSA signature with caller input random function. This API can be used for FIPS test.
762 : *
763 : * @param[in] ec_context Pointer to EC context for signature generation.
764 : * @param[in] hash_nid hash NID
765 : * @param[in] message_hash Pointer to octet message hash to be signed.
766 : * @param[in] hash_size Size of the message hash in bytes.
767 : * @param[out] signature Pointer to buffer to receive EC-DSA signature.
768 : * @param[in, out] sig_size On input, the size of signature buffer in bytes.
769 : * On output, the size of data returned in signature buffer in bytes.
770 : * @param[in] random_func random number function
771 : *
772 : * @retval true signature successfully generated in EC-DSA.
773 : * @retval false signature generation failed.
774 : * @retval false sig_size is too small.
775 : **/
776 1 : bool libspdm_ecdsa_sign_ex(void *ec_context, size_t hash_nid,
777 : const uint8_t *message_hash, size_t hash_size,
778 : uint8_t *signature, size_t *sig_size,
779 : int (*random_func)(void *, unsigned char *, size_t))
780 : {
781 : int ret;
782 : mbedtls_ecdh_context *ctx;
783 : mbedtls_mpi bn_r;
784 : mbedtls_mpi bn_s;
785 : size_t r_size;
786 : size_t s_size;
787 : size_t half_size;
788 :
789 1 : if (ec_context == NULL || message_hash == NULL) {
790 0 : return false;
791 : }
792 :
793 1 : if (signature == NULL) {
794 0 : return false;
795 : }
796 :
797 1 : ctx = ec_context;
798 1 : switch (mbedtls_ecdh_get_grp_id(ctx)) {
799 1 : case MBEDTLS_ECP_DP_SECP256R1:
800 1 : half_size = 32;
801 1 : break;
802 0 : case MBEDTLS_ECP_DP_SECP384R1:
803 0 : half_size = 48;
804 0 : break;
805 0 : case MBEDTLS_ECP_DP_SECP521R1:
806 0 : half_size = 66;
807 0 : break;
808 0 : default:
809 0 : return false;
810 : }
811 1 : if (*sig_size < (size_t)(half_size * 2)) {
812 0 : *sig_size = half_size * 2;
813 0 : return false;
814 : }
815 1 : *sig_size = half_size * 2;
816 1 : libspdm_zero_mem(signature, *sig_size);
817 :
818 1 : switch (hash_nid) {
819 1 : case LIBSPDM_CRYPTO_NID_SHA256:
820 1 : if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) {
821 0 : return false;
822 : }
823 1 : break;
824 :
825 0 : case LIBSPDM_CRYPTO_NID_SHA384:
826 0 : if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) {
827 0 : return false;
828 : }
829 0 : break;
830 :
831 0 : case LIBSPDM_CRYPTO_NID_SHA512:
832 0 : if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) {
833 0 : return false;
834 : }
835 0 : break;
836 :
837 0 : case LIBSPDM_CRYPTO_NID_SHA3_256:
838 0 : if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) {
839 0 : return false;
840 : }
841 0 : break;
842 :
843 0 : case LIBSPDM_CRYPTO_NID_SHA3_384:
844 0 : if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) {
845 0 : return false;
846 : }
847 0 : break;
848 :
849 0 : case LIBSPDM_CRYPTO_NID_SHA3_512:
850 0 : if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) {
851 0 : return false;
852 : }
853 0 : break;
854 :
855 0 : default:
856 0 : return false;
857 : }
858 :
859 1 : mbedtls_mpi_init(&bn_r);
860 1 : mbedtls_mpi_init(&bn_s);
861 :
862 : /*retrieve random number*/
863 1 : ret = mbedtls_ecdsa_sign(&ctx->MBEDTLS_PRIVATE(grp), &bn_r, &bn_s,
864 1 : &ctx->MBEDTLS_PRIVATE(d), message_hash,
865 : hash_size, random_func, NULL);
866 1 : if (ret != 0) {
867 0 : return false;
868 : }
869 :
870 1 : r_size = mbedtls_mpi_size(&bn_r);
871 1 : s_size = mbedtls_mpi_size(&bn_s);
872 1 : LIBSPDM_ASSERT(r_size <= half_size && s_size <= half_size);
873 :
874 1 : ret = mbedtls_mpi_write_binary(
875 1 : &bn_r, &signature[0 + half_size - r_size], r_size);
876 1 : if (ret != 0) {
877 0 : mbedtls_mpi_free(&bn_r);
878 0 : mbedtls_mpi_free(&bn_s);
879 0 : return false;
880 : }
881 1 : ret = mbedtls_mpi_write_binary(
882 1 : &bn_s, &signature[half_size + half_size - s_size], s_size);
883 1 : if (ret != 0) {
884 0 : mbedtls_mpi_free(&bn_r);
885 0 : mbedtls_mpi_free(&bn_s);
886 0 : return false;
887 : }
888 :
889 1 : mbedtls_mpi_free(&bn_r);
890 1 : mbedtls_mpi_free(&bn_s);
891 :
892 1 : return true;
893 : }
894 : #endif/*LIBSPDM_FIPS_MODE*/
|