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