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, ¶meters->p.b, 0);
418 BnTo2B(data->prime, ¶meters->p.b, parameters->p.t.size);
419 BnTo2B(data->a, ¶meters->a.b, 0);
420 BnTo2B(data->b, ¶meters->b.b, 0);
421 BnTo2B(data->base.x, ¶meters->gX.b, parameters->p.t.size);
422 BnTo2B(data->base.y, ¶meters->gY.b, parameters->p.t.size);
423 // BnTo2B(data->base.x, ¶meters->gX.b, 0);
424 // BnTo2B(data->base.y, ¶meters->gY.b, 0);
425 BnTo2B(data->order, ¶meters->n.b, 0);
426 BnTo2B(data->h, ¶meters->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