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 other
22  *  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 
36 //** Introduction
37 //
38 // This file contains the math functions that are not implemented in the BnMath
39 // library (yet). These math functions will call the wolfcrypt library to execute
40 // the operations. There is a difference between the internal format and the
41 // wolfcrypt format. To call the wolfcrypt function, a mp_int structure is created
42 // for each passed variable. We define USE_FAST_MATH wolfcrypt option, which allocates
43 // mp_int on the stack. We must copy each word to the new structure, and set the used
44 // size.
45 //
46 // Not using USE_FAST_MATH would allow for a simple pointer swap for the big integer
47 // buffer 'd', however wolfcrypt expects to manage this memory, and will swap out
48 // the pointer to and from temporary variables and free the reference underneath us.
49 // Using USE_FAST_MATH also instructs wolfcrypt to use the stack for all these
50 // intermediate variables
51 
52 
53 //** Includes and Defines
54 #include "Tpm.h"
55 
56 #ifdef MATH_LIB_WOLF
57 #include "BnConvert_fp.h"
58 #include "TpmToWolfMath_fp.h"
59 
60 #define WOLF_HALF_RADIX     (RADIX_BITS == 64 && !defined(FP_64BIT))
61 
62 //** Functions
63 
64 //*** BnFromWolf()
65 // This function converts a wolfcrypt mp_int to a TPM bignum. In this implementation
66 // it is assumed that wolfcrypt used the same format for a big number as does the
67 // TPM -- an array of native-endian words in little-endian order.
68 void
BnFromWolf(bigNum bn,mp_int * wolfBn)69 BnFromWolf(
70     bigNum          bn,
71     mp_int          *wolfBn
72     )
73 {
74     if(bn != NULL)
75     {
76         int         i;
77 #if WOLF_HALF_RADIX
78         pAssert((unsigned)wolfBn->used <= 2 * BnGetAllocated(bn));
79 #else
80         pAssert((unsigned)wolfBn->used <= BnGetAllocated(bn));
81 #endif
82         for (i = 0; i < wolfBn->used; i++)
83         {
84 #if WOLF_HALF_RADIX
85             if (i & 1)
86                 bn->d[i/2] |= (crypt_uword_t)wolfBn->dp[i] << 32;
87             else
88                 bn->d[i/2] = wolfBn->dp[i];
89 #else
90             bn->d[i] = wolfBn->dp[i];
91 #endif
92         }
93 
94 #if WOLF_HALF_RADIX
95         BnSetTop(bn, (wolfBn->used + 1)/2);
96 #else
97         BnSetTop(bn, wolfBn->used);
98 #endif
99     }
100 }
101 
102 //*** BnToWolf()
103 // This function converts a TPM bignum to a wolfcrypt mp_init, and has the same
104 // assumptions as made by BnFromWolf()
105 void
BnToWolf(mp_int * toInit,bigConst initializer)106 BnToWolf(
107     mp_int              *toInit,
108     bigConst            initializer
109     )
110 {
111     uint32_t         i;
112     if (toInit != NULL && initializer != NULL)
113     {
114         for (i = 0; i < initializer->size; i++)
115         {
116 #if WOLF_HALF_RADIX
117             toInit->dp[2 * i] = (fp_digit)initializer->d[i];
118             toInit->dp[2 * i + 1] = (fp_digit)(initializer->d[i] >> 32);
119 #else
120             toInit->dp[i] = initializer->d[i];
121 #endif
122         }
123 
124 #if WOLF_HALF_RADIX
125         toInit->used = (int)initializer->size * 2;
126         if (toInit->dp[toInit->used - 1] == 0 && toInit->dp[toInit->used - 2] != 0)
127             --toInit->used;
128 #else
129         toInit->used = (int)initializer->size;
130 #endif
131         toInit->sign = 0;
132     }
133 }
134 
135 //*** MpInitialize()
136 // This function initializes an wolfcrypt mp_int.
137 mp_int *
MpInitialize(mp_int * toInit)138 MpInitialize(
139     mp_int              *toInit
140 )
141 {
142     mp_init( toInit );
143     return toInit;
144 }
145 
146 #if LIBRARY_COMPATIBILITY_CHECK
147 //** MathLibraryCompatibililtyCheck()
148 // This function is only used during development to make sure that the library
149 // that is being referenced is using the same size of data structures as the TPM.
150 BOOL
MathLibraryCompatibilityCheck(void)151 MathLibraryCompatibilityCheck(
152     void
153     )
154 {
155     BN_VAR(tpmTemp, 64 * 8); // allocate some space for a test value
156     crypt_uword_t           i;
157     TPM2B_TYPE(TEST, 16);
158     TPM2B_TEST              test = {{16, {0x0F, 0x0E, 0x0D, 0x0C,
159                                           0x0B, 0x0A, 0x09, 0x08,
160                                           0x07, 0x06, 0x05, 0x04,
161                                           0x03, 0x02, 0x01, 0x00}}};
162     // Convert the test TPM2B to a bigNum
163     BnFrom2B(tpmTemp, &test.b);
164     MP_INITIALIZED(wolfTemp, tpmTemp);
165     (wolfTemp); // compiler warning
166     // Make sure the values are consistent
167     VERIFY(wolfTemp->used * sizeof(fp_digit) == (int)tpmTemp->size * sizeof(crypt_uword_t));
168     for(i = 0; i < tpmTemp->size; i++)
169         VERIFY(((crypt_uword_t*)wolfTemp->dp)[i] == tpmTemp->d[i]);
170     return 1;
171 Error:
172     return 0;
173 }
174 #endif
175 
176 //*** BnModMult()
177 // Does multiply and divide returning the remainder of the divide.
178 LIB_EXPORT BOOL
BnModMult(bigNum result,bigConst op1,bigConst op2,bigConst modulus)179 BnModMult(
180     bigNum              result,
181     bigConst            op1,
182     bigConst            op2,
183     bigConst            modulus
184     )
185 {
186     WOLF_ENTER();
187     BOOL                OK;
188     MP_INITIALIZED(bnOp1, op1);
189     MP_INITIALIZED(bnOp2, op2);
190     MP_INITIALIZED(bnTemp, NULL);
191     BN_VAR(temp, LARGEST_NUMBER_BITS * 2);
192 
193     pAssert(BnGetAllocated(result) >= BnGetSize(modulus));
194 
195     OK = (mp_mul( bnOp1, bnOp2, bnTemp ) == MP_OKAY);
196     if(OK)
197     {
198         BnFromWolf(temp, bnTemp);
199         OK = BnDiv(NULL, result, temp, modulus);
200     }
201 
202     WOLF_LEAVE();
203     return OK;
204 }
205 
206 //*** BnMult()
207 // Multiplies two numbers
208 LIB_EXPORT BOOL
BnMult(bigNum result,bigConst multiplicand,bigConst multiplier)209 BnMult(
210     bigNum               result,
211     bigConst             multiplicand,
212     bigConst             multiplier
213     )
214 {
215     WOLF_ENTER();
216     BOOL                OK;
217     MP_INITIALIZED(bnTemp, NULL);
218     MP_INITIALIZED(bnA, multiplicand);
219     MP_INITIALIZED(bnB, multiplier);
220 
221     pAssert(result->allocated >=
222             (BITS_TO_CRYPT_WORDS(BnSizeInBits(multiplicand)
223                                  + BnSizeInBits(multiplier))));
224 
225     OK = (mp_mul( bnA, bnB, bnTemp ) == MP_OKAY);
226     if(OK)
227     {
228         BnFromWolf(result, bnTemp);
229     }
230 
231     WOLF_LEAVE();
232     return OK;
233 }
234 
235 //*** BnDiv()
236 // This function divides two bigNum values. The function returns FALSE if
237 // there is an error in the operation.
238 LIB_EXPORT BOOL
BnDiv(bigNum quotient,bigNum remainder,bigConst dividend,bigConst divisor)239 BnDiv(
240     bigNum               quotient,
241     bigNum               remainder,
242     bigConst             dividend,
243     bigConst             divisor
244     )
245 {
246     WOLF_ENTER();
247     BOOL        OK;
248     MP_INITIALIZED(bnQ, quotient);
249     MP_INITIALIZED(bnR, remainder);
250     MP_INITIALIZED(bnDend, dividend);
251     MP_INITIALIZED(bnSor, divisor);
252     pAssert(!BnEqualZero(divisor));
253     if(BnGetSize(dividend) < BnGetSize(divisor))
254     {
255         if(quotient)
256             BnSetWord(quotient, 0);
257         if(remainder)
258             BnCopy(remainder, dividend);
259         OK = TRUE;
260     }
261     else
262     {
263         pAssert((quotient == NULL)
264                 || (quotient->allocated >= (unsigned)(dividend->size
265                                                       - divisor->size)));
266         pAssert((remainder == NULL)
267                 || (remainder->allocated >= divisor->size));
268         OK = (mp_div(bnDend , bnSor, bnQ, bnR) == MP_OKAY);
269         if(OK)
270         {
271             BnFromWolf(quotient, bnQ);
272             BnFromWolf(remainder, bnR);
273         }
274     }
275 
276     WOLF_LEAVE();
277     return OK;
278 }
279 
280 #if ALG_RSA
281 //*** BnGcd()
282 // Get the greatest common divisor of two numbers
283 LIB_EXPORT BOOL
BnGcd(bigNum gcd,bigConst number1,bigConst number2)284 BnGcd(
285     bigNum      gcd,            // OUT: the common divisor
286     bigConst    number1,        // IN:
287     bigConst    number2         // IN:
288     )
289 {
290     WOLF_ENTER();
291     BOOL            OK;
292     MP_INITIALIZED(bnGcd, gcd);
293     MP_INITIALIZED(bn1, number1);
294     MP_INITIALIZED(bn2, number2);
295     pAssert(gcd != NULL);
296     OK = (mp_gcd( bn1, bn2, bnGcd ) == MP_OKAY);
297     if(OK)
298     {
299         BnFromWolf(gcd, bnGcd);
300     }
301     WOLF_LEAVE();
302     return OK;
303 }
304 
305 //***BnModExp()
306 // Do modular exponentiation using bigNum values. The conversion from a mp_int to
307 // a bigNum is trivial as they are based on the same structure
308 LIB_EXPORT BOOL
BnModExp(bigNum result,bigConst number,bigConst exponent,bigConst modulus)309 BnModExp(
310     bigNum               result,         // OUT: the result
311     bigConst             number,         // IN: number to exponentiate
312     bigConst             exponent,       // IN:
313     bigConst             modulus         // IN:
314     )
315 {
316     WOLF_ENTER();
317     BOOL            OK;
318     MP_INITIALIZED(bnResult, result);
319     MP_INITIALIZED(bnN, number);
320     MP_INITIALIZED(bnE, exponent);
321     MP_INITIALIZED(bnM, modulus);
322     OK = (mp_exptmod( bnN, bnE, bnM, bnResult ) == MP_OKAY);
323     if(OK)
324     {
325         BnFromWolf(result, bnResult);
326     }
327 
328     WOLF_LEAVE();
329     return OK;
330 }
331 
332 //*** BnModInverse()
333 // Modular multiplicative inverse
334 LIB_EXPORT BOOL
BnModInverse(bigNum result,bigConst number,bigConst modulus)335 BnModInverse(
336     bigNum               result,
337     bigConst             number,
338     bigConst             modulus
339     )
340 {
341     WOLF_ENTER();
342     BOOL            OK;
343     MP_INITIALIZED(bnResult, result);
344     MP_INITIALIZED(bnN, number);
345     MP_INITIALIZED(bnM, modulus);
346 
347     OK = (mp_invmod(bnN, bnM, bnResult) == MP_OKAY);
348     if(OK)
349     {
350         BnFromWolf(result, bnResult);
351     }
352 
353     WOLF_LEAVE();
354     return OK;
355 }
356 #endif // TPM_ALG_RSA
357 
358 #if ALG_ECC
359 
360 //*** PointFromWolf()
361 // Function to copy the point result from a wolf ecc_point to a bigNum
362 void
PointFromWolf(bigPoint pOut,ecc_point * pIn)363 PointFromWolf(
364     bigPoint         pOut,      // OUT: resulting point
365     ecc_point       *pIn       // IN: the point to return
366     )
367 {
368     BnFromWolf(pOut->x, pIn->x);
369     BnFromWolf(pOut->y, pIn->y);
370     BnFromWolf(pOut->z, pIn->z);
371 }
372 
373 //*** PointToWolf()
374 // Function to copy the point result from a bigNum to a wolf ecc_point
375 void
PointToWolf(ecc_point * pOut,pointConst pIn)376 PointToWolf(
377     ecc_point      *pOut,      // OUT: resulting point
378     pointConst      pIn       // IN: the point to return
379     )
380 {
381     BnToWolf(pOut->x, pIn->x);
382     BnToWolf(pOut->y, pIn->y);
383     BnToWolf(pOut->z, pIn->z);
384 }
385 
386 //*** EcPointInitialized()
387 // Allocate and initialize a point.
388 static ecc_point *
EcPointInitialized(pointConst initializer)389 EcPointInitialized(
390     pointConst          initializer
391     )
392 {
393     ecc_point           *P;
394 
395     P = wc_ecc_new_point();
396     pAssert(P != NULL);
397     // mp_int x,y,z are stack allocated.
398     // initializer is not required
399     if (P != NULL && initializer != NULL)
400     {
401         PointToWolf( P, initializer );
402     }
403 
404     return P;
405 }
406 
407 //*** BnEccModMult()
408 // This function does a point multiply of the form R = [d]S
409 // return type: BOOL
410 //  FALSE       failure in operation; treat as result being point at infinity
411 LIB_EXPORT BOOL
BnEccModMult(bigPoint R,pointConst S,bigConst d,bigCurve E)412 BnEccModMult(
413     bigPoint             R,         // OUT: computed point
414     pointConst           S,         // IN: point to multiply by 'd' (optional)
415     bigConst             d,         // IN: scalar for [d]S
416     bigCurve             E
417     )
418 {
419     WOLF_ENTER();
420     BOOL                 OK;
421     MP_INITIALIZED(bnD, d);
422     MP_INITIALIZED(bnPrime, CurveGetPrime(E));
423     POINT_CREATE(pS, NULL);
424     POINT_CREATE(pR, NULL);
425 
426     if(S == NULL)
427         S = CurveGetG(AccessCurveData(E));
428 
429     PointToWolf(pS, S);
430 
431     OK = (wc_ecc_mulmod(bnD, pS, pR, NULL, bnPrime, 1 ) == MP_OKAY);
432     if(OK)
433     {
434         PointFromWolf(R, pR);
435     }
436 
437     POINT_DELETE(pR);
438     POINT_DELETE(pS);
439 
440     WOLF_LEAVE();
441     return !BnEqualZero(R->z);
442 }
443 
444 //*** BnEccModMult2()
445 // This function does a point multiply of the form R = [d]G + [u]Q
446 // return type: BOOL
447 //  FALSE       failure in operation; treat as result being point at infinity
448 LIB_EXPORT BOOL
BnEccModMult2(bigPoint R,pointConst S,bigConst d,pointConst Q,bigConst u,bigCurve E)449 BnEccModMult2(
450     bigPoint             R,         // OUT: computed point
451     pointConst           S,         // IN: optional point
452     bigConst             d,         // IN: scalar for [d]S or [d]G
453     pointConst           Q,         // IN: second point
454     bigConst             u,         // IN: second scalar
455     bigCurve             E          // IN: curve
456     )
457 {
458     WOLF_ENTER();
459     BOOL                 OK;
460     POINT_CREATE(pR, NULL);
461     POINT_CREATE(pS, NULL);
462     POINT_CREATE(pQ, Q);
463     MP_INITIALIZED(bnD, d);
464     MP_INITIALIZED(bnU, u);
465     MP_INITIALIZED(bnPrime, CurveGetPrime(E));
466     MP_INITIALIZED(bnA, CurveGet_a(E));
467 
468     if(S == NULL)
469         S = CurveGetG(AccessCurveData(E));
470     PointToWolf( pS, S );
471 
472     OK = (ecc_mul2add(pS, bnD, pQ, bnU, pR, bnA, bnPrime, NULL) == MP_OKAY);
473     if(OK)
474     {
475         PointFromWolf(R, pR);
476     }
477 
478     POINT_DELETE(pS);
479     POINT_DELETE(pQ);
480     POINT_DELETE(pR);
481 
482     WOLF_LEAVE();
483     return !BnEqualZero(R->z);
484 }
485 
486 //** BnEccAdd()
487 // This function does addition of two points.
488 // return type: BOOL
489 //  FALSE       failure in operation; treat as result being point at infinity
490 LIB_EXPORT BOOL
BnEccAdd(bigPoint R,pointConst S,pointConst Q,bigCurve E)491 BnEccAdd(
492     bigPoint             R,         // OUT: computed point
493     pointConst           S,         // IN: point to multiply by 'd'
494     pointConst           Q,         // IN: second point
495     bigCurve             E          // IN: curve
496     )
497 {
498     WOLF_ENTER();
499     BOOL                 OK;
500     mp_digit             mp;
501     POINT_CREATE(pR, NULL);
502     POINT_CREATE(pS, S);
503     POINT_CREATE(pQ, Q);
504     MP_INITIALIZED(bnA, CurveGet_a(E));
505     MP_INITIALIZED(bnMod, CurveGetPrime(E));
506 //
507     OK = (mp_montgomery_setup(bnMod, &mp) == MP_OKAY);
508     OK = OK && (ecc_projective_add_point(pS, pQ, pR, bnA, bnMod, mp ) == MP_OKAY);
509     if(OK)
510     {
511         PointFromWolf(R, pR);
512     }
513 
514     POINT_DELETE(pS);
515     POINT_DELETE(pQ);
516     POINT_DELETE(pR);
517 
518     WOLF_LEAVE();
519     return !BnEqualZero(R->z);
520 }
521 
522 #endif // TPM_ALG_ECC
523 
524 #endif // MATH_LIB_WOLF