/src/libspdm/os_stub/cryptlib_mbedtls/pk/ec.c
Line | Count | Source |
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 | | void *libspdm_ec_new_by_nid(size_t nid) |
31 | 308 | { |
32 | 308 | mbedtls_ecdh_context *ctx; |
33 | 308 | mbedtls_ecp_group_id grp_id; |
34 | 308 | int ret; |
35 | | |
36 | 308 | ctx = allocate_zero_pool(sizeof(mbedtls_ecdh_context)); |
37 | 308 | if (ctx == NULL) { |
38 | 0 | return NULL; |
39 | 0 | } |
40 | 308 | switch (nid) { |
41 | 308 | case LIBSPDM_CRYPTO_NID_SECP256R1: |
42 | 308 | case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P256: |
43 | 308 | grp_id = MBEDTLS_ECP_DP_SECP256R1; |
44 | 308 | break; |
45 | 0 | case LIBSPDM_CRYPTO_NID_SECP384R1: |
46 | 0 | 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 | 0 | 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 | 308 | } |
56 | | |
57 | 308 | mbedtls_ecdh_init(ctx); |
58 | 308 | ret = mbedtls_ecdh_setup(ctx, grp_id); |
59 | 308 | if (ret != 0) { |
60 | 0 | goto error; |
61 | 0 | } |
62 | 308 | return ctx; |
63 | 0 | error: |
64 | 0 | free_pool(ctx); |
65 | 0 | return NULL; |
66 | 308 | } |
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 | | void libspdm_ec_free(void *ec_context) |
75 | 9.27k | { |
76 | 9.27k | mbedtls_ecdh_free(ec_context); |
77 | 9.27k | free_pool(ec_context); |
78 | 9.27k | } |
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 | | bool libspdm_ec_set_pub_key(void *ec_context, const uint8_t *public_key, |
96 | | size_t public_key_size) |
97 | 0 | { |
98 | 0 | mbedtls_ecdh_context *ctx; |
99 | 0 | int ret; |
100 | 0 | size_t half_size; |
101 | |
|
102 | 0 | if (ec_context == NULL || public_key == NULL) { |
103 | 0 | return false; |
104 | 0 | } |
105 | | |
106 | 0 | ctx = ec_context; |
107 | 0 | switch (mbedtls_ecdh_get_grp_id(ctx)) { |
108 | 0 | case MBEDTLS_ECP_DP_SECP256R1: |
109 | 0 | half_size = 32; |
110 | 0 | 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 | 0 | } |
120 | 0 | if (public_key_size != half_size * 2) { |
121 | 0 | return false; |
122 | 0 | } |
123 | | |
124 | 0 | ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), |
125 | 0 | public_key, half_size); |
126 | 0 | if (ret != 0) { |
127 | 0 | return false; |
128 | 0 | } |
129 | 0 | ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), |
130 | 0 | public_key + half_size, half_size); |
131 | 0 | if (ret != 0) { |
132 | 0 | return false; |
133 | 0 | } |
134 | 0 | ret = mbedtls_mpi_lset(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1); |
135 | 0 | if (ret != 0) { |
136 | 0 | return false; |
137 | 0 | } |
138 | | |
139 | 0 | return true; |
140 | 0 | } |
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 | | bool libspdm_ec_set_priv_key(void *ec_context, const uint8_t *private_key, |
158 | | size_t private_key_size) |
159 | 0 | { |
160 | 0 | mbedtls_ecdh_context *ctx; |
161 | 0 | int ret; |
162 | 0 | size_t half_size; |
163 | |
|
164 | 0 | if (ec_context == NULL || private_key == NULL) { |
165 | 0 | return false; |
166 | 0 | } |
167 | | |
168 | 0 | ctx = ec_context; |
169 | 0 | switch (mbedtls_ecdh_get_grp_id(ctx)) { |
170 | 0 | case MBEDTLS_ECP_DP_SECP256R1: |
171 | 0 | half_size = 32; |
172 | 0 | 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 | 0 | } |
182 | 0 | if (private_key_size != half_size) { |
183 | 0 | return false; |
184 | 0 | } |
185 | | |
186 | 0 | ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(d), private_key, |
187 | 0 | private_key_size); |
188 | 0 | if (ret != 0) { |
189 | 0 | return false; |
190 | 0 | } |
191 | | |
192 | 0 | return true; |
193 | 0 | } |
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 | | bool libspdm_ec_get_pub_key(void *ec_context, uint8_t *public_key, |
212 | | size_t *public_key_size) |
213 | 0 | { |
214 | 0 | mbedtls_ecdh_context *ctx; |
215 | 0 | int ret; |
216 | 0 | size_t half_size; |
217 | 0 | size_t x_size; |
218 | 0 | size_t y_size; |
219 | |
|
220 | 0 | if (ec_context == NULL || public_key_size == NULL) { |
221 | 0 | return false; |
222 | 0 | } |
223 | | |
224 | 0 | if (public_key == NULL && *public_key_size != 0) { |
225 | 0 | return false; |
226 | 0 | } |
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 | 0 | } |
242 | 0 | if (*public_key_size < half_size * 2) { |
243 | 0 | *public_key_size = half_size * 2; |
244 | 0 | return false; |
245 | 0 | } |
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 | 0 | } |
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 | 0 | y_size); |
261 | 0 | if (ret != 0) { |
262 | 0 | return false; |
263 | 0 | } |
264 | | |
265 | 0 | return true; |
266 | 0 | } |
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 | | bool libspdm_ec_check_key(const void *ec_context) |
282 | 0 | { |
283 | | /* TBD*/ |
284 | 0 | return true; |
285 | 0 | } |
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 | | bool libspdm_ec_generate_key(void *ec_context, uint8_t *public_data, |
317 | | size_t *public_size) |
318 | 308 | { |
319 | 308 | mbedtls_ecdh_context *ctx; |
320 | 308 | int ret; |
321 | 308 | size_t half_size; |
322 | 308 | size_t x_size; |
323 | 308 | size_t y_size; |
324 | | |
325 | 308 | if (ec_context == NULL || public_size == NULL) { |
326 | 0 | return false; |
327 | 0 | } |
328 | | |
329 | 308 | if (public_data == NULL && *public_size != 0) { |
330 | 0 | return false; |
331 | 0 | } |
332 | | |
333 | 308 | ctx = ec_context; |
334 | 308 | ret = mbedtls_ecdh_gen_public(&ctx->MBEDTLS_PRIVATE(grp), |
335 | 308 | &ctx->MBEDTLS_PRIVATE(d), |
336 | 308 | &ctx->MBEDTLS_PRIVATE(Q), libspdm_myrand, |
337 | 308 | NULL); |
338 | 308 | if (ret != 0) { |
339 | 0 | return false; |
340 | 0 | } |
341 | | |
342 | 308 | switch (mbedtls_ecdh_get_grp_id(ctx)) { |
343 | 308 | case MBEDTLS_ECP_DP_SECP256R1: |
344 | 308 | half_size = 32; |
345 | 308 | 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 | 308 | } |
355 | 308 | if (*public_size < half_size * 2) { |
356 | 0 | *public_size = half_size * 2; |
357 | 0 | return false; |
358 | 0 | } |
359 | 308 | *public_size = half_size * 2; |
360 | 308 | libspdm_zero_mem(public_data, *public_size); |
361 | | |
362 | 308 | x_size = mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X)); |
363 | 308 | y_size = mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y)); |
364 | 308 | LIBSPDM_ASSERT(x_size <= half_size && y_size <= half_size); |
365 | | |
366 | 308 | ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), |
367 | 308 | &public_data[0 + half_size - x_size], x_size); |
368 | 308 | if (ret != 0) { |
369 | 0 | return false; |
370 | 0 | } |
371 | 308 | ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), |
372 | 308 | &public_data[half_size + half_size - y_size], |
373 | 308 | y_size); |
374 | 308 | if (ret != 0) { |
375 | 0 | return false; |
376 | 0 | } |
377 | | |
378 | 308 | return true; |
379 | 308 | } |
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 | | 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 | 0 | { |
415 | 0 | mbedtls_ecdh_context *ctx; |
416 | 0 | size_t half_size; |
417 | 0 | int ret; |
418 | |
|
419 | 0 | if (ec_context == NULL || peer_public == NULL || key_size == NULL || |
420 | 0 | key == NULL) { |
421 | 0 | return false; |
422 | 0 | } |
423 | | |
424 | 0 | if (peer_public_size > INT_MAX) { |
425 | 0 | return false; |
426 | 0 | } |
427 | | |
428 | 0 | ctx = ec_context; |
429 | 0 | switch (mbedtls_ecdh_get_grp_id(ctx)) { |
430 | 0 | case MBEDTLS_ECP_DP_SECP256R1: |
431 | 0 | half_size = 32; |
432 | 0 | 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 | 0 | } |
442 | 0 | if (peer_public_size != half_size * 2) { |
443 | 0 | return false; |
444 | 0 | } |
445 | | |
446 | 0 | ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Qp).MBEDTLS_PRIVATE(X), |
447 | 0 | peer_public, half_size); |
448 | 0 | if (ret != 0) { |
449 | 0 | return false; |
450 | 0 | } |
451 | 0 | ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(Qp).MBEDTLS_PRIVATE(Y), |
452 | 0 | peer_public + half_size, half_size); |
453 | 0 | if (ret != 0) { |
454 | 0 | return false; |
455 | 0 | } |
456 | 0 | ret = mbedtls_mpi_lset(&ctx->MBEDTLS_PRIVATE(Qp).MBEDTLS_PRIVATE(Z), 1); |
457 | 0 | if (ret != 0) { |
458 | 0 | return false; |
459 | 0 | } |
460 | | |
461 | 0 | ret = mbedtls_ecdh_compute_shared(&ctx->MBEDTLS_PRIVATE(grp), |
462 | 0 | &ctx->MBEDTLS_PRIVATE(z), |
463 | 0 | &ctx->MBEDTLS_PRIVATE(Qp), |
464 | 0 | &ctx->MBEDTLS_PRIVATE(d), |
465 | 0 | libspdm_myrand, NULL); |
466 | 0 | if (ret != 0) { |
467 | 0 | return false; |
468 | 0 | } |
469 | | |
470 | 0 | if (mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(z)) > *key_size) { |
471 | 0 | return false; |
472 | 0 | } |
473 | | |
474 | 0 | *key_size = ctx->MBEDTLS_PRIVATE(grp).pbits / 8 + |
475 | 0 | ((ctx->MBEDTLS_PRIVATE(grp).pbits % 8) != 0); |
476 | 0 | ret = mbedtls_mpi_write_binary(&ctx->MBEDTLS_PRIVATE(z), key, *key_size); |
477 | 0 | if (ret != 0) { |
478 | 0 | return false; |
479 | 0 | } |
480 | | |
481 | 0 | return true; |
482 | 0 | } |
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 | | 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 | 210 | { |
517 | 210 | int ret; |
518 | 210 | mbedtls_ecdh_context *ctx; |
519 | 210 | mbedtls_mpi bn_r; |
520 | 210 | mbedtls_mpi bn_s; |
521 | 210 | size_t r_size; |
522 | 210 | size_t s_size; |
523 | 210 | size_t half_size; |
524 | | |
525 | 210 | if (ec_context == NULL || message_hash == NULL) { |
526 | 0 | return false; |
527 | 0 | } |
528 | | |
529 | 210 | if (signature == NULL) { |
530 | 0 | return false; |
531 | 0 | } |
532 | | |
533 | 210 | ctx = ec_context; |
534 | 210 | switch (mbedtls_ecdh_get_grp_id(ctx)) { |
535 | 210 | case MBEDTLS_ECP_DP_SECP256R1: |
536 | 210 | half_size = 32; |
537 | 210 | 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 | 210 | } |
547 | 210 | if (*sig_size < (size_t)(half_size * 2)) { |
548 | 0 | *sig_size = half_size * 2; |
549 | 0 | return false; |
550 | 0 | } |
551 | 210 | *sig_size = half_size * 2; |
552 | 210 | libspdm_zero_mem(signature, *sig_size); |
553 | | |
554 | 210 | switch (hash_nid) { |
555 | 210 | case LIBSPDM_CRYPTO_NID_SHA256: |
556 | 210 | if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { |
557 | 0 | return false; |
558 | 0 | } |
559 | 210 | break; |
560 | | |
561 | 210 | case LIBSPDM_CRYPTO_NID_SHA384: |
562 | 0 | if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { |
563 | 0 | return false; |
564 | 0 | } |
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 | 0 | } |
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 | 0 | } |
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 | 0 | } |
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 | 0 | } |
589 | 0 | break; |
590 | | |
591 | 0 | default: |
592 | 0 | return false; |
593 | 210 | } |
594 | | |
595 | 210 | mbedtls_mpi_init(&bn_r); |
596 | 210 | mbedtls_mpi_init(&bn_s); |
597 | | |
598 | 210 | ret = mbedtls_ecdsa_sign(&ctx->MBEDTLS_PRIVATE(grp), &bn_r, &bn_s, |
599 | 210 | &ctx->MBEDTLS_PRIVATE(d), message_hash, |
600 | 210 | hash_size, libspdm_myrand, NULL); |
601 | 210 | if (ret != 0) { |
602 | 0 | return false; |
603 | 0 | } |
604 | | |
605 | 210 | r_size = mbedtls_mpi_size(&bn_r); |
606 | 210 | s_size = mbedtls_mpi_size(&bn_s); |
607 | 210 | LIBSPDM_ASSERT(r_size <= half_size && s_size <= half_size); |
608 | | |
609 | 210 | ret = mbedtls_mpi_write_binary( |
610 | 210 | &bn_r, &signature[0 + half_size - r_size], r_size); |
611 | 210 | if (ret != 0) { |
612 | 0 | mbedtls_mpi_free(&bn_r); |
613 | 0 | mbedtls_mpi_free(&bn_s); |
614 | 0 | return false; |
615 | 0 | } |
616 | 210 | ret = mbedtls_mpi_write_binary( |
617 | 210 | &bn_s, &signature[half_size + half_size - s_size], s_size); |
618 | 210 | if (ret != 0) { |
619 | 0 | mbedtls_mpi_free(&bn_r); |
620 | 0 | mbedtls_mpi_free(&bn_s); |
621 | 0 | return false; |
622 | 0 | } |
623 | | |
624 | 210 | mbedtls_mpi_free(&bn_r); |
625 | 210 | mbedtls_mpi_free(&bn_s); |
626 | | |
627 | 210 | return true; |
628 | 210 | } |
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 | | 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 | 8 | { |
657 | 8 | int ret; |
658 | 8 | mbedtls_ecdh_context *ctx; |
659 | 8 | mbedtls_mpi bn_r; |
660 | 8 | mbedtls_mpi bn_s; |
661 | 8 | size_t half_size; |
662 | | |
663 | 8 | if (ec_context == NULL || message_hash == NULL || signature == NULL) { |
664 | 0 | return false; |
665 | 0 | } |
666 | | |
667 | 8 | if (sig_size > INT_MAX || sig_size == 0) { |
668 | 0 | return false; |
669 | 0 | } |
670 | | |
671 | 8 | ctx = ec_context; |
672 | 8 | switch (mbedtls_ecdh_get_grp_id(ctx)) { |
673 | 8 | case MBEDTLS_ECP_DP_SECP256R1: |
674 | 8 | half_size = 32; |
675 | 8 | 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 | 8 | } |
685 | 8 | if (sig_size != (size_t)(half_size * 2)) { |
686 | 0 | return false; |
687 | 0 | } |
688 | | |
689 | 8 | switch (hash_nid) { |
690 | 8 | case LIBSPDM_CRYPTO_NID_SHA256: |
691 | 8 | if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { |
692 | 0 | return false; |
693 | 0 | } |
694 | 8 | break; |
695 | | |
696 | 8 | case LIBSPDM_CRYPTO_NID_SHA384: |
697 | 0 | if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { |
698 | 0 | return false; |
699 | 0 | } |
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 | 0 | } |
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 | 0 | } |
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 | 0 | } |
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 | 0 | } |
724 | 0 | break; |
725 | | |
726 | 0 | default: |
727 | 0 | return false; |
728 | 8 | } |
729 | | |
730 | 8 | mbedtls_mpi_init(&bn_r); |
731 | 8 | mbedtls_mpi_init(&bn_s); |
732 | | |
733 | 8 | ret = mbedtls_mpi_read_binary(&bn_r, signature, half_size); |
734 | 8 | if (ret != 0) { |
735 | 0 | mbedtls_mpi_free(&bn_r); |
736 | 0 | mbedtls_mpi_free(&bn_s); |
737 | 0 | return false; |
738 | 0 | } |
739 | 8 | ret = mbedtls_mpi_read_binary(&bn_s, signature + half_size, half_size); |
740 | 8 | if (ret != 0) { |
741 | 0 | mbedtls_mpi_free(&bn_r); |
742 | 0 | mbedtls_mpi_free(&bn_s); |
743 | 0 | return false; |
744 | 0 | } |
745 | | |
746 | 8 | ret = mbedtls_ecdsa_verify(&ctx->MBEDTLS_PRIVATE(grp), message_hash, |
747 | 8 | hash_size, &ctx->MBEDTLS_PRIVATE(Q), |
748 | 8 | &bn_r, &bn_s); |
749 | 8 | mbedtls_mpi_free(&bn_r); |
750 | 8 | mbedtls_mpi_free(&bn_s); |
751 | | |
752 | 8 | if (ret != 0) { |
753 | 6 | return false; |
754 | 6 | } |
755 | | |
756 | 2 | return true; |
757 | 8 | } |
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 | | 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 | | if (ec_context == NULL || message_hash == NULL) { |
790 | | return false; |
791 | | } |
792 | | |
793 | | if (signature == NULL) { |
794 | | return false; |
795 | | } |
796 | | |
797 | | ctx = ec_context; |
798 | | switch (mbedtls_ecdh_get_grp_id(ctx)) { |
799 | | case MBEDTLS_ECP_DP_SECP256R1: |
800 | | half_size = 32; |
801 | | break; |
802 | | case MBEDTLS_ECP_DP_SECP384R1: |
803 | | half_size = 48; |
804 | | break; |
805 | | case MBEDTLS_ECP_DP_SECP521R1: |
806 | | half_size = 66; |
807 | | break; |
808 | | default: |
809 | | return false; |
810 | | } |
811 | | if (*sig_size < (size_t)(half_size * 2)) { |
812 | | *sig_size = half_size * 2; |
813 | | return false; |
814 | | } |
815 | | *sig_size = half_size * 2; |
816 | | libspdm_zero_mem(signature, *sig_size); |
817 | | |
818 | | switch (hash_nid) { |
819 | | case LIBSPDM_CRYPTO_NID_SHA256: |
820 | | if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { |
821 | | return false; |
822 | | } |
823 | | break; |
824 | | |
825 | | case LIBSPDM_CRYPTO_NID_SHA384: |
826 | | if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { |
827 | | return false; |
828 | | } |
829 | | break; |
830 | | |
831 | | case LIBSPDM_CRYPTO_NID_SHA512: |
832 | | if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { |
833 | | return false; |
834 | | } |
835 | | break; |
836 | | |
837 | | case LIBSPDM_CRYPTO_NID_SHA3_256: |
838 | | if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) { |
839 | | return false; |
840 | | } |
841 | | break; |
842 | | |
843 | | case LIBSPDM_CRYPTO_NID_SHA3_384: |
844 | | if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) { |
845 | | return false; |
846 | | } |
847 | | break; |
848 | | |
849 | | case LIBSPDM_CRYPTO_NID_SHA3_512: |
850 | | if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) { |
851 | | return false; |
852 | | } |
853 | | break; |
854 | | |
855 | | default: |
856 | | return false; |
857 | | } |
858 | | |
859 | | mbedtls_mpi_init(&bn_r); |
860 | | mbedtls_mpi_init(&bn_s); |
861 | | |
862 | | /*retrieve random number*/ |
863 | | ret = mbedtls_ecdsa_sign(&ctx->MBEDTLS_PRIVATE(grp), &bn_r, &bn_s, |
864 | | &ctx->MBEDTLS_PRIVATE(d), message_hash, |
865 | | hash_size, random_func, NULL); |
866 | | if (ret != 0) { |
867 | | return false; |
868 | | } |
869 | | |
870 | | r_size = mbedtls_mpi_size(&bn_r); |
871 | | s_size = mbedtls_mpi_size(&bn_s); |
872 | | LIBSPDM_ASSERT(r_size <= half_size && s_size <= half_size); |
873 | | |
874 | | ret = mbedtls_mpi_write_binary( |
875 | | &bn_r, &signature[0 + half_size - r_size], r_size); |
876 | | if (ret != 0) { |
877 | | mbedtls_mpi_free(&bn_r); |
878 | | mbedtls_mpi_free(&bn_s); |
879 | | return false; |
880 | | } |
881 | | ret = mbedtls_mpi_write_binary( |
882 | | &bn_s, &signature[half_size + half_size - s_size], s_size); |
883 | | if (ret != 0) { |
884 | | mbedtls_mpi_free(&bn_r); |
885 | | mbedtls_mpi_free(&bn_s); |
886 | | return false; |
887 | | } |
888 | | |
889 | | mbedtls_mpi_free(&bn_r); |
890 | | mbedtls_mpi_free(&bn_s); |
891 | | |
892 | | return true; |
893 | | } |
894 | | #endif/*LIBSPDM_FIPS_MODE*/ |