• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //** Includes and Defines
36 #include "Tpm.h"
37 
38 #if ALG_ECC
39 
40 // This version requires that the new format for ECC data be used
41 #if !USE_BN_ECC_DATA
42 #error "Need to SET USE_BN_ECC_DATA to YES in Implementaion.h"
43 #endif
44 
45 //** Functions
46 
47 #if SIMULATION
48 void
EccSimulationEnd(void)49 EccSimulationEnd(
50     void
51     )
52 {
53 #if SIMULATION
54 // put things to be printed at the end of the simulation here
55 #endif
56 }
57 #endif // SIMULATION
58 
59 //*** CryptEccInit()
60 // This function is called at _TPM_Init
61 BOOL
CryptEccInit(void)62 CryptEccInit(
63     void
64     )
65 {
66     return TRUE;
67 }
68 
69 //*** CryptEccStartup()
70 // This function is called at TPM2_Startup().
71 BOOL
CryptEccStartup(void)72 CryptEccStartup(
73     void
74     )
75 {
76     return TRUE;
77 }
78 
79 //*** ClearPoint2B(generic)
80 // Initialize the size values of a TPMS_ECC_POINT structure.
81 void
ClearPoint2B(TPMS_ECC_POINT * p)82 ClearPoint2B(
83     TPMS_ECC_POINT      *p          // IN: the point
84     )
85 {
86     if(p != NULL)
87     {
88         p->x.t.size = 0;
89         p->y.t.size = 0;
90     }
91 }
92 
93 //*** CryptEccGetParametersByCurveId()
94 // This function returns a pointer to the curve data that is associated with
95 // the indicated curveId.
96 // If there is no curve with the indicated ID, the function returns NULL. This
97 // function is in this module so that it can be called by GetCurve data.
98 //  Return Type: const ECC_CURVE_DATA
99 //      NULL            curve with the indicated TPM_ECC_CURVE is not implemented
100 //      != NULL         pointer to the curve data
101 LIB_EXPORT const ECC_CURVE *
CryptEccGetParametersByCurveId(TPM_ECC_CURVE curveId)102 CryptEccGetParametersByCurveId(
103     TPM_ECC_CURVE       curveId     // IN: the curveID
104     )
105 {
106     int          i;
107     for(i = 0; i < ECC_CURVE_COUNT; i++)
108     {
109         if(eccCurves[i].curveId == curveId)
110             return &eccCurves[i];
111     }
112     return NULL;
113 }
114 
115 //*** CryptEccGetKeySizeForCurve()
116 // This function returns the key size in bits of the indicated curve.
117 LIB_EXPORT UINT16
CryptEccGetKeySizeForCurve(TPM_ECC_CURVE curveId)118 CryptEccGetKeySizeForCurve(
119     TPM_ECC_CURVE            curveId    // IN: the curve
120     )
121 {
122     const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
123     UINT16           keySizeInBits;
124 //
125     keySizeInBits = (curve != NULL) ? curve->keySizeBits : 0;
126     return keySizeInBits;
127 }
128 
129 //*** GetCurveData()
130 // This function returns the a pointer for the parameter data
131 // associated with a curve.
132 const ECC_CURVE_DATA *
GetCurveData(TPM_ECC_CURVE curveId)133 GetCurveData(
134     TPM_ECC_CURVE        curveId     // IN: the curveID
135     )
136 {
137     const ECC_CURVE      *curve = CryptEccGetParametersByCurveId(curveId);
138     return (curve != NULL) ? curve->curveData : NULL;
139 }
140 
141 //***CryptEccGetOID()
142 const BYTE *
CryptEccGetOID(TPM_ECC_CURVE curveId)143 CryptEccGetOID(
144     TPM_ECC_CURVE       curveId
145 )
146 {
147     const ECC_CURVE         *curve = CryptEccGetParametersByCurveId(curveId);
148     return (curve != NULL) ? curve->OID : NULL;
149 }
150 
151 //*** CryptEccGetCurveByIndex()
152 // This function returns the number of the 'i'-th implemented curve. The normal
153 // use would be to call this function with 'i' starting at 0. When the 'i' is greater
154 // than or equal to the number of implemented curves, TPM_ECC_NONE is returned.
155 LIB_EXPORT TPM_ECC_CURVE
CryptEccGetCurveByIndex(UINT16 i)156 CryptEccGetCurveByIndex(
157     UINT16               i
158     )
159 {
160     if(i >= ECC_CURVE_COUNT)
161         return TPM_ECC_NONE;
162     return eccCurves[i].curveId;
163 }
164 
165 //*** CryptEccGetParameter()
166 // This function returns an ECC curve parameter. The parameter is
167 // selected by a single character designator from the set of ""PNABXYH"".
168 //  Return Type: BOOL
169 //      TRUE(1)         curve exists and parameter returned
170 //      FALSE(0)        curve does not exist or parameter selector
171 LIB_EXPORT BOOL
CryptEccGetParameter(TPM2B_ECC_PARAMETER * out,char p,TPM_ECC_CURVE curveId)172 CryptEccGetParameter(
173     TPM2B_ECC_PARAMETER     *out,       // OUT: place to put parameter
174     char                     p,         // IN: the parameter selector
175     TPM_ECC_CURVE            curveId    // IN: the curve id
176     )
177 {
178     const ECC_CURVE_DATA    *curve = GetCurveData(curveId);
179     bigConst                 parameter = NULL;
180 
181     if(curve != NULL)
182     {
183         switch(p)
184         {
185             case 'p':
186                 parameter = CurveGetPrime(curve);
187                 break;
188             case 'n':
189                 parameter = CurveGetOrder(curve);
190                 break;
191             case 'a':
192                 parameter = CurveGet_a(curve);
193                 break;
194             case 'b':
195                 parameter = CurveGet_b(curve);
196                 break;
197             case 'x':
198                 parameter = CurveGetGx(curve);
199                 break;
200             case 'y':
201                 parameter = CurveGetGy(curve);
202                 break;
203             case 'h':
204                 parameter = CurveGetCofactor(curve);
205                 break;
206             default:
207                 FAIL(FATAL_ERROR_INTERNAL);
208                 break;
209         }
210     }
211     // If not debugging and we get here with parameter still NULL, had better
212     // not try to convert so just return FALSE instead.
213     return (parameter != NULL) ? BnTo2B(parameter, &out->b, 0) : 0;
214 }
215 
216 //*** CryptCapGetECCCurve()
217 // This function returns the list of implemented ECC curves.
218 //  Return Type: TPMI_YES_NO
219 //      YES             if no more ECC curve is available
220 //      NO              if there are more ECC curves not reported
221 TPMI_YES_NO
CryptCapGetECCCurve(TPM_ECC_CURVE curveID,UINT32 maxCount,TPML_ECC_CURVE * curveList)222 CryptCapGetECCCurve(
223     TPM_ECC_CURVE    curveID,       // IN: the starting ECC curve
224     UINT32           maxCount,      // IN: count of returned curves
225     TPML_ECC_CURVE  *curveList      // OUT: ECC curve list
226     )
227 {
228     TPMI_YES_NO       more = NO;
229     UINT16            i;
230     UINT32            count = ECC_CURVE_COUNT;
231     TPM_ECC_CURVE     curve;
232 
233     // Initialize output property list
234     curveList->count = 0;
235 
236     // The maximum count of curves we may return is MAX_ECC_CURVES
237     if(maxCount > MAX_ECC_CURVES) maxCount = MAX_ECC_CURVES;
238 
239     // Scan the eccCurveValues array
240     for(i = 0; i < count; i++)
241     {
242         curve = CryptEccGetCurveByIndex(i);
243         // If curveID is less than the starting curveID, skip it
244         if(curve < curveID)
245             continue;
246         if(curveList->count < maxCount)
247         {
248             // If we have not filled up the return list, add more curves to
249             // it
250             curveList->eccCurves[curveList->count] = curve;
251             curveList->count++;
252         }
253         else
254         {
255             // If the return list is full but we still have curves
256             // available, report this and stop iterating
257             more = YES;
258             break;
259         }
260     }
261     return more;
262 }
263 
264 //*** CryptGetCurveSignScheme()
265 // This function will return a pointer to the scheme of the curve.
266 const TPMT_ECC_SCHEME *
CryptGetCurveSignScheme(TPM_ECC_CURVE curveId)267 CryptGetCurveSignScheme(
268     TPM_ECC_CURVE    curveId        // IN: The curve selector
269     )
270 {
271     const ECC_CURVE         *curve = CryptEccGetParametersByCurveId(curveId);
272 
273     if(curve != NULL)
274         return &(curve->sign);
275     else
276         return NULL;
277 }
278 
279 //*** CryptGenerateR()
280 // This function computes the commit random value for a split signing scheme.
281 //
282 // If 'c' is NULL, it indicates that 'r' is being generated
283 // for TPM2_Commit.
284 // If 'c' is not NULL, the TPM will validate that the 'gr.commitArray'
285 // bit associated with the input value of 'c' is SET. If not, the TPM
286 // returns FALSE and no 'r' value is generated.
287 //  Return Type: BOOL
288 //      TRUE(1)         r value computed
289 //      FALSE(0)        no r value computed
290 BOOL
CryptGenerateR(TPM2B_ECC_PARAMETER * r,UINT16 * c,TPMI_ECC_CURVE curveID,TPM2B_NAME * name)291 CryptGenerateR(
292     TPM2B_ECC_PARAMETER     *r,             // OUT: the generated random value
293     UINT16                  *c,             // IN/OUT: count value.
294     TPMI_ECC_CURVE           curveID,       // IN: the curve for the value
295     TPM2B_NAME              *name           // IN: optional name of a key to
296                                             //     associate with 'r'
297     )
298 {
299     // This holds the marshaled g_commitCounter.
300     TPM2B_TYPE(8B, 8);
301     TPM2B_8B                 cntr = {{8,{0}}};
302     UINT32                   iterations;
303     TPM2B_ECC_PARAMETER      n;
304     UINT64                   currentCount = gr.commitCounter;
305     UINT16                   t1;
306 //
307     if(!CryptEccGetParameter(&n, 'n', curveID))
308         return FALSE;
309 
310      // If this is the commit phase, use the current value of the commit counter
311     if(c != NULL)
312     {
313         // if the array bit is not set, can't use the value.
314         if(!TEST_BIT((*c & COMMIT_INDEX_MASK), gr.commitArray))
315             return FALSE;
316 
317         // If it is the sign phase, figure out what the counter value was
318         // when the commitment was made.
319         //
320         // When gr.commitArray has less than 64K bits, the extra
321         // bits of 'c' are used as a check to make sure that the
322         // signing operation is not using an out of range count value
323         t1 = (UINT16)currentCount;
324 
325         // If the lower bits of c are greater or equal to the lower bits of t1
326         // then the upper bits of t1 must be one more than the upper bits
327         // of c
328         if((*c & COMMIT_INDEX_MASK) >= (t1 & COMMIT_INDEX_MASK))
329             // Since the counter is behind, reduce the current count
330             currentCount = currentCount - (COMMIT_INDEX_MASK + 1);
331 
332         t1 = (UINT16)currentCount;
333         if((t1 & ~COMMIT_INDEX_MASK) != (*c & ~COMMIT_INDEX_MASK))
334             return FALSE;
335         // set the counter to the value that was
336         // present when the commitment was made
337         currentCount = (currentCount & 0xffffffffffff0000) | *c;
338     }
339     // Marshal the count value to a TPM2B buffer for the KDF
340     cntr.t.size = sizeof(currentCount);
341     UINT64_TO_BYTE_ARRAY(currentCount, cntr.t.buffer);
342 
343     // Now can do the KDF to create the random value for the signing operation
344     // During the creation process, we may generate an r that does not meet the
345     // requirements of the random value.
346     // want to generate a new r.
347     r->t.size = n.t.size;
348 
349     for(iterations = 1; iterations < 1000000;)
350     {
351         int     i;
352         CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &gr.commitNonce.b, COMMIT_STRING,
353                   &name->b, &cntr.b, n.t.size * 8, r->t.buffer, &iterations, FALSE);
354 
355         // "random" value must be less than the prime
356         if(UnsignedCompareB(r->b.size, r->b.buffer, n.t.size, n.t.buffer) >= 0)
357             continue;
358 
359         // in this implementation it is required that at least bit
360         // in the upper half of the number be set
361         for(i = n.t.size / 2; i >= 0; i--)
362             if(r->b.buffer[i] != 0)
363                 return TRUE;
364     }
365     return FALSE;
366 }
367 
368 //*** CryptCommit()
369 // This function is called when the count value is committed. The 'gr.commitArray'
370 // value associated with the current count value is SET and g_commitCounter is
371 // incremented. The low-order 16 bits of old value of the counter is returned.
372 UINT16
CryptCommit(void)373 CryptCommit(
374     void
375     )
376 {
377     UINT16      oldCount = (UINT16)gr.commitCounter;
378     gr.commitCounter++;
379     SET_BIT(oldCount & COMMIT_INDEX_MASK, gr.commitArray);
380     return oldCount;
381 }
382 
383 //*** CryptEndCommit()
384 // This function is called when the signing operation using the committed value
385 // is completed. It clears the gr.commitArray bit associated with the count
386 // value so that it can't be used again.
387 void
CryptEndCommit(UINT16 c)388 CryptEndCommit(
389     UINT16           c              // IN: the counter value of the commitment
390     )
391 {
392     ClearBit((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray));
393 }
394 
395 //*** CryptEccGetParameters()
396 // This function returns the ECC parameter details of the given curve.
397 //  Return Type: BOOL
398 //      TRUE(1)         success
399 //      FALSE(0)        unsupported ECC curve ID
400 BOOL
CryptEccGetParameters(TPM_ECC_CURVE curveId,TPMS_ALGORITHM_DETAIL_ECC * parameters)401 CryptEccGetParameters(
402     TPM_ECC_CURVE                curveId,       // IN: ECC curve ID
403     TPMS_ALGORITHM_DETAIL_ECC   *parameters     // OUT: ECC parameters
404     )
405 {
406     const ECC_CURVE             *curve = CryptEccGetParametersByCurveId(curveId);
407     const ECC_CURVE_DATA        *data;
408     BOOL                         found = curve != NULL;
409 
410     if(found)
411     {
412         data = curve->curveData;
413         parameters->curveID = curve->curveId;
414         parameters->keySize = curve->keySizeBits;
415         parameters->kdf = curve->kdf;
416         parameters->sign = curve->sign;
417 //        BnTo2B(data->prime, &parameters->p.b, 0);
418         BnTo2B(data->prime, &parameters->p.b, parameters->p.t.size);
419         BnTo2B(data->a, &parameters->a.b, 0);
420         BnTo2B(data->b, &parameters->b.b, 0);
421         BnTo2B(data->base.x, &parameters->gX.b, parameters->p.t.size);
422         BnTo2B(data->base.y, &parameters->gY.b, parameters->p.t.size);
423 //        BnTo2B(data->base.x, &parameters->gX.b, 0);
424 //        BnTo2B(data->base.y, &parameters->gY.b, 0);
425         BnTo2B(data->order, &parameters->n.b, 0);
426         BnTo2B(data->h, &parameters->h.b, 0);
427     }
428     return found;
429 }
430 
431 //*** BnGetCurvePrime()
432 // This function is used to get just the prime modulus associated with a curve.
433 const bignum_t *
BnGetCurvePrime(TPM_ECC_CURVE curveId)434 BnGetCurvePrime(
435     TPM_ECC_CURVE            curveId
436     )
437 {
438     const ECC_CURVE_DATA    *C = GetCurveData(curveId);
439     return (C != NULL) ? CurveGetPrime(C) : NULL;
440 }
441 
442 //*** BnGetCurveOrder()
443 // This function is used to get just the curve order
444 const bignum_t *
BnGetCurveOrder(TPM_ECC_CURVE curveId)445 BnGetCurveOrder(
446     TPM_ECC_CURVE            curveId
447     )
448 {
449     const ECC_CURVE_DATA    *C = GetCurveData(curveId);
450     return (C != NULL) ? CurveGetOrder(C) : NULL;
451 }
452 
453 //*** BnIsOnCurve()
454 // This function checks if a point is on the curve.
455 BOOL
BnIsOnCurve(pointConst Q,const ECC_CURVE_DATA * C)456 BnIsOnCurve(
457     pointConst                   Q,
458     const ECC_CURVE_DATA        *C
459     )
460 {
461     BN_VAR(right, (MAX_ECC_KEY_BITS * 3));
462     BN_VAR(left, (MAX_ECC_KEY_BITS * 2));
463     bigConst                   prime = CurveGetPrime(C);
464 //
465     // Show that point is on the curve y^2 = x^3 + ax + b;
466     // Or y^2 = x(x^2 + a) + b
467     // y^2
468     BnMult(left, Q->y, Q->y);
469 
470     BnMod(left, prime);
471 // x^2
472     BnMult(right, Q->x, Q->x);
473 
474     // x^2 + a
475     BnAdd(right, right, CurveGet_a(C));
476 
477 //    BnMod(right, CurveGetPrime(C));
478     // x(x^2 + a)
479     BnMult(right, right, Q->x);
480 
481     // x(x^2 + a) + b
482     BnAdd(right, right, CurveGet_b(C));
483 
484     BnMod(right, prime);
485     if(BnUnsignedCmp(left, right) == 0)
486         return TRUE;
487     else
488         return FALSE;
489 }
490 
491 //*** BnIsValidPrivateEcc()
492 // Checks that 0 < 'x' < 'q'
493 BOOL
BnIsValidPrivateEcc(bigConst x,bigCurve E)494 BnIsValidPrivateEcc(
495     bigConst                 x,         // IN: private key to check
496     bigCurve                 E          // IN: the curve to check
497     )
498 {
499     BOOL        retVal;
500     retVal = (!BnEqualZero(x)
501               && (BnUnsignedCmp(x, CurveGetOrder(AccessCurveData(E))) < 0));
502     return retVal;
503 }
504 
505 LIB_EXPORT BOOL
CryptEccIsValidPrivateKey(TPM2B_ECC_PARAMETER * d,TPM_ECC_CURVE curveId)506 CryptEccIsValidPrivateKey(
507     TPM2B_ECC_PARAMETER     *d,
508     TPM_ECC_CURVE            curveId
509     )
510 {
511     BN_INITIALIZED(bnD, MAX_ECC_PARAMETER_BYTES * 8, d);
512     return !BnEqualZero(bnD) && (BnUnsignedCmp(bnD, BnGetCurveOrder(curveId)) < 0);
513 }
514 
515 //*** BnPointMul()
516 // This function does a point multiply of the form 'R' = ['d']'S' + ['u']'Q' where the
517 // parameters are bigNum values. If 'S' is NULL and d is not NULL, then it computes
518 // 'R' = ['d']'G' + ['u']'Q'  or just 'R' = ['d']'G' if 'u' and 'Q' are NULL.
519 // If 'skipChecks' is TRUE, then the function will not verify that the inputs are
520 // correct for the domain. This would be the case when the values were created by the
521 // CryptoEngine code.
522 // It will return TPM_RC_NO_RESULT if the resulting point is the point at infinity.
523 //  Return Type: TPM_RC
524 //      TPM_RC_NO_RESULT        result of multiplication is a point at infinity
525 //      TPM_RC_ECC_POINT        'S' or 'Q' is not on the curve
526 //      TPM_RC_VALUE            'd' or 'u' is not < n
527 TPM_RC
BnPointMult(bigPoint R,pointConst S,bigConst d,pointConst Q,bigConst u,bigCurve E)528 BnPointMult(
529     bigPoint             R,         // OUT: computed point
530     pointConst           S,         // IN: optional point to multiply by 'd'
531     bigConst             d,         // IN: scalar for [d]S or [d]G
532     pointConst           Q,         // IN: optional second point
533     bigConst             u,         // IN: optional second scalar
534     bigCurve             E          // IN: curve parameters
535     )
536 {
537     BOOL                 OK;
538 //
539     TEST(TPM_ALG_ECDH);
540 
541     // Need one scalar
542     OK = (d != NULL || u != NULL);
543 
544     // If S is present, then d has to be present. If S is not
545     // present, then d may or may not be present
546     OK = OK && (((S == NULL) == (d == NULL)) || (d != NULL));
547 
548     // either both u and Q have to be provided or neither can be provided (don't
549     // know what to do if only one is provided.
550     OK = OK && ((u == NULL) == (Q == NULL));
551 
552     OK = OK && (E != NULL);
553     if(!OK)
554         return TPM_RC_VALUE;
555 
556 
557     OK = (S == NULL) || BnIsOnCurve(S, AccessCurveData(E));
558     OK = OK && ((Q == NULL) || BnIsOnCurve(Q, AccessCurveData(E)));
559     if(!OK)
560         return TPM_RC_ECC_POINT;
561 
562     if((d != NULL) && (S == NULL))
563         S = CurveGetG(AccessCurveData(E));
564     // If only one scalar, don't need Shamir's trick
565     if((d == NULL) || (u == NULL))
566     {
567         if(d == NULL)
568             OK = BnEccModMult(R, Q, u, E);
569         else
570             OK = BnEccModMult(R, S, d, E);
571     }
572     else
573     {
574         OK = BnEccModMult2(R, S, d, Q, u, E);
575     }
576     return  (OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT);
577 }
578 
579 //***BnEccGetPrivate()
580 // This function gets random values that are the size of the key plus 64 bits. The
581 // value is reduced (mod ('q' - 1)) and incremented by 1 ('q' is the order of the
582 // curve. This produces a value ('d') such that 1 <= 'd' < 'q'. This is the method
583 // of FIPS 186-4 Section B.4.1 ""Key Pair Generation Using Extra Random Bits"".
584 //  Return Type: BOOL
585 //      TRUE(1)         success
586 //      FALSE(0)        failure generating private key
587 BOOL
BnEccGetPrivate(bigNum dOut,const ECC_CURVE_DATA * C,RAND_STATE * rand)588 BnEccGetPrivate(
589     bigNum                   dOut,      // OUT: the qualified random value
590     const ECC_CURVE_DATA    *C,         // IN: curve for which the private key
591                                         //     needs to be appropriate
592     RAND_STATE              *rand       // IN: state for DRBG
593     )
594 {
595     bigConst                 order = CurveGetOrder(C);
596     BOOL                     OK;
597     UINT32                   orderBits = BnSizeInBits(order);
598     UINT32                   orderBytes = BITS_TO_BYTES(orderBits);
599     BN_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64);
600     BN_VAR(nMinus1, MAX_ECC_KEY_BITS);
601 //
602     OK = BnGetRandomBits(bnExtraBits, (orderBytes * 8) + 64, rand);
603     OK = OK && BnSubWord(nMinus1, order, 1);
604     OK = OK && BnMod(bnExtraBits, nMinus1);
605     OK = OK && BnAddWord(dOut, bnExtraBits, 1);
606     return OK && !g_inFailureMode;
607 }
608 
609 //*** BnEccGenerateKeyPair()
610 // This function gets a private scalar from the source of random bits and does
611 // the point multiply to get the public key.
612 BOOL
BnEccGenerateKeyPair(bigNum bnD,bn_point_t * ecQ,bigCurve E,RAND_STATE * rand)613 BnEccGenerateKeyPair(
614     bigNum               bnD,            // OUT: private scalar
615     bn_point_t          *ecQ,            // OUT: public point
616     bigCurve             E,              // IN: curve for the point
617     RAND_STATE          *rand            // IN: DRBG state to use
618     )
619 {
620     BOOL                 OK = FALSE;
621     // Get a private scalar
622     OK = BnEccGetPrivate(bnD, AccessCurveData(E), rand);
623 
624     // Do a point multiply
625     OK = OK && BnEccModMult(ecQ, NULL, bnD, E);
626     if(!OK)
627         BnSetWord(ecQ->z, 0);
628     else
629         BnSetWord(ecQ->z, 1);
630     return OK;
631 }
632 
633 //***CryptEccNewKeyPair(***)
634 // This function creates an ephemeral ECC. It is ephemeral in that
635 // is expected that the private part of the key will be discarded
636 LIB_EXPORT TPM_RC
CryptEccNewKeyPair(TPMS_ECC_POINT * Qout,TPM2B_ECC_PARAMETER * dOut,TPM_ECC_CURVE curveId)637 CryptEccNewKeyPair(
638     TPMS_ECC_POINT          *Qout,      // OUT: the public point
639     TPM2B_ECC_PARAMETER     *dOut,      // OUT: the private scalar
640     TPM_ECC_CURVE            curveId    // IN: the curve for the key
641     )
642 {
643     CURVE_INITIALIZED(E, curveId);
644     POINT(ecQ);
645     ECC_NUM(bnD);
646     BOOL                    OK;
647 
648     if(E == NULL)
649         return TPM_RC_CURVE;
650 
651     TEST(TPM_ALG_ECDH);
652     OK = BnEccGenerateKeyPair(bnD, ecQ, E, NULL);
653     if(OK)
654     {
655         BnPointTo2B(Qout, ecQ, E);
656         BnTo2B(bnD, &dOut->b, Qout->x.t.size);
657     }
658     else
659     {
660         Qout->x.t.size = Qout->y.t.size = dOut->t.size = 0;
661     }
662     CURVE_FREE(E);
663     return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
664 }
665 
666 //*** CryptEccPointMultiply()
667 // This function computes 'R' := ['dIn']'G' + ['uIn']'QIn'. Where 'dIn' and
668 // 'uIn' are scalars, 'G' and 'QIn' are points on the specified curve and 'G' is the
669 // default generator of the curve.
670 //
671 // The 'xOut' and 'yOut' parameters are optional and may be set to NULL if not
672 // used.
673 //
674 // It is not necessary to provide 'uIn' if 'QIn' is specified but one of 'uIn' and
675 // 'dIn' must be provided. If 'dIn' and 'QIn' are specified but 'uIn' is not
676 // provided, then 'R' = ['dIn']'QIn'.
677 //
678 // If the multiply produces the point at infinity, the TPM_RC_NO_RESULT is returned.
679 //
680 // The sizes of 'xOut' and yOut' will be set to be the size of the degree of
681 // the curve
682 //
683 // It is a fatal error if 'dIn' and 'uIn' are both unspecified (NULL) or if 'Qin'
684 // or 'Rout' is unspecified.
685 //
686 //  Return Type: TPM_RC
687 //      TPM_RC_ECC_POINT         the point 'Pin' or 'Qin' is not on the curve
688 //      TPM_RC_NO_RESULT         the product point is at infinity
689 //      TPM_RC_CURVE             bad curve
690 //      TPM_RC_VALUE             'dIn' or 'uIn' out of range
691 //
692 LIB_EXPORT TPM_RC
CryptEccPointMultiply(TPMS_ECC_POINT * Rout,TPM_ECC_CURVE curveId,TPMS_ECC_POINT * Pin,TPM2B_ECC_PARAMETER * dIn,TPMS_ECC_POINT * Qin,TPM2B_ECC_PARAMETER * uIn)693 CryptEccPointMultiply(
694     TPMS_ECC_POINT      *Rout,              // OUT: the product point R
695     TPM_ECC_CURVE        curveId,           // IN: the curve to use
696     TPMS_ECC_POINT      *Pin,               // IN: first point (can be null)
697     TPM2B_ECC_PARAMETER *dIn,               // IN: scalar value for [dIn]Qin
698                                             //     the Pin
699     TPMS_ECC_POINT      *Qin,               // IN: point Q
700     TPM2B_ECC_PARAMETER *uIn                // IN: scalar value for the multiplier
701                                             //     of Q
702     )
703 {
704     CURVE_INITIALIZED(E, curveId);
705     POINT_INITIALIZED(ecP, Pin);
706     ECC_INITIALIZED(bnD, dIn);      // If dIn is null, then bnD is null
707     ECC_INITIALIZED(bnU, uIn);
708     POINT_INITIALIZED(ecQ, Qin);
709     POINT(ecR);
710     TPM_RC             retVal;
711 //
712     retVal = BnPointMult(ecR, ecP, bnD, ecQ, bnU, E);
713 
714     if(retVal == TPM_RC_SUCCESS)
715         BnPointTo2B(Rout, ecR, E);
716     else
717         ClearPoint2B(Rout);
718     CURVE_FREE(E);
719     return retVal;
720 }
721 
722 //*** CryptEccIsPointOnCurve()
723 // This function is used to test if a point is on a defined curve. It does this
724 // by checking that 'y'^2 mod 'p' = 'x'^3 + 'a'*'x' + 'b' mod 'p'.
725 //
726 // It is a fatal error if 'Q' is not specified (is NULL).
727 //  Return Type: BOOL
728 //      TRUE(1)         point is on curve
729 //      FALSE(0)        point is not on curve or curve is not supported
730 LIB_EXPORT BOOL
CryptEccIsPointOnCurve(TPM_ECC_CURVE curveId,TPMS_ECC_POINT * Qin)731 CryptEccIsPointOnCurve(
732     TPM_ECC_CURVE            curveId,       // IN: the curve selector
733     TPMS_ECC_POINT          *Qin            // IN: the point.
734     )
735 {
736     const ECC_CURVE_DATA    *C = GetCurveData(curveId);
737     POINT_INITIALIZED(ecQ, Qin);
738     BOOL            OK;
739 //
740     pAssert(Qin != NULL);
741     OK = (C != NULL && (BnIsOnCurve(ecQ, C)));
742     return OK;
743 }
744 
745 //*** CryptEccGenerateKey()
746 // This function generates an ECC key pair based on the input parameters.
747 // This routine uses KDFa to produce candidate numbers. The method is according
748 // to FIPS 186-3, section B.1.2 "Key Pair Generation by Testing Candidates."
749 // According to the method in FIPS 186-3, the resulting private value 'd' should be
750 // 1 <= 'd' < 'n' where 'n' is the order of the base point.
751 //
752 // It is a fatal error if 'Qout', 'dOut', is not provided (is NULL).
753 //
754 // If the curve is not supported
755 // If 'seed' is not provided, then a random number will be used for the key
756 //  Return Type: TPM_RC
757 //      TPM_RC_CURVE            curve is not supported
758 //      TPM_RC_NO_RESULT        could not verify key with signature (FIPS only)
759 LIB_EXPORT TPM_RC
CryptEccGenerateKey(TPMT_PUBLIC * publicArea,TPMT_SENSITIVE * sensitive,RAND_STATE * rand)760 CryptEccGenerateKey(
761     TPMT_PUBLIC         *publicArea,        // IN/OUT: The public area template for
762                                             //      the new key. The public key
763                                             //      area will be replaced computed
764                                             //      ECC public key
765     TPMT_SENSITIVE      *sensitive,         // OUT: the sensitive area will be
766                                             //      updated to contain the private
767                                             //      ECC key and the symmetric
768                                             //      encryption key
769     RAND_STATE          *rand               // IN: if not NULL, the deterministic
770                                             //     RNG state
771     )
772 {
773     CURVE_INITIALIZED(E, publicArea->parameters.eccDetail.curveID);
774     ECC_NUM(bnD);
775     POINT(ecQ);
776     BOOL                     OK;
777     TPM_RC                   retVal;
778 //
779     TEST(TPM_ALG_ECDSA); // ECDSA is used to verify each key
780 
781     // Validate parameters
782     if(E == NULL)
783         ERROR_RETURN(TPM_RC_CURVE);
784 
785     publicArea->unique.ecc.x.t.size = 0;
786     publicArea->unique.ecc.y.t.size = 0;
787     sensitive->sensitive.ecc.t.size = 0;
788 
789     OK = BnEccGenerateKeyPair(bnD, ecQ, E, rand);
790     if(OK)
791     {
792         BnPointTo2B(&publicArea->unique.ecc, ecQ, E);
793         BnTo2B(bnD, &sensitive->sensitive.ecc.b, publicArea->unique.ecc.x.t.size);
794     }
795 #if FIPS_COMPLIANT
796     // See if PWCT is required
797     if(OK && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign))
798     {
799         ECC_NUM(bnT);
800         ECC_NUM(bnS);
801         TPM2B_DIGEST            digest;
802 //
803         TEST(TPM_ALG_ECDSA);
804         digest.t.size = MIN(sensitive->sensitive.ecc.t.size, sizeof(digest.t.buffer));
805         // Get a random value to sign using the built in DRBG state
806         DRBG_Generate(NULL, digest.t.buffer, digest.t.size);
807         if(g_inFailureMode)
808             return TPM_RC_FAILURE;
809         BnSignEcdsa(bnT, bnS, E, bnD, &digest, NULL);
810         // and make sure that we can validate the signature
811         OK = BnValidateSignatureEcdsa(bnT, bnS, E, ecQ, &digest) == TPM_RC_SUCCESS;
812     }
813 #endif
814     retVal = (OK) ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
815 Exit:
816     CURVE_FREE(E);
817     return retVal;
818 }
819 
820 #endif  // ALG_ECC