blob: 8b9f3620bcf49e992e98cd0608adbde01443d907 [file] [log] [blame]
Vadim Bendebury56797522015-05-20 10:32:25 -07001// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 4: Supporting Routines
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
Vadim Bendebury0a050712015-05-29 11:35:04 -07008#include <string.h>
9
Vadim Bendebury56797522015-05-20 10:32:25 -070010#include "OsslCryptoEngine.h"
Vadim Bendebury0a050712015-05-29 11:35:04 -070011
Vadim Bendebury56797522015-05-20 10:32:25 -070012#ifdef TPM_ALG_ECC
13#include "CpriDataEcc.h"
14#include "CpriDataEcc.c"
15//
16//
17// Functions
18//
19// _cpri__EccStartup()
20//
21// This function is called at TPM Startup to initialize the crypto units.
22// In this implementation, no initialization is performed at startup but a future version may initialize the self-
23// test functions here.
24//
25LIB_EXPORT BOOL
26_cpri__EccStartup(
27 void
28 )
29{
30 return TRUE;
31}
32//
33//
34// _cpri__GetCurveIdByIndex()
35//
36// This function returns the number of the i-th implemented curve. The normal use would be to call this
37// function with i starting at 0. When the i is greater than or equal to the number of implemented curves,
38// TPM_ECC_NONE is returned.
39//
40LIB_EXPORT TPM_ECC_CURVE
41_cpri__GetCurveIdByIndex(
42 UINT16 i
43 )
44{
45 if(i >= ECC_CURVE_COUNT)
46 return TPM_ECC_NONE;
47 return eccCurves[i].curveId;
48}
49LIB_EXPORT UINT32
50_cpri__EccGetCurveCount(
51 void
52 )
53{
54 return ECC_CURVE_COUNT;
55}
56//
57//
58// _cpri__EccGetParametersByCurveId()
59//
60// This function returns a pointer to the curve data that is associated with the indicated curveId. If there is no
61// curve with the indicated ID, the function returns NULL.
62//
63//
64//
65//
66// Return Value Meaning
67//
68// NULL curve with the indicated TPM_ECC_CURVE value is not
69// implemented
70// non-NULL pointer to the curve data
71//
72LIB_EXPORT const ECC_CURVE *
73_cpri__EccGetParametersByCurveId(
74 TPM_ECC_CURVE curveId // IN: the curveID
75 )
76{
77 int i;
78 for(i = 0; i < ECC_CURVE_COUNT; i++)
79 {
80 if(eccCurves[i].curveId == curveId)
81 return &eccCurves[i];
82 }
83 FAIL(FATAL_ERROR_INTERNAL);
Vadim Bendebury0a050712015-05-29 11:35:04 -070084
85 return NULL; // Never reached.
Vadim Bendebury56797522015-05-20 10:32:25 -070086}
87static const ECC_CURVE_DATA *
88GetCurveData(
89 TPM_ECC_CURVE curveId // IN: the curveID
90 )
91{
92 const ECC_CURVE *curve = _cpri__EccGetParametersByCurveId(curveId);
93 return curve->curveData;
94}
95//
96//
97// Point2B()
98//
99// This function makes a TPMS_ECC_POINT from a BIGNUM EC_POINT.
100//
101static BOOL
102Point2B(
103 EC_GROUP *group, // IN: group for the point
104 TPMS_ECC_POINT *p, // OUT: receives the converted point
105 EC_POINT *ecP, // IN: the point to convert
106 INT16 size, // IN: size of the coordinates
107 BN_CTX *context // IN: working context
108 )
109{
110 BIGNUM *bnX;
111 BIGNUM *bnY;
112 BN_CTX_start(context);
113 bnX = BN_CTX_get(context);
114 bnY = BN_CTX_get(context);
115 if( bnY == NULL
116 // Get the coordinate values
117 || EC_POINT_get_affine_coordinates_GFp(group, ecP, bnX, bnY, context) != 1
118 // Convert x
119 || (!BnTo2B(&p->x.b, bnX, size))
120 // Convert y
121 || (!BnTo2B(&p->y.b, bnY, size))
122 )
123 FAIL(FATAL_ERROR_INTERNAL);
124 BN_CTX_end(context);
125 return TRUE;
126}
127//
128//
129// EccCurveInit()
130//
131// This function initializes the OpenSSL() group definition structure
132// This function is only used within this file.
133// It is a fatal error if groupContext is not provided.
134//
135// Return Value Meaning
136//
137// NULL the TPM_ECC_CURVE is not valid
138// non-NULL points to a structure in groupContext static EC_GROUP *
139//
140static EC_GROUP *
141EccCurveInit(
142 TPM_ECC_CURVE curveId, // IN: the ID of the curve
143 BN_CTX *groupContext // IN: the context in which the group is to be
144 // created
145 )
146{
147 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
148 EC_GROUP *group = NULL;
149 EC_POINT *P = NULL;
150 BN_CTX *context;
151 BIGNUM *bnP;
152 BIGNUM *bnA;
153 BIGNUM *bnB;
154 BIGNUM *bnX;
155 BIGNUM *bnY;
156 BIGNUM *bnN;
157 BIGNUM *bnH;
158 int ok = FALSE;
159 // Context must be provided and curve selector must be valid
160 pAssert(groupContext != NULL && curveData != NULL);
161 context = BN_CTX_new();
162 if(context == NULL)
163 FAIL(FATAL_ERROR_ALLOCATION);
164 BN_CTX_start(context);
165 bnP = BN_CTX_get(context);
166 bnA = BN_CTX_get(context);
167 bnB = BN_CTX_get(context);
168 bnX = BN_CTX_get(context);
169 bnY = BN_CTX_get(context);
170 bnN = BN_CTX_get(context);
171 bnH = BN_CTX_get(context);
172 if (bnH == NULL)
173 goto Cleanup;
174 // Convert the number formats
175 BnFrom2B(bnP, curveData->p);
176 BnFrom2B(bnA, curveData->a);
177 BnFrom2B(bnB, curveData->b);
178 BnFrom2B(bnX, curveData->x);
179 BnFrom2B(bnY, curveData->y);
180 BnFrom2B(bnN, curveData->n);
181 BnFrom2B(bnH, curveData->h);
182 // initialize EC group, associate a generator point and initialize the point
183 // from the parameter data
184 ok = ( (group = EC_GROUP_new_curve_GFp(bnP, bnA, bnB, groupContext)) != NULL
185 && (P = EC_POINT_new(group)) != NULL
186 && EC_POINT_set_affine_coordinates_GFp(group, P, bnX, bnY, groupContext)
187 && EC_GROUP_set_generator(group, P, bnN, bnH)
188 );
189Cleanup:
190 if (!ok && group != NULL)
191 {
192 EC_GROUP_free(group);
193 group = NULL;
194 }
195 if(P != NULL)
196 EC_POINT_free(P);
197 BN_CTX_end(context);
198 BN_CTX_free(context);
199 return group;
200}
201//
202//
203// PointFrom2B()
204//
205// This function sets the coordinates of an existing BN Point from a TPMS_ECC_POINT.
206//
207static EC_POINT *
208PointFrom2B(
209 EC_GROUP *group, // IN: the group for the point
210 EC_POINT *ecP, // IN: an existing BN point in the group
211 TPMS_ECC_POINT *p, // IN: the 2B coordinates of the point
212 BN_CTX *context // IN: the BIGNUM context
213 )
214{
215 BIGNUM *bnX;
216 BIGNUM *bnY;
217 // If the point is not allocated then just return a NULL
218 if(ecP == NULL)
219 return NULL;
220 BN_CTX_start(context);
221 bnX = BN_CTX_get(context);
222 bnY = BN_CTX_get(context);
223 if( // Set the coordinates of the point
224 bnY == NULL
225 || BN_bin2bn(p->x.t.buffer, p->x.t.size, bnX) == NULL
226 || BN_bin2bn(p->y.t.buffer, p->y.t.size, bnY) == NULL
227 || !EC_POINT_set_affine_coordinates_GFp(group, ecP, bnX, bnY, context)
228 )
229 FAIL(FATAL_ERROR_INTERNAL);
230 BN_CTX_end(context);
231 return ecP;
232}
233//
234//
235// EccInitPoint2B()
236//
237// This function allocates a point in the provided group and initializes it with the values in a
238// TPMS_ECC_POINT.
239//
240static EC_POINT *
241EccInitPoint2B(
242 EC_GROUP *group, // IN: group for the point
243 TPMS_ECC_POINT *p, // IN: the coordinates for the point
244 BN_CTX *context // IN: the BIGNUM context
245 )
246{
247 EC_POINT *ecP;
248 BN_CTX_start(context);
249 ecP = EC_POINT_new(group);
250 if(PointFrom2B(group, ecP, p, context) == NULL)
251 FAIL(FATAL_ERROR_INTERNAL);
252 BN_CTX_end(context);
253 return ecP;
254}
255//
256//
257// PointMul()
258//
259// This function does a point multiply and checks for the result being the point at infinity. Q = ([A]G + [B]P)
260//
261// Return Value Meaning
262//
263// CRYPT_NO_RESULT point is at infinity
264// CRYPT_SUCCESS point not at infinity
265//
266static CRYPT_RESULT
267PointMul(
268 EC_GROUP *group, // IN: group curve
269 EC_POINT *ecpQ, // OUT: result
270 BIGNUM *bnA, // IN: scalar for [A]G
271 EC_POINT *ecpP, // IN: point for [B]P
272 BIGNUM *bnB, // IN: scalar for [B]P
273 BN_CTX *context // IN: working context
274 )
275{
276 if(EC_POINT_mul(group, ecpQ, bnA, ecpP, bnB, context) != 1)
277 FAIL(FATAL_ERROR_INTERNAL);
278 if(EC_POINT_is_at_infinity(group, ecpQ))
279 return CRYPT_NO_RESULT;
280 return CRYPT_SUCCESS;
281}
282//
283//
284// GetRandomPrivate()
285//
286// This function gets a random value (d) to use as a private ECC key and then qualifies the key so that it is
287// between 0 < d < n.
288// It is a fatal error if dOut or pIn is not provided or if the size of pIn is larger than MAX_ECC_KEY_BYTES
289// (the largest buffer size of a TPM2B_ECC_PARAMETER)
290//
291static void
292GetRandomPrivate(
293 TPM2B_ECC_PARAMETER *dOut, // OUT: the qualified random value
294 const TPM2B *pIn // IN: the maximum value for the key
295 )
296{
297 int i;
298 BYTE *pb;
299 pAssert(pIn != NULL && dOut != NULL && pIn->size <= MAX_ECC_KEY_BYTES);
300 // Set the size of the output
301 dOut->t.size = pIn->size;
302 // Get some random bits
303 while(TRUE)
304 {
305 _cpri__GenerateRandom(dOut->t.size, dOut->t.buffer);
306 // See if the d < n
307 if(memcmp(dOut->t.buffer, pIn->buffer, pIn->size) < 0)
308 {
309 // dOut < n so make sure that 0 < dOut
310 for(pb = dOut->t.buffer, i = dOut->t.size; i > 0; i--)
311 {
312 if(*pb++ != 0)
313 return;
314 }
315 }
316 }
317}
318//
319//
Vadim Bendebury56797522015-05-20 10:32:25 -0700320// _cpri__EccPointMultiply
321//
322// This function computes 'R := [dIn]G + [uIn]QIn. Where dIn and uIn are scalars, G and QIn are points on
323// the specified curve and G is the default generator of the curve.
324// The xOut and yOut parameters are optional and may be set to NULL if not used.
325// It is not necessary to provide uIn if QIn is specified but one of uIn and dIn must be provided. If dIn and
326// QIn are specified but uIn is not provided, then R = [dIn]QIn.
327// If the multiply produces the point at infinity, the CRYPT_NO_RESULT is returned.
328// The sizes of xOut and yOut' will be set to be the size of the degree of the curve
329// It is a fatal error if dIn and uIn are both unspecified (NULL) or if Qin or Rout is unspecified.
330//
331//
332//
333//
334// Return Value Meaning
335//
336// CRYPT_SUCCESS point multiplication succeeded
337// CRYPT_POINT the point Qin is not on the curve
338// CRYPT_NO_RESULT the product point is at infinity
339//
340LIB_EXPORT CRYPT_RESULT
341_cpri__EccPointMultiply(
342 TPMS_ECC_POINT *Rout, // OUT: the product point R
343 TPM_ECC_CURVE curveId, // IN: the curve to use
344 TPM2B_ECC_PARAMETER *dIn, // IN: value to multiply against the
345 // curve generator
346 TPMS_ECC_POINT *Qin, // IN: point Q
347 TPM2B_ECC_PARAMETER *uIn // IN: scalar value for the multiplier
348 // of Q
349 )
350{
351 BN_CTX *context;
352 BIGNUM *bnD;
353 BIGNUM *bnU;
354 EC_GROUP *group;
355 EC_POINT *R = NULL;
356 EC_POINT *Q = NULL;
357 CRYPT_RESULT retVal = CRYPT_SUCCESS;
358 // Validate that the required parameters are provided.
359 pAssert((dIn != NULL || uIn != NULL) && (Qin != NULL || dIn != NULL));
360 // If a point is provided for the multiply, make sure that it is on the curve
361 if(Qin != NULL && !_cpri__EccIsPointOnCurve(curveId, Qin))
362 return CRYPT_POINT;
363 context = BN_CTX_new();
364 if(context == NULL)
365 FAIL(FATAL_ERROR_ALLOCATION);
366 BN_CTX_start(context);
367 bnU = BN_CTX_get(context);
368 bnD = BN_CTX_get(context);
369 group = EccCurveInit(curveId, context);
370 // There should be no path for getting a bad curve ID into this function.
371 pAssert(group != NULL);
372 // check allocations should have worked and allocate R
373 if( bnD == NULL
374 || (R = EC_POINT_new(group)) == NULL)
375 FAIL(FATAL_ERROR_ALLOCATION);
376 // If Qin is present, create the point
377 if(Qin != NULL)
378 {
379 // Assume the size variables do not overflow. This should not happen in
380 // the contexts in which this function will be called.
381 assert2Bsize(Qin->x.t);
382 assert2Bsize(Qin->x.t);
383 Q = EccInitPoint2B(group, Qin, context);
384 }
385 if(dIn != NULL)
386 {
387 // Assume the size variables do not overflow, which should not happen in
388 // the contexts that this function will be called.
389 assert2Bsize(dIn->t);
390 BnFrom2B(bnD, &dIn->b);
391 }
392 else
393 bnD = NULL;
394 // If uIn is specified, initialize its BIGNUM
395 if(uIn != NULL)
396 {
397 // Assume the size variables do not overflow, which should not happen in
398 // the contexts that this function will be called.
399 assert2Bsize(uIn->t);
400 BnFrom2B(bnU, &uIn->b);
401 }
402 // If uIn is not specified but Q is, then we are going to
403 // do R = [d]Q
404 else if(Qin != NULL)
405 {
406 bnU = bnD;
407 bnD = NULL;
408 }
409 // If neither Q nor u is specified, then null this pointer
410 else
411 bnU = NULL;
412 // Use the generator of the curve
413 if((retVal = PointMul(group, R, bnD, Q, bnU, context)) == CRYPT_SUCCESS)
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -0700414 Point2B(group, Rout, R, (INT16) ((EC_GROUP_get_degree(group)+7)/8), context);
Vadim Bendebury56797522015-05-20 10:32:25 -0700415 if (Q)
416 EC_POINT_free(Q);
417 if(R)
418 EC_POINT_free(R);
419 if(group)
420 EC_GROUP_free(group);
421 BN_CTX_end(context);
422 BN_CTX_free(context);
423 return retVal;
424}
nagendra modadugu16e65be2016-03-08 11:05:25 -0800425#if defined TPM_ALG_ECDAA || defined TPM_ALG_SM2 //%
Vadim Bendebury56797522015-05-20 10:32:25 -0700426//
427//
428// ClearPoint2B()
429//
430// Initialize the size values of a point
431//
432static void
433ClearPoint2B(
434 TPMS_ECC_POINT *p // IN: the point
435 )
436{
437 if(p != NULL) {
438 p->x.t.size = 0;
439 p->y.t.size = 0;
440 }
441}
Vadim Bendebury56797522015-05-20 10:32:25 -0700442//
443//
444// _cpri__EccCommitCompute()
445//
446// This function performs the point multiply operations required by TPM2_Commit().
447// If B or M is provided, they must be on the curve defined by curveId. This routine does not check that they
448// are on the curve and results are unpredictable if they are not.
449//
450//
451//
452// It is a fatal error if r or d is NULL. If B is not NULL, then it is a fatal error if K and L are both NULL. If M is
453// not NULL, then it is a fatal error if E is NULL.
454//
455// Return Value Meaning
456//
457// CRYPT_SUCCESS computations completed normally
458// CRYPT_NO_RESULT if K, L or E was computed to be the point at infinity
459// CRYPT_CANCEL a cancel indication was asserted during this function
460//
461LIB_EXPORT CRYPT_RESULT
462_cpri__EccCommitCompute(
463 TPMS_ECC_POINT *K, // OUT: [d]B or [r]Q
464 TPMS_ECC_POINT *L, // OUT: [r]B
465 TPMS_ECC_POINT *E, // OUT: [r]M
466 TPM_ECC_CURVE curveId, // IN: the curve for the computations
467 TPMS_ECC_POINT *M, // IN: M (optional)
468 TPMS_ECC_POINT *B, // IN: B (optional)
469 TPM2B_ECC_PARAMETER *d, // IN: d (required)
470 TPM2B_ECC_PARAMETER *r // IN: the computed r value (required)
471 )
472{
473 BN_CTX *context;
Vadim Bendebury0a050712015-05-29 11:35:04 -0700474 BIGNUM *bnY, *bnR, *bnD;
Vadim Bendebury56797522015-05-20 10:32:25 -0700475 EC_GROUP *group;
476 EC_POINT *pK = NULL, *pL = NULL, *pE = NULL, *pM = NULL, *pB = NULL;
477 UINT16 keySizeInBytes;
478 CRYPT_RESULT retVal = CRYPT_SUCCESS;
479 // Validate that the required parameters are provided.
480 // Note: E has to be provided if computing E := [r]Q or E := [r]M. Will do
481 // E := [r]Q if both M and B are NULL.
Vadim Bendebury0a050712015-05-29 11:35:04 -0700482
483 pAssert((r && (K || !B) && (L || !B)) || (E || (!M && B)));
Vadim Bendebury56797522015-05-20 10:32:25 -0700484 context = BN_CTX_new();
485 if(context == NULL)
486 FAIL(FATAL_ERROR_ALLOCATION);
487 BN_CTX_start(context);
488 bnR = BN_CTX_get(context);
489 bnD = BN_CTX_get(context);
Vadim Bendebury56797522015-05-20 10:32:25 -0700490 bnY = BN_CTX_get(context);
491 if(bnY == NULL)
492 FAIL(FATAL_ERROR_ALLOCATION);
493 // Initialize the output points in case they are not computed
494 ClearPoint2B(K);
495 ClearPoint2B(L);
496 ClearPoint2B(E);
497 if((group = EccCurveInit(curveId, context)) == NULL)
498 {
499 retVal = CRYPT_PARAMETER;
500 goto Cleanup2;
501 }
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -0700502 keySizeInBytes = (UINT16) ((EC_GROUP_get_degree(group)+7)/8);
Vadim Bendebury56797522015-05-20 10:32:25 -0700503 // Sizes of the r and d parameters may not be zero
504 pAssert(((int) r->t.size > 0) && ((int) d->t.size > 0));
505 // Convert scalars to BIGNUM
506 BnFrom2B(bnR, &r->b);
507 BnFrom2B(bnD, &d->b);
508 // If B is provided, compute K=[d]B and L=[r]B
509 if(B != NULL)
510 {
511 // Allocate the points to receive the value
512 if( (pK = EC_POINT_new(group)) == NULL
513 || (pL = EC_POINT_new(group)) == NULL)
514 FAIL(FATAL_ERROR_ALLOCATION);
515 // need to compute K = [d]B
516 // Allocate and initialize BIGNUM version of B
517 pB = EccInitPoint2B(group, B, context);
518 // do the math for K = [d]B
519 if((retVal = PointMul(group, pK, NULL, pB, bnD, context)) != CRYPT_SUCCESS)
520 goto Cleanup;
521 // Convert BN K to TPM2B K
522 Point2B(group, K, pK, (INT16)keySizeInBytes, context);
523 // compute L= [r]B after checking for cancel
524 if(_plat__IsCanceled())
525 {
526 retVal = CRYPT_CANCEL;
527 goto Cleanup;
528 }
529 // compute L = [r]B
530 if((retVal = PointMul(group, pL, NULL, pB, bnR, context)) != CRYPT_SUCCESS)
531 goto Cleanup;
532 // Convert BN L to TPM2B L
533 Point2B(group, L, pL, (INT16)keySizeInBytes, context);
534 }
535 if(M != NULL || B == NULL)
536 {
537 // if this is the third point multiply, check for cancel first
538 if(B != NULL && _plat__IsCanceled())
539 {
540 retVal = CRYPT_CANCEL;
541 goto Cleanup;
542 }
543 // Allocate E
544 if((pE = EC_POINT_new(group)) == NULL)
545 FAIL(FATAL_ERROR_ALLOCATION);
546 // Create BIGNUM version of M unless M is NULL
547 if(M != NULL)
548 {
549 // M provided so initialize a BIGNUM M and compute E = [r]M
550 pM = EccInitPoint2B(group, M, context);
551 retVal = PointMul(group, pE, NULL, pM, bnR, context);
552 }
553 else
554 // compute E = [r]G (this is only done if M and B are both NULL
555 retVal = PointMul(group, pE, bnR, NULL, NULL, context);
556 if(retVal == CRYPT_SUCCESS)
557 // Convert E to 2B format
558 Point2B(group, E, pE, (INT16)keySizeInBytes, context);
559 }
560Cleanup:
561 EC_GROUP_free(group);
562 if(pK != NULL) EC_POINT_free(pK);
563 if(pL != NULL) EC_POINT_free(pL);
564 if(pE != NULL) EC_POINT_free(pE);
565 if(pM != NULL) EC_POINT_free(pM);
566 if(pB != NULL) EC_POINT_free(pB);
567Cleanup2:
568 BN_CTX_end(context);
569 BN_CTX_free(context);
570 return retVal;
571}
572#endif //%
573//
574//
575// _cpri__EccIsPointOnCurve()
576//
577// This function is used to test if a point is on a defined curve. It does this by checking that y^2 mod p = x^3
578// + a*x + b mod p
579// It is a fatal error if Q is not specified (is NULL).
580//
581// Return Value Meaning
582//
583// TRUE point is on curve
584// FALSE point is not on curve or curve is not supported
585//
586LIB_EXPORT BOOL
587_cpri__EccIsPointOnCurve(
588 TPM_ECC_CURVE curveId, // IN: the curve selector
589 TPMS_ECC_POINT *Q // IN: the point.
590 )
591{
592 BN_CTX *context;
593 BIGNUM *bnX;
594 BIGNUM *bnY;
595 BIGNUM *bnA;
596 BIGNUM *bnB;
597 BIGNUM *bnP;
598 BIGNUM *bn3;
599 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
600 BOOL retVal;
601 pAssert(Q != NULL && curveData != NULL);
602 if((context = BN_CTX_new()) == NULL)
603 FAIL(FATAL_ERROR_ALLOCATION);
604 BN_CTX_start(context);
605 bnX = BN_CTX_get(context);
606 bnY = BN_CTX_get(context);
607 bnA = BN_CTX_get(context);
608 bnB = BN_CTX_get(context);
609 bn3 = BN_CTX_get(context);
610 bnP = BN_CTX_get(context);
611 if(bnP == NULL)
612 FAIL(FATAL_ERROR_ALLOCATION);
613 // Convert values
614 if ( !BN_bin2bn(Q->x.t.buffer, Q->x.t.size, bnX)
615 || !BN_bin2bn(Q->y.t.buffer, Q->y.t.size, bnY)
616 || !BN_bin2bn(curveData->p->buffer, curveData->p->size, bnP)
617 || !BN_bin2bn(curveData->a->buffer, curveData->a->size, bnA)
618 || !BN_set_word(bn3, 3)
619 || !BN_bin2bn(curveData->b->buffer, curveData->b->size, bnB)
620 )
621 FAIL(FATAL_ERROR_INTERNAL);
622 // The following sequence is probably not optimal but it seems to be correct.
623 // compute x^3 + a*x + b mod p
624 // first, compute a*x mod p
625 if( !BN_mod_mul(bnA, bnA, bnX, bnP, context)
626//
627 // next, compute a*x + b mod p
628 || !BN_mod_add(bnA, bnA, bnB, bnP, context)
629 // next, compute X^3 mod p
630 || !BN_mod_exp(bnX, bnX, bn3, bnP, context)
631 // finally, compute x^3 + a*x + b mod p
632 || !BN_mod_add(bnX, bnX, bnA, bnP, context)
633 // then compute y^2
634 || !BN_mod_mul(bnY, bnY, bnY, bnP, context)
635 )
636 FAIL(FATAL_ERROR_INTERNAL);
637 retVal = BN_cmp(bnX, bnY) == 0;
638 BN_CTX_end(context);
639 BN_CTX_free(context);
640 return retVal;
641}
642//
643//
644// _cpri__GenerateKeyEcc()
645//
646// This function generates an ECC key pair based on the input parameters. This routine uses KDFa() to
647// produce candidate numbers. The method is according to FIPS 186-3, section B.4.1 "GKey() Pair
648// Generation Using Extra Random Bits." According to the method in FIPS 186-3, the resulting private value
649// d should be 1 <= d < n where n is the order of the base point. In this implementation, the range of the
650// private value is further restricted to be 2^(nLen/2) <= d < n where nLen is the order of n.
651//
652// EXAMPLE: If the curve is NIST-P256, then nLen is 256 bits and d will need to be between 2^128 <= d < n
653//
654// It is a fatal error if Qout, dOut, or seed is not provided (is NULL).
655//
656// Return Value Meaning
657//
658// CRYPT_PARAMETER the hash algorithm is not supported
659//
660LIB_EXPORT CRYPT_RESULT
661_cpri__GenerateKeyEcc(
662 TPMS_ECC_POINT *Qout, // OUT: the public point
663 TPM2B_ECC_PARAMETER *dOut, // OUT: the private scalar
664 TPM_ECC_CURVE curveId, // IN: the curve identifier
665 TPM_ALG_ID hashAlg, // IN: hash algorithm to use in the key
666 // generation process
667 TPM2B *seed, // IN: the seed to use
668 const char *label, // IN: A label for the generation
669 // process.
670 TPM2B *extra, // IN: Party 1 data for the KDF
671 UINT32 *counter // IN/OUT: Counter value to allow KDF
672 // iteration to be propagated across
673 // multiple functions
674 )
675{
676 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
677 INT16 keySizeInBytes;
678 UINT32 count = 0;
679 CRYPT_RESULT retVal;
680 UINT16 hLen = _cpri__GetDigestSize(hashAlg);
681 BIGNUM *bnNm1; // Order of the curve minus one
682 BIGNUM *bnD; // the private scalar
683 BN_CTX *context; // the context for the BIGNUM values
684 BYTE withExtra[MAX_ECC_KEY_BYTES + 8]; // trial key with
685 //extra bits
Vadim Bendebury0a050712015-05-29 11:35:04 -0700686 TPM2B_4_BYTE_VALUE marshaledCounter = {.t = {4}};
Vadim Bendebury56797522015-05-20 10:32:25 -0700687 UINT32 totalBits;
688 // Validate parameters (these are fatal)
689 pAssert( seed != NULL && dOut != NULL && Qout != NULL && curveData != NULL);
690 // Non-fatal parameter checks.
691 if(hLen <= 0)
692 return CRYPT_PARAMETER;
693 // allocate the local BN values
694 context = BN_CTX_new();
695 if(context == NULL)
696 FAIL(FATAL_ERROR_ALLOCATION);
697 BN_CTX_start(context);
698 bnNm1 = BN_CTX_get(context);
699 bnD = BN_CTX_get(context);
700 // The size of the input scalars is limited by the size of the size of a
701 // TPM2B_ECC_PARAMETER. Make sure that it is not irrational.
702 pAssert((int) curveData->n->size <= MAX_ECC_KEY_BYTES);
703 if( bnD == NULL
704 || BN_bin2bn(curveData->n->buffer, curveData->n->size, bnNm1) == NULL
705 || (keySizeInBytes = (INT16) BN_num_bytes(bnNm1)) > MAX_ECC_KEY_BYTES)
706 FAIL(FATAL_ERROR_INTERNAL);
707 // get the total number of bits
708 totalBits = BN_num_bits(bnNm1) + 64;
709 // Reduce bnNm1 from 'n' to 'n' - 1
710 BN_sub_word(bnNm1, 1);
711 // Initialize the count value
712 if(counter != NULL)
713 count = *counter;
714 if(count == 0)
715 count = 1;
716 // Start search for key (should be quick)
717 for(; count != 0; count++)
718 {
719 UINT32_TO_BYTE_ARRAY(count, marshaledCounter.t.buffer);
720 _cpri__KDFa(hashAlg, seed, label, extra, &marshaledCounter.b,
721 totalBits, withExtra, NULL, FALSE);
722 // Convert the result and modular reduce
723 // Assume the size variables do not overflow, which should not happen in
724 // the contexts that this function will be called.
725 pAssert(keySizeInBytes <= MAX_ECC_KEY_BYTES);
726 if ( BN_bin2bn(withExtra, keySizeInBytes+8, bnD) == NULL
727 || BN_mod(bnD, bnD, bnNm1, context) != 1)
728 FAIL(FATAL_ERROR_INTERNAL);
729 // Add one to get 0 < d < n
730 BN_add_word(bnD, 1);
731 if(BnTo2B(&dOut->b, bnD, keySizeInBytes) != 1)
732 FAIL(FATAL_ERROR_INTERNAL);
733 // Do the point multiply to create the public portion of the key. If
734 // the multiply generates the point at infinity (unlikely), do another
735 // iteration.
736 if( (retVal = _cpri__EccPointMultiply(Qout, curveId, dOut, NULL, NULL))
737 != CRYPT_NO_RESULT)
738 break;
739 }
740 if(count == 0) // if counter wrapped, then the TPM should go into failure mode
741 FAIL(FATAL_ERROR_INTERNAL);
742 // Free up allocated BN values
743 BN_CTX_end(context);
744 BN_CTX_free(context);
745 if(counter != NULL)
746 *counter = count;
747 return retVal;
748}
749//
750//
751// _cpri__GetEphemeralEcc()
752//
753// This function creates an ephemeral ECC. It is ephemeral in that is expected that the private part of the
754// key will be discarded
755//
756LIB_EXPORT CRYPT_RESULT
757_cpri__GetEphemeralEcc(
758 TPMS_ECC_POINT *Qout, // OUT: the public point
759 TPM2B_ECC_PARAMETER *dOut, // OUT: the private scalar
760 TPM_ECC_CURVE curveId // IN: the curve for the key
761 )
762{
763 CRYPT_RESULT retVal;
764 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
765 pAssert(curveData != NULL);
766 // Keep getting random values until one is found that doesn't create a point
767 // at infinity. This will never, ever, ever, ever, ever, happen but if it does
768 // we have to get a next random value.
769 while(TRUE)
770 {
771 GetRandomPrivate(dOut, curveData->p);
772 // _cpri__EccPointMultiply does not return CRYPT_ECC_POINT if no point is
773 // provided. CRYPT_PARAMTER should not be returned because the curve ID
774 // has to be supported. Thus the only possible error is CRYPT_NO_RESULT.
775 retVal = _cpri__EccPointMultiply(Qout, curveId, dOut, NULL, NULL);
776 if(retVal != CRYPT_NO_RESULT)
777 return retVal; // Will return CRYPT_SUCCESS
778 }
779}
780#ifdef TPM_ALG_ECDSA //%
781//
782//
783// SignEcdsa()
784//
785// This function implements the ECDSA signing algorithm. The method is described in the comments below.
786// It is a fatal error if rOut, sOut, dIn, or digest are not provided.
787//
788LIB_EXPORT CRYPT_RESULT
789SignEcdsa(
790 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature
791 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature
792 TPM_ECC_CURVE curveId, // IN: the curve used in the signature
793 // process
794 TPM2B_ECC_PARAMETER *dIn, // IN: the private key
795 TPM2B *digest // IN: the value to sign
796 )
797{
798 BIGNUM *bnK;
799 BIGNUM *bnIk;
800 BIGNUM *bnN;
801 BIGNUM *bnR;
802//
803 BIGNUM *bnD;
804 BIGNUM *bnZ;
805 TPM2B_ECC_PARAMETER k;
806 TPMS_ECC_POINT R;
807 BN_CTX *context;
808 CRYPT_RESULT retVal = CRYPT_SUCCESS;
809 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
810 pAssert(rOut != NULL && sOut != NULL && dIn != NULL && digest != NULL);
811 context = BN_CTX_new();
812 if(context == NULL)
813 FAIL(FATAL_ERROR_ALLOCATION);
814 BN_CTX_start(context);
815 bnN = BN_CTX_get(context);
816 bnZ = BN_CTX_get(context);
817 bnR = BN_CTX_get(context);
818 bnD = BN_CTX_get(context);
819 bnIk = BN_CTX_get(context);
820 bnK = BN_CTX_get(context);
821 // Assume the size variables do not overflow, which should not happen in
822 // the contexts that this function will be called.
823 pAssert(curveData->n->size <= MAX_ECC_PARAMETER_BYTES);
824 if( bnK == NULL
825 || BN_bin2bn(curveData->n->buffer, curveData->n->size, bnN) == NULL)
826 FAIL(FATAL_ERROR_INTERNAL);
827// The algorithm as described in "Suite B Implementer's Guide to FIPS 186-3(ECDSA)"
828// 1. Use one of the routines in Appendix A.2 to generate (k, k^-1), a per-message
829// secret number and its inverse modulo n. Since n is prime, the
830// output will be invalid only if there is a failure in the RBG.
831// 2. Compute the elliptic curve point R = [k]G = (xR, yR) using EC scalar
832// multiplication (see [Routines]), where G is the base point included in
833// the set of domain parameters.
834// 3. Compute r = xR mod n. If r = 0, then return to Step 1. 1.
835// 4. Use the selected hash function to compute H = Hash(M).
836// 5. Convert the bit string H to an integer e as described in Appendix B.2.
837// 6. Compute s = (k^-1 * (e + d * r)) mod n. If s = 0, return to Step 1.2.
838// 7. Return (r, s).
839 // Generate a random value k in the range 1 <= k < n
840 // Want a K value that is the same size as the curve order
841 k.t.size = curveData->n->size;
842 while(TRUE) // This implements the loop at step 6. If s is zero, start over.
843 {
844 while(TRUE)
845 {
846 // Step 1 and 2 -- generate an ephemeral key and the modular inverse
847 // of the private key.
848 while(TRUE)
849 {
850 GetRandomPrivate(&k, curveData->n);
851 // Do the point multiply to generate a point and check to see if
852 // the point it at infinity
853 if( _cpri__EccPointMultiply(&R, curveId, &k, NULL, NULL)
854 != CRYPT_NO_RESULT)
855 break; // can only be CRYPT_SUCCESS
856 }
857 // x coordinate is mod p. Make it mod n
858 // Assume the size variables do not overflow, which should not happen
859 // in the contexts that this function will be called.
860 assert2Bsize(R.x.t);
861 BN_bin2bn(R.x.t.buffer, R.x.t.size, bnR);
862 BN_mod(bnR, bnR, bnN, context);
863 // Make sure that it is not zero;
864 if(BN_is_zero(bnR))
865 continue;
866 // Make sure that a modular inverse exists
867 // Assume the size variables do not overflow, which should not happen
868 // in the contexts that this function will be called.
869 assert2Bsize(k.t);
870 BN_bin2bn(k.t.buffer, k.t.size, bnK);
871 if( BN_mod_inverse(bnIk, bnK, bnN, context) != NULL)
872 break;
873 }
874 // Set z = leftmost bits of the digest
875 // NOTE: This is implemented such that the key size needs to be
876 // an even number of bytes in length.
877 if(digest->size > curveData->n->size)
878 {
879 // Assume the size variables do not overflow, which should not happen
880 // in the contexts that this function will be called.
881 pAssert(curveData->n->size <= MAX_ECC_KEY_BYTES);
882 // digest is larger than n so truncate
883 BN_bin2bn(digest->buffer, curveData->n->size, bnZ);
884 }
885 else
886 {
887 // Assume the size variables do not overflow, which should not happen
888 // in the contexts that this function will be called.
889 pAssert(digest->size <= MAX_DIGEST_SIZE);
890 // digest is same or smaller than n so use it all
891 BN_bin2bn(digest->buffer, digest->size, bnZ);
892 }
893 // Assume the size variables do not overflow, which should not happen in
894 // the contexts that this function will be called.
895 assert2Bsize(dIn->t);
896 if( bnZ == NULL
897 // need the private scalar of the signing key
898 || BN_bin2bn(dIn->t.buffer, dIn->t.size, bnD) == NULL)
899 FAIL(FATAL_ERROR_INTERNAL);
900 // NOTE: When the result of an operation is going to be reduced mod x
901 // any modular multiplication is done so that the intermediate values
902 // don't get too large.
903 //
904 // now have inverse of K (bnIk), z (bnZ), r (bnR), d (bnD) and n (bnN)
905 // Compute s = k^-1 (z + r*d)(mod n)
906 // first do d = r*d mod n
907 if( !BN_mod_mul(bnD, bnR, bnD, bnN, context)
908 // d = z + r * d
909 || !BN_add(bnD, bnZ, bnD)
910 // d = k^(-1)(z + r * d)(mod n)
911 || !BN_mod_mul(bnD, bnIk, bnD, bnN, context)
912 // convert to TPM2B format
913 || !BnTo2B(&sOut->b, bnD, curveData->n->size)
914 // and write the modular reduced version of r
915 // NOTE: this was deferred to reduce the number of
916 // error checks.
917 || !BnTo2B(&rOut->b, bnR, curveData->n->size))
918 FAIL(FATAL_ERROR_INTERNAL);
919 if(!BN_is_zero(bnD))
920 break; // signature not zero so done
921 // if the signature value was zero, start over
922 }
923 // Free up allocated BN values
924 BN_CTX_end(context);
925 BN_CTX_free(context);
926 return retVal;
927}
928#endif //%
929#if defined TPM_ALG_ECDAA || defined TPM_ALG_ECSCHNORR //%
930//
931//
932// EcDaa()
933//
934// This function is used to perform a modified Schnorr signature for ECDAA.
935// This function performs s = k + T * d mod n where
936// a) 'k is a random, or pseudo-random value used in the commit phase
937// b) T is the digest to be signed, and
938// c) d is a private key.
939// If tIn is NULL then use tOut as T
940//
941// Return Value Meaning
942//
943// CRYPT_SUCCESS signature created
944//
945static CRYPT_RESULT
946EcDaa(
947 TPM2B_ECC_PARAMETER *tOut, // OUT: T component of the signature
948 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature
949 TPM_ECC_CURVE curveId, // IN: the curve used in signing
950 TPM2B_ECC_PARAMETER *dIn, // IN: the private key
951 TPM2B *tIn, // IN: the value to sign
952 TPM2B_ECC_PARAMETER *kIn // IN: a random value from commit
953 )
954{
955 BIGNUM *bnN, *bnK, *bnT, *bnD;
956 BN_CTX *context;
957 const TPM2B *n;
958 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
959 BOOL OK = TRUE;
960 // Parameter checks
961 pAssert( sOut != NULL && dIn != NULL && tOut != NULL
962 && kIn != NULL && curveData != NULL);
963 // this just saves key strokes
964 n = curveData->n;
965 if(tIn != NULL)
966 Copy2B(&tOut->b, tIn);
967 // The size of dIn and kIn input scalars is limited by the size of the size
968 // of a TPM2B_ECC_PARAMETER and tIn can be no larger than a digest.
969 // Make sure they are within range.
970 pAssert( (int) dIn->t.size <= MAX_ECC_KEY_BYTES
971 && (int) kIn->t.size <= MAX_ECC_KEY_BYTES
972//
973 && (int) tOut->t.size <= MAX_DIGEST_SIZE
974 );
975 context = BN_CTX_new();
976 if(context == NULL)
977 FAIL(FATAL_ERROR_ALLOCATION);
978 BN_CTX_start(context);
979 bnN = BN_CTX_get(context);
980 bnK = BN_CTX_get(context);
981 bnT = BN_CTX_get(context);
982 bnD = BN_CTX_get(context);
983 // Check for allocation problems
984 if(bnD == NULL)
985 FAIL(FATAL_ERROR_ALLOCATION);
986 // Convert values
987 if( BN_bin2bn(n->buffer, n->size, bnN) == NULL
988 || BN_bin2bn(kIn->t.buffer, kIn->t.size, bnK) == NULL
989 || BN_bin2bn(dIn->t.buffer, dIn->t.size, bnD) == NULL
990 || BN_bin2bn(tOut->t.buffer, tOut->t.size, bnT) == NULL)
991 FAIL(FATAL_ERROR_INTERNAL);
992 // Compute T = T mod n
993 OK = OK && BN_mod(bnT, bnT, bnN, context);
994 // compute (s = k + T * d mod n)
995 // d = T * d mod n
996 OK = OK && BN_mod_mul(bnD, bnT, bnD, bnN, context) == 1;
997 // d = k + T * d mod n
998 OK = OK && BN_mod_add(bnD, bnK, bnD, bnN, context) == 1;
999 // s = d
1000 OK = OK && BnTo2B(&sOut->b, bnD, n->size);
1001 // r = T
1002 OK = OK && BnTo2B(&tOut->b, bnT, n->size);
1003 if(!OK)
1004 FAIL(FATAL_ERROR_INTERNAL);
1005 // Cleanup
1006 BN_CTX_end(context);
1007 BN_CTX_free(context);
1008 return CRYPT_SUCCESS;
1009}
1010#endif //%
1011#ifdef TPM_ALG_ECSCHNORR //%
1012//
1013//
Vadim Bendebury0343d5b2015-10-08 17:31:34 -07001014// Mod2B()
1015//
1016// Function does modular reduction of TPM2B values.
1017//
1018static CRYPT_RESULT
1019Mod2B(
1020 TPM2B *x, // IN/OUT: value to reduce
1021 const TPM2B *n // IN: mod
1022 )
1023{
1024 int compare;
1025 compare = _math__uComp(x->size, x->buffer, n->size, n->buffer);
1026 if(compare < 0)
1027 // if x < n, then mod is x
1028 return CRYPT_SUCCESS;
1029 if(compare == 0)
1030 {
1031 // if x == n then mod is 0
1032 x->size = 0;
1033 x->buffer[0] = 0;
1034 return CRYPT_SUCCESS;
1035 }
1036 return _math__Div(x, n, NULL, x);
1037}
1038
1039//
1040//
Vadim Bendebury56797522015-05-20 10:32:25 -07001041// SchnorrEcc()
1042//
1043// This function is used to perform a modified Schnorr signature.
1044// This function will generate a random value k and compute
1045// a) (xR, yR) = [k]G
1046// b) r = hash(P || xR)(mod n)
1047// c) s= k + r * ds
1048// d) return the tuple T, s
1049//
1050//
1051//
1052//
1053// Return Value Meaning
1054//
1055// CRYPT_SUCCESS signature created
1056// CRYPT_SCHEME hashAlg can't produce zero-length digest
1057//
1058static CRYPT_RESULT
1059SchnorrEcc(
1060 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature
1061 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature
1062 TPM_ALG_ID hashAlg, // IN: hash algorithm used
1063 TPM_ECC_CURVE curveId, // IN: the curve used in signing
1064 TPM2B_ECC_PARAMETER *dIn, // IN: the private key
1065 TPM2B *digest, // IN: the digest to sign
1066 TPM2B_ECC_PARAMETER *kIn // IN: for testing
1067 )
1068{
1069 TPM2B_ECC_PARAMETER k;
1070 BIGNUM *bnR, *bnN, *bnK, *bnT, *bnD;
1071 BN_CTX *context;
1072 const TPM2B *n;
1073 EC_POINT *pR = NULL;
1074 EC_GROUP *group = NULL;
1075 CPRI_HASH_STATE hashState;
1076 UINT16 digestSize = _cpri__GetDigestSize(hashAlg);
1077 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1078 TPM2B_TYPE(T, MAX(MAX_DIGEST_SIZE, MAX_ECC_PARAMETER_BYTES));
1079 TPM2B_T T2b;
1080 BOOL OK = TRUE;
1081 // Parameter checks
1082 // Must have a place for the 'r' and 's' parts of the signature, a private
1083 // key ('d')
1084 pAssert( rOut != NULL && sOut != NULL && dIn != NULL
1085 && digest != NULL && curveData != NULL);
1086 // to save key strokes
1087 n = curveData->n;
1088 // If the digest does not produce a hash, then null the signature and return
1089 // a failure.
1090 if(digestSize == 0)
1091 {
1092 rOut->t.size = 0;
1093 sOut->t.size = 0;
1094 return CRYPT_SCHEME;
1095 }
1096 // Allocate big number values
1097 context = BN_CTX_new();
1098 if(context == NULL)
1099 FAIL(FATAL_ERROR_ALLOCATION);
1100 BN_CTX_start(context);
1101 bnR = BN_CTX_get(context);
1102 bnN = BN_CTX_get(context);
1103 bnK = BN_CTX_get(context);
1104 bnT = BN_CTX_get(context);
1105 bnD = BN_CTX_get(context);
1106 if( bnD == NULL
1107 // initialize the group parameters
1108 || (group = EccCurveInit(curveId, context)) == NULL
1109 // allocate a local point
1110 || (pR = EC_POINT_new(group)) == NULL
1111 )
1112 FAIL(FATAL_ERROR_ALLOCATION);
1113 if(BN_bin2bn(curveData->n->buffer, curveData->n->size, bnN) == NULL)
1114 FAIL(FATAL_ERROR_INTERNAL);
1115 while(OK)
1116 {
1117// a) set k to a random value such that 1 k n-1
1118 if(kIn != NULL)
1119 {
1120 Copy2B(&k.b, &kIn->b); // copy input k if testing
1121 OK = FALSE; // not OK to loop
1122 }
1123 else
1124 // If get a random value in the correct range
1125 GetRandomPrivate(&k, n);
1126 // Convert 'k' and generate pR = ['k']G
1127 BnFrom2B(bnK, &k.b);
1128// b) compute E (xE, yE) [k]G
1129 if(PointMul(group, pR, bnK, NULL, NULL, context) == CRYPT_NO_RESULT)
1130// c) if E is the point at infinity, go to a)
1131 continue;
1132// d) compute e xE (mod n)
1133 // Get the x coordinate of the point
1134 EC_POINT_get_affine_coordinates_GFp(group, pR, bnR, NULL, context);
1135 // make (mod n)
1136 BN_mod(bnR, bnR, bnN, context);
1137// e) if e is zero, go to a)
1138 if(BN_is_zero(bnR))
1139 continue;
1140 // Convert xR to a string (use T as a temp)
1141 BnTo2B(&T2b.b, bnR, (UINT16)(BN_num_bits(bnR)+7)/8);
1142// f) compute r HschemeHash(P || e) (mod n)
1143 _cpri__StartHash(hashAlg, FALSE, &hashState);
1144 _cpri__UpdateHash(&hashState, digest->size, digest->buffer);
1145 _cpri__UpdateHash(&hashState, T2b.t.size, T2b.t.buffer);
1146 if(_cpri__CompleteHash(&hashState, digestSize, T2b.b.buffer) != digestSize)
1147 FAIL(FATAL_ERROR_INTERNAL);
1148 T2b.t.size = digestSize;
1149 BnFrom2B(bnT, &T2b.b);
1150 BN_div(NULL, bnT, bnT, bnN, context);
1151 BnTo2B(&rOut->b, bnT, (UINT16)BN_num_bytes(bnT));
1152 // We have a value and we are going to exit the loop successfully
1153 OK = TRUE;
1154 break;
1155 }
1156 // Cleanup
1157 EC_POINT_free(pR);
1158 EC_GROUP_free(group);
1159 BN_CTX_end(context);
1160 BN_CTX_free(context);
1161 // If we have a value, finish the signature
1162 if(OK)
1163 return EcDaa(rOut, sOut, curveId, dIn, NULL, &k);
1164 else
1165 return CRYPT_NO_RESULT;
1166}
1167#endif //%
1168#ifdef TPM_ALG_SM2 //%
1169#ifdef _SM2_SIGN_DEBUG //%
1170static int
1171cmp_bn2hex(
1172 BIGNUM *bn, // IN: big number value
1173 const char *c // IN: character string number
1174 )
1175{
1176 int result;
1177 BIGNUM *bnC = BN_new();
1178 pAssert(bnC != NULL);
1179 BN_hex2bn(&bnC, c);
1180 result = BN_ucmp(bn, bnC);
1181 BN_free(bnC);
1182 return result;
1183}
1184static int
1185cmp_2B2hex(
1186 TPM2B *a, // IN: TPM2B number to compare
1187 const char *c // IN: character string
1188 )
1189{
1190 int result;
1191 int sl = strlen(c);
1192 BIGNUM *bnA;
1193 result = (a->size * 2) - sl;
1194 if(result != 0)
1195 return result;
1196 pAssert((bnA = BN_bin2bn(a->buffer, a->size, NULL)) != NULL);
1197 result = cmp_bn2hex(bnA, c);
1198 BN_free(bnA);
1199 return result;
1200}
1201static void
1202cpy_hexTo2B(
1203 TPM2B *b, // OUT: receives value
1204 const char *c // IN: source string
1205 )
1206{
1207 BIGNUM *bnB = BN_new();
1208 pAssert((strlen(c) & 1) == 0); // must have an even number of digits
1209 b->size = strlen(c) / 2;
1210 BN_hex2bn(&bnB, c);
1211 pAssert(bnB != NULL);
1212 BnTo2B(b, bnB, b->size);
1213 BN_free(bnB);
1214}
1215#endif //% _SM2_SIGN_DEBUG
1216//
1217//
1218// SignSM2()
1219//
1220// This function signs a digest using the method defined in SM2 Part 2. The method in the standard will add
1221// a header to the message to be signed that is a hash of the values that define the key. This then hashed
1222// with the message to produce a digest (e) that is signed. This function signs e.
1223//
1224//
1225//
1226//
1227// Return Value Meaning
1228//
1229// CRYPT_SUCCESS sign worked
1230//
1231static CRYPT_RESULT
1232SignSM2(
1233 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature
1234 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature
1235 TPM_ECC_CURVE curveId, // IN: the curve used in signing
1236 TPM2B_ECC_PARAMETER *dIn, // IN: the private key
1237 TPM2B *digest // IN: the digest to sign
1238 )
1239{
1240 BIGNUM *bnR;
1241 BIGNUM *bnS;
1242 BIGNUM *bnN;
1243 BIGNUM *bnK;
1244 BIGNUM *bnX1;
1245 BIGNUM *bnD;
1246 BIGNUM *bnT; // temp
1247 BIGNUM *bnE;
1248 BN_CTX *context;
Vadim Bendebury56797522015-05-20 10:32:25 -07001249 TPM2B_ECC_PARAMETER k;
1250 TPMS_ECC_POINT p2Br;
1251 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1252 pAssert(curveData != NULL);
1253 context = BN_CTX_new();
1254 BN_CTX_start(context);
1255 bnK = BN_CTX_get(context);
1256 bnR = BN_CTX_get(context);
1257 bnS = BN_CTX_get(context);
1258 bnX1 = BN_CTX_get(context);
1259 bnN = BN_CTX_get(context);
1260 bnD = BN_CTX_get(context);
1261 bnT = BN_CTX_get(context);
1262 bnE = BN_CTX_get(context);
1263 if(bnE == NULL)
1264 FAIL(FATAL_ERROR_ALLOCATION);
1265 BnFrom2B(bnE, digest);
1266 BnFrom2B(bnN, curveData->n);
1267 BnFrom2B(bnD, &dIn->b);
1268#ifdef _SM2_SIGN_DEBUG
1269BN_hex2bn(&bnE, "B524F552CD82B8B028476E005C377FB19A87E6FC682D48BB5D42E3D9B9EFFE76");
1270BN_hex2bn(&bnD, "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263");
1271#endif
1272// A3: Use random number generator to generate random number 1 <= k <= n-1;
1273// NOTE: Ax: numbers are from the SM2 standard
1274 k.t.size = curveData->n->size;
1275loop:
1276 {
1277 // Get a random number
1278 _cpri__GenerateRandom(k.t.size, k.t.buffer);
1279#ifdef _SM2_SIGN_DEBUG
1280BN_hex2bn(&bnK, "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F");
1281BnTo2B(&k.b,bnK, 32);
1282k.t.size = 32;
1283#endif
1284 //make sure that the number is 0 < k < n
1285 BnFrom2B(bnK, &k.b);
1286 if( BN_ucmp(bnK, bnN) >= 0
1287 || BN_is_zero(bnK))
1288 goto loop;
1289// A4: Figure out the point of elliptic curve (x1, y1)=[k]G, and according
1290// to details specified in 4.2.7 in Part 1 of this document, transform the
1291// data type of x1 into an integer;
1292 if( _cpri__EccPointMultiply(&p2Br, curveId, &k, NULL, NULL)
1293 == CRYPT_NO_RESULT)
1294 goto loop;
1295 BnFrom2B(bnX1, &p2Br.x.b);
1296// A5: Figure out r = (e + x1) mod n,
1297 if(!BN_mod_add(bnR, bnE, bnX1, bnN, context))
1298 FAIL(FATAL_ERROR_INTERNAL);
1299#ifdef _SM2_SIGN_DEBUG
1300pAssert(cmp_bn2hex(bnR,
1301 "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1")
1302 == 0);
1303#endif
1304 // if r=0 or r+k=n, return to A3;
1305 if(!BN_add(bnT, bnK, bnR))
1306 FAIL(FATAL_ERROR_INTERNAL);
1307 if(BN_is_zero(bnR) || BN_ucmp(bnT, bnN) == 0)
1308 goto loop;
1309// A6: Figure out s = ((1 + dA)^-1 (k - r dA)) mod n, if s=0, return to A3;
1310 // compute t = (1+d)-1
1311 BN_copy(bnT, bnD);
1312 if( !BN_add_word(bnT, 1)
1313 || !BN_mod_inverse(bnT, bnT, bnN, context) // (1 + dA)^-1 mod n
1314 )
1315 FAIL(FATAL_ERROR_INTERNAL);
1316#ifdef _SM2_SIGN_DEBUG
1317pAssert(cmp_bn2hex(bnT,
1318 "79BFCF3052C80DA7B939E0C6914A18CBB2D96D8555256E83122743A7D4F5F956")
1319 == 0);
1320#endif
1321 // compute s = t * (k - r * dA) mod n
1322 if( !BN_mod_mul(bnS, bnD, bnR, bnN, context) // (r * dA) mod n
1323 || !BN_mod_sub(bnS, bnK, bnS, bnN, context) // (k - (r * dA) mod n
1324 || !BN_mod_mul(bnS, bnT, bnS, bnN, context))// t * (k - (r * dA) mod n
1325 FAIL(FATAL_ERROR_INTERNAL);
1326#ifdef _SM2_SIGN_DEBUG
1327pAssert(cmp_bn2hex(bnS,
1328 "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7")
1329 == 0);
1330#endif
1331 if(BN_is_zero(bnS))
1332 goto loop;
1333 }
1334// A7: According to details specified in 4.2.1 in Part 1 of this document, transform
1335// the data type of r, s into bit strings, signature of message M is (r, s).
1336 BnTo2B(&rOut->b, bnR, curveData->n->size);
1337 BnTo2B(&sOut->b, bnS, curveData->n->size);
1338#ifdef _SM2_SIGN_DEBUG
1339pAssert(cmp_2B2hex(&rOut->b,
1340 "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1")
1341 == 0);
1342pAssert(cmp_2B2hex(&sOut->b,
1343 "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7")
1344 == 0);
1345#endif
1346 BN_CTX_end(context);
1347 BN_CTX_free(context);
1348 return CRYPT_SUCCESS;
1349}
1350#endif //% TPM_ALG_SM2
1351//
1352//
1353// _cpri__SignEcc()
1354//
1355// This function is the dispatch function for the various ECC-based signing schemes.
1356//
1357// Return Value Meaning
1358//
1359// CRYPT_SCHEME scheme is not supported
1360//
1361LIB_EXPORT CRYPT_RESULT
1362_cpri__SignEcc(
1363 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature
1364 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature
1365 TPM_ALG_ID scheme, // IN: the scheme selector
1366 TPM_ALG_ID hashAlg, // IN: the hash algorithm if need
1367 TPM_ECC_CURVE curveId, // IN: the curve used in the signature
1368 // process
1369 TPM2B_ECC_PARAMETER *dIn, // IN: the private key
1370 TPM2B *digest, // IN: the digest to sign
1371 TPM2B_ECC_PARAMETER *kIn // IN: k for input
1372 )
1373{
1374 switch (scheme)
1375 {
1376 case TPM_ALG_ECDSA:
1377 // SignEcdsa always works
1378 return SignEcdsa(rOut, sOut, curveId, dIn, digest);
1379 break;
1380#ifdef TPM_ALG_ECDAA
1381 case TPM_ALG_ECDAA:
1382 if(rOut != NULL)
1383 rOut->b.size = 0;
1384 return EcDaa(rOut, sOut, curveId, dIn, digest, kIn);
1385 break;
1386#endif
1387#ifdef TPM_ALG_ECSCHNORR
1388 case TPM_ALG_ECSCHNORR:
1389 return SchnorrEcc(rOut, sOut, hashAlg, curveId, dIn, digest, kIn);
1390 break;
1391#endif
1392#ifdef TPM_ALG_SM2
1393 case TPM_ALG_SM2:
1394 return SignSM2(rOut, sOut, curveId, dIn, digest);
1395 break;
1396#endif
1397 default:
1398 return CRYPT_SCHEME;
1399 }
1400}
1401#ifdef TPM_ALG_ECDSA //%
1402//
1403//
1404// ValidateSignatureEcdsa()
1405//
1406// This function validates an ECDSA signature. rIn and sIn shoudl have been checked to make sure that
1407// they are not zero.
1408//
1409// Return Value Meaning
1410//
1411// CRYPT_SUCCESS signature valid
1412// CRYPT_FAIL signature not valid
1413//
1414static CRYPT_RESULT
1415ValidateSignatureEcdsa(
1416 TPM2B_ECC_PARAMETER *rIn, // IN: r component of the signature
1417 TPM2B_ECC_PARAMETER *sIn, // IN: s component of the signature
1418 TPM_ECC_CURVE curveId, // IN: the curve used in the signature
1419 // process
1420 TPMS_ECC_POINT *Qin, // IN: the public point of the key
1421 TPM2B *digest // IN: the digest that was signed
1422 )
1423{
1424 TPM2B_ECC_PARAMETER U1;
1425 TPM2B_ECC_PARAMETER U2;
1426 TPMS_ECC_POINT R;
1427 const TPM2B *n;
1428 BN_CTX *context;
1429 EC_POINT *pQ = NULL;
1430 EC_GROUP *group = NULL;
1431 BIGNUM *bnU1;
1432 BIGNUM *bnU2;
1433 BIGNUM *bnR;
1434 BIGNUM *bnS;
1435 BIGNUM *bnW;
1436 BIGNUM *bnV;
1437 BIGNUM *bnN;
1438 BIGNUM *bnE;
Vadim Bendebury56797522015-05-20 10:32:25 -07001439 BIGNUM *bnQx;
1440 BIGNUM *bnQy;
1441 CRYPT_RESULT retVal = CRYPT_FAIL;
1442 int t;
1443 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1444 // The curve selector should have been filtered by the unmarshaling process
1445 pAssert (curveData != NULL);
1446 n = curveData->n;
1447// 1. If r and s are not both integers in the interval [1, n - 1], output
1448// INVALID.
1449// rIn and sIn are known to be greater than zero (was checked by the caller).
1450 if( _math__uComp(rIn->t.size, rIn->t.buffer, n->size, n->buffer) >= 0
1451 || _math__uComp(sIn->t.size, sIn->t.buffer, n->size, n->buffer) >= 0
1452 )
1453 return CRYPT_FAIL;
1454 context = BN_CTX_new();
1455 if(context == NULL)
1456 FAIL(FATAL_ERROR_ALLOCATION);
1457 BN_CTX_start(context);
1458 bnR = BN_CTX_get(context);
1459 bnS = BN_CTX_get(context);
1460 bnN = BN_CTX_get(context);
1461 bnE = BN_CTX_get(context);
1462 bnV = BN_CTX_get(context);
1463 bnW = BN_CTX_get(context);
Vadim Bendebury56797522015-05-20 10:32:25 -07001464 bnQx = BN_CTX_get(context);
1465 bnQy = BN_CTX_get(context);
1466 bnU1 = BN_CTX_get(context);
1467 bnU2 = BN_CTX_get(context);
1468 // Assume the size variables do not overflow, which should not happen in
1469 // the contexts that this function will be called.
1470 assert2Bsize(Qin->x.t);
1471 assert2Bsize(rIn->t);
1472 assert2Bsize(sIn->t);
1473 // BN_CTX_get() is sticky so only need to check the last value to know that
1474 // all worked.
1475 if( bnU2 == NULL
1476 // initialize the group parameters
1477 || (group = EccCurveInit(curveId, context)) == NULL
1478 // allocate a local point
1479 || (pQ = EC_POINT_new(group)) == NULL
1480 // use the public key values (QxIn and QyIn) to initialize Q
1481 || BN_bin2bn(Qin->x.t.buffer, Qin->x.t.size, bnQx) == NULL
1482 || BN_bin2bn(Qin->x.t.buffer, Qin->x.t.size, bnQy) == NULL
1483 || !EC_POINT_set_affine_coordinates_GFp(group, pQ, bnQx, bnQy, context)
1484 // convert the signature values
1485 || BN_bin2bn(rIn->t.buffer, rIn->t.size, bnR) == NULL
1486 || BN_bin2bn(sIn->t.buffer, sIn->t.size, bnS) == NULL
1487 // convert the curve order
1488 || BN_bin2bn(curveData->n->buffer, curveData->n->size, bnN) == NULL)
1489 FAIL(FATAL_ERROR_INTERNAL);
1490// 2. Use the selected hash function to compute H0 = Hash(M0).
1491 // This is an input parameter
1492// 3. Convert the bit string H0 to an integer e as described in Appendix B.2.
1493 t = (digest->size > rIn->t.size) ? rIn->t.size : digest->size;
1494 if(BN_bin2bn(digest->buffer, t, bnE) == NULL)
1495 FAIL(FATAL_ERROR_INTERNAL);
1496// 4. Compute w = (s')^-1 mod n, using the routine in Appendix B.1.
1497 if (BN_mod_inverse(bnW, bnS, bnN, context) == NULL)
1498 FAIL(FATAL_ERROR_INTERNAL);
1499// 5. Compute u1 = (e' * w) mod n, and compute u2 = (r' * w) mod n.
1500 if( !BN_mod_mul(bnU1, bnE, bnW, bnN, context)
1501 || !BN_mod_mul(bnU2, bnR, bnW, bnN, context))
1502 FAIL(FATAL_ERROR_INTERNAL);
1503 BnTo2B(&U1.b, bnU1, (INT16) BN_num_bytes(bnU1));
1504 BnTo2B(&U2.b, bnU2, (INT16) BN_num_bytes(bnU2));
1505// 6. Compute the elliptic curve point R = (xR, yR) = u1G+u2Q, using EC
1506// scalar multiplication and EC addition (see [Routines]). If R is equal to
1507// the point at infinity O, output INVALID.
1508 if(_cpri__EccPointMultiply(&R, curveId, &U1, Qin, &U2) == CRYPT_SUCCESS)
1509 {
1510 // 7. Compute v = Rx mod n.
1511 if( BN_bin2bn(R.x.t.buffer, R.x.t.size, bnV) == NULL
1512 || !BN_mod(bnV, bnV, bnN, context))
1513 FAIL(FATAL_ERROR_INTERNAL);
1514 // 8. Compare v and r0. If v = r0, output VALID; otherwise, output INVALID
1515 if(BN_cmp(bnV, bnR) == 0)
1516 retVal = CRYPT_SUCCESS;
1517 }
1518 if(pQ != NULL) EC_POINT_free(pQ);
1519 if(group != NULL) EC_GROUP_free(group);
1520 BN_CTX_end(context);
1521 BN_CTX_free(context);
1522 return retVal;
1523}
1524#endif //% TPM_ALG_ECDSA
1525#ifdef TPM_ALG_ECSCHNORR //%
1526//
1527//
1528// ValidateSignatureEcSchnorr()
1529//
1530// This function is used to validate an EC Schnorr signature. rIn and sIn are required to be greater than
1531// zero. This is checked in _cpri__ValidateSignatureEcc().
1532//
1533// Return Value Meaning
1534//
1535// CRYPT_SUCCESS signature valid
1536// CRYPT_FAIL signature not valid
1537// CRYPT_SCHEME hashAlg is not supported
1538//
1539static CRYPT_RESULT
1540ValidateSignatureEcSchnorr(
1541 TPM2B_ECC_PARAMETER *rIn, // IN: r component of the signature
1542 TPM2B_ECC_PARAMETER *sIn, // IN: s component of the signature
1543 TPM_ALG_ID hashAlg, // IN: hash algorithm of the signature
1544 TPM_ECC_CURVE curveId, // IN: the curve used in the signature
1545 // process
1546 TPMS_ECC_POINT *Qin, // IN: the public point of the key
1547 TPM2B *digest // IN: the digest that was signed
1548 )
1549{
1550 TPMS_ECC_POINT pE;
1551 const TPM2B *n;
1552 CPRI_HASH_STATE hashState;
1553 TPM2B_DIGEST rPrime;
1554 TPM2B_ECC_PARAMETER minusR;
1555 UINT16 digestSize = _cpri__GetDigestSize(hashAlg);
1556 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1557 // The curve parameter should have been filtered by unmarshaling code
1558 pAssert(curveData != NULL);
1559 if(digestSize == 0)
1560 return CRYPT_SCHEME;
1561 // Input parameter validation
1562 pAssert(rIn != NULL && sIn != NULL && Qin != NULL && digest != NULL);
1563 n = curveData->n;
1564 // if sIn or rIn are not between 1 and N-1, signature check fails
1565 // sIn and rIn were verified to be non-zero by the caller
1566 if( _math__uComp(sIn->b.size, sIn->b.buffer, n->size, n->buffer) >= 0
1567 || _math__uComp(rIn->b.size, rIn->b.buffer, n->size, n->buffer) >= 0
1568 )
1569 return CRYPT_FAIL;
1570 //E = [s]InG - [r]InQ
1571 _math__sub(n->size, n->buffer,
1572 rIn->t.size, rIn->t.buffer,
1573 &minusR.t.size, minusR.t.buffer);
1574 if(_cpri__EccPointMultiply(&pE, curveId, sIn, Qin, &minusR) != CRYPT_SUCCESS)
1575 return CRYPT_FAIL;
1576 // Ex = Ex mod N
1577 if(Mod2B(&pE.x.b, n) != CRYPT_SUCCESS)
1578 FAIL(FATAL_ERROR_INTERNAL);
1579 _math__Normalize2B(&pE.x.b);
1580 // rPrime = h(digest || pE.x) mod n;
1581 _cpri__StartHash(hashAlg, FALSE, &hashState);
1582 _cpri__UpdateHash(&hashState, digest->size, digest->buffer);
1583 _cpri__UpdateHash(&hashState, pE.x.t.size, pE.x.t.buffer);
1584 if(_cpri__CompleteHash(&hashState, digestSize, rPrime.t.buffer) != digestSize)
1585 FAIL(FATAL_ERROR_INTERNAL);
1586 rPrime.t.size = digestSize;
1587 // rPrime = rPrime (mod n)
1588 if(Mod2B(&rPrime.b, n) != CRYPT_SUCCESS)
1589 FAIL(FATAL_ERROR_INTERNAL);
1590 // if the values don't match, then the signature is bad
1591 if(_math__uComp(rIn->t.size, rIn->t.buffer,
1592 rPrime.t.size, rPrime.t.buffer) != 0)
1593 return CRYPT_FAIL;
1594 else
1595 return CRYPT_SUCCESS;
1596}
1597#endif //% TPM_ALG_ECSCHNORR
1598#ifdef TPM_ALG_SM2 //%
1599//
1600//
1601// ValidateSignatueSM2Dsa()
1602//
1603// This function is used to validate an SM2 signature.
1604//
1605// Return Value Meaning
1606//
1607// CRYPT_SUCCESS signature valid
1608// CRYPT_FAIL signature not valid
1609//
1610static CRYPT_RESULT
1611ValidateSignatureSM2Dsa(
1612 TPM2B_ECC_PARAMETER *rIn, // IN: r component of the signature
1613 TPM2B_ECC_PARAMETER *sIn, // IN: s component of the signature
1614 TPM_ECC_CURVE curveId, // IN: the curve used in the signature
1615 // process
1616 TPMS_ECC_POINT *Qin, // IN: the public point of the key
1617 TPM2B *digest // IN: the digest that was signed
1618 )
1619{
1620 BIGNUM *bnR;
1621 BIGNUM *bnRp;
1622 BIGNUM *bnT;
1623 BIGNUM *bnS;
1624 BIGNUM *bnE;
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07001625 BIGNUM *order;
Vadim Bendebury56797522015-05-20 10:32:25 -07001626 EC_POINT *pQ;
1627 BN_CTX *context;
1628 EC_GROUP *group = NULL;
1629 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1630 BOOL fail = FALSE;
1631//
1632 if((context = BN_CTX_new()) == NULL || curveData == NULL)
1633 FAIL(FATAL_ERROR_INTERNAL);
1634 bnR = BN_CTX_get(context);
1635 bnRp= BN_CTX_get(context);
1636 bnE = BN_CTX_get(context);
1637 bnT = BN_CTX_get(context);
1638 bnS = BN_CTX_get(context);
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07001639 order = BN_CTX_get(context);
1640 if( order == NULL
Vadim Bendebury56797522015-05-20 10:32:25 -07001641 || (group = EccCurveInit(curveId, context)) == NULL)
1642 FAIL(FATAL_ERROR_INTERNAL);
1643#ifdef _SM2_SIGN_DEBUG
1644 cpy_hexTo2B(&Qin->x.b,
1645 "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A");
1646 cpy_hexTo2B(&Qin->y.b,
1647 "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857");
1648 cpy_hexTo2B(digest,
1649 "B524F552CD82B8B028476E005C377FB19A87E6FC682D48BB5D42E3D9B9EFFE76");
1650#endif
1651 pQ = EccInitPoint2B(group, Qin, context);
1652#ifdef _SM2_SIGN_DEBUG
1653 pAssert(EC_POINT_get_affine_coordinates_GFp(group, pQ, bnT, bnS, context));
1654 pAssert(cmp_bn2hex(bnT,
1655 "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A")
1656 == 0);
1657 pAssert(cmp_bn2hex(bnS,
1658 "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857")
1659 == 0);
1660#endif
1661 BnFrom2B(bnR, &rIn->b);
1662 BnFrom2B(bnS, &sIn->b);
1663 BnFrom2B(bnE, digest);
1664#ifdef _SM2_SIGN_DEBUG
1665// Make sure that the input signature is the test signature
1666pAssert(cmp_2B2hex(&rIn->b,
1667 "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1") == 0);
1668pAssert(cmp_2B2hex(&sIn->b,
1669 "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7") == 0);
1670#endif
1671// a) verify that r and s are in the inclusive interval 1 to (n 1)
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07001672 if (!EC_GROUP_get_order(group, order, context)) goto Cleanup;
1673 fail = (BN_ucmp(bnR, order) >= 0);
1674 fail = (BN_ucmp(bnS, order) >= 0) || fail;
Vadim Bendebury56797522015-05-20 10:32:25 -07001675 if(fail)
1676 // There is no reason to continue. Since r and s are inputs from the caller,
1677 // they can know that the values are not in the proper range. So, exiting here
1678 // does not disclose any information.
1679 goto Cleanup;
1680// b) compute t := (r + s) mod n
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07001681 if(!BN_mod_add(bnT, bnR, bnS, order, context))
Vadim Bendebury56797522015-05-20 10:32:25 -07001682 FAIL(FATAL_ERROR_INTERNAL);
1683#ifdef _SM2_SIGN_DEBUG
1684 pAssert(cmp_bn2hex(bnT,
1685 "2B75F07ED7ECE7CCC1C8986B991F441AD324D6D619FE06DD63ED32E0C997C801")
1686 == 0);
1687#endif
1688// c) verify that t > 0
1689 if(BN_is_zero(bnT)) {
1690 fail = TRUE;
1691 // set to a value that should allow rest of the computations to run without
1692 // trouble
1693 BN_copy(bnT, bnS);
1694 }
1695// d) compute (x, y) := [s]G + [t]Q
1696 if(!EC_POINT_mul(group, pQ, bnS, pQ, bnT, context))
1697 FAIL(FATAL_ERROR_INTERNAL);
1698 // Get the x coordinate of the point
1699 if(!EC_POINT_get_affine_coordinates_GFp(group, pQ, bnT, NULL, context))
1700 FAIL(FATAL_ERROR_INTERNAL);
1701#ifdef _SM2_SIGN_DEBUG
1702 pAssert(cmp_bn2hex(bnT,
1703 "110FCDA57615705D5E7B9324AC4B856D23E6D9188B2AE47759514657CE25D112")
1704 == 0);
1705#endif
1706// e) compute r' := (e + x) mod n (the x coordinate is in bnT)
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07001707 if(!BN_mod_add(bnRp, bnE, bnT, order, context))
Vadim Bendebury56797522015-05-20 10:32:25 -07001708 FAIL(FATAL_ERROR_INTERNAL);
1709// f) verify that r' = r
1710 fail = BN_ucmp(bnR, bnRp) != 0 || fail;
1711Cleanup:
1712 if(pQ) EC_POINT_free(pQ);
1713 if(group) EC_GROUP_free(group);
1714 BN_CTX_end(context);
1715 BN_CTX_free(context);
1716 if(fail)
1717 return CRYPT_FAIL;
1718 else
1719 return CRYPT_SUCCESS;
1720}
1721#endif //% TPM_ALG_SM2
1722//
1723//
1724// _cpri__ValidateSignatureEcc()
1725//
1726// This function validates
1727//
1728// Return Value Meaning
1729//
1730// CRYPT_SUCCESS signature is valid
1731// CRYPT_FAIL not a valid signature
1732// CRYPT_SCHEME unsupported scheme
1733//
1734LIB_EXPORT CRYPT_RESULT
1735_cpri__ValidateSignatureEcc(
1736 TPM2B_ECC_PARAMETER *rIn, // IN: r component of the signature
1737 TPM2B_ECC_PARAMETER *sIn, // IN: s component of the signature
1738 TPM_ALG_ID scheme, // IN: the scheme selector
1739 TPM_ALG_ID hashAlg, // IN: the hash algorithm used (not used
1740 // in all schemes)
1741 TPM_ECC_CURVE curveId, // IN: the curve used in the signature
1742 // process
1743 TPMS_ECC_POINT *Qin, // IN: the public point of the key
1744 TPM2B *digest // IN: the digest that was signed
1745 )
1746{
1747 CRYPT_RESULT retVal;
1748 // return failure if either part of the signature is zero
1749 if(_math__Normalize2B(&rIn->b) == 0 || _math__Normalize2B(&sIn->b) == 0)
1750 return CRYPT_FAIL;
1751 switch (scheme)
1752 {
1753 case TPM_ALG_ECDSA:
1754 retVal = ValidateSignatureEcdsa(rIn, sIn, curveId, Qin, digest);
1755 break;
1756#ifdef TPM_ALG_ECSCHNORR
1757 case TPM_ALG_ECSCHNORR:
1758 retVal = ValidateSignatureEcSchnorr(rIn, sIn, hashAlg, curveId, Qin,
1759 digest);
1760 break;
1761#endif
1762#ifdef TPM_ALG_SM2
1763 case TPM_ALG_SM2:
1764 retVal = ValidateSignatureSM2Dsa(rIn, sIn, curveId, Qin, digest);
1765#endif
1766 default:
1767 retVal = CRYPT_SCHEME;
1768 break;
1769 }
1770 return retVal;
1771}
1772#if CC_ZGen_2Phase == YES //%
1773#ifdef TPM_ALG_ECMQV
1774//
1775//
1776// avf1()
1777//
1778// This function does the associated value computation required by MQV key exchange. Process:
1779// a) Convert xQ to an integer xqi using the convention specified in Appendix C.3.
1780// b) Calculate xqm = xqi mod 2^ceil(f/2) (where f = ceil(log2(n)).
1781// c) Calculate the associate value function avf(Q) = xqm + 2ceil(f / 2)
1782//
1783static BOOL
1784avf1(
1785 BIGNUM *bnX, // IN/OUT: the reduced value
1786 BIGNUM *bnN // IN: the order of the curve
1787 )
1788{
1789// compute f = 2^(ceil(ceil(log2(n)) / 2))
1790 int f = (BN_num_bits(bnN) + 1) / 2;
1791// x' = 2^f + (x mod 2^f)
1792 BN_mask_bits(bnX, f); // This is mod 2*2^f but it doesn't matter because
1793 // the next operation will SET the extra bit anyway
1794 BN_set_bit(bnX, f);
1795 return TRUE;
1796}
1797//
1798//
1799// C_2_2_MQV()
1800//
1801// This function performs the key exchange defined in SP800-56A 6.1.1.4 Full MQV, C(2, 2, ECC MQV).
1802// CAUTION: Implementation of this function may require use of essential claims in patents not owned by
1803// TCG members.
1804// Points QsB() and QeB() are required to be on the curve of inQsA. The function will fail, possibly
1805// catastrophically, if this is not the case.
1806//
1807//
1808//
1809// Return Value Meaning
1810//
1811// CRYPT_SUCCESS results is valid
1812// CRYPT_NO_RESULT the value for dsA does not give a valid point on the curve
1813//
1814static CRYPT_RESULT
1815C_2_2_MQV(
1816 TPMS_ECC_POINT *outZ, // OUT: the computed point
1817 TPM_ECC_CURVE curveId, // IN: the curve for the computations
1818 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
1819 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
1820 TPMS_ECC_POINT *QsB, // IN: static public party B key
1821 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
1822 )
1823{
1824 BN_CTX *context;
1825 EC_POINT *pQeA = NULL;
1826 EC_POINT *pQeB = NULL;
1827 EC_POINT *pQsB = NULL;
1828 EC_GROUP *group = NULL;
1829 BIGNUM *bnTa;
1830 BIGNUM *bnDeA;
1831 BIGNUM *bnDsA;
1832 BIGNUM *bnXeA; // x coordinate of ephemeral party A key
1833 BIGNUM *bnH;
1834 BIGNUM *bnN;
1835 BIGNUM *bnXeB;
1836 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1837 CRYPT_RESULT retVal;
1838 pAssert( curveData != NULL && outZ != NULL && dsA != NULL
1839 && deA != NULL && QsB != NULL && QeB != NULL);
1840 context = BN_CTX_new();
1841 if(context == NULL || curveData == NULL)
1842 FAIL(FATAL_ERROR_ALLOCATION);
1843 BN_CTX_start(context);
1844 bnTa = BN_CTX_get(context);
1845 bnDeA = BN_CTX_get(context);
1846 bnDsA = BN_CTX_get(context);
1847 bnXeA = BN_CTX_get(context);
1848 bnH = BN_CTX_get(context);
1849 bnN = BN_CTX_get(context);
1850 bnXeB = BN_CTX_get(context);
1851 if(bnXeB == NULL)
1852 FAIL(FATAL_ERROR_ALLOCATION);
1853// Process:
1854// 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
1855// 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
1856// 3. If P = O, output an error indicator.
1857// 4. Z=xP, where xP is the x-coordinate of P.
1858 // Initialize group parameters and local values of input
1859 if((group = EccCurveInit(curveId, context)) == NULL)
1860 FAIL(FATAL_ERROR_INTERNAL);
1861 if((pQeA = EC_POINT_new(group)) == NULL)
1862 FAIL(FATAL_ERROR_ALLOCATION);
1863 BnFrom2B(bnDeA, &deA->b);
1864 BnFrom2B(bnDsA, &dsA->b);
1865 BnFrom2B(bnH, curveData->h);
1866 BnFrom2B(bnN, curveData->n);
1867 BnFrom2B(bnXeB, &QeB->x.b);
1868 pQeB = EccInitPoint2B(group, QeB, context);
1869 pQsB = EccInitPoint2B(group, QsB, context);
1870 // Compute the public ephemeral key pQeA = [de,A]G
1871 if( (retVal = PointMul(group, pQeA, bnDeA, NULL, NULL, context))
1872 != CRYPT_SUCCESS)
1873 goto Cleanup;
1874 if(EC_POINT_get_affine_coordinates_GFp(group, pQeA, bnXeA, NULL, context) != 1)
1875 FAIL(FATAL_ERROR_INTERNAL);
1876// 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
1877// tA := (ds,A + de,A avf(Xe,A)) mod n (3)
1878// Compute 'tA' = ('deA' + 'dsA' avf('XeA')) mod n
1879 // Ta = avf(XeA);
1880 BN_copy(bnTa, bnXeA);
1881 avf1(bnTa, bnN);
1882 if(// do Ta = ds,A * Ta mod n = dsA * avf(XeA) mod n
1883 !BN_mod_mul(bnTa, bnDsA, bnTa, bnN, context)
1884 // now Ta = deA + Ta mod n = deA + dsA * avf(XeA) mod n
1885 || !BN_mod_add(bnTa, bnDeA, bnTa, bnN, context)
1886 )
1887 FAIL(FATAL_ERROR_INTERNAL);
1888// 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
1889// Put this in because almost every case of h is == 1 so skip the call when
1890 // not necessary.
1891 if(!BN_is_one(bnH))
1892 {
1893 // Cofactor is not 1 so compute Ta := Ta * h mod n
1894 if(!BN_mul(bnTa, bnTa, bnH, context))
1895 FAIL(FATAL_ERROR_INTERNAL);
1896 }
1897 // Now that 'tA' is (h * 'tA' mod n)
1898 // 'outZ' = (tA)(Qe,B + avf(Qe,B)Qs,B).
1899 // first, compute XeB = avf(XeB)
1900 avf1(bnXeB, bnN);
1901 // QsB := [XeB]QsB
1902 if( !EC_POINT_mul(group, pQsB, NULL, pQsB, bnXeB, context)
1903 // QeB := QsB + QeB
1904 || !EC_POINT_add(group, pQeB, pQeB, pQsB, context)
1905 )
1906 FAIL(FATAL_ERROR_INTERNAL);
1907 // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
1908 if(PointMul(group, pQeB, NULL, pQeB, bnTa, context) == CRYPT_SUCCESS)
1909 // Convert BIGNUM E to TPM2B E
1910 Point2B(group, outZ, pQeB, (INT16)BN_num_bytes(bnN), context);
1911Cleanup:
1912 if(pQeA != NULL) EC_POINT_free(pQeA);
1913 if(pQeB != NULL) EC_POINT_free(pQeB);
1914 if(pQsB != NULL) EC_POINT_free(pQsB);
1915 if(group != NULL) EC_GROUP_free(group);
1916 BN_CTX_end(context);
1917 BN_CTX_free(context);
1918 return retVal;
1919}
1920#endif // TPM_ALG_ECMQV
1921#ifdef TPM_ALG_SM2 //%
1922//
1923//
1924// avfSm2()
1925//
1926// This function does the associated value computation required by SM2 key exchange. This is different
1927// form the avf() in the international standards because it returns a value that is half the size of the value
1928// returned by the standard avf. For example, if n is 15, Ws (w in the standard) is 2 but the W here is 1. This
1929// means that an input value of 14 (1110b) would return a value of 110b with the standard but 10b with the
1930// scheme in SM2.
1931//
1932static BOOL
1933avfSm2(
1934 BIGNUM *bnX, // IN/OUT: the reduced value
1935 BIGNUM *bnN // IN: the order of the curve
1936 )
1937{
1938// a) set w := ceil(ceil(log2(n)) / 2) - 1
1939 int w = ((BN_num_bits(bnN) + 1) / 2) - 1;
1940// b) set x' := 2^w + ( x & (2^w - 1))
1941// This is just like the avf for MQV where x' = 2^w + (x mod 2^w)
1942 BN_mask_bits(bnX, w); // as wiht avf1, this is too big by a factor of 2 but
1943 // it doesn't matter becasue we SET the extra bit anyway
1944 BN_set_bit(bnX, w);
1945 return TRUE;
1946}
1947//
1948// SM2KeyExchange() This function performs the key exchange defined in SM2. The first step is to compute
1949// tA = (dsA + deA avf(Xe,A)) mod n Then, compute the Z value from outZ = (h tA mod n) (QsA +
1950// [avf(QeB().x)](QeB())). The function will compute the ephemeral public key from the ephemeral private
1951// key. All points are required to be on the curve of inQsA. The function will fail catastrophically if this is not
1952// the case
1953//
1954// Return Value Meaning
1955//
1956// CRYPT_SUCCESS results is valid
1957// CRYPT_NO_RESULT the value for dsA does not give a valid point on the curve
1958//
1959static CRYPT_RESULT
1960SM2KeyExchange(
1961 TPMS_ECC_POINT *outZ, // OUT: the computed point
1962 TPM_ECC_CURVE curveId, // IN: the curve for the computations
1963 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
1964 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
1965 TPMS_ECC_POINT *QsB, // IN: static public party B key
1966 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
1967 )
1968{
1969 BN_CTX *context;
1970 EC_POINT *pQeA = NULL;
1971 EC_POINT *pQeB = NULL;
1972 EC_POINT *pQsB = NULL;
1973 EC_GROUP *group = NULL;
1974 BIGNUM *bnTa;
1975 BIGNUM *bnDeA;
1976 BIGNUM *bnDsA;
1977 BIGNUM *bnXeA; // x coordinate of ephemeral party A key
1978 BIGNUM *bnH;
1979 BIGNUM *bnN;
1980 BIGNUM *bnXeB;
1981//
1982 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1983 CRYPT_RESULT retVal;
1984 pAssert( curveData != NULL && outZ != NULL && dsA != NULL
1985 && deA != NULL && QsB != NULL && QeB != NULL);
1986 context = BN_CTX_new();
1987 if(context == NULL || curveData == NULL)
1988 FAIL(FATAL_ERROR_ALLOCATION);
1989 BN_CTX_start(context);
1990 bnTa = BN_CTX_get(context);
1991 bnDeA = BN_CTX_get(context);
1992 bnDsA = BN_CTX_get(context);
1993 bnXeA = BN_CTX_get(context);
1994 bnH = BN_CTX_get(context);
1995 bnN = BN_CTX_get(context);
1996 bnXeB = BN_CTX_get(context);
1997 if(bnXeB == NULL)
1998 FAIL(FATAL_ERROR_ALLOCATION);
1999 // Initialize group parameters and local values of input
2000 if((group = EccCurveInit(curveId, context)) == NULL)
2001 FAIL(FATAL_ERROR_INTERNAL);
2002 if((pQeA = EC_POINT_new(group)) == NULL)
2003 FAIL(FATAL_ERROR_ALLOCATION);
2004 BnFrom2B(bnDeA, &deA->b);
2005 BnFrom2B(bnDsA, &dsA->b);
2006 BnFrom2B(bnH, curveData->h);
2007 BnFrom2B(bnN, curveData->n);
2008 BnFrom2B(bnXeB, &QeB->x.b);
2009 pQeB = EccInitPoint2B(group, QeB, context);
2010 pQsB = EccInitPoint2B(group, QsB, context);
2011 // Compute the public ephemeral key pQeA = [de,A]G
2012 if( (retVal = PointMul(group, pQeA, bnDeA, NULL, NULL, context))
2013 != CRYPT_SUCCESS)
2014 goto Cleanup;
2015 if(EC_POINT_get_affine_coordinates_GFp(group, pQeA, bnXeA, NULL, context) != 1)
2016 FAIL(FATAL_ERROR_INTERNAL);
2017// tA := (ds,A + de,A avf(Xe,A)) mod n (3)
2018// Compute 'tA' = ('dsA' + 'deA' avf('XeA')) mod n
2019 // Ta = avf(XeA);
2020 BN_copy(bnTa, bnXeA);
2021 avfSm2(bnTa, bnN);
2022 if(// do Ta = de,A * Ta mod n = deA * avf(XeA) mod n
2023 !BN_mod_mul(bnTa, bnDeA, bnTa, bnN, context)
2024 // now Ta = dsA + Ta mod n = dsA + deA * avf(XeA) mod n
2025 || !BN_mod_add(bnTa, bnDsA, bnTa, bnN, context)
2026 )
2027 FAIL(FATAL_ERROR_INTERNAL);
2028// outZ ? [h tA mod n] (Qs,B + [avf(Xe,B)](Qe,B)) (4)
2029 // Put this in because almost every case of h is == 1 so skip the call when
2030 // not necessary.
2031 if(!BN_is_one(bnH))
2032 {
2033 // Cofactor is not 1 so compute Ta := Ta * h mod n
2034 if(!BN_mul(bnTa, bnTa, bnH, context))
2035 FAIL(FATAL_ERROR_INTERNAL);
2036 }
2037 // Now that 'tA' is (h * 'tA' mod n)
2038 // 'outZ' = ['tA'](QsB + [avf(QeB.x)](QeB)).
2039 // first, compute XeB = avf(XeB)
2040 avfSm2(bnXeB, bnN);
2041 // QeB := [XeB]QeB
2042 if( !EC_POINT_mul(group, pQeB, NULL, pQeB, bnXeB, context)
2043 // QeB := QsB + QeB
2044 || !EC_POINT_add(group, pQeB, pQeB, pQsB, context)
2045 )
2046 FAIL(FATAL_ERROR_INTERNAL);
2047 // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
2048 if(PointMul(group, pQeB, NULL, pQeB, bnTa, context) == CRYPT_SUCCESS)
2049 // Convert BIGNUM E to TPM2B E
2050 Point2B(group, outZ, pQeB, (INT16)BN_num_bytes(bnN), context);
2051Cleanup:
2052 if(pQeA != NULL) EC_POINT_free(pQeA);
2053 if(pQeB != NULL) EC_POINT_free(pQeB);
2054 if(pQsB != NULL) EC_POINT_free(pQsB);
2055 if(group != NULL) EC_GROUP_free(group);
2056 BN_CTX_end(context);
2057 BN_CTX_free(context);
2058 return retVal;
2059}
2060#endif //% TPM_ALG_SM2
2061//
2062//
2063// C_2_2_ECDH()
2064//
2065// This function performs the two phase key exchange defined in SP800-56A, 6.1.1.2 Full Unified Model,
2066// C(2, 2, ECC CDH).
2067//
2068static CRYPT_RESULT
2069C_2_2_ECDH(
2070 TPMS_ECC_POINT *outZ1, // OUT: Zs
2071 TPMS_ECC_POINT *outZ2, // OUT: Ze
2072 TPM_ECC_CURVE curveId, // IN: the curve for the computations
2073 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
2074 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
2075 TPMS_ECC_POINT *QsB, // IN: static public party B key
2076 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
2077 )
2078{
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07002079 BIGNUM *order;
Vadim Bendebury56797522015-05-20 10:32:25 -07002080 BN_CTX *context;
2081 EC_POINT *pQ = NULL;
2082 EC_GROUP *group = NULL;
2083 BIGNUM *bnD;
2084 INT16 size;
2085 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
2086 context = BN_CTX_new();
2087 if(context == NULL || curveData == NULL)
2088 FAIL(FATAL_ERROR_ALLOCATION);
2089 BN_CTX_start(context);
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07002090 order = BN_CTX_get(context);
Vadim Bendebury56797522015-05-20 10:32:25 -07002091 if((bnD = BN_CTX_get(context)) == NULL)
2092 FAIL(FATAL_ERROR_INTERNAL);
2093 // Initialize group parameters and local values of input
2094 if((group = EccCurveInit(curveId, context)) == NULL)
2095 FAIL(FATAL_ERROR_INTERNAL);
Jocelyn Bohrddcb1ce2015-08-14 15:32:09 -07002096 if (!EC_GROUP_get_order(group, order, context))
2097 FAIL(FATAL_ERROR_INTERNAL);
2098 size = (INT16)BN_num_bytes(order);
Vadim Bendebury56797522015-05-20 10:32:25 -07002099 // Get the static private key of A
2100 BnFrom2B(bnD, &dsA->b);
2101 // Initialize the static public point from B
2102 pQ = EccInitPoint2B(group, QsB, context);
2103 // Do the point multiply for the Zs value
2104 if(PointMul(group, pQ, NULL, pQ, bnD, context) != CRYPT_NO_RESULT)
2105 // Convert the Zs value
2106 Point2B(group, outZ1, pQ, size, context);
2107 // Get the ephemeral private key of A
2108 BnFrom2B(bnD, &deA->b);
2109 // Initalize the ephemeral public point from B
2110 PointFrom2B(group, pQ, QeB, context);
2111 // Do the point multiply for the Ze value
2112 if(PointMul(group, pQ, NULL, pQ, bnD, context) != CRYPT_NO_RESULT)
2113 // Convert the Ze value.
2114 Point2B(group, outZ2, pQ, size, context);
2115 if(pQ != NULL) EC_POINT_free(pQ);
2116 if(group != NULL) EC_GROUP_free(group);
2117 BN_CTX_end(context);
2118 BN_CTX_free(context);
2119 return CRYPT_SUCCESS;
2120}
2121//
2122//
2123// _cpri__C_2_2_KeyExchange()
2124//
2125// This function is the dispatch routine for the EC key exchange function that use two ephemeral and two
2126// static keys.
2127//
2128// Return Value Meaning
2129//
2130// CRYPT_SCHEME scheme is not defined
2131//
2132LIB_EXPORT CRYPT_RESULT
2133_cpri__C_2_2_KeyExchange(
2134 TPMS_ECC_POINT *outZ1, // OUT: a computed point
2135 TPMS_ECC_POINT *outZ2, // OUT: and optional second point
2136 TPM_ECC_CURVE curveId, // IN: the curve for the computations
2137 TPM_ALG_ID scheme, // IN: the key exchange scheme
2138 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
2139 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
2140 TPMS_ECC_POINT *QsB, // IN: static public party B key
2141 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
2142 )
2143{
2144 pAssert( outZ1 != NULL
2145 && dsA != NULL && deA != NULL
2146 && QsB != NULL && QeB != NULL);
2147 // Initalize the output points so that they are empty until one of the
2148 // functions decides otherwise
2149 outZ1->x.b.size = 0;
2150 outZ1->y.b.size = 0;
2151 if(outZ2 != NULL)
2152 {
2153 outZ2->x.b.size = 0;
2154 outZ2->y.b.size = 0;
2155 }
2156 switch (scheme)
2157 {
2158 case TPM_ALG_ECDH:
2159 return C_2_2_ECDH(outZ1, outZ2, curveId, dsA, deA, QsB, QeB);
2160 break;
2161#ifdef TPM_ALG_ECMQV
2162 case TPM_ALG_ECMQV:
2163 return C_2_2_MQV(outZ1, curveId, dsA, deA, QsB, QeB);
2164 break;
2165#endif
2166#ifdef TPM_ALG_SM2
2167 case TPM_ALG_SM2:
2168 return SM2KeyExchange(outZ1, curveId, dsA, deA, QsB, QeB);
2169 break;
2170#endif
2171 default:
2172 return CRYPT_SCHEME;
2173 }
2174}
2175#else //%
2176//
2177// Stub used when the 2-phase key exchange is not defined so that the linker has something to associate
2178// with the value in the .def file.
2179//
2180LIB_EXPORT CRYPT_RESULT
2181_cpri__C_2_2_KeyExchange(
2182 void
2183 )
2184{
2185 return CRYPT_FAIL;
2186}
2187#endif //% CC_ZGen_2Phase
2188#endif // TPM_ALG_ECC