VirtualBox

source: vbox/trunk/src/libs/libtpms-0.10.0/src/tpm2/crypto/openssl/CryptEccMain.c@ 108932

Last change on this file since 108932 was 108932, checked in by vboxsync, 2 weeks ago

libtpms-0.10.0: Applied and adjusted our libtpms changes to 0.9.6. jiraref:VBP-1320

File size: 30.1 KB
Line 
1/********************************************************************************/
2/* */
3/* ECC Main */
4/* Written by Ken Goldman */
5/* IBM Thomas J. Watson Research Center */
6/* */
7/* Licenses and Notices */
8/* */
9/* 1. Copyright Licenses: */
10/* */
11/* - Trusted Computing Group (TCG) grants to the user of the source code in */
12/* this specification (the "Source Code") a worldwide, irrevocable, */
13/* nonexclusive, royalty free, copyright license to reproduce, create */
14/* derivative works, distribute, display and perform the Source Code and */
15/* derivative works thereof, and to grant others the rights granted herein. */
16/* */
17/* - The TCG grants to the user of the other parts of the specification */
18/* (other than the Source Code) the rights to reproduce, distribute, */
19/* display, and perform the specification solely for the purpose of */
20/* developing products based on such documents. */
21/* */
22/* 2. Source Code Distribution Conditions: */
23/* */
24/* - Redistributions of Source Code must retain the above copyright licenses, */
25/* this list of conditions and the following disclaimers. */
26/* */
27/* - Redistributions in binary form must reproduce the above copyright */
28/* licenses, this list of conditions and the following disclaimers in the */
29/* documentation and/or other materials provided with the distribution. */
30/* */
31/* 3. Disclaimers: */
32/* */
33/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
34/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
35/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
36/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
37/* Contact TCG Administration ([email protected]) for */
38/* information on specification licensing rights available through TCG */
39/* membership agreements. */
40/* */
41/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
42/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
43/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
44/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
45/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
46/* */
47/* - Without limitation, TCG and its members and licensors disclaim all */
48/* liability, including liability for infringement of any proprietary */
49/* rights, relating to use of information in this specification and to the */
50/* implementation of this specification, and TCG disclaims all liability for */
51/* cost of procurement of substitute goods or services, lost profits, loss */
52/* of use, loss of data or any incidental, consequential, direct, indirect, */
53/* or special damages, whether under contract, tort, warranty or otherwise, */
54/* arising in any way out of use or reliance upon this specification or any */
55/* information herein. */
56/* */
57/* (c) Copyright IBM Corp. and others, 2016 - 2024 */
58/* */
59/********************************************************************************/
60
61//** Includes and Defines
62#include "Tpm.h"
63#include "TpmMath_Util_fp.h"
64#include "TpmEcc_Util_fp.h"
65#include "TpmEcc_Signature_ECDSA_fp.h" // required for pairwise test in key generation
66#include "Helpers_fp.h" // libtpms added
67#if ALG_ECC
68//** Functions
69
70# if SIMULATION
71void EccSimulationEnd(void)
72{
73# if SIMULATION
74 // put things to be printed at the end of the simulation here
75# endif
76}
77# endif // SIMULATION
78
79//*** CryptEccInit()
80// This function is called at _TPM_Init
81BOOL CryptEccInit(void)
82{
83 return TRUE;
84}
85
86//*** CryptEccStartup()
87// This function is called at TPM2_Startup().
88BOOL CryptEccStartup(void)
89{
90 return TRUE;
91}
92
93//*** ClearPoint2B(generic)
94// Initialize the size values of a TPMS_ECC_POINT structure.
95void ClearPoint2B(TPMS_ECC_POINT* p // IN: the point
96 )
97{
98 if(p != NULL)
99 {
100 p->x.t.size = 0;
101 p->y.t.size = 0;
102 }
103}
104
105//*** CryptEccGetParametersByCurveId()
106// This function returns a pointer to the curve data that is associated with
107// the indicated curveId.
108// If there is no curve with the indicated ID, the function returns NULL. This
109// function is in this module so that it can be called by GetCurve data.
110// Return Type: const TPM_ECC_CURVE_METADATA
111// NULL curve with the indicated TPM_ECC_CURVE is not implemented
112// != NULL pointer to the curve data
113LIB_EXPORT const TPM_ECC_CURVE_METADATA* CryptEccGetParametersByCurveId(
114 TPM_ECC_CURVE curveId // IN: the curveID
115 )
116{
117 int i;
118 for(i = 0; i < ECC_CURVE_COUNT; i++)
119 {
120 if(eccCurves[i].curveId == curveId)
121 return &eccCurves[i];
122 }
123 return NULL;
124}
125
126//*** CryptEccGetKeySizeForCurve()
127// This function returns the key size in bits of the indicated curve.
128LIB_EXPORT UINT16 CryptEccGetKeySizeForCurve(TPM_ECC_CURVE curveId // IN: the curve
129 )
130{
131 const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId);
132 UINT16 keySizeInBits;
133 //
134 keySizeInBits = (curve != NULL) ? curve->keySizeBits : 0;
135 return keySizeInBits;
136}
137
138//***CryptEccGetOID()
139const BYTE* CryptEccGetOID(TPM_ECC_CURVE curveId)
140{
141 const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId);
142 return (curve != NULL) ? curve->OID : NULL;
143}
144
145//*** CryptEccGetCurveByIndex()
146// This function returns the number of the 'i'-th implemented curve. The normal
147// use would be to call this function with 'i' starting at 0. When the 'i' is greater
148// than or equal to the number of implemented curves, TPM_ECC_NONE is returned.
149LIB_EXPORT TPM_ECC_CURVE CryptEccGetCurveByIndex(UINT16 i)
150{
151 if(i >= ECC_CURVE_COUNT)
152 return TPM_ECC_NONE;
153 return eccCurves[i].curveId;
154}
155
156//*** CryptCapGetECCCurve()
157// This function returns the list of implemented ECC curves.
158// Return Type: TPMI_YES_NO
159// YES if no more ECC curve is available
160// NO if there are more ECC curves not reported
161TPMI_YES_NO
162CryptCapGetECCCurve(TPM_ECC_CURVE curveID, // IN: the starting ECC curve
163 UINT32 maxCount, // IN: count of returned curves
164 TPML_ECC_CURVE* curveList // OUT: ECC curve list
165 )
166{
167 TPMI_YES_NO more = NO;
168 UINT16 i;
169 UINT32 count = ECC_CURVE_COUNT;
170 TPM_ECC_CURVE curve;
171
172 // Initialize output property list
173 curveList->count = 0;
174
175 // The maximum count of curves we may return is MAX_ECC_CURVES
176 if(maxCount > MAX_ECC_CURVES)
177 maxCount = MAX_ECC_CURVES;
178
179 // Scan the eccCurveValues array
180 for(i = 0; i < count; i++)
181 {
182 curve = CryptEccGetCurveByIndex(i);
183 // If curveID is less than the starting curveID, skip it
184 if(curve < curveID)
185 continue;
186 if (!CryptEccIsCurveRuntimeUsable(curve)) // libtpms added begin
187 continue;
188 if (!RuntimeAlgorithmKeySizeCheckEnabled(&g_RuntimeProfile.RuntimeAlgorithm,
189 TPM_ALG_ECC,
190 CryptEccGetKeySizeForCurve(curve),
191 curve,
192 g_RuntimeProfile.stateFormatLevel))
193 continue; // libtpms added end
194 if(curveList->count < maxCount)
195 {
196 // If we have not filled up the return list, add more curves to
197 // it
198 curveList->eccCurves[curveList->count] = curve;
199 curveList->count++;
200 }
201 else
202 {
203 // If the return list is full but we still have curves
204 // available, report this and stop iterating
205 more = YES;
206 break;
207 }
208 }
209 return more;
210}
211
212//*** CryptCapGetOneECCCurve()
213// This function returns whether the ECC curve is implemented.
214BOOL CryptCapGetOneECCCurve(TPM_ECC_CURVE curveID // IN: the ECC curve
215 )
216{
217 UINT16 i;
218
219 if (!CryptEccIsCurveRuntimeUsable(curveID) || // libtpms added begin
220 !RuntimeAlgorithmKeySizeCheckEnabled(&g_RuntimeProfile.RuntimeAlgorithm,
221 TPM_ALG_ECC,
222 CryptEccGetKeySizeForCurve(curveID),
223 curveID,
224 g_RuntimeProfile.stateFormatLevel))
225 return FALSE; // libtpms added end
226
227 // Scan the eccCurveValues array
228 for(i = 0; i < ECC_CURVE_COUNT; i++)
229 {
230 if(CryptEccGetCurveByIndex(i) == curveID)
231 {
232 return TRUE;
233 }
234 }
235 return FALSE;
236}
237
238//*** CryptGetCurveSignScheme()
239// This function will return a pointer to the scheme of the curve.
240const TPMT_ECC_SCHEME* CryptGetCurveSignScheme(
241 TPM_ECC_CURVE curveId // IN: The curve selector
242 )
243{
244 const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId);
245
246 if(curve != NULL)
247 return &(curve->sign);
248 else
249 return NULL;
250}
251
252//*** CryptGenerateR()
253// This function computes the commit random value for a split signing scheme.
254//
255// If 'c' is NULL, it indicates that 'r' is being generated
256// for TPM2_Commit.
257// If 'c' is not NULL, the TPM will validate that the 'gr.commitArray'
258// bit associated with the input value of 'c' is SET. If not, the TPM
259// returns FALSE and no 'r' value is generated.
260// Return Type: BOOL
261// TRUE(1) r value computed
262// FALSE(0) no r value computed
263BOOL CryptGenerateR(TPM2B_ECC_PARAMETER* r, // OUT: the generated random value
264 UINT16* c, // IN/OUT: count value.
265 TPMI_ECC_CURVE curveID, // IN: the curve for the value
266 TPM2B_NAME* name // IN: optional name of a key to
267 // associate with 'r'
268 )
269{
270 // This holds the marshaled g_commitCounter.
271 TPM2B_TYPE(8B, 8);
272 TPM2B_8B cntr = {{8, {0}}};
273 UINT32 iterations;
274 TPM2B_ECC_PARAMETER n;
275 UINT64 currentCount = gr.commitCounter;
276 UINT16 t1;
277 //
278 if(!TpmMath_IntTo2B(ExtEcc_CurveGetOrder(curveID), (TPM2B*)&n, 0))
279 return FALSE;
280
281 // If this is the commit phase, use the current value of the commit counter
282 if(c != NULL)
283 {
284 // if the array bit is not set, can't use the value.
285 if(!TEST_BIT((*c & COMMIT_INDEX_MASK), gr.commitArray))
286 return FALSE;
287
288 // If it is the sign phase, figure out what the counter value was
289 // when the commitment was made.
290 //
291 // When gr.commitArray has less than 64K bits, the extra
292 // bits of 'c' are used as a check to make sure that the
293 // signing operation is not using an out of range count value
294 t1 = (UINT16)currentCount;
295
296 // If the lower bits of c are greater or equal to the lower bits of t1
297 // then the upper bits of t1 must be one more than the upper bits
298 // of c
299 if((*c & COMMIT_INDEX_MASK) >= (t1 & COMMIT_INDEX_MASK))
300 // Since the counter is behind, reduce the current count
301 currentCount = currentCount - (COMMIT_INDEX_MASK + 1);
302
303 t1 = (UINT16)currentCount;
304 if((t1 & ~COMMIT_INDEX_MASK) != (*c & ~COMMIT_INDEX_MASK))
305 return FALSE;
306 // set the counter to the value that was
307 // present when the commitment was made
308 currentCount = (currentCount & 0xffffffffffff0000ULL) | *c; /* libtpms changed */
309 }
310 // Marshal the count value to a TPM2B buffer for the KDF
311 cntr.t.size = sizeof(currentCount);
312 UINT64_TO_BYTE_ARRAY(currentCount, cntr.t.buffer);
313
314 // Now can do the KDF to create the random value for the signing operation
315 // During the creation process, we may generate an r that does not meet the
316 // requirements of the random value.
317 // want to generate a new r.
318 r->t.size = n.t.size;
319
320 for(iterations = 1; iterations < 1000000;)
321 {
322 int i;
323 CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG,
324 &gr.commitNonce.b,
325 COMMIT_STRING,
326 (TPM2B *)name, // libtpms changed
327 &cntr.b,
328 n.t.size * 8,
329 r->t.buffer,
330 &iterations,
331 FALSE);
332
333 // "random" value must be less than the prime
334 if(UnsignedCompareB(r->b.size, r->b.buffer, n.t.size, n.t.buffer) >= 0)
335 continue;
336
337 // in this implementation it is required that at least bit
338 // in the upper half of the number be set
339 for(i = n.t.size / 2; i >= 0; i--)
340 if(r->b.buffer[i] != 0)
341 return TRUE;
342 }
343 return FALSE;
344}
345
346//*** CryptCommit()
347// This function is called when the count value is committed. The 'gr.commitArray'
348// value associated with the current count value is SET and g_commitCounter is
349// incremented. The low-order 16 bits of old value of the counter is returned.
350UINT16
351CryptCommit(void)
352{
353 UINT16 oldCount = (UINT16)gr.commitCounter;
354 gr.commitCounter++;
355 SET_BIT(oldCount & COMMIT_INDEX_MASK, gr.commitArray);
356 return oldCount;
357}
358
359//*** CryptEndCommit()
360// This function is called when the signing operation using the committed value
361// is completed. It clears the gr.commitArray bit associated with the count
362// value so that it can't be used again.
363void CryptEndCommit(UINT16 c // IN: the counter value of the commitment
364 )
365{
366 ClearBit((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray));
367}
368
369//*** CryptEccGetParameters()
370// This function returns the ECC parameter details of the given curve.
371// Return Type: BOOL
372// TRUE(1) success
373// FALSE(0) unsupported ECC curve ID
374BOOL CryptEccGetParameters(
375 TPM_ECC_CURVE curveId, // IN: ECC curve ID
376 TPMS_ALGORITHM_DETAIL_ECC* parameters // OUT: ECC parameters
377 )
378{
379 const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId);
380 BOOL found = curve != NULL;
381
382 if(found)
383 {
384 parameters->curveID = curve->curveId;
385 parameters->keySize = curve->keySizeBits;
386 parameters->kdf = curve->kdf;
387 parameters->sign = curve->sign;
388 // BnTo2B(data->prime, &parameters->p.b, 0);
389 found = found
390 && TpmMath_IntTo2B(ExtEcc_CurveGetPrime(curveId),
391 &parameters->p.b,
392 parameters->p.t.size);
393 found = found
394 && TpmMath_IntTo2B(ExtEcc_CurveGet_a(curveId), &parameters->a.b,
395 parameters->p.t.size /* libtpms changed for HLK */);
396 found = found
397 && TpmMath_IntTo2B(ExtEcc_CurveGet_b(curveId), &parameters->b.b,
398 parameters->p.t.size /* libtpms changed for HLK */);
399 found = found
400 && TpmMath_IntTo2B(ExtEcc_CurveGetGx(curveId),
401 &parameters->gX.b,
402 parameters->p.t.size);
403 found = found
404 && TpmMath_IntTo2B(ExtEcc_CurveGetGy(curveId),
405 &parameters->gY.b,
406 parameters->p.t.size);
407 // BnTo2B(data->base.x, &parameters->gX.b, 0);
408 // BnTo2B(data->base.y, &parameters->gY.b, 0);
409 found =
410 found
411 && TpmMath_IntTo2B(ExtEcc_CurveGetOrder(curveId), &parameters->n.b, 0);
412 found =
413 found
414 && TpmMath_IntTo2B(ExtEcc_CurveGetCofactor(curveId), &parameters->h.b, 0);
415 // if we got into this IF but failed to get a parameter from the external
416 // library, our crypto systems are broken; enter failure mode.
417 if(!found)
418 {
419 FAIL(FATAL_ERROR_MATHLIBRARY);
420 }
421 }
422 return found;
423}
424
425//*** TpmEcc_IsValidPrivateEcc()
426// Checks that 0 < 'x' < 'q'
427BOOL TpmEcc_IsValidPrivateEcc(const Crypt_Int* x, // IN: private key to check
428 const Crypt_EccCurve* E // IN: the curve to check
429 )
430{
431 BOOL retVal;
432 retVal =
433 (!ExtMath_IsZero(x)
434 && (ExtMath_UnsignedCmp(x, ExtEcc_CurveGetOrder(ExtEcc_CurveGetCurveId(E)))
435 < 0));
436 return retVal;
437}
438
439LIB_EXPORT BOOL CryptEccIsValidPrivateKey(TPM2B_ECC_PARAMETER* d,
440 TPM_ECC_CURVE curveId)
441{
442 CRYPT_INT_INITIALIZED(bnD, MAX_ECC_PARAMETER_BYTES * 8, d);
443 return !ExtMath_IsZero(bnD)
444 && (ExtMath_UnsignedCmp(bnD, ExtEcc_CurveGetOrder(curveId)) < 0);
445}
446
447//*** TpmEcc_PointMult()
448// This function does a point multiply of the form 'R' = ['d']'S' + ['u']'Q' where the
449// parameters are Crypt_Int* values. If 'S' is NULL and d is not NULL, then it computes
450// 'R' = ['d']'G' + ['u']'Q' or just 'R' = ['d']'G' if 'u' and 'Q' are NULL.
451// If 'skipChecks' is TRUE, then the function will not verify that the inputs are
452// correct for the domain. This would be the case when the values were created by the
453// CryptoEngine code.
454// It will return TPM_RC_NO_RESULT if the resulting point is the point at infinity.
455// Return Type: TPM_RC
456// TPM_RC_NO_RESULT result of multiplication is a point at infinity
457// TPM_RC_ECC_POINT 'S' or 'Q' is not on the curve
458// TPM_RC_VALUE 'd' or 'u' is not < n
459TPM_RC
460TpmEcc_PointMult(Crypt_Point* R, // OUT: computed point
461 const Crypt_Point* S, // IN: optional point to multiply by 'd'
462 const Crypt_Int* d, // IN: scalar for [d]S or [d]G
463 const Crypt_Point* Q, // IN: optional second point
464 const Crypt_Int* u, // IN: optional second scalar
465 const Crypt_EccCurve* E // IN: curve parameters
466 )
467{
468 BOOL OK;
469 //
470 TPM_DO_SELF_TEST(TPM_ALG_ECDH);
471
472 // Need one scalar
473 OK = (d != NULL || u != NULL);
474
475 // If S is present, then d has to be present. If S is not
476 // present, then d may or may not be present
477 OK = OK && (((S == NULL) == (d == NULL)) || (d != NULL));
478
479 // either both u and Q have to be provided or neither can be provided (don't
480 // know what to do if only one is provided.
481 OK = OK && ((u == NULL) == (Q == NULL));
482
483 OK = OK && (E != NULL);
484 if(!OK)
485 return TPM_RC_VALUE;
486
487 OK = (S == NULL) || ExtEcc_IsPointOnCurve(S, E);
488 OK = OK && ((Q == NULL) || ExtEcc_IsPointOnCurve(Q, E));
489 if(!OK)
490 return TPM_RC_ECC_POINT;
491
492 if((d != NULL) && (S == NULL))
493 S = ExtEcc_CurveGetG(ExtEcc_CurveGetCurveId(E));
494 // If only one scalar, don't need Shamir's trick
495 if((d == NULL) || (u == NULL))
496 {
497 if(d == NULL)
498 OK = ExtEcc_PointMultiply(R, Q, u, E);
499 else
500 OK = ExtEcc_PointMultiply(R, S, d, E);
501 }
502 else
503 {
504 OK = ExtEcc_PointMultiplyAndAdd(R, S, d, Q, u, E);
505 }
506 return (OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT);
507}
508
509//***TpmEcc_GenPrivateScalar()
510// This function gets random values that are the size of the key plus 64 bits. The
511// value is reduced (mod ('q' - 1)) and incremented by 1 ('q' is the order of the
512// curve. This produces a value ('d') such that 1 <= 'd' < 'q'. This is the method
513// of FIPS 186-4 Section B.4.1 ""Key Pair Generation Using Extra Random Bits"".
514// Return Type: BOOL
515// TRUE(1) success
516// FALSE(0) failure generating private key
517#if !USE_OPENSSL_FUNCTIONS_EC // libtpms added
518BOOL TpmEcc_GenPrivateScalar(
519 Crypt_Int* dOut, // OUT: the qualified random value
520 const Crypt_EccCurve* E, // IN: curve for which the private key
521 // needs to be appropriate
522 RAND_STATE* rand // IN: state for DRBG
523 )
524{
525 TPM_ECC_CURVE curveId = ExtEcc_CurveGetCurveId(E);
526 const Crypt_Int* order = ExtEcc_CurveGetOrder(curveId);
527 BOOL OK;
528 UINT32 orderBits = ExtMath_SizeInBits(order);
529 UINT32 orderBytes = BITS_TO_BYTES(orderBits);
530 CRYPT_INT_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64);
531 CRYPT_INT_VAR(nMinus1, MAX_ECC_KEY_BITS);
532 //
533 OK = TpmMath_GetRandomInteger(bnExtraBits, (orderBytes * 8) + 64, rand);
534 OK = OK && ExtMath_SubtractWord(nMinus1, order, 1);
535 OK = OK && ExtMath_Mod(bnExtraBits, nMinus1);
536 OK = OK && ExtMath_AddWord(dOut, bnExtraBits, 1);
537 return OK && !g_inFailureMode;
538}
539#else // libtpms added begin
540BOOL TpmEcc_GenPrivateScalar(
541 Crypt_Int* dOut, // OUT: the qualified random value
542 const Crypt_EccCurve* E, // IN: curve for which the private key
543 // needs to be appropriate
544 const EC_GROUP* G, // IN: the EC_GROUP to use; must be != NULL for rand == NULL
545 BOOL noLeadingZeros, // IN: require that all bytes in the private key be set
546 // result may not have leading zero bytes
547 RAND_STATE* rand // IN: state for DRBG
548 )
549{
550 TPM_ECC_CURVE curveId = ExtEcc_CurveGetCurveId(E);
551 const Crypt_Int* order = ExtEcc_CurveGetOrder(curveId);
552 BOOL OK;
553 UINT32 orderBits = ExtMath_SizeInBits(order);
554 UINT32 orderBytes = BITS_TO_BYTES(orderBits);
555 UINT32 requestedBits = 0;
556 CRYPT_INT_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64);
557 CRYPT_INT_VAR(nMinus1, MAX_ECC_KEY_BITS);
558
559 if (rand == NULL) {
560 if (noLeadingZeros)
561 requestedBits = orderBits;
562
563 return OpenSSLEccGetPrivate((bigNum)dOut, G, requestedBits);
564 }
565
566 //
567 OK = TpmMath_GetRandomInteger(bnExtraBits, (orderBytes * 8) + 64, rand);
568 OK = OK && ExtMath_SubtractWord(nMinus1, order, 1);
569 OK = OK && ExtMath_Mod(bnExtraBits, nMinus1);
570 OK = OK && ExtMath_AddWord(dOut, bnExtraBits, 1);
571 return OK && !g_inFailureMode;
572}
573#endif // USE_OPENSSL_FUNCTIONS_EC libtpms added end
574
575#if !USE_OPENSSL_FUNCTIONS_EC // libtpms added
576//*** TpmEcc_GenerateKeyPair()
577// This function gets a private scalar from the source of random bits and does
578// the point multiply to get the public key.
579BOOL TpmEcc_GenerateKeyPair(Crypt_Int* bnD, // OUT: private scalar
580 Crypt_Point* ecQ, // OUT: public point
581 const Crypt_EccCurve* E, // IN: curve for the point
582 RAND_STATE* rand // IN: DRBG state to use
583 )
584{
585 BOOL OK = FALSE;
586 // Get a private scalar
587 OK = TpmEcc_GenPrivateScalar(bnD, E, rand);
588
589 // Do a point multiply
590 OK = OK && ExtEcc_PointMultiply(ecQ, NULL, bnD, E);
591 return OK;
592}
593
594#else // libtpms added begin
595
596/* In this version of BnEccGenerateKeyPair we take a dual approach to constant
597 time requirements: For curves whose order is at the byte boundary, e.g.
598 NIST P224/P256/P384, we make sure that bnD has all bytes set (no leading zeros)
599 so that OpenSSL BIGNUM code will not reduce the number of bytes and the
600 subsequent BnEccModMult() would run faster for a shoter value. For all other
601 curves whose order is not at the byte boundary, e.g. NIST P521, we simply
602 always add the order of the curve to bnD and call BnEccModMult() with the
603 result bnD1, which leads to the same result. */
604BOOL TpmEcc_GenerateKeyPair(Crypt_Int* bnD, // OUT: private scalar
605 Crypt_Point* ecQ, // OUT: public point
606 const Crypt_EccCurve* E, // IN: curve for the point
607 RAND_STATE* rand // IN: DRBG state to use
608 )
609{
610 BOOL OK = FALSE;
611 TPM_ECC_CURVE curveId = ExtEcc_CurveGetCurveId(E);
612 const Crypt_Int* order = ExtEcc_CurveGetOrder(curveId);
613 UINT32 orderBits = ExtMath_SizeInBits(order);
614 BOOL atByteBoundary = (orderBits & 7) == 0;
615 BOOL noLeadingZeros = atByteBoundary;
616 CRYPT_ECC_NUM(bnD1);
617
618 // We request that bnD not have leading zeros if it is at byte-boundary,
619 // like for example it is the case for NIST P256.
620 OK = TpmEcc_GenPrivateScalar(bnD, E, E->G, noLeadingZeros, rand);
621 if (!atByteBoundary) {
622 // for NIST P521 we can add the order to bnD to ensure we have
623 // a constant amount of bytes; the result is the same as if we
624 // were doing the BnEccModMult() calculation with bnD.
625 OK = OK && ExtMath_Add(bnD1, bnD, order);
626 OK = OK && ExtEcc_PointMultiply(ecQ, NULL, bnD1, E);
627 } else {
628 OK = OK && ExtEcc_PointMultiply(ecQ, NULL, bnD, E);
629 }
630 return OK;
631}
632
633#endif // libtpms added end
634
635//***CryptEccNewKeyPair(***)
636// This function creates an ephemeral ECC. It is ephemeral in that
637// is expected that the private part of the key will be discarded
638LIB_EXPORT TPM_RC CryptEccNewKeyPair(
639 TPMS_ECC_POINT* Qout, // OUT: the public point
640 TPM2B_ECC_PARAMETER* dOut, // OUT: the private scalar
641 TPM_ECC_CURVE curveId // IN: the curve for the key
642 )
643{
644 CRYPT_CURVE_INITIALIZED(E, curveId);
645 CRYPT_POINT_VAR(ecQ);
646 CRYPT_ECC_NUM(bnD);
647 BOOL OK;
648
649 if(E == NULL)
650 return TPM_RC_CURVE;
651
652 TPM_DO_SELF_TEST(TPM_ALG_ECDH);
653 OK = TpmEcc_GenerateKeyPair(bnD, ecQ, E, NULL);
654 if(OK)
655 {
656 TpmEcc_PointTo2B(Qout, ecQ, E);
657 TpmMath_IntTo2B(bnD, &dOut->b, Qout->x.t.size);
658 }
659 else
660 {
661 Qout->x.t.size = Qout->y.t.size = dOut->t.size = 0;
662 }
663 CRYPT_CURVE_FREE(E);
664 return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
665}
666
667//*** CryptEccPointMultiply()
668// This function computes 'R' := ['dIn']'G' + ['uIn']'QIn'. Where 'dIn' and
669// 'uIn' are scalars, 'G' and 'QIn' are points on the specified curve and 'G' is the
670// default generator of the curve.
671//
672// The 'xOut' and 'yOut' parameters are optional and may be set to NULL if not
673// used.
674//
675// It is not necessary to provide 'uIn' if 'QIn' is specified but one of 'uIn' and
676// 'dIn' must be provided. If 'dIn' and 'QIn' are specified but 'uIn' is not
677// provided, then 'R' = ['dIn']'QIn'.
678//
679// If the multiply produces the point at infinity, the TPM_RC_NO_RESULT is returned.
680//
681// The sizes of 'xOut' and yOut' will be set to be the size of the degree of
682// the curve
683//
684// It is a fatal error if 'dIn' and 'uIn' are both unspecified (NULL) or if 'Qin'
685// or 'Rout' is unspecified.
686//
687// Return Type: TPM_RC
688// TPM_RC_ECC_POINT the point 'Pin' or 'Qin' is not on the curve
689// TPM_RC_NO_RESULT the product point is at infinity
690// TPM_RC_CURVE bad curve
691// TPM_RC_VALUE 'dIn' or 'uIn' out of range
692//
693LIB_EXPORT TPM_RC 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 CRYPT_CURVE_INITIALIZED(E, curveId);
705 CRYPT_POINT_INITIALIZED(ecP, Pin);
706 CRYPT_ECC_INITIALIZED(bnD, dIn); // If dIn is null, then bnD is null
707 CRYPT_ECC_INITIALIZED(bnU, uIn);
708 CRYPT_POINT_INITIALIZED(ecQ, Qin);
709 CRYPT_POINT_VAR(ecR);
710 TPM_RC retVal;
711 //
712 retVal = TpmEcc_PointMult(ecR, ecP, bnD, ecQ, bnU, E);
713
714 if(retVal == TPM_RC_SUCCESS)
715 TpmEcc_PointTo2B(Rout, ecR, E);
716 else
717 ClearPoint2B(Rout);
718 CRYPT_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
730LIB_EXPORT BOOL CryptEccIsPointOnCurve(
731 TPM_ECC_CURVE curveId, // IN: the curve selector
732 TPMS_ECC_POINT* Qin // IN: the point.
733 )
734{
735 CRYPT_CURVE_INITIALIZED(E, curveId);
736 CRYPT_POINT_INITIALIZED(ecQ, Qin);
737 BOOL OK;
738 //
739 pAssert(Qin != NULL);
740 OK = (E != NULL && (ExtEcc_IsPointOnCurve(ecQ, E)));
741 CRYPT_CURVE_FREE(E); // libtpms added
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)
759LIB_EXPORT TPM_RC CryptEccGenerateKey(
760 TPMT_PUBLIC* publicArea, // IN/OUT: The public area template for
761 // the new key. The public key
762 // area will be replaced computed
763 // ECC public key
764 TPMT_SENSITIVE* sensitive, // OUT: the sensitive area will be
765 // updated to contain the private
766 // ECC key and the symmetric
767 // encryption key
768 RAND_STATE* rand // IN: if not NULL, the deterministic
769 // RNG state
770 )
771{
772 CRYPT_CURVE_INITIALIZED(E, publicArea->parameters.eccDetail.curveID);
773 CRYPT_ECC_NUM(bnD);
774 CRYPT_POINT_VAR(ecQ);
775 BOOL OK;
776 TPM_RC retVal;
777 //
778 TPM_DO_SELF_TEST(TPM_ALG_ECDSA); // ECDSA is used to verify each key
779
780 // Validate parameters
781 if(E == NULL)
782 ERROR_EXIT(TPM_RC_CURVE);
783
784 publicArea->unique.ecc.x.t.size = 0;
785 publicArea->unique.ecc.y.t.size = 0;
786 sensitive->sensitive.ecc.t.size = 0;
787
788 OK = TpmEcc_GenerateKeyPair(bnD, ecQ, E, rand);
789 if(OK)
790 {
791 TpmEcc_PointTo2B(&publicArea->unique.ecc, ecQ, E);
792 TpmMath_IntTo2B(
793 bnD, &sensitive->sensitive.ecc.b, publicArea->unique.ecc.x.t.size);
794 }
795//# if FIPS_COMPLIANT // libtpms changed
796 // See if PWCT is required
797 if(OK && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign) && // libtpms changed begin
798 RuntimeProfileRequiresAttributeFlags(&g_RuntimeProfile,
799 RUNTIME_ATTRIBUTE_PAIRWISE_CONSISTENCY_TEST)) // libtpms changed end
800 {
801 CRYPT_ECC_NUM(bnT);
802 CRYPT_ECC_NUM(bnS);
803 TPM2B_DIGEST digest;
804 //
805 TPM_DO_SELF_TEST(TPM_ALG_ECDSA);
806 digest.t.size = MIN(sensitive->sensitive.ecc.t.size, sizeof(digest.t.buffer));
807 // Get a random value to sign using the built in DRBG state
808 DRBG_Generate(NULL, digest.t.buffer, digest.t.size);
809 if(g_inFailureMode)
810 return TPM_RC_FAILURE;
811 TpmEcc_SignEcdsa(bnT, bnS, E, bnD, &digest, NULL);
812 // and make sure that we can validate the signature
813 OK = TpmEcc_ValidateSignatureEcdsa(bnT, bnS, E, ecQ, &digest)
814 == TPM_RC_SUCCESS;
815 }
816//# endif // libtpms changed
817 retVal = (OK) ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
818 Exit:
819 CRYPT_CURVE_FREE(E);
820 return retVal;
821}
822
823// libtpms added begin
824// Support for some curves may be compiled in but they may not be
825// supported by openssl's crypto library.
826LIB_EXPORT BOOL
827CryptEccIsCurveRuntimeUsable(
828 TPMI_ECC_CURVE curveId
829 )
830{
831 CRYPT_CURVE_INITIALIZED(E, curveId);
832 if (E == NULL)
833 return FALSE;
834 CRYPT_CURVE_FREE(E);
835 return TRUE;
836}
837// libtpms added end
838
839#endif // ALG_ECC
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette