]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
CryptoPkg: Add EC support
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptEc.c
1 /** @file
2 Elliptic Curve and ECDH API implementation based on OpenSSL
3
4 Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "InternalCryptLib.h"
10 #include <openssl/objects.h>
11 #include <openssl/bn.h>
12 #include <openssl/ec.h>
13
14 // =====================================================================================
15 // Basic Elliptic Curve Primitives
16 // =====================================================================================
17
18 /**
19 Return the Nid of certain ECC curve.
20
21 @param[in] CryptoNid Identifying number for the ECC curve (Defined in
22 BaseCryptLib.h).
23
24 @retval !=-1 On success.
25 @retval -1 ECC curve not supported.
26 **/
27 STATIC
28 INT32
29 CryptoNidToOpensslNid (
30 IN UINTN CryptoNid
31 )
32 {
33 INT32 Nid;
34
35 switch (CryptoNid) {
36 case CRYPTO_NID_SECP256R1:
37 Nid = NID_X9_62_prime256v1;
38 break;
39 case CRYPTO_NID_SECP384R1:
40 Nid = NID_secp384r1;
41 break;
42 case CRYPTO_NID_SECP521R1:
43 Nid = NID_secp521r1;
44 break;
45 default:
46 return -1;
47 }
48
49 return Nid;
50 }
51
52 /**
53 Initialize new opaque EcGroup object. This object represents an EC curve and
54 and is used for calculation within this group. This object should be freed
55 using EcGroupFree() function.
56
57 @param[in] CryptoNid Identifying number for the ECC curve (Defined in
58 BaseCryptLib.h).
59
60 @retval EcGroup object On success.
61 @retval NULL On failure.
62 **/
63 VOID *
64 EFIAPI
65 EcGroupInit (
66 IN UINTN CryptoNid
67 )
68 {
69 INT32 Nid;
70
71 Nid = CryptoNidToOpensslNid (CryptoNid);
72
73 if (Nid < 0) {
74 return NULL;
75 }
76
77 return EC_GROUP_new_by_curve_name (Nid);
78 }
79
80 /**
81 Get EC curve parameters. While elliptic curve equation is Y^2 mod P = (X^3 + AX + B) Mod P.
82 This function will set the provided Big Number objects to the corresponding
83 values. The caller needs to make sure all the "out" BigNumber parameters
84 are properly initialized.
85
86 @param[in] EcGroup EC group object.
87 @param[out] BnPrime Group prime number.
88 @param[out] BnA A coefficient.
89 @param[out] BnB B coefficient..
90 @param[in] BnCtx BN context.
91
92 @retval TRUE On success.
93 @retval FALSE Otherwise.
94 **/
95 BOOLEAN
96 EFIAPI
97 EcGroupGetCurve (
98 IN CONST VOID *EcGroup,
99 OUT VOID *BnPrime,
100 OUT VOID *BnA,
101 OUT VOID *BnB,
102 IN VOID *BnCtx
103 )
104 {
105 return (BOOLEAN)EC_GROUP_get_curve (EcGroup, BnPrime, BnA, BnB, BnCtx);
106 }
107
108 /**
109 Get EC group order.
110 This function will set the provided Big Number object to the corresponding
111 value. The caller needs to make sure that the "out" BigNumber parameter
112 is properly initialized.
113
114 @param[in] EcGroup EC group object.
115 @param[out] BnOrder Group prime number.
116
117 @retval TRUE On success.
118 @retval FALSE Otherwise.
119 **/
120 BOOLEAN
121 EFIAPI
122 EcGroupGetOrder (
123 IN VOID *EcGroup,
124 OUT VOID *BnOrder
125 )
126 {
127 return (BOOLEAN)EC_GROUP_get_order (EcGroup, BnOrder, NULL);
128 }
129
130 /**
131 Free previously allocated EC group object using EcGroupInit().
132
133 @param[in] EcGroup EC group object to free.
134 **/
135 VOID
136 EFIAPI
137 EcGroupFree (
138 IN VOID *EcGroup
139 )
140 {
141 EC_GROUP_free (EcGroup);
142 }
143
144 /**
145 Initialize new opaque EC Point object. This object represents an EC point
146 within the given EC group (curve).
147
148 @param[in] EC Group, properly initialized using EcGroupInit().
149
150 @retval EC Point object On success.
151 @retval NULL On failure.
152 **/
153 VOID *
154 EFIAPI
155 EcPointInit (
156 IN CONST VOID *EcGroup
157 )
158 {
159 return EC_POINT_new (EcGroup);
160 }
161
162 /**
163 Free previously allocated EC Point object using EcPointInit().
164
165 @param[in] EcPoint EC Point to free.
166 @param[in] Clear TRUE iff the memory should be cleared.
167 **/
168 VOID
169 EFIAPI
170 EcPointDeInit (
171 IN VOID *EcPoint,
172 IN BOOLEAN Clear
173 )
174 {
175 if (Clear) {
176 EC_POINT_clear_free (EcPoint);
177 } else {
178 EC_POINT_free (EcPoint);
179 }
180 }
181
182 /**
183 Get EC point affine (x,y) coordinates.
184 This function will set the provided Big Number objects to the corresponding
185 values. The caller needs to make sure all the "out" BigNumber parameters
186 are properly initialized.
187
188 @param[in] EcGroup EC group object.
189 @param[in] EcPoint EC point object.
190 @param[out] BnX X coordinate.
191 @param[out] BnY Y coordinate.
192 @param[in] BnCtx BN context, created with BigNumNewContext().
193
194 @retval TRUE On success.
195 @retval FALSE Otherwise.
196 **/
197 BOOLEAN
198 EFIAPI
199 EcPointGetAffineCoordinates (
200 IN CONST VOID *EcGroup,
201 IN CONST VOID *EcPoint,
202 OUT VOID *BnX,
203 OUT VOID *BnY,
204 IN VOID *BnCtx
205 )
206 {
207 return (BOOLEAN)EC_POINT_get_affine_coordinates (EcGroup, EcPoint, BnX, BnY, BnCtx);
208 }
209
210 /**
211 Set EC point affine (x,y) coordinates.
212
213 @param[in] EcGroup EC group object.
214 @param[in] EcPoint EC point object.
215 @param[in] BnX X coordinate.
216 @param[in] BnY Y coordinate.
217 @param[in] BnCtx BN context, created with BigNumNewContext().
218
219 @retval TRUE On success.
220 @retval FALSE Otherwise.
221 **/
222 BOOLEAN
223 EFIAPI
224 EcPointSetAffineCoordinates (
225 IN CONST VOID *EcGroup,
226 IN VOID *EcPoint,
227 IN CONST VOID *BnX,
228 IN CONST VOID *BnY,
229 IN VOID *BnCtx
230 )
231 {
232 return (BOOLEAN)EC_POINT_set_affine_coordinates (EcGroup, EcPoint, BnX, BnY, BnCtx);
233 }
234
235 /**
236 EC Point addition. EcPointResult = EcPointA + EcPointB.
237
238 @param[in] EcGroup EC group object.
239 @param[out] EcPointResult EC point to hold the result. The point should
240 be properly initialized.
241 @param[in] EcPointA EC Point.
242 @param[in] EcPointB EC Point.
243 @param[in] BnCtx BN context, created with BigNumNewContext().
244
245 @retval TRUE On success.
246 @retval FALSE Otherwise.
247 **/
248 BOOLEAN
249 EFIAPI
250 EcPointAdd (
251 IN CONST VOID *EcGroup,
252 OUT VOID *EcPointResult,
253 IN CONST VOID *EcPointA,
254 IN CONST VOID *EcPointB,
255 IN VOID *BnCtx
256 )
257 {
258 return (BOOLEAN)EC_POINT_add (EcGroup, EcPointResult, EcPointA, EcPointB, BnCtx);
259 }
260
261 /**
262 Variable EC point multiplication. EcPointResult = EcPoint * BnPScalar.
263
264 @param[in] EcGroup EC group object.
265 @param[out] EcPointResult EC point to hold the result. The point should
266 be properly initialized.
267 @param[in] EcPoint EC Point.
268 @param[in] BnPScalar P Scalar.
269 @param[in] BnCtx BN context, created with BigNumNewContext().
270
271 @retval TRUE On success.
272 @retval FALSE Otherwise.
273 **/
274 BOOLEAN
275 EFIAPI
276 EcPointMul (
277 IN CONST VOID *EcGroup,
278 OUT VOID *EcPointResult,
279 IN CONST VOID *EcPoint,
280 IN CONST VOID *BnPScalar,
281 IN VOID *BnCtx
282 )
283 {
284 return (BOOLEAN)EC_POINT_mul (EcGroup, EcPointResult, NULL, EcPoint, BnPScalar, BnCtx);
285 }
286
287 /**
288 Calculate the inverse of the supplied EC point.
289
290 @param[in] EcGroup EC group object.
291 @param[in,out] EcPoint EC point to invert.
292 @param[in] BnCtx BN context, created with BigNumNewContext().
293
294 @retval TRUE On success.
295 @retval FALSE Otherwise.
296 **/
297 BOOLEAN
298 EFIAPI
299 EcPointInvert (
300 IN CONST VOID *EcGroup,
301 IN OUT VOID *EcPoint,
302 IN VOID *BnCtx
303 )
304 {
305 return (BOOLEAN)EC_POINT_invert (EcGroup, EcPoint, BnCtx);
306 }
307
308 /**
309 Check if the supplied point is on EC curve.
310
311 @param[in] EcGroup EC group object.
312 @param[in] EcPoint EC point to check.
313 @param[in] BnCtx BN context, created with BigNumNewContext().
314
315 @retval TRUE On curve.
316 @retval FALSE Otherwise.
317 **/
318 BOOLEAN
319 EFIAPI
320 EcPointIsOnCurve (
321 IN CONST VOID *EcGroup,
322 IN CONST VOID *EcPoint,
323 IN VOID *BnCtx
324 )
325 {
326 return EC_POINT_is_on_curve (EcGroup, EcPoint, BnCtx) == 1;
327 }
328
329 /**
330 Check if the supplied point is at infinity.
331
332 @param[in] EcGroup EC group object.
333 @param[in] EcPoint EC point to check.
334
335 @retval TRUE At infinity.
336 @retval FALSE Otherwise.
337 **/
338 BOOLEAN
339 EFIAPI
340 EcPointIsAtInfinity (
341 IN CONST VOID *EcGroup,
342 IN CONST VOID *EcPoint
343 )
344 {
345 return EC_POINT_is_at_infinity (EcGroup, EcPoint) == 1;
346 }
347
348 /**
349 Check if EC points are equal.
350
351 @param[in] EcGroup EC group object.
352 @param[in] EcPointA EC point A.
353 @param[in] EcPointB EC point B.
354 @param[in] BnCtx BN context, created with BigNumNewContext().
355
356 @retval TRUE A == B.
357 @retval FALSE Otherwise.
358 **/
359 BOOLEAN
360 EFIAPI
361 EcPointEqual (
362 IN CONST VOID *EcGroup,
363 IN CONST VOID *EcPointA,
364 IN CONST VOID *EcPointB,
365 IN VOID *BnCtx
366 )
367 {
368 return EC_POINT_cmp (EcGroup, EcPointA, EcPointB, BnCtx) == 0;
369 }
370
371 /**
372 Set EC point compressed coordinates. Points can be described in terms of
373 their compressed coordinates. For a point (x, y), for any given value for x
374 such that the point is on the curve there will only ever be two possible
375 values for y. Therefore, a point can be set using this function where BnX is
376 the x coordinate and YBit is a value 0 or 1 to identify which of the two
377 possible values for y should be used.
378
379 @param[in] EcGroup EC group object.
380 @param[in] EcPoint EC Point.
381 @param[in] BnX X coordinate.
382 @param[in] YBit 0 or 1 to identify which Y value is used.
383 @param[in] BnCtx BN context, created with BigNumNewContext().
384
385 @retval TRUE On success.
386 @retval FALSE Otherwise.
387 **/
388 BOOLEAN
389 EFIAPI
390 EcPointSetCompressedCoordinates (
391 IN CONST VOID *EcGroup,
392 IN VOID *EcPoint,
393 IN CONST VOID *BnX,
394 IN UINT8 YBit,
395 IN VOID *BnCtx
396 )
397 {
398 return (BOOLEAN)EC_POINT_set_compressed_coordinates (EcGroup, EcPoint, BnX, YBit, BnCtx);
399 }
400
401 // =====================================================================================
402 // Elliptic Curve Diffie Hellman Primitives
403 // =====================================================================================
404
405 /**
406 Allocates and Initializes one Elliptic Curve Context for subsequent use
407 with the NID.
408
409 @param[in] Nid Identifying number for the ECC curve (Defined in
410 BaseCryptLib.h).
411 @return Pointer to the Elliptic Curve Context that has been initialized.
412 If the allocations fails, EcNewByNid() returns NULL.
413 **/
414 VOID *
415 EFIAPI
416 EcNewByNid (
417 IN UINTN Nid
418 )
419 {
420 INT32 OpenSslNid;
421
422 OpenSslNid = CryptoNidToOpensslNid (Nid);
423 if (OpenSslNid < 0) {
424 return NULL;
425 }
426
427 return (VOID *)EC_KEY_new_by_curve_name (OpenSslNid);
428 }
429
430 /**
431 Release the specified EC context.
432
433 @param[in] EcContext Pointer to the EC context to be released.
434 **/
435 VOID
436 EFIAPI
437 EcFree (
438 IN VOID *EcContext
439 )
440 {
441 EC_KEY_free ((EC_KEY *)EcContext);
442 }
443
444 /**
445 Generates EC key and returns EC public key (X, Y), Please note, this function uses
446 pseudo random number generator. The caller must make sure RandomSeed()
447 function was properly called before.
448 The Ec context should be correctly initialized by EcNewByNid.
449 This function generates random secret, and computes the public key (X, Y), which is
450 returned via parameter Public, PublicSize.
451 X is the first half of Public with size being PublicSize / 2,
452 Y is the second half of Public with size being PublicSize / 2.
453 EC context is updated accordingly.
454 If the Public buffer is too small to hold the public X, Y, FALSE is returned and
455 PublicSize is set to the required buffer size to obtain the public X, Y.
456 For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte is Y.
457 For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte is Y.
458 For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte is Y.
459 If EcContext is NULL, then return FALSE.
460 If PublicSize is NULL, then return FALSE.
461 If PublicSize is large enough but Public is NULL, then return FALSE.
462 @param[in, out] EcContext Pointer to the EC context.
463 @param[out] PublicKey Pointer to t buffer to receive generated public X,Y.
464 @param[in, out] PublicKeySize On input, the size of Public buffer in bytes.
465 On output, the size of data returned in Public buffer in bytes.
466 @retval TRUE EC public X,Y generation succeeded.
467 @retval FALSE EC public X,Y generation failed.
468 @retval FALSE PublicKeySize is not large enough.
469 **/
470 BOOLEAN
471 EFIAPI
472 EcGenerateKey (
473 IN OUT VOID *EcContext,
474 OUT UINT8 *PublicKey,
475 IN OUT UINTN *PublicKeySize
476 )
477 {
478 EC_KEY *EcKey;
479 CONST EC_GROUP *Group;
480 CONST EC_POINT *EcPoint;
481 BOOLEAN RetVal;
482 BIGNUM *BnX;
483 BIGNUM *BnY;
484 UINTN HalfSize;
485 INTN XSize;
486 INTN YSize;
487
488 if ((EcContext == NULL) || (PublicKeySize == NULL)) {
489 return FALSE;
490 }
491
492 if ((PublicKey == NULL) && (*PublicKeySize != 0)) {
493 return FALSE;
494 }
495
496 EcKey = (EC_KEY *)EcContext;
497 Group = EC_KEY_get0_group (EcKey);
498 HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;
499
500 // Assume RAND_seed was called
501 if (EC_KEY_generate_key (EcKey) != 1) {
502 return FALSE;
503 }
504
505 if (*PublicKeySize < HalfSize * 2) {
506 *PublicKeySize = HalfSize * 2;
507 return FALSE;
508 }
509
510 *PublicKeySize = HalfSize * 2;
511
512 EcPoint = EC_KEY_get0_public_key (EcKey);
513 if (EcPoint == NULL) {
514 return FALSE;
515 }
516
517 RetVal = FALSE;
518 BnX = BN_new ();
519 BnY = BN_new ();
520 if ((BnX == NULL) || (BnY == NULL)) {
521 goto fail;
522 }
523
524 if (EC_POINT_get_affine_coordinates (Group, EcPoint, BnX, BnY, NULL) != 1) {
525 goto fail;
526 }
527
528 XSize = BN_num_bytes (BnX);
529 YSize = BN_num_bytes (BnY);
530 if ((XSize <= 0) || (YSize <= 0)) {
531 goto fail;
532 }
533
534 ASSERT ((UINTN)XSize <= HalfSize && (UINTN)YSize <= HalfSize);
535
536 ZeroMem (PublicKey, *PublicKeySize);
537 BN_bn2bin (BnX, &PublicKey[0 + HalfSize - XSize]);
538 BN_bn2bin (BnY, &PublicKey[HalfSize + HalfSize - YSize]);
539
540 RetVal = TRUE;
541
542 fail:
543 BN_free (BnX);
544 BN_free (BnY);
545 return RetVal;
546 }
547
548 /**
549 Gets the public key component from the established EC context.
550 The Ec context should be correctly initialized by EcNewByNid, and successfully
551 generate key pair from EcGenerateKey().
552 For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte is Y.
553 For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte is Y.
554 For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte is Y.
555 @param[in, out] EcContext Pointer to EC context being set.
556 @param[out] PublicKey Pointer to t buffer to receive generated public X,Y.
557 @param[in, out] PublicKeySize On input, the size of Public buffer in bytes.
558 On output, the size of data returned in Public buffer in bytes.
559 @retval TRUE EC key component was retrieved successfully.
560 @retval FALSE Invalid EC key component.
561 **/
562 BOOLEAN
563 EFIAPI
564 EcGetPubKey (
565 IN OUT VOID *EcContext,
566 OUT UINT8 *PublicKey,
567 IN OUT UINTN *PublicKeySize
568 )
569 {
570 EC_KEY *EcKey;
571 CONST EC_GROUP *Group;
572 CONST EC_POINT *EcPoint;
573 BIGNUM *BnX;
574 BIGNUM *BnY;
575 UINTN HalfSize;
576 INTN XSize;
577 INTN YSize;
578 BOOLEAN RetVal;
579
580 if ((EcContext == NULL) || (PublicKeySize == NULL)) {
581 return FALSE;
582 }
583
584 if ((PublicKey == NULL) && (*PublicKeySize != 0)) {
585 return FALSE;
586 }
587
588 EcKey = (EC_KEY *)EcContext;
589 Group = EC_KEY_get0_group (EcKey);
590 HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;
591 if (*PublicKeySize < HalfSize * 2) {
592 *PublicKeySize = HalfSize * 2;
593 return FALSE;
594 }
595
596 *PublicKeySize = HalfSize * 2;
597
598 EcPoint = EC_KEY_get0_public_key (EcKey);
599 if (EcPoint == NULL) {
600 return FALSE;
601 }
602
603 RetVal = FALSE;
604 BnX = BN_new ();
605 BnY = BN_new ();
606 if ((BnX == NULL) || (BnY == NULL)) {
607 goto fail;
608 }
609
610 if (EC_POINT_get_affine_coordinates (Group, EcPoint, BnX, BnY, NULL) != 1) {
611 goto fail;
612 }
613
614 XSize = BN_num_bytes (BnX);
615 YSize = BN_num_bytes (BnY);
616 if ((XSize <= 0) || (YSize <= 0)) {
617 goto fail;
618 }
619
620 ASSERT ((UINTN)XSize <= HalfSize && (UINTN)YSize <= HalfSize);
621
622 if (PublicKey != NULL) {
623 ZeroMem (PublicKey, *PublicKeySize);
624 BN_bn2bin (BnX, &PublicKey[0 + HalfSize - XSize]);
625 BN_bn2bin (BnY, &PublicKey[HalfSize + HalfSize - YSize]);
626 }
627
628 RetVal = TRUE;
629
630 fail:
631 BN_free (BnX);
632 BN_free (BnY);
633 return RetVal;
634 }
635
636 /**
637 Computes exchanged common key.
638 Given peer's public key (X, Y), this function computes the exchanged common key,
639 based on its own context including value of curve parameter and random secret.
640 X is the first half of PeerPublic with size being PeerPublicSize / 2,
641 Y is the second half of PeerPublic with size being PeerPublicSize / 2.
642 If public key is compressed, the PeerPublic will only contain half key (X).
643 If EcContext is NULL, then return FALSE.
644 If PeerPublic is NULL, then return FALSE.
645 If PeerPublicSize is 0, then return FALSE.
646 If Key is NULL, then return FALSE.
647 If KeySize is not large enough, then return FALSE.
648 For P-256, the PeerPublicSize is 64. First 32-byte is X, Second 32-byte is Y.
649 For P-384, the PeerPublicSize is 96. First 48-byte is X, Second 48-byte is Y.
650 For P-521, the PeerPublicSize is 132. First 66-byte is X, Second 66-byte is Y.
651 @param[in, out] EcContext Pointer to the EC context.
652 @param[in] PeerPublic Pointer to the peer's public X,Y.
653 @param[in] PeerPublicSize Size of peer's public X,Y in bytes.
654 @param[in] CompressFlag Flag of PeerPublic is compressed or not.
655 @param[out] Key Pointer to the buffer to receive generated key.
656 @param[in, out] KeySize On input, the size of Key buffer in bytes.
657 On output, the size of data returned in Key buffer in bytes.
658 @retval TRUE EC exchanged key generation succeeded.
659 @retval FALSE EC exchanged key generation failed.
660 @retval FALSE KeySize is not large enough.
661 **/
662 BOOLEAN
663 EFIAPI
664 EcDhComputeKey (
665 IN OUT VOID *EcContext,
666 IN CONST UINT8 *PeerPublic,
667 IN UINTN PeerPublicSize,
668 IN CONST INT32 *CompressFlag,
669 OUT UINT8 *Key,
670 IN OUT UINTN *KeySize
671 )
672 {
673 EC_KEY *EcKey;
674 EC_KEY *PeerEcKey;
675 CONST EC_GROUP *Group;
676 BOOLEAN RetVal;
677 BIGNUM *BnX;
678 BIGNUM *BnY;
679 EC_POINT *Point;
680 INT32 OpenSslNid;
681 UINTN HalfSize;
682
683 if ((EcContext == NULL) || (PeerPublic == NULL) || (KeySize == NULL)) {
684 return FALSE;
685 }
686
687 if ((Key == NULL) && (*KeySize != 0)) {
688 return FALSE;
689 }
690
691 if (PeerPublicSize > INT_MAX) {
692 return FALSE;
693 }
694
695 EcKey = (EC_KEY *)EcContext;
696 Group = EC_KEY_get0_group (EcKey);
697 HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;
698 if ((CompressFlag == NULL) && (PeerPublicSize != HalfSize * 2)) {
699 return FALSE;
700 }
701
702 if ((CompressFlag != NULL) && (PeerPublicSize != HalfSize)) {
703 return FALSE;
704 }
705
706 if (*KeySize < HalfSize) {
707 *KeySize = HalfSize;
708 return FALSE;
709 }
710
711 *KeySize = HalfSize;
712
713 RetVal = FALSE;
714 Point = NULL;
715 BnX = BN_bin2bn (PeerPublic, (INT32)HalfSize, NULL);
716 BnY = NULL;
717 Point = EC_POINT_new (Group);
718 PeerEcKey = NULL;
719 if ((BnX == NULL) || (Point == NULL)) {
720 goto fail;
721 }
722
723 if (CompressFlag == NULL) {
724 BnY = BN_bin2bn (PeerPublic + HalfSize, (INT32)HalfSize, NULL);
725 if (BnY == NULL) {
726 goto fail;
727 }
728
729 if (EC_POINT_set_affine_coordinates (Group, Point, BnX, BnY, NULL) != 1) {
730 goto fail;
731 }
732 } else {
733 if (EC_POINT_set_compressed_coordinates (Group, Point, BnX, *CompressFlag, NULL) != 1) {
734 goto fail;
735 }
736 }
737
738 // Validate NIST ECDH public key
739 OpenSslNid = EC_GROUP_get_curve_name (Group);
740 PeerEcKey = EC_KEY_new_by_curve_name (OpenSslNid);
741 if (PeerEcKey == NULL) {
742 goto fail;
743 }
744
745 if (EC_KEY_set_public_key (PeerEcKey, Point) != 1) {
746 goto fail;
747 }
748
749 if (EC_KEY_check_key (PeerEcKey) != 1) {
750 goto fail;
751 }
752
753 if (ECDH_compute_key (Key, *KeySize, Point, EcKey, NULL) <= 0) {
754 goto fail;
755 }
756
757 RetVal = TRUE;
758
759 fail:
760 BN_free (BnX);
761 BN_free (BnY);
762 EC_POINT_free (Point);
763 EC_KEY_free (PeerEcKey);
764 return RetVal;
765 }