]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
CryptoPkg/Library: Cleanup BaseCryptLib and TlsLib
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptEc.c
CommitLineData
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
27STATIC\r
28INT32\r
29CryptoNidToOpensslNid (\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
63VOID *\r
64EFIAPI\r
65EcGroupInit (\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
95BOOLEAN\r
96EFIAPI\r
97EcGroupGetCurve (\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
120BOOLEAN\r
121EFIAPI\r
122EcGroupGetOrder (\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
135VOID\r
136EFIAPI\r
137EcGroupFree (\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
153VOID *\r
154EFIAPI\r
155EcPointInit (\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
168VOID\r
169EFIAPI\r
170EcPointDeInit (\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
197BOOLEAN\r
198EFIAPI\r
199EcPointGetAffineCoordinates (\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
222BOOLEAN\r
223EFIAPI\r
224EcPointSetAffineCoordinates (\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
248BOOLEAN\r
249EFIAPI\r
250EcPointAdd (\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
274BOOLEAN\r
275EFIAPI\r
276EcPointMul (\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
297BOOLEAN\r
298EFIAPI\r
299EcPointInvert (\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
318BOOLEAN\r
319EFIAPI\r
320EcPointIsOnCurve (\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
338BOOLEAN\r
339EFIAPI\r
340EcPointIsAtInfinity (\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
359BOOLEAN\r
360EFIAPI\r
361EcPointEqual (\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
388BOOLEAN\r
389EFIAPI\r
390EcPointSetCompressedCoordinates (\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
414VOID *\r
415EFIAPI\r
416EcNewByNid (\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
435VOID\r
436EFIAPI\r
437EcFree (\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
470BOOLEAN\r
471EFIAPI\r
472EcGenerateKey (\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
542fail:\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
562BOOLEAN\r
563EFIAPI\r
564EcGetPubKey (\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
630fail:\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
662BOOLEAN\r
663EFIAPI\r
664EcDhComputeKey (\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
759fail:\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
796BOOLEAN\r
797EFIAPI\r
798EcDsaSign (\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
925BOOLEAN\r
926EFIAPI\r
927EcDsaVerify (\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