]>
Commit | Line | Data |
---|---|---|
988e4d8f YL |
1 | /** @file\r |
2 | Elliptic Curve and ECDH API implementation based on OpenSSL\r | |
3 | \r | |
4 | Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r | |
5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
6 | \r | |
7 | **/\r | |
8 | \r | |
9 | #include "InternalCryptLib.h"\r | |
10 | #include <openssl/objects.h>\r | |
11 | #include <openssl/bn.h>\r | |
12 | #include <openssl/ec.h>\r | |
13 | \r | |
14 | // =====================================================================================\r | |
15 | // Basic Elliptic Curve Primitives\r | |
16 | // =====================================================================================\r | |
17 | \r | |
18 | /**\r | |
19 | Return the Nid of certain ECC curve.\r | |
20 | \r | |
21 | @param[in] CryptoNid Identifying number for the ECC curve (Defined in\r | |
22 | BaseCryptLib.h).\r | |
23 | \r | |
24 | @retval !=-1 On success.\r | |
25 | @retval -1 ECC curve not supported.\r | |
26 | **/\r | |
27 | STATIC\r | |
28 | INT32\r | |
29 | CryptoNidToOpensslNid (\r | |
30 | IN UINTN CryptoNid\r | |
31 | )\r | |
32 | {\r | |
33 | INT32 Nid;\r | |
34 | \r | |
35 | switch (CryptoNid) {\r | |
36 | case CRYPTO_NID_SECP256R1:\r | |
37 | Nid = NID_X9_62_prime256v1;\r | |
38 | break;\r | |
39 | case CRYPTO_NID_SECP384R1:\r | |
40 | Nid = NID_secp384r1;\r | |
41 | break;\r | |
42 | case CRYPTO_NID_SECP521R1:\r | |
43 | Nid = NID_secp521r1;\r | |
44 | break;\r | |
45 | default:\r | |
46 | return -1;\r | |
47 | }\r | |
48 | \r | |
49 | return Nid;\r | |
50 | }\r | |
51 | \r | |
52 | /**\r | |
53 | Initialize new opaque EcGroup object. This object represents an EC curve and\r | |
54 | and is used for calculation within this group. This object should be freed\r | |
55 | using EcGroupFree() function.\r | |
56 | \r | |
57 | @param[in] CryptoNid Identifying number for the ECC curve (Defined in\r | |
58 | BaseCryptLib.h).\r | |
59 | \r | |
60 | @retval EcGroup object On success.\r | |
61 | @retval NULL On failure.\r | |
62 | **/\r | |
63 | VOID *\r | |
64 | EFIAPI\r | |
65 | EcGroupInit (\r | |
66 | IN UINTN CryptoNid\r | |
67 | )\r | |
68 | {\r | |
69 | INT32 Nid;\r | |
70 | \r | |
71 | Nid = CryptoNidToOpensslNid (CryptoNid);\r | |
72 | \r | |
73 | if (Nid < 0) {\r | |
74 | return NULL;\r | |
75 | }\r | |
76 | \r | |
77 | return EC_GROUP_new_by_curve_name (Nid);\r | |
78 | }\r | |
79 | \r | |
80 | /**\r | |
81 | Get EC curve parameters. While elliptic curve equation is Y^2 mod P = (X^3 + AX + B) Mod P.\r | |
82 | This function will set the provided Big Number objects to the corresponding\r | |
83 | values. The caller needs to make sure all the "out" BigNumber parameters\r | |
84 | are properly initialized.\r | |
85 | \r | |
86 | @param[in] EcGroup EC group object.\r | |
87 | @param[out] BnPrime Group prime number.\r | |
88 | @param[out] BnA A coefficient.\r | |
89 | @param[out] BnB B coefficient..\r | |
90 | @param[in] BnCtx BN context.\r | |
91 | \r | |
92 | @retval TRUE On success.\r | |
93 | @retval FALSE Otherwise.\r | |
94 | **/\r | |
95 | BOOLEAN\r | |
96 | EFIAPI\r | |
97 | EcGroupGetCurve (\r | |
98 | IN CONST VOID *EcGroup,\r | |
99 | OUT VOID *BnPrime,\r | |
100 | OUT VOID *BnA,\r | |
101 | OUT VOID *BnB,\r | |
102 | IN VOID *BnCtx\r | |
103 | )\r | |
104 | {\r | |
105 | return (BOOLEAN)EC_GROUP_get_curve (EcGroup, BnPrime, BnA, BnB, BnCtx);\r | |
106 | }\r | |
107 | \r | |
108 | /**\r | |
109 | Get EC group order.\r | |
110 | This function will set the provided Big Number object to the corresponding\r | |
111 | value. The caller needs to make sure that the "out" BigNumber parameter\r | |
112 | is properly initialized.\r | |
113 | \r | |
114 | @param[in] EcGroup EC group object.\r | |
115 | @param[out] BnOrder Group prime number.\r | |
116 | \r | |
117 | @retval TRUE On success.\r | |
118 | @retval FALSE Otherwise.\r | |
119 | **/\r | |
120 | BOOLEAN\r | |
121 | EFIAPI\r | |
122 | EcGroupGetOrder (\r | |
123 | IN VOID *EcGroup,\r | |
124 | OUT VOID *BnOrder\r | |
125 | )\r | |
126 | {\r | |
127 | return (BOOLEAN)EC_GROUP_get_order (EcGroup, BnOrder, NULL);\r | |
128 | }\r | |
129 | \r | |
130 | /**\r | |
131 | Free previously allocated EC group object using EcGroupInit().\r | |
132 | \r | |
133 | @param[in] EcGroup EC group object to free.\r | |
134 | **/\r | |
135 | VOID\r | |
136 | EFIAPI\r | |
137 | EcGroupFree (\r | |
138 | IN VOID *EcGroup\r | |
139 | )\r | |
140 | {\r | |
141 | EC_GROUP_free (EcGroup);\r | |
142 | }\r | |
143 | \r | |
144 | /**\r | |
145 | Initialize new opaque EC Point object. This object represents an EC point\r | |
146 | within the given EC group (curve).\r | |
147 | \r | |
148 | @param[in] EC Group, properly initialized using EcGroupInit().\r | |
149 | \r | |
150 | @retval EC Point object On success.\r | |
151 | @retval NULL On failure.\r | |
152 | **/\r | |
153 | VOID *\r | |
154 | EFIAPI\r | |
155 | EcPointInit (\r | |
156 | IN CONST VOID *EcGroup\r | |
157 | )\r | |
158 | {\r | |
159 | return EC_POINT_new (EcGroup);\r | |
160 | }\r | |
161 | \r | |
162 | /**\r | |
163 | Free previously allocated EC Point object using EcPointInit().\r | |
164 | \r | |
165 | @param[in] EcPoint EC Point to free.\r | |
166 | @param[in] Clear TRUE iff the memory should be cleared.\r | |
167 | **/\r | |
168 | VOID\r | |
169 | EFIAPI\r | |
170 | EcPointDeInit (\r | |
171 | IN VOID *EcPoint,\r | |
172 | IN BOOLEAN Clear\r | |
173 | )\r | |
174 | {\r | |
175 | if (Clear) {\r | |
176 | EC_POINT_clear_free (EcPoint);\r | |
177 | } else {\r | |
178 | EC_POINT_free (EcPoint);\r | |
179 | }\r | |
180 | }\r | |
181 | \r | |
182 | /**\r | |
183 | Get EC point affine (x,y) coordinates.\r | |
184 | This function will set the provided Big Number objects to the corresponding\r | |
185 | values. The caller needs to make sure all the "out" BigNumber parameters\r | |
186 | are properly initialized.\r | |
187 | \r | |
188 | @param[in] EcGroup EC group object.\r | |
189 | @param[in] EcPoint EC point object.\r | |
190 | @param[out] BnX X coordinate.\r | |
191 | @param[out] BnY Y coordinate.\r | |
192 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
193 | \r | |
194 | @retval TRUE On success.\r | |
195 | @retval FALSE Otherwise.\r | |
196 | **/\r | |
197 | BOOLEAN\r | |
198 | EFIAPI\r | |
199 | EcPointGetAffineCoordinates (\r | |
200 | IN CONST VOID *EcGroup,\r | |
201 | IN CONST VOID *EcPoint,\r | |
202 | OUT VOID *BnX,\r | |
203 | OUT VOID *BnY,\r | |
204 | IN VOID *BnCtx\r | |
205 | )\r | |
206 | {\r | |
207 | return (BOOLEAN)EC_POINT_get_affine_coordinates (EcGroup, EcPoint, BnX, BnY, BnCtx);\r | |
208 | }\r | |
209 | \r | |
210 | /**\r | |
211 | Set EC point affine (x,y) coordinates.\r | |
212 | \r | |
213 | @param[in] EcGroup EC group object.\r | |
214 | @param[in] EcPoint EC point object.\r | |
215 | @param[in] BnX X coordinate.\r | |
216 | @param[in] BnY Y coordinate.\r | |
217 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
218 | \r | |
219 | @retval TRUE On success.\r | |
220 | @retval FALSE Otherwise.\r | |
221 | **/\r | |
222 | BOOLEAN\r | |
223 | EFIAPI\r | |
224 | EcPointSetAffineCoordinates (\r | |
225 | IN CONST VOID *EcGroup,\r | |
226 | IN VOID *EcPoint,\r | |
227 | IN CONST VOID *BnX,\r | |
228 | IN CONST VOID *BnY,\r | |
229 | IN VOID *BnCtx\r | |
230 | )\r | |
231 | {\r | |
232 | return (BOOLEAN)EC_POINT_set_affine_coordinates (EcGroup, EcPoint, BnX, BnY, BnCtx);\r | |
233 | }\r | |
234 | \r | |
235 | /**\r | |
236 | EC Point addition. EcPointResult = EcPointA + EcPointB.\r | |
237 | \r | |
238 | @param[in] EcGroup EC group object.\r | |
239 | @param[out] EcPointResult EC point to hold the result. The point should\r | |
240 | be properly initialized.\r | |
241 | @param[in] EcPointA EC Point.\r | |
242 | @param[in] EcPointB EC Point.\r | |
243 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
244 | \r | |
245 | @retval TRUE On success.\r | |
246 | @retval FALSE Otherwise.\r | |
247 | **/\r | |
248 | BOOLEAN\r | |
249 | EFIAPI\r | |
250 | EcPointAdd (\r | |
251 | IN CONST VOID *EcGroup,\r | |
252 | OUT VOID *EcPointResult,\r | |
253 | IN CONST VOID *EcPointA,\r | |
254 | IN CONST VOID *EcPointB,\r | |
255 | IN VOID *BnCtx\r | |
256 | )\r | |
257 | {\r | |
258 | return (BOOLEAN)EC_POINT_add (EcGroup, EcPointResult, EcPointA, EcPointB, BnCtx);\r | |
259 | }\r | |
260 | \r | |
261 | /**\r | |
262 | Variable EC point multiplication. EcPointResult = EcPoint * BnPScalar.\r | |
263 | \r | |
264 | @param[in] EcGroup EC group object.\r | |
265 | @param[out] EcPointResult EC point to hold the result. The point should\r | |
266 | be properly initialized.\r | |
267 | @param[in] EcPoint EC Point.\r | |
268 | @param[in] BnPScalar P Scalar.\r | |
269 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
270 | \r | |
271 | @retval TRUE On success.\r | |
272 | @retval FALSE Otherwise.\r | |
273 | **/\r | |
274 | BOOLEAN\r | |
275 | EFIAPI\r | |
276 | EcPointMul (\r | |
277 | IN CONST VOID *EcGroup,\r | |
278 | OUT VOID *EcPointResult,\r | |
279 | IN CONST VOID *EcPoint,\r | |
280 | IN CONST VOID *BnPScalar,\r | |
281 | IN VOID *BnCtx\r | |
282 | )\r | |
283 | {\r | |
284 | return (BOOLEAN)EC_POINT_mul (EcGroup, EcPointResult, NULL, EcPoint, BnPScalar, BnCtx);\r | |
285 | }\r | |
286 | \r | |
287 | /**\r | |
288 | Calculate the inverse of the supplied EC point.\r | |
289 | \r | |
290 | @param[in] EcGroup EC group object.\r | |
291 | @param[in,out] EcPoint EC point to invert.\r | |
292 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
293 | \r | |
294 | @retval TRUE On success.\r | |
295 | @retval FALSE Otherwise.\r | |
296 | **/\r | |
297 | BOOLEAN\r | |
298 | EFIAPI\r | |
299 | EcPointInvert (\r | |
300 | IN CONST VOID *EcGroup,\r | |
301 | IN OUT VOID *EcPoint,\r | |
302 | IN VOID *BnCtx\r | |
303 | )\r | |
304 | {\r | |
305 | return (BOOLEAN)EC_POINT_invert (EcGroup, EcPoint, BnCtx);\r | |
306 | }\r | |
307 | \r | |
308 | /**\r | |
309 | Check if the supplied point is on EC curve.\r | |
310 | \r | |
311 | @param[in] EcGroup EC group object.\r | |
312 | @param[in] EcPoint EC point to check.\r | |
313 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
314 | \r | |
315 | @retval TRUE On curve.\r | |
316 | @retval FALSE Otherwise.\r | |
317 | **/\r | |
318 | BOOLEAN\r | |
319 | EFIAPI\r | |
320 | EcPointIsOnCurve (\r | |
321 | IN CONST VOID *EcGroup,\r | |
322 | IN CONST VOID *EcPoint,\r | |
323 | IN VOID *BnCtx\r | |
324 | )\r | |
325 | {\r | |
326 | return EC_POINT_is_on_curve (EcGroup, EcPoint, BnCtx) == 1;\r | |
327 | }\r | |
328 | \r | |
329 | /**\r | |
330 | Check if the supplied point is at infinity.\r | |
331 | \r | |
332 | @param[in] EcGroup EC group object.\r | |
333 | @param[in] EcPoint EC point to check.\r | |
334 | \r | |
335 | @retval TRUE At infinity.\r | |
336 | @retval FALSE Otherwise.\r | |
337 | **/\r | |
338 | BOOLEAN\r | |
339 | EFIAPI\r | |
340 | EcPointIsAtInfinity (\r | |
341 | IN CONST VOID *EcGroup,\r | |
342 | IN CONST VOID *EcPoint\r | |
343 | )\r | |
344 | {\r | |
345 | return EC_POINT_is_at_infinity (EcGroup, EcPoint) == 1;\r | |
346 | }\r | |
347 | \r | |
348 | /**\r | |
349 | Check if EC points are equal.\r | |
350 | \r | |
351 | @param[in] EcGroup EC group object.\r | |
352 | @param[in] EcPointA EC point A.\r | |
353 | @param[in] EcPointB EC point B.\r | |
354 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
355 | \r | |
356 | @retval TRUE A == B.\r | |
357 | @retval FALSE Otherwise.\r | |
358 | **/\r | |
359 | BOOLEAN\r | |
360 | EFIAPI\r | |
361 | EcPointEqual (\r | |
362 | IN CONST VOID *EcGroup,\r | |
363 | IN CONST VOID *EcPointA,\r | |
364 | IN CONST VOID *EcPointB,\r | |
365 | IN VOID *BnCtx\r | |
366 | )\r | |
367 | {\r | |
368 | return EC_POINT_cmp (EcGroup, EcPointA, EcPointB, BnCtx) == 0;\r | |
369 | }\r | |
370 | \r | |
371 | /**\r | |
372 | Set EC point compressed coordinates. Points can be described in terms of\r | |
373 | their compressed coordinates. For a point (x, y), for any given value for x\r | |
374 | such that the point is on the curve there will only ever be two possible\r | |
375 | values for y. Therefore, a point can be set using this function where BnX is\r | |
376 | the x coordinate and YBit is a value 0 or 1 to identify which of the two\r | |
377 | possible values for y should be used.\r | |
378 | \r | |
379 | @param[in] EcGroup EC group object.\r | |
380 | @param[in] EcPoint EC Point.\r | |
381 | @param[in] BnX X coordinate.\r | |
382 | @param[in] YBit 0 or 1 to identify which Y value is used.\r | |
383 | @param[in] BnCtx BN context, created with BigNumNewContext().\r | |
384 | \r | |
385 | @retval TRUE On success.\r | |
386 | @retval FALSE Otherwise.\r | |
387 | **/\r | |
388 | BOOLEAN\r | |
389 | EFIAPI\r | |
390 | EcPointSetCompressedCoordinates (\r | |
391 | IN CONST VOID *EcGroup,\r | |
392 | IN VOID *EcPoint,\r | |
393 | IN CONST VOID *BnX,\r | |
394 | IN UINT8 YBit,\r | |
395 | IN VOID *BnCtx\r | |
396 | )\r | |
397 | {\r | |
398 | return (BOOLEAN)EC_POINT_set_compressed_coordinates (EcGroup, EcPoint, BnX, YBit, BnCtx);\r | |
399 | }\r | |
400 | \r | |
401 | // =====================================================================================\r | |
402 | // Elliptic Curve Diffie Hellman Primitives\r | |
403 | // =====================================================================================\r | |
404 | \r | |
405 | /**\r | |
406 | Allocates and Initializes one Elliptic Curve Context for subsequent use\r | |
407 | with the NID.\r | |
408 | \r | |
409 | @param[in] Nid Identifying number for the ECC curve (Defined in\r | |
410 | BaseCryptLib.h).\r | |
411 | @return Pointer to the Elliptic Curve Context that has been initialized.\r | |
412 | If the allocations fails, EcNewByNid() returns NULL.\r | |
413 | **/\r | |
414 | VOID *\r | |
415 | EFIAPI\r | |
416 | EcNewByNid (\r | |
417 | IN UINTN Nid\r | |
418 | )\r | |
419 | {\r | |
420 | INT32 OpenSslNid;\r | |
421 | \r | |
422 | OpenSslNid = CryptoNidToOpensslNid (Nid);\r | |
423 | if (OpenSslNid < 0) {\r | |
424 | return NULL;\r | |
425 | }\r | |
426 | \r | |
427 | return (VOID *)EC_KEY_new_by_curve_name (OpenSslNid);\r | |
428 | }\r | |
429 | \r | |
430 | /**\r | |
431 | Release the specified EC context.\r | |
432 | \r | |
433 | @param[in] EcContext Pointer to the EC context to be released.\r | |
434 | **/\r | |
435 | VOID\r | |
436 | EFIAPI\r | |
437 | EcFree (\r | |
438 | IN VOID *EcContext\r | |
439 | )\r | |
440 | {\r | |
441 | EC_KEY_free ((EC_KEY *)EcContext);\r | |
442 | }\r | |
443 | \r | |
444 | /**\r | |
445 | Generates EC key and returns EC public key (X, Y), Please note, this function uses\r | |
446 | pseudo random number generator. The caller must make sure RandomSeed()\r | |
447 | function was properly called before.\r | |
448 | The Ec context should be correctly initialized by EcNewByNid.\r | |
449 | This function generates random secret, and computes the public key (X, Y), which is\r | |
450 | returned via parameter Public, PublicSize.\r | |
451 | X is the first half of Public with size being PublicSize / 2,\r | |
452 | Y is the second half of Public with size being PublicSize / 2.\r | |
453 | EC context is updated accordingly.\r | |
454 | If the Public buffer is too small to hold the public X, Y, FALSE is returned and\r | |
455 | PublicSize is set to the required buffer size to obtain the public X, Y.\r | |
456 | For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte is Y.\r | |
457 | For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte is Y.\r | |
458 | For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte is Y.\r | |
459 | If EcContext is NULL, then return FALSE.\r | |
460 | If PublicSize is NULL, then return FALSE.\r | |
461 | If PublicSize is large enough but Public is NULL, then return FALSE.\r | |
462 | @param[in, out] EcContext Pointer to the EC context.\r | |
463 | @param[out] PublicKey Pointer to t buffer to receive generated public X,Y.\r | |
464 | @param[in, out] PublicKeySize On input, the size of Public buffer in bytes.\r | |
465 | On output, the size of data returned in Public buffer in bytes.\r | |
466 | @retval TRUE EC public X,Y generation succeeded.\r | |
467 | @retval FALSE EC public X,Y generation failed.\r | |
468 | @retval FALSE PublicKeySize is not large enough.\r | |
469 | **/\r | |
470 | BOOLEAN\r | |
471 | EFIAPI\r | |
472 | EcGenerateKey (\r | |
473 | IN OUT VOID *EcContext,\r | |
474 | OUT UINT8 *PublicKey,\r | |
475 | IN OUT UINTN *PublicKeySize\r | |
476 | )\r | |
477 | {\r | |
478 | EC_KEY *EcKey;\r | |
479 | CONST EC_GROUP *Group;\r | |
480 | CONST EC_POINT *EcPoint;\r | |
481 | BOOLEAN RetVal;\r | |
482 | BIGNUM *BnX;\r | |
483 | BIGNUM *BnY;\r | |
484 | UINTN HalfSize;\r | |
485 | INTN XSize;\r | |
486 | INTN YSize;\r | |
487 | \r | |
488 | if ((EcContext == NULL) || (PublicKeySize == NULL)) {\r | |
489 | return FALSE;\r | |
490 | }\r | |
491 | \r | |
492 | if ((PublicKey == NULL) && (*PublicKeySize != 0)) {\r | |
493 | return FALSE;\r | |
494 | }\r | |
495 | \r | |
496 | EcKey = (EC_KEY *)EcContext;\r | |
497 | Group = EC_KEY_get0_group (EcKey);\r | |
498 | HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;\r | |
499 | \r | |
500 | // Assume RAND_seed was called\r | |
501 | if (EC_KEY_generate_key (EcKey) != 1) {\r | |
502 | return FALSE;\r | |
503 | }\r | |
504 | \r | |
505 | if (*PublicKeySize < HalfSize * 2) {\r | |
506 | *PublicKeySize = HalfSize * 2;\r | |
507 | return FALSE;\r | |
508 | }\r | |
509 | \r | |
510 | *PublicKeySize = HalfSize * 2;\r | |
511 | \r | |
512 | EcPoint = EC_KEY_get0_public_key (EcKey);\r | |
513 | if (EcPoint == NULL) {\r | |
514 | return FALSE;\r | |
515 | }\r | |
516 | \r | |
517 | RetVal = FALSE;\r | |
518 | BnX = BN_new ();\r | |
519 | BnY = BN_new ();\r | |
520 | if ((BnX == NULL) || (BnY == NULL)) {\r | |
521 | goto fail;\r | |
522 | }\r | |
523 | \r | |
524 | if (EC_POINT_get_affine_coordinates (Group, EcPoint, BnX, BnY, NULL) != 1) {\r | |
525 | goto fail;\r | |
526 | }\r | |
527 | \r | |
528 | XSize = BN_num_bytes (BnX);\r | |
529 | YSize = BN_num_bytes (BnY);\r | |
530 | if ((XSize <= 0) || (YSize <= 0)) {\r | |
531 | goto fail;\r | |
532 | }\r | |
533 | \r | |
534 | ASSERT ((UINTN)XSize <= HalfSize && (UINTN)YSize <= HalfSize);\r | |
535 | \r | |
536 | ZeroMem (PublicKey, *PublicKeySize);\r | |
537 | BN_bn2bin (BnX, &PublicKey[0 + HalfSize - XSize]);\r | |
538 | BN_bn2bin (BnY, &PublicKey[HalfSize + HalfSize - YSize]);\r | |
539 | \r | |
540 | RetVal = TRUE;\r | |
541 | \r | |
542 | fail:\r | |
543 | BN_free (BnX);\r | |
544 | BN_free (BnY);\r | |
545 | return RetVal;\r | |
546 | }\r | |
547 | \r | |
548 | /**\r | |
549 | Gets the public key component from the established EC context.\r | |
550 | The Ec context should be correctly initialized by EcNewByNid, and successfully\r | |
551 | generate key pair from EcGenerateKey().\r | |
552 | For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte is Y.\r | |
553 | For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte is Y.\r | |
554 | For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte is Y.\r | |
555 | @param[in, out] EcContext Pointer to EC context being set.\r | |
556 | @param[out] PublicKey Pointer to t buffer to receive generated public X,Y.\r | |
557 | @param[in, out] PublicKeySize On input, the size of Public buffer in bytes.\r | |
558 | On output, the size of data returned in Public buffer in bytes.\r | |
559 | @retval TRUE EC key component was retrieved successfully.\r | |
560 | @retval FALSE Invalid EC key component.\r | |
561 | **/\r | |
562 | BOOLEAN\r | |
563 | EFIAPI\r | |
564 | EcGetPubKey (\r | |
565 | IN OUT VOID *EcContext,\r | |
566 | OUT UINT8 *PublicKey,\r | |
567 | IN OUT UINTN *PublicKeySize\r | |
568 | )\r | |
569 | {\r | |
570 | EC_KEY *EcKey;\r | |
571 | CONST EC_GROUP *Group;\r | |
572 | CONST EC_POINT *EcPoint;\r | |
573 | BIGNUM *BnX;\r | |
574 | BIGNUM *BnY;\r | |
575 | UINTN HalfSize;\r | |
576 | INTN XSize;\r | |
577 | INTN YSize;\r | |
578 | BOOLEAN RetVal;\r | |
579 | \r | |
580 | if ((EcContext == NULL) || (PublicKeySize == NULL)) {\r | |
581 | return FALSE;\r | |
582 | }\r | |
583 | \r | |
584 | if ((PublicKey == NULL) && (*PublicKeySize != 0)) {\r | |
585 | return FALSE;\r | |
586 | }\r | |
587 | \r | |
588 | EcKey = (EC_KEY *)EcContext;\r | |
589 | Group = EC_KEY_get0_group (EcKey);\r | |
590 | HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;\r | |
591 | if (*PublicKeySize < HalfSize * 2) {\r | |
592 | *PublicKeySize = HalfSize * 2;\r | |
593 | return FALSE;\r | |
594 | }\r | |
595 | \r | |
596 | *PublicKeySize = HalfSize * 2;\r | |
597 | \r | |
598 | EcPoint = EC_KEY_get0_public_key (EcKey);\r | |
599 | if (EcPoint == NULL) {\r | |
600 | return FALSE;\r | |
601 | }\r | |
602 | \r | |
603 | RetVal = FALSE;\r | |
604 | BnX = BN_new ();\r | |
605 | BnY = BN_new ();\r | |
606 | if ((BnX == NULL) || (BnY == NULL)) {\r | |
607 | goto fail;\r | |
608 | }\r | |
609 | \r | |
610 | if (EC_POINT_get_affine_coordinates (Group, EcPoint, BnX, BnY, NULL) != 1) {\r | |
611 | goto fail;\r | |
612 | }\r | |
613 | \r | |
614 | XSize = BN_num_bytes (BnX);\r | |
615 | YSize = BN_num_bytes (BnY);\r | |
616 | if ((XSize <= 0) || (YSize <= 0)) {\r | |
617 | goto fail;\r | |
618 | }\r | |
619 | \r | |
620 | ASSERT ((UINTN)XSize <= HalfSize && (UINTN)YSize <= HalfSize);\r | |
621 | \r | |
622 | if (PublicKey != NULL) {\r | |
623 | ZeroMem (PublicKey, *PublicKeySize);\r | |
624 | BN_bn2bin (BnX, &PublicKey[0 + HalfSize - XSize]);\r | |
625 | BN_bn2bin (BnY, &PublicKey[HalfSize + HalfSize - YSize]);\r | |
626 | }\r | |
627 | \r | |
628 | RetVal = TRUE;\r | |
629 | \r | |
630 | fail:\r | |
631 | BN_free (BnX);\r | |
632 | BN_free (BnY);\r | |
633 | return RetVal;\r | |
634 | }\r | |
635 | \r | |
636 | /**\r | |
637 | Computes exchanged common key.\r | |
638 | Given peer's public key (X, Y), this function computes the exchanged common key,\r | |
639 | based on its own context including value of curve parameter and random secret.\r | |
640 | X is the first half of PeerPublic with size being PeerPublicSize / 2,\r | |
641 | Y is the second half of PeerPublic with size being PeerPublicSize / 2.\r | |
642 | If public key is compressed, the PeerPublic will only contain half key (X).\r | |
643 | If EcContext is NULL, then return FALSE.\r | |
644 | If PeerPublic is NULL, then return FALSE.\r | |
645 | If PeerPublicSize is 0, then return FALSE.\r | |
646 | If Key is NULL, then return FALSE.\r | |
647 | If KeySize is not large enough, then return FALSE.\r | |
648 | For P-256, the PeerPublicSize is 64. First 32-byte is X, Second 32-byte is Y.\r | |
649 | For P-384, the PeerPublicSize is 96. First 48-byte is X, Second 48-byte is Y.\r | |
650 | For P-521, the PeerPublicSize is 132. First 66-byte is X, Second 66-byte is Y.\r | |
651 | @param[in, out] EcContext Pointer to the EC context.\r | |
652 | @param[in] PeerPublic Pointer to the peer's public X,Y.\r | |
653 | @param[in] PeerPublicSize Size of peer's public X,Y in bytes.\r | |
654 | @param[in] CompressFlag Flag of PeerPublic is compressed or not.\r | |
655 | @param[out] Key Pointer to the buffer to receive generated key.\r | |
656 | @param[in, out] KeySize On input, the size of Key buffer in bytes.\r | |
657 | On output, the size of data returned in Key buffer in bytes.\r | |
658 | @retval TRUE EC exchanged key generation succeeded.\r | |
659 | @retval FALSE EC exchanged key generation failed.\r | |
660 | @retval FALSE KeySize is not large enough.\r | |
661 | **/\r | |
662 | BOOLEAN\r | |
663 | EFIAPI\r | |
664 | EcDhComputeKey (\r | |
665 | IN OUT VOID *EcContext,\r | |
666 | IN CONST UINT8 *PeerPublic,\r | |
667 | IN UINTN PeerPublicSize,\r | |
668 | IN CONST INT32 *CompressFlag,\r | |
669 | OUT UINT8 *Key,\r | |
670 | IN OUT UINTN *KeySize\r | |
671 | )\r | |
672 | {\r | |
673 | EC_KEY *EcKey;\r | |
674 | EC_KEY *PeerEcKey;\r | |
675 | CONST EC_GROUP *Group;\r | |
676 | BOOLEAN RetVal;\r | |
677 | BIGNUM *BnX;\r | |
678 | BIGNUM *BnY;\r | |
679 | EC_POINT *Point;\r | |
680 | INT32 OpenSslNid;\r | |
681 | UINTN HalfSize;\r | |
682 | \r | |
683 | if ((EcContext == NULL) || (PeerPublic == NULL) || (KeySize == NULL)) {\r | |
684 | return FALSE;\r | |
685 | }\r | |
686 | \r | |
687 | if ((Key == NULL) && (*KeySize != 0)) {\r | |
688 | return FALSE;\r | |
689 | }\r | |
690 | \r | |
691 | if (PeerPublicSize > INT_MAX) {\r | |
692 | return FALSE;\r | |
693 | }\r | |
694 | \r | |
695 | EcKey = (EC_KEY *)EcContext;\r | |
696 | Group = EC_KEY_get0_group (EcKey);\r | |
697 | HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;\r | |
698 | if ((CompressFlag == NULL) && (PeerPublicSize != HalfSize * 2)) {\r | |
699 | return FALSE;\r | |
700 | }\r | |
701 | \r | |
702 | if ((CompressFlag != NULL) && (PeerPublicSize != HalfSize)) {\r | |
703 | return FALSE;\r | |
704 | }\r | |
705 | \r | |
706 | if (*KeySize < HalfSize) {\r | |
707 | *KeySize = HalfSize;\r | |
708 | return FALSE;\r | |
709 | }\r | |
710 | \r | |
711 | *KeySize = HalfSize;\r | |
712 | \r | |
713 | RetVal = FALSE;\r | |
714 | Point = NULL;\r | |
715 | BnX = BN_bin2bn (PeerPublic, (INT32)HalfSize, NULL);\r | |
716 | BnY = NULL;\r | |
717 | Point = EC_POINT_new (Group);\r | |
718 | PeerEcKey = NULL;\r | |
719 | if ((BnX == NULL) || (Point == NULL)) {\r | |
720 | goto fail;\r | |
721 | }\r | |
722 | \r | |
723 | if (CompressFlag == NULL) {\r | |
724 | BnY = BN_bin2bn (PeerPublic + HalfSize, (INT32)HalfSize, NULL);\r | |
725 | if (BnY == NULL) {\r | |
726 | goto fail;\r | |
727 | }\r | |
728 | \r | |
729 | if (EC_POINT_set_affine_coordinates (Group, Point, BnX, BnY, NULL) != 1) {\r | |
730 | goto fail;\r | |
731 | }\r | |
732 | } else {\r | |
733 | if (EC_POINT_set_compressed_coordinates (Group, Point, BnX, *CompressFlag, NULL) != 1) {\r | |
734 | goto fail;\r | |
735 | }\r | |
736 | }\r | |
737 | \r | |
738 | // Validate NIST ECDH public key\r | |
739 | OpenSslNid = EC_GROUP_get_curve_name (Group);\r | |
740 | PeerEcKey = EC_KEY_new_by_curve_name (OpenSslNid);\r | |
741 | if (PeerEcKey == NULL) {\r | |
742 | goto fail;\r | |
743 | }\r | |
744 | \r | |
745 | if (EC_KEY_set_public_key (PeerEcKey, Point) != 1) {\r | |
746 | goto fail;\r | |
747 | }\r | |
748 | \r | |
749 | if (EC_KEY_check_key (PeerEcKey) != 1) {\r | |
750 | goto fail;\r | |
751 | }\r | |
752 | \r | |
753 | if (ECDH_compute_key (Key, *KeySize, Point, EcKey, NULL) <= 0) {\r | |
754 | goto fail;\r | |
755 | }\r | |
756 | \r | |
757 | RetVal = TRUE;\r | |
758 | \r | |
759 | fail:\r | |
760 | BN_free (BnX);\r | |
761 | BN_free (BnY);\r | |
762 | EC_POINT_free (Point);\r | |
763 | EC_KEY_free (PeerEcKey);\r | |
764 | return RetVal;\r | |
765 | }\r | |
f21a1d48 QZ |
766 | \r |
767 | /**\r | |
768 | Carries out the EC-DSA signature.\r | |
769 | \r | |
770 | This function carries out the EC-DSA signature.\r | |
771 | If the Signature buffer is too small to hold the contents of signature, FALSE\r | |
772 | is returned and SigSize is set to the required buffer size to obtain the signature.\r | |
773 | \r | |
774 | If EcContext is NULL, then return FALSE.\r | |
775 | If MessageHash is NULL, then return FALSE.\r | |
776 | If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.\r | |
777 | If SigSize is large enough but Signature is NULL, then return FALSE.\r | |
778 | \r | |
779 | For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.\r | |
780 | For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.\r | |
781 | For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.\r | |
782 | \r | |
783 | @param[in] EcContext Pointer to EC context for signature generation.\r | |
784 | @param[in] HashNid hash NID\r | |
785 | @param[in] MessageHash Pointer to octet message hash to be signed.\r | |
786 | @param[in] HashSize Size of the message hash in bytes.\r | |
787 | @param[out] Signature Pointer to buffer to receive EC-DSA signature.\r | |
788 | @param[in, out] SigSize On input, the size of Signature buffer in bytes.\r | |
789 | On output, the size of data returned in Signature buffer in bytes.\r | |
790 | \r | |
791 | @retval TRUE Signature successfully generated in EC-DSA.\r | |
792 | @retval FALSE Signature generation failed.\r | |
793 | @retval FALSE SigSize is too small.\r | |
794 | \r | |
795 | **/\r | |
796 | BOOLEAN\r | |
797 | EFIAPI\r | |
798 | EcDsaSign (\r | |
799 | IN VOID *EcContext,\r | |
800 | IN UINTN HashNid,\r | |
801 | IN CONST UINT8 *MessageHash,\r | |
802 | IN UINTN HashSize,\r | |
803 | OUT UINT8 *Signature,\r | |
804 | IN OUT UINTN *SigSize\r | |
805 | )\r | |
806 | {\r | |
807 | EC_KEY *EcKey;\r | |
808 | ECDSA_SIG *EcDsaSig;\r | |
809 | INT32 OpenSslNid;\r | |
810 | UINT8 HalfSize;\r | |
811 | BIGNUM *R;\r | |
812 | BIGNUM *S;\r | |
813 | INTN RSize;\r | |
814 | INTN SSize;\r | |
815 | \r | |
816 | if ((EcContext == NULL) || (MessageHash == NULL)) {\r | |
817 | return FALSE;\r | |
818 | }\r | |
819 | \r | |
820 | if (Signature == NULL) {\r | |
821 | return FALSE;\r | |
822 | }\r | |
823 | \r | |
824 | EcKey = (EC_KEY *)EcContext;\r | |
825 | OpenSslNid = EC_GROUP_get_curve_name (EC_KEY_get0_group (EcKey));\r | |
826 | switch (OpenSslNid) {\r | |
827 | case NID_X9_62_prime256v1:\r | |
828 | HalfSize = 32;\r | |
829 | break;\r | |
830 | case NID_secp384r1:\r | |
831 | HalfSize = 48;\r | |
832 | break;\r | |
833 | case NID_secp521r1:\r | |
834 | HalfSize = 66;\r | |
835 | break;\r | |
836 | default:\r | |
837 | return FALSE;\r | |
838 | }\r | |
839 | \r | |
840 | if (*SigSize < (UINTN)(HalfSize * 2)) {\r | |
841 | *SigSize = HalfSize * 2;\r | |
842 | return FALSE;\r | |
843 | }\r | |
844 | \r | |
845 | *SigSize = HalfSize * 2;\r | |
846 | ZeroMem (Signature, *SigSize);\r | |
847 | \r | |
848 | switch (HashNid) {\r | |
849 | case CRYPTO_NID_SHA256:\r | |
850 | if (HashSize != SHA256_DIGEST_SIZE) {\r | |
851 | return FALSE;\r | |
852 | }\r | |
853 | \r | |
854 | break;\r | |
855 | \r | |
856 | case CRYPTO_NID_SHA384:\r | |
857 | if (HashSize != SHA384_DIGEST_SIZE) {\r | |
858 | return FALSE;\r | |
859 | }\r | |
860 | \r | |
861 | break;\r | |
862 | \r | |
863 | case CRYPTO_NID_SHA512:\r | |
864 | if (HashSize != SHA512_DIGEST_SIZE) {\r | |
865 | return FALSE;\r | |
866 | }\r | |
867 | \r | |
868 | break;\r | |
869 | \r | |
870 | default:\r | |
871 | return FALSE;\r | |
872 | }\r | |
873 | \r | |
874 | EcDsaSig = ECDSA_do_sign (\r | |
875 | MessageHash,\r | |
876 | (UINT32)HashSize,\r | |
877 | (EC_KEY *)EcContext\r | |
878 | );\r | |
879 | if (EcDsaSig == NULL) {\r | |
880 | return FALSE;\r | |
881 | }\r | |
882 | \r | |
883 | ECDSA_SIG_get0 (EcDsaSig, (CONST BIGNUM **)&R, (CONST BIGNUM **)&S);\r | |
884 | \r | |
885 | RSize = BN_num_bytes (R);\r | |
886 | SSize = BN_num_bytes (S);\r | |
887 | if ((RSize <= 0) || (SSize <= 0)) {\r | |
888 | ECDSA_SIG_free (EcDsaSig);\r | |
889 | return FALSE;\r | |
890 | }\r | |
891 | \r | |
892 | ASSERT ((UINTN)RSize <= HalfSize && (UINTN)SSize <= HalfSize);\r | |
893 | \r | |
894 | BN_bn2bin (R, &Signature[0 + HalfSize - RSize]);\r | |
895 | BN_bn2bin (S, &Signature[HalfSize + HalfSize - SSize]);\r | |
896 | \r | |
897 | ECDSA_SIG_free (EcDsaSig);\r | |
898 | \r | |
899 | return TRUE;\r | |
900 | }\r | |
901 | \r | |
902 | /**\r | |
903 | Verifies the EC-DSA signature.\r | |
904 | \r | |
905 | If EcContext is NULL, then return FALSE.\r | |
906 | If MessageHash is NULL, then return FALSE.\r | |
907 | If Signature is NULL, then return FALSE.\r | |
908 | If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.\r | |
909 | \r | |
910 | For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.\r | |
911 | For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.\r | |
912 | For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.\r | |
913 | \r | |
914 | @param[in] EcContext Pointer to EC context for signature verification.\r | |
915 | @param[in] HashNid hash NID\r | |
916 | @param[in] MessageHash Pointer to octet message hash to be checked.\r | |
917 | @param[in] HashSize Size of the message hash in bytes.\r | |
918 | @param[in] Signature Pointer to EC-DSA signature to be verified.\r | |
919 | @param[in] SigSize Size of signature in bytes.\r | |
920 | \r | |
921 | @retval TRUE Valid signature encoded in EC-DSA.\r | |
922 | @retval FALSE Invalid signature or invalid EC context.\r | |
923 | \r | |
924 | **/\r | |
925 | BOOLEAN\r | |
926 | EFIAPI\r | |
927 | EcDsaVerify (\r | |
928 | IN VOID *EcContext,\r | |
929 | IN UINTN HashNid,\r | |
930 | IN CONST UINT8 *MessageHash,\r | |
931 | IN UINTN HashSize,\r | |
932 | IN CONST UINT8 *Signature,\r | |
933 | IN UINTN SigSize\r | |
934 | )\r | |
935 | {\r | |
936 | INT32 Result;\r | |
937 | EC_KEY *EcKey;\r | |
938 | ECDSA_SIG *EcDsaSig;\r | |
939 | INT32 OpenSslNid;\r | |
940 | UINT8 HalfSize;\r | |
941 | BIGNUM *R;\r | |
942 | BIGNUM *S;\r | |
943 | \r | |
944 | if ((EcContext == NULL) || (MessageHash == NULL) || (Signature == NULL)) {\r | |
945 | return FALSE;\r | |
946 | }\r | |
947 | \r | |
948 | if ((SigSize > INT_MAX) || (SigSize == 0)) {\r | |
949 | return FALSE;\r | |
950 | }\r | |
951 | \r | |
952 | EcKey = (EC_KEY *)EcContext;\r | |
953 | OpenSslNid = EC_GROUP_get_curve_name (EC_KEY_get0_group (EcKey));\r | |
954 | switch (OpenSslNid) {\r | |
955 | case NID_X9_62_prime256v1:\r | |
956 | HalfSize = 32;\r | |
957 | break;\r | |
958 | case NID_secp384r1:\r | |
959 | HalfSize = 48;\r | |
960 | break;\r | |
961 | case NID_secp521r1:\r | |
962 | HalfSize = 66;\r | |
963 | break;\r | |
964 | default:\r | |
965 | return FALSE;\r | |
966 | }\r | |
967 | \r | |
968 | if (SigSize != (UINTN)(HalfSize * 2)) {\r | |
969 | return FALSE;\r | |
970 | }\r | |
971 | \r | |
972 | switch (HashNid) {\r | |
973 | case CRYPTO_NID_SHA256:\r | |
974 | if (HashSize != SHA256_DIGEST_SIZE) {\r | |
975 | return FALSE;\r | |
976 | }\r | |
977 | \r | |
978 | break;\r | |
979 | \r | |
980 | case CRYPTO_NID_SHA384:\r | |
981 | if (HashSize != SHA384_DIGEST_SIZE) {\r | |
982 | return FALSE;\r | |
983 | }\r | |
984 | \r | |
985 | break;\r | |
986 | \r | |
987 | case CRYPTO_NID_SHA512:\r | |
988 | if (HashSize != SHA512_DIGEST_SIZE) {\r | |
989 | return FALSE;\r | |
990 | }\r | |
991 | \r | |
992 | break;\r | |
993 | \r | |
994 | default:\r | |
995 | return FALSE;\r | |
996 | }\r | |
997 | \r | |
998 | EcDsaSig = ECDSA_SIG_new ();\r | |
999 | if (EcDsaSig == NULL) {\r | |
1000 | ECDSA_SIG_free (EcDsaSig);\r | |
1001 | return FALSE;\r | |
1002 | }\r | |
1003 | \r | |
1004 | R = BN_bin2bn (Signature, (UINT32)HalfSize, NULL);\r | |
1005 | S = BN_bin2bn (Signature + HalfSize, (UINT32)HalfSize, NULL);\r | |
1006 | if ((R == NULL) || (S == NULL)) {\r | |
1007 | ECDSA_SIG_free (EcDsaSig);\r | |
1008 | return FALSE;\r | |
1009 | }\r | |
1010 | \r | |
1011 | ECDSA_SIG_set0 (EcDsaSig, R, S);\r | |
1012 | \r | |
1013 | Result = ECDSA_do_verify (\r | |
1014 | MessageHash,\r | |
1015 | (UINT32)HashSize,\r | |
1016 | EcDsaSig,\r | |
1017 | (EC_KEY *)EcContext\r | |
1018 | );\r | |
1019 | \r | |
1020 | ECDSA_SIG_free (EcDsaSig);\r | |
1021 | \r | |
1022 | return (Result == 1);\r | |
1023 | }\r |