1 /* Microsoft Reference Implementation for TPM 2.0
2  *
3  *  The copyright in this software is being made available under the BSD License,
4  *  included below. This software may be subject to other third party and
5  *  contributor rights, including patent rights, and no such rights are granted
6  *  under this license.
7  *
8  *  Copyright (c) Microsoft Corporation
9  *
10  *  All rights reserved.
11  *
12  *  BSD License
13  *
14  *  Redistribution and use in source and binary forms, with or without modification,
15  *  are permitted provided that the following conditions are met:
16  *
17  *  Redistributions of source code must retain the above copyright notice, this list
18  *  of conditions and the following disclaimer.
19  *
20  *  Redistributions in binary form must reproduce the above copyright notice, this
21  *  list of conditions and the following disclaimer in the documentation and/or
22  *  other materials provided with the distribution.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28  *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 //** Introduction
36 // The functions in this file provide the low-level interface between the TPM code
37 // and the big number and elliptic curve math routines in OpenSSL.
38 //
39 // Most math on big numbers require a context. The context contains the memory in
40 // which OpenSSL creates and manages the big number values. When a OpenSSL math
41 // function will be called that modifies a BIGNUM value, that value must be created in
42 // an OpenSSL context. The first line of code in such a function must be:
43 // OSSL_ENTER(); and the last operation before returning must be OSSL_LEAVE().
44 // OpenSSL variables can then be created with BnNewVariable(). Constant values to be
45 // used by OpenSSL are created from the bigNum values passed to the functions in this
46 // file. Space for the BIGNUM control block is allocated in the stack of the
47 // function and then it is initialized by calling BigInitialized(). That function
48 // sets up the values in the BIGNUM structure and sets the data pointer to point to
49 // the data in the bignum_t. This is only used when the value is known to be a
50 // constant in the called function.
51 //
52 // Because the allocations of constants is on the local stack and the
53 // OSSL_ENTER()/OSSL_LEAVE() pair flushes everything created in OpenSSL memory, there
54 // should be no chance of a memory leak.
55 
56 //** Includes and Defines
57 #include "Tpm.h"
58 
59 #ifdef MATH_LIB_OSSL
60 #include "TpmToOsslMath_fp.h"
61 
62 //** Functions
63 
64 //*** OsslToTpmBn()
65 // This function converts an OpenSSL BIGNUM to a TPM bignum. In this implementation
66 // it is assumed that OpenSSL uses a different control structure but the same data
67 // layout -- an array of native-endian words in little-endian order.
68 //  Return Type: BOOL
69 //      TRUE(1)         success
70 //      FALSE(0)        failure because value will not fit or OpenSSL variable doesn't
71 //                      exist
72 BOOL
OsslToTpmBn(bigNum bn,BIGNUM * osslBn)73 OsslToTpmBn(
74     bigNum          bn,
75     BIGNUM          *osslBn
76     )
77 {
78     VERIFY(osslBn != NULL);
79     // If the bn is NULL, it means that an output value pointer was NULL meaning that
80     // the results is simply to be discarded.
81     if(bn != NULL)
82     {
83         int         i;
84     //
85         VERIFY((unsigned)osslBn->width <= BnGetAllocated(bn));
86         for(i = 0; i < osslBn->width; i++)
87             bn->d[i] = osslBn->d[i];
88         BnSetTop(bn, osslBn->width);
89     }
90     return TRUE;
91 Error:
92     return FALSE;
93 }
94 
95 //*** BigInitialized()
96 // This function initializes an OSSL BIGNUM from a TPM bigConst. Do not use this for
97 // values that are passed to OpenSLL when they are not declared as const in the
98 // function prototype. Instead, use BnNewVariable().
99 BIGNUM *
BigInitialized(BIGNUM * toInit,bigConst initializer)100 BigInitialized(
101     BIGNUM             *toInit,
102     bigConst            initializer
103     )
104 {
105     if(initializer == NULL)
106         FAIL(FATAL_ERROR_PARAMETER);
107     if(toInit == NULL || initializer == NULL)
108         return NULL;
109     toInit->d = (BN_ULONG *)&initializer->d[0];
110     toInit->dmax = (int)initializer->allocated;
111     toInit->width = (int)initializer->size;
112     toInit->neg = 0;
113     toInit->flags = 0;
114     return toInit;
115 }
116 
117 #ifndef OSSL_DEBUG
118 #   define BIGNUM_PRINT(label, bn, eol)
119 #   define DEBUG_PRINT(x)
120 #else
121 #   define DEBUG_PRINT(x)   printf("%s", x)
122 #   define BIGNUM_PRINT(label, bn, eol) BIGNUM_print((label), (bn), (eol))
123 
124 //*** BIGNUM_print()
125 static void
BIGNUM_print(const char * label,const BIGNUM * a,BOOL eol)126 BIGNUM_print(
127     const char      *label,
128     const BIGNUM    *a,
129     BOOL             eol
130     )
131 {
132     BN_ULONG        *d;
133     int              i;
134     int              notZero = FALSE;
135 
136     if(label != NULL)
137         printf("%s", label);
138     if(a == NULL)
139     {
140         printf("NULL");
141         goto done;
142     }
143     if (a->neg)
144         printf("-");
145     for(i = a->top, d = &a->d[i - 1]; i > 0; i--)
146     {
147         int         j;
148         BN_ULONG    l = *d--;
149         for(j = BN_BITS2 - 8; j >= 0; j -= 8)
150         {
151             BYTE    b = (BYTE)((l >> j) & 0xFF);
152             notZero = notZero || (b != 0);
153             if(notZero)
154                 printf("%02x", b);
155         }
156         if(!notZero)
157             printf("0");
158     }
159 done:
160     if(eol)
161         printf("\n");
162     return;
163 }
164 #endif
165 
166 //*** BnNewVariable()
167 // This function allocates a new variable in the provided context. If the context
168 // does not exist or the allocation fails, it is a catastrophic failure.
169 static BIGNUM *
BnNewVariable(BN_CTX * CTX)170 BnNewVariable(
171     BN_CTX          *CTX
172 )
173 {
174     BIGNUM          *new;
175 //
176     // This check is intended to protect against calling this function without
177     // having initialized the CTX.
178     if((CTX == NULL) || ((new = BN_CTX_get(CTX)) == NULL))
179         FAIL(FATAL_ERROR_ALLOCATION);
180     return new;
181 }
182 
183 #if LIBRARY_COMPATIBILITY_CHECK
184 
185 //*** MathLibraryCompatibilityCheck()
186 BOOL
MathLibraryCompatibilityCheck(void)187 MathLibraryCompatibilityCheck(
188     void
189     )
190 {
191     OSSL_ENTER();
192     BIGNUM              *osslTemp = BnNewVariable(CTX);
193     crypt_uword_t        i;
194     BYTE                 test[] = {0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18,
195                                    0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
196                                    0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
197                                    0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
198     BN_VAR(tpmTemp, sizeof(test) * 8); // allocate some space for a test value
199 //
200     // Convert the test data to a bigNum
201     BnFromBytes(tpmTemp, test, sizeof(test));
202     // Convert the test data to an OpenSSL BIGNUM
203     BN_bin2bn(test, sizeof(test), osslTemp);
204     // Make sure the values are consistent
205     VERIFY(osslTemp->width == (int)tpmTemp->size);
206     for(i = 0; i < tpmTemp->size; i++)
207         VERIFY(osslTemp->d[i] == tpmTemp->d[i]);
208     OSSL_LEAVE();
209     return 1;
210 Error:
211     return 0;
212 }
213 #endif
214 
215 //*** BnModMult()
216 // This function does a modular multiply. It first does a multiply and then a divide
217 // and returns the remainder of the divide.
218 //  Return Type: BOOL
219 //      TRUE(1)         success
220 //      FALSE(0)        failure in operation
221 LIB_EXPORT BOOL
BnModMult(bigNum result,bigConst op1,bigConst op2,bigConst modulus)222 BnModMult(
223     bigNum              result,
224     bigConst            op1,
225     bigConst            op2,
226     bigConst            modulus
227     )
228 {
229     OSSL_ENTER();
230     BOOL                OK = TRUE;
231     BIGNUM              *bnResult = BN_NEW();
232     BIGNUM              *bnTemp = BN_NEW();
233     BIG_INITIALIZED(bnOp1, op1);
234     BIG_INITIALIZED(bnOp2, op2);
235     BIG_INITIALIZED(bnMod, modulus);
236 //
237     VERIFY(BN_mul(bnTemp, bnOp1, bnOp2, CTX));
238     VERIFY(BN_div(NULL, bnResult, bnTemp, bnMod, CTX));
239     VERIFY(OsslToTpmBn(result, bnResult));
240     goto Exit;
241 Error:
242     OK = FALSE;
243 Exit:
244     OSSL_LEAVE();
245     return OK;
246 }
247 
248 //*** BnMult()
249 // Multiplies two numbers
250 //  Return Type: BOOL
251 //      TRUE(1)         success
252 //      FALSE(0)        failure in operation
253 LIB_EXPORT BOOL
BnMult(bigNum result,bigConst multiplicand,bigConst multiplier)254 BnMult(
255     bigNum               result,
256     bigConst             multiplicand,
257     bigConst             multiplier
258     )
259 {
260     OSSL_ENTER();
261     BIGNUM              *bnTemp = BN_NEW();
262     BOOL                 OK = TRUE;
263     BIG_INITIALIZED(bnA, multiplicand);
264     BIG_INITIALIZED(bnB, multiplier);
265 //
266     VERIFY(BN_mul(bnTemp, bnA, bnB, CTX));
267     VERIFY(OsslToTpmBn(result, bnTemp));
268     goto Exit;
269 Error:
270     OK = FALSE;
271 Exit:
272     OSSL_LEAVE();
273     return OK;
274 }
275 
276 //*** BnDiv()
277 // This function divides two bigNum values. The function returns FALSE if
278 // there is an error in the operation.
279 //  Return Type: BOOL
280 //      TRUE(1)         success
281 //      FALSE(0)        failure in operation
282 LIB_EXPORT BOOL
BnDiv(bigNum quotient,bigNum remainder,bigConst dividend,bigConst divisor)283 BnDiv(
284     bigNum               quotient,
285     bigNum               remainder,
286     bigConst             dividend,
287     bigConst             divisor
288     )
289 {
290     OSSL_ENTER();
291     BIGNUM              *bnQ = BN_NEW();
292     BIGNUM              *bnR = BN_NEW();
293     BOOL                 OK = TRUE;
294     BIG_INITIALIZED(bnDend, dividend);
295     BIG_INITIALIZED(bnSor, divisor);
296 //
297     if(BnEqualZero(divisor))
298         FAIL(FATAL_ERROR_DIVIDE_ZERO);
299     VERIFY(BN_div(bnQ, bnR, bnDend, bnSor, CTX));
300     VERIFY(OsslToTpmBn(quotient, bnQ));
301     VERIFY(OsslToTpmBn(remainder, bnR));
302     DEBUG_PRINT("In BnDiv:\n");
303     BIGNUM_PRINT("   bnDividend: ", bnDend, TRUE);
304     BIGNUM_PRINT("    bnDivisor: ", bnSor, TRUE);
305     BIGNUM_PRINT("   bnQuotient: ", bnQ, TRUE);
306     BIGNUM_PRINT("  bnRemainder: ", bnR, TRUE);
307     goto Exit;
308 Error:
309     OK = FALSE;
310 Exit:
311     OSSL_LEAVE();
312     return OK;
313 }
314 
315 #if ALG_RSA
316 //*** BnGcd()
317 // Get the greatest common divisor of two numbers
318 //  Return Type: BOOL
319 //      TRUE(1)         success
320 //      FALSE(0)        failure in operation
321 LIB_EXPORT BOOL
BnGcd(bigNum gcd,bigConst number1,bigConst number2)322 BnGcd(
323     bigNum      gcd,            // OUT: the common divisor
324     bigConst    number1,        // IN:
325     bigConst    number2         // IN:
326     )
327 {
328     OSSL_ENTER();
329     BIGNUM              *bnGcd = BN_NEW();
330     BOOL                 OK = TRUE;
331     BIG_INITIALIZED(bn1, number1);
332     BIG_INITIALIZED(bn2, number2);
333 //
334     VERIFY(BN_gcd(bnGcd, bn1, bn2, CTX));
335     VERIFY(OsslToTpmBn(gcd, bnGcd));
336     goto Exit;
337 Error:
338     OK = FALSE;
339 Exit:
340     OSSL_LEAVE();
341     return OK;
342 }
343 
344 //***BnModExp()
345 // Do modular exponentiation using bigNum values. The conversion from a bignum_t to
346 // a bigNum is trivial as they are based on the same structure
347 //  Return Type: BOOL
348 //      TRUE(1)         success
349 //      FALSE(0)        failure in operation
350 LIB_EXPORT BOOL
BnModExp(bigNum result,bigConst number,bigConst exponent,bigConst modulus)351 BnModExp(
352     bigNum               result,         // OUT: the result
353     bigConst             number,         // IN: number to exponentiate
354     bigConst             exponent,       // IN:
355     bigConst             modulus         // IN:
356     )
357 {
358     OSSL_ENTER();
359     BIGNUM              *bnResult = BN_NEW();
360     BOOL                 OK = TRUE;
361     BIG_INITIALIZED(bnN, number);
362     BIG_INITIALIZED(bnE, exponent);
363     BIG_INITIALIZED(bnM, modulus);
364 //
365     VERIFY(BN_mod_exp(bnResult, bnN, bnE, bnM, CTX));
366     VERIFY(OsslToTpmBn(result, bnResult));
367     goto Exit;
368 Error:
369     OK = FALSE;
370 Exit:
371     OSSL_LEAVE();
372     return OK;
373 }
374 
375 //*** BnModInverse()
376 // Modular multiplicative inverse
377 //  Return Type: BOOL
378 //      TRUE(1)         success
379 //      FALSE(0)        failure in operation
380 LIB_EXPORT BOOL
BnModInverse(bigNum result,bigConst number,bigConst modulus)381 BnModInverse(
382     bigNum               result,
383     bigConst             number,
384     bigConst             modulus
385     )
386 {
387     OSSL_ENTER();
388     BIGNUM              *bnResult = BN_NEW();
389     BOOL                 OK = TRUE;
390     BIG_INITIALIZED(bnN, number);
391     BIG_INITIALIZED(bnM, modulus);
392 //
393     VERIFY(BN_mod_inverse(bnResult, bnN, bnM, CTX) != NULL);
394     VERIFY(OsslToTpmBn(result, bnResult));
395     goto Exit;
396 Error:
397     OK = FALSE;
398 Exit:
399     OSSL_LEAVE();
400     return OK;
401 }
402 #endif // ALG_RSA
403 
404 #if ALG_ECC
405 
406 //*** PointFromOssl()
407 // Function to copy the point result from an OSSL function to a bigNum
408 //  Return Type: BOOL
409 //      TRUE(1)         success
410 //      FALSE(0)        failure in operation
411 static BOOL
PointFromOssl(bigPoint pOut,EC_POINT * pIn,bigCurve E)412 PointFromOssl(
413     bigPoint         pOut,      // OUT: resulting point
414     EC_POINT        *pIn,       // IN: the point to return
415     bigCurve         E          // IN: the curve
416     )
417 {
418     BIGNUM         *x = NULL;
419     BIGNUM         *y = NULL;
420     BOOL            OK;
421     BN_CTX_start(E->CTX);
422 //
423     x = BN_CTX_get(E->CTX);
424     y = BN_CTX_get(E->CTX);
425 
426     if(y == NULL)
427         FAIL(FATAL_ERROR_ALLOCATION);
428     // If this returns false, then the point is at infinity
429     OK = EC_POINT_get_affine_coordinates_GFp(E->G, pIn, x, y, E->CTX);
430     if(OK)
431     {
432         OsslToTpmBn(pOut->x, x);
433         OsslToTpmBn(pOut->y, y);
434         BnSetWord(pOut->z, 1);
435     }
436     else
437         BnSetWord(pOut->z, 0);
438     BN_CTX_end(E->CTX);
439     return OK;
440 }
441 
442 //*** EcPointInitialized()
443 // Allocate and initialize a point.
444 static EC_POINT *
EcPointInitialized(pointConst initializer,bigCurve E)445 EcPointInitialized(
446     pointConst          initializer,
447     bigCurve            E
448     )
449 {
450     EC_POINT            *P = NULL;
451 
452     if(initializer != NULL)
453     {
454         BIG_INITIALIZED(bnX, initializer->x);
455         BIG_INITIALIZED(bnY, initializer->y);
456         if(E == NULL)
457             FAIL(FATAL_ERROR_ALLOCATION);
458         P = EC_POINT_new(E->G);
459         if(!EC_POINT_set_affine_coordinates_GFp(E->G, P, bnX, bnY, E->CTX))
460             P = NULL;
461     }
462     return P;
463 }
464 
465 //*** BnCurveInitialize()
466 // This function initializes the OpenSSL curve information structure. This
467 // structure points to the TPM-defined values for the curve, to the context for the
468 // number values in the frame, and to the OpenSSL-defined group values.
469 //  Return Type: bigCurve *
470 //      NULL        the TPM_ECC_CURVE is not valid or there was a problem in
471 //                  in initializing the curve data
472 //      non-NULL    points to 'E'
473 LIB_EXPORT bigCurve
BnCurveInitialize(bigCurve E,TPM_ECC_CURVE curveId)474 BnCurveInitialize(
475     bigCurve          E,           // IN: curve structure to initialize
476     TPM_ECC_CURVE     curveId      // IN: curve identifier
477 )
478 {
479     const ECC_CURVE_DATA    *C = GetCurveData(curveId);
480     if(C == NULL)
481         E = NULL;
482     if(E != NULL)
483     {
484         // This creates the OpenSSL memory context that stays in effect as long as the
485         // curve (E) is defined.
486         OSSL_ENTER();                       // if the allocation fails, the TPM fails
487         EC_POINT                *P = NULL;
488         BIG_INITIALIZED(bnP, C->prime);
489         BIG_INITIALIZED(bnA, C->a);
490         BIG_INITIALIZED(bnB, C->b);
491         BIG_INITIALIZED(bnX, C->base.x);
492         BIG_INITIALIZED(bnY, C->base.y);
493         BIG_INITIALIZED(bnN, C->order);
494         BIG_INITIALIZED(bnH, C->h);
495     //
496         E->C = C;
497         E->CTX = CTX;
498 
499         // initialize EC group, associate a generator point and initialize the point
500         // from the parameter data
501         // Create a group structure
502         E->G = EC_GROUP_new_curve_GFp(bnP, bnA, bnB, CTX);
503         VERIFY(E->G != NULL);
504 
505         // Allocate a point in the group that will be used in setting the
506         // generator. This is not needed after the generator is set.
507         P = EC_POINT_new(E->G);
508         VERIFY(P != NULL);
509 
510         // Need to use this in case Montgomery method is being used
511         VERIFY(EC_POINT_set_affine_coordinates_GFp(E->G, P, bnX, bnY, CTX));
512         // Now set the generator
513         VERIFY(EC_GROUP_set_generator(E->G, P, bnN, bnH));
514 
515         EC_POINT_free(P);
516         goto Exit;
517 Error:
518         EC_POINT_free(P);
519         BnCurveFree(E);
520         E = NULL;
521     }
522 Exit:
523     return E;
524 }
525 
526 //*** BnCurveFree()
527 // This function will free the allocated components of the curve and end the
528 // frame in which the curve data exists
529 LIB_EXPORT void
BnCurveFree(bigCurve E)530 BnCurveFree(
531     bigCurve                    E
532 )
533 {
534     if(E)
535     {
536         EC_GROUP_free(E->G);
537         OsslContextLeave(E->CTX);
538     }
539 }
540 
541 
542 //*** BnEccModMult()
543 // This function does a point multiply of the form R = [d]S
544 //  Return Type: BOOL
545 //      TRUE(1)         success
546 //      FALSE(0)        failure in operation; treat as result being point at infinity
547 LIB_EXPORT BOOL
BnEccModMult(bigPoint R,pointConst S,bigConst d,bigCurve E)548 BnEccModMult(
549     bigPoint             R,         // OUT: computed point
550     pointConst           S,         // IN: point to multiply by 'd' (optional)
551     bigConst             d,         // IN: scalar for [d]S
552     bigCurve             E
553     )
554 {
555     EC_POINT            *pR = EC_POINT_new(E->G);
556     EC_POINT            *pS = EcPointInitialized(S, E);
557     BIG_INITIALIZED(bnD, d);
558 
559     if(S == NULL)
560         EC_POINT_mul(E->G, pR, bnD, NULL, NULL, E->CTX);
561     else
562         EC_POINT_mul(E->G, pR, NULL, pS, bnD, E->CTX);
563     PointFromOssl(R, pR, E);
564     EC_POINT_free(pR);
565     EC_POINT_free(pS);
566     return !BnEqualZero(R->z);
567 }
568 
569 //*** BnEccModMult2()
570 // This function does a point multiply of the form R = [d]G + [u]Q
571 //  Return Type: BOOL
572 //      TRUE(1)         success
573 //      FALSE(0)        failure in operation; treat as result being point at infinity
574 LIB_EXPORT BOOL
BnEccModMult2(bigPoint R,pointConst S,bigConst d,pointConst Q,bigConst u,bigCurve E)575 BnEccModMult2(
576     bigPoint             R,         // OUT: computed point
577     pointConst           S,         // IN: optional point
578     bigConst             d,         // IN: scalar for [d]S or [d]G
579     pointConst           Q,         // IN: second point
580     bigConst             u,         // IN: second scalar
581     bigCurve             E          // IN: curve
582     )
583 {
584     EC_POINT            *pR = EC_POINT_new(E->G);
585     BIG_INITIALIZED(bnD, d);
586     EC_POINT            *pQ = EcPointInitialized(Q, E);
587     BIG_INITIALIZED(bnU, u);
588 
589     if(S == NULL || S == (pointConst)&(AccessCurveData(E)->base))
590         EC_POINT_mul(E->G, pR, bnD, pQ, bnU, E->CTX);
591     else
592     {
593         return FALSE;
594     }
595     PointFromOssl(R, pR, E);
596     EC_POINT_free(pR);
597     EC_POINT_free(pQ);
598     return !BnEqualZero(R->z);
599 }
600 
601 //** BnEccAdd()
602 // This function does addition of two points.
603 //  Return Type: BOOL
604 //      TRUE(1)         success
605 //      FALSE(0)        failure in operation; treat as result being point at infinity
606 LIB_EXPORT BOOL
BnEccAdd(bigPoint R,pointConst S,pointConst Q,bigCurve E)607 BnEccAdd(
608     bigPoint             R,         // OUT: computed point
609     pointConst           S,         // IN: point to multiply by 'd'
610     pointConst           Q,         // IN: second point
611     bigCurve             E          // IN: curve
612     )
613 {
614     EC_POINT            *pR = EC_POINT_new(E->G);
615     EC_POINT            *pS = EcPointInitialized(S, E);
616     EC_POINT            *pQ = EcPointInitialized(Q, E);
617 //
618     EC_POINT_add(E->G, pR, pS, pQ, E->CTX);
619 
620     PointFromOssl(R, pR, E);
621     EC_POINT_free(pR);
622     EC_POINT_free(pS);
623     EC_POINT_free(pQ);
624     return !BnEqualZero(R->z);
625 }
626 
627 #endif // ALG_ECC
628 
629 
630 #endif // MATHLIB OSSL
631