/********************************************************************************/ /* */ /* ECC Main */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* */ /* Licenses and Notices */ /* */ /* 1. Copyright Licenses: */ /* */ /* - Trusted Computing Group (TCG) grants to the user of the source code in */ /* this specification (the "Source Code") a worldwide, irrevocable, */ /* nonexclusive, royalty free, copyright license to reproduce, create */ /* derivative works, distribute, display and perform the Source Code and */ /* derivative works thereof, and to grant others the rights granted herein. */ /* */ /* - The TCG grants to the user of the other parts of the specification */ /* (other than the Source Code) the rights to reproduce, distribute, */ /* display, and perform the specification solely for the purpose of */ /* developing products based on such documents. */ /* */ /* 2. Source Code Distribution Conditions: */ /* */ /* - Redistributions of Source Code must retain the above copyright licenses, */ /* this list of conditions and the following disclaimers. */ /* */ /* - Redistributions in binary form must reproduce the above copyright */ /* licenses, this list of conditions and the following disclaimers in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* 3. Disclaimers: */ /* */ /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ /* information on specification licensing rights available through TCG */ /* membership agreements. */ /* */ /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ /* */ /* - Without limitation, TCG and its members and licensors disclaim all */ /* liability, including liability for infringement of any proprietary */ /* rights, relating to use of information in this specification and to the */ /* implementation of this specification, and TCG disclaims all liability for */ /* cost of procurement of substitute goods or services, lost profits, loss */ /* of use, loss of data or any incidental, consequential, direct, indirect, */ /* or special damages, whether under contract, tort, warranty or otherwise, */ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ /* (c) Copyright IBM Corp. and others, 2016 - 2024 */ /* */ /********************************************************************************/ //** Includes and Defines #include "Tpm.h" #include "TpmMath_Util_fp.h" #include "TpmEcc_Util_fp.h" #include "TpmEcc_Signature_ECDSA_fp.h" // required for pairwise test in key generation #if ALG_ECC //** Functions # if SIMULATION void EccSimulationEnd(void) { # if SIMULATION // put things to be printed at the end of the simulation here # endif } # endif // SIMULATION //*** CryptEccInit() // This function is called at _TPM_Init BOOL CryptEccInit(void) { return TRUE; } //*** CryptEccStartup() // This function is called at TPM2_Startup(). BOOL CryptEccStartup(void) { return TRUE; } //*** ClearPoint2B(generic) // Initialize the size values of a TPMS_ECC_POINT structure. void ClearPoint2B(TPMS_ECC_POINT* p // IN: the point ) { if(p != NULL) { p->x.t.size = 0; p->y.t.size = 0; } } //*** CryptEccGetParametersByCurveId() // This function returns a pointer to the curve data that is associated with // the indicated curveId. // If there is no curve with the indicated ID, the function returns NULL. This // function is in this module so that it can be called by GetCurve data. // Return Type: const TPM_ECC_CURVE_METADATA // NULL curve with the indicated TPM_ECC_CURVE is not implemented // != NULL pointer to the curve data LIB_EXPORT const TPM_ECC_CURVE_METADATA* CryptEccGetParametersByCurveId( TPM_ECC_CURVE curveId // IN: the curveID ) { int i; for(i = 0; i < ECC_CURVE_COUNT; i++) { if(eccCurves[i].curveId == curveId) return &eccCurves[i]; } return NULL; } //*** CryptEccGetKeySizeForCurve() // This function returns the key size in bits of the indicated curve. LIB_EXPORT UINT16 CryptEccGetKeySizeForCurve(TPM_ECC_CURVE curveId // IN: the curve ) { const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId); UINT16 keySizeInBits; // keySizeInBits = (curve != NULL) ? curve->keySizeBits : 0; return keySizeInBits; } //***CryptEccGetOID() const BYTE* CryptEccGetOID(TPM_ECC_CURVE curveId) { const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId); return (curve != NULL) ? curve->OID : NULL; } //*** CryptEccGetCurveByIndex() // This function returns the number of the 'i'-th implemented curve. The normal // use would be to call this function with 'i' starting at 0. When the 'i' is greater // than or equal to the number of implemented curves, TPM_ECC_NONE is returned. LIB_EXPORT TPM_ECC_CURVE CryptEccGetCurveByIndex(UINT16 i) { if(i >= ECC_CURVE_COUNT) return TPM_ECC_NONE; return eccCurves[i].curveId; } //*** CryptCapGetECCCurve() // This function returns the list of implemented ECC curves. // Return Type: TPMI_YES_NO // YES if no more ECC curve is available // NO if there are more ECC curves not reported TPMI_YES_NO CryptCapGetECCCurve(TPM_ECC_CURVE curveID, // IN: the starting ECC curve UINT32 maxCount, // IN: count of returned curves TPML_ECC_CURVE* curveList // OUT: ECC curve list ) { TPMI_YES_NO more = NO; UINT16 i; UINT32 count = ECC_CURVE_COUNT; TPM_ECC_CURVE curve; // Initialize output property list curveList->count = 0; // The maximum count of curves we may return is MAX_ECC_CURVES if(maxCount > MAX_ECC_CURVES) maxCount = MAX_ECC_CURVES; // Scan the eccCurveValues array for(i = 0; i < count; i++) { curve = CryptEccGetCurveByIndex(i); // If curveID is less than the starting curveID, skip it if(curve < curveID) continue; if(curveList->count < maxCount) { // If we have not filled up the return list, add more curves to // it curveList->eccCurves[curveList->count] = curve; curveList->count++; } else { // If the return list is full but we still have curves // available, report this and stop iterating more = YES; break; } } return more; } //*** CryptCapGetOneECCCurve() // This function returns whether the ECC curve is implemented. BOOL CryptCapGetOneECCCurve(TPM_ECC_CURVE curveID // IN: the ECC curve ) { UINT16 i; // Scan the eccCurveValues array for(i = 0; i < ECC_CURVE_COUNT; i++) { if(CryptEccGetCurveByIndex(i) == curveID) { return TRUE; } } return FALSE; } //*** CryptGetCurveSignScheme() // This function will return a pointer to the scheme of the curve. const TPMT_ECC_SCHEME* CryptGetCurveSignScheme( TPM_ECC_CURVE curveId // IN: The curve selector ) { const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId); if(curve != NULL) return &(curve->sign); else return NULL; } //*** CryptGenerateR() // This function computes the commit random value for a split signing scheme. // // If 'c' is NULL, it indicates that 'r' is being generated // for TPM2_Commit. // If 'c' is not NULL, the TPM will validate that the 'gr.commitArray' // bit associated with the input value of 'c' is SET. If not, the TPM // returns FALSE and no 'r' value is generated. // Return Type: BOOL // TRUE(1) r value computed // FALSE(0) no r value computed BOOL CryptGenerateR(TPM2B_ECC_PARAMETER* r, // OUT: the generated random value UINT16* c, // IN/OUT: count value. TPMI_ECC_CURVE curveID, // IN: the curve for the value TPM2B_NAME* name // IN: optional name of a key to // associate with 'r' ) { // This holds the marshaled g_commitCounter. TPM2B_TYPE(8B, 8); TPM2B_8B cntr = {{8, {0}}}; UINT32 iterations; TPM2B_ECC_PARAMETER n; UINT64 currentCount = gr.commitCounter; UINT16 t1; // if(!TpmMath_IntTo2B(ExtEcc_CurveGetOrder(curveID), (TPM2B*)&n, 0)) return FALSE; // If this is the commit phase, use the current value of the commit counter if(c != NULL) { // if the array bit is not set, can't use the value. if(!TEST_BIT((*c & COMMIT_INDEX_MASK), gr.commitArray)) return FALSE; // If it is the sign phase, figure out what the counter value was // when the commitment was made. // // When gr.commitArray has less than 64K bits, the extra // bits of 'c' are used as a check to make sure that the // signing operation is not using an out of range count value t1 = (UINT16)currentCount; // If the lower bits of c are greater or equal to the lower bits of t1 // then the upper bits of t1 must be one more than the upper bits // of c if((*c & COMMIT_INDEX_MASK) >= (t1 & COMMIT_INDEX_MASK)) // Since the counter is behind, reduce the current count currentCount = currentCount - (COMMIT_INDEX_MASK + 1); t1 = (UINT16)currentCount; if((t1 & ~COMMIT_INDEX_MASK) != (*c & ~COMMIT_INDEX_MASK)) return FALSE; // set the counter to the value that was // present when the commitment was made currentCount = (currentCount & 0xffffffffffff0000) | *c; } // Marshal the count value to a TPM2B buffer for the KDF cntr.t.size = sizeof(currentCount); UINT64_TO_BYTE_ARRAY(currentCount, cntr.t.buffer); // Now can do the KDF to create the random value for the signing operation // During the creation process, we may generate an r that does not meet the // requirements of the random value. // want to generate a new r. r->t.size = n.t.size; for(iterations = 1; iterations < 1000000;) { int i; CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &gr.commitNonce.b, COMMIT_STRING, &name->b, &cntr.b, n.t.size * 8, r->t.buffer, &iterations, FALSE); // "random" value must be less than the prime if(UnsignedCompareB(r->b.size, r->b.buffer, n.t.size, n.t.buffer) >= 0) continue; // in this implementation it is required that at least bit // in the upper half of the number be set for(i = n.t.size / 2; i >= 0; i--) if(r->b.buffer[i] != 0) return TRUE; } return FALSE; } //*** CryptCommit() // This function is called when the count value is committed. The 'gr.commitArray' // value associated with the current count value is SET and g_commitCounter is // incremented. The low-order 16 bits of old value of the counter is returned. UINT16 CryptCommit(void) { UINT16 oldCount = (UINT16)gr.commitCounter; gr.commitCounter++; SET_BIT(oldCount & COMMIT_INDEX_MASK, gr.commitArray); return oldCount; } //*** CryptEndCommit() // This function is called when the signing operation using the committed value // is completed. It clears the gr.commitArray bit associated with the count // value so that it can't be used again. void CryptEndCommit(UINT16 c // IN: the counter value of the commitment ) { ClearBit((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray)); } //*** CryptEccGetParameters() // This function returns the ECC parameter details of the given curve. // Return Type: BOOL // TRUE(1) success // FALSE(0) unsupported ECC curve ID BOOL CryptEccGetParameters( TPM_ECC_CURVE curveId, // IN: ECC curve ID TPMS_ALGORITHM_DETAIL_ECC* parameters // OUT: ECC parameters ) { const TPM_ECC_CURVE_METADATA* curve = CryptEccGetParametersByCurveId(curveId); BOOL found = curve != NULL; if(found) { parameters->curveID = curve->curveId; parameters->keySize = curve->keySizeBits; parameters->kdf = curve->kdf; parameters->sign = curve->sign; // BnTo2B(data->prime, ¶meters->p.b, 0); found = found && TpmMath_IntTo2B(ExtEcc_CurveGetPrime(curveId), ¶meters->p.b, parameters->p.t.size); found = found && TpmMath_IntTo2B(ExtEcc_CurveGet_a(curveId), ¶meters->a.b, 0); found = found && TpmMath_IntTo2B(ExtEcc_CurveGet_b(curveId), ¶meters->b.b, 0); found = found && TpmMath_IntTo2B(ExtEcc_CurveGetGx(curveId), ¶meters->gX.b, parameters->p.t.size); found = found && TpmMath_IntTo2B(ExtEcc_CurveGetGy(curveId), ¶meters->gY.b, parameters->p.t.size); // BnTo2B(data->base.x, ¶meters->gX.b, 0); // BnTo2B(data->base.y, ¶meters->gY.b, 0); found = found && TpmMath_IntTo2B(ExtEcc_CurveGetOrder(curveId), ¶meters->n.b, 0); found = found && TpmMath_IntTo2B(ExtEcc_CurveGetCofactor(curveId), ¶meters->h.b, 0); // if we got into this IF but failed to get a parameter from the external // library, our crypto systems are broken; enter failure mode. if(!found) { FAIL(FATAL_ERROR_MATHLIBRARY); } } return found; } //*** TpmEcc_IsValidPrivateEcc() // Checks that 0 < 'x' < 'q' BOOL TpmEcc_IsValidPrivateEcc(const Crypt_Int* x, // IN: private key to check const Crypt_EccCurve* E // IN: the curve to check ) { BOOL retVal; retVal = (!ExtMath_IsZero(x) && (ExtMath_UnsignedCmp(x, ExtEcc_CurveGetOrder(ExtEcc_CurveGetCurveId(E))) < 0)); return retVal; } LIB_EXPORT BOOL CryptEccIsValidPrivateKey(TPM2B_ECC_PARAMETER* d, TPM_ECC_CURVE curveId) { CRYPT_INT_INITIALIZED(bnD, MAX_ECC_PARAMETER_BYTES * 8, d); return !ExtMath_IsZero(bnD) && (ExtMath_UnsignedCmp(bnD, ExtEcc_CurveGetOrder(curveId)) < 0); } //*** TpmEcc_PointMult() // This function does a point multiply of the form 'R' = ['d']'S' + ['u']'Q' where the // parameters are Crypt_Int* values. If 'S' is NULL and d is not NULL, then it computes // 'R' = ['d']'G' + ['u']'Q' or just 'R' = ['d']'G' if 'u' and 'Q' are NULL. // If 'skipChecks' is TRUE, then the function will not verify that the inputs are // correct for the domain. This would be the case when the values were created by the // CryptoEngine code. // It will return TPM_RC_NO_RESULT if the resulting point is the point at infinity. // Return Type: TPM_RC // TPM_RC_NO_RESULT result of multiplication is a point at infinity // TPM_RC_ECC_POINT 'S' or 'Q' is not on the curve // TPM_RC_VALUE 'd' or 'u' is not < n TPM_RC TpmEcc_PointMult(Crypt_Point* R, // OUT: computed point const Crypt_Point* S, // IN: optional point to multiply by 'd' const Crypt_Int* d, // IN: scalar for [d]S or [d]G const Crypt_Point* Q, // IN: optional second point const Crypt_Int* u, // IN: optional second scalar const Crypt_EccCurve* E // IN: curve parameters ) { BOOL OK; // TPM_DO_SELF_TEST(TPM_ALG_ECDH); // Need one scalar OK = (d != NULL || u != NULL); // If S is present, then d has to be present. If S is not // present, then d may or may not be present OK = OK && (((S == NULL) == (d == NULL)) || (d != NULL)); // either both u and Q have to be provided or neither can be provided (don't // know what to do if only one is provided. OK = OK && ((u == NULL) == (Q == NULL)); OK = OK && (E != NULL); if(!OK) return TPM_RC_VALUE; OK = (S == NULL) || ExtEcc_IsPointOnCurve(S, E); OK = OK && ((Q == NULL) || ExtEcc_IsPointOnCurve(Q, E)); if(!OK) return TPM_RC_ECC_POINT; if((d != NULL) && (S == NULL)) S = ExtEcc_CurveGetG(ExtEcc_CurveGetCurveId(E)); // If only one scalar, don't need Shamir's trick if((d == NULL) || (u == NULL)) { if(d == NULL) OK = ExtEcc_PointMultiply(R, Q, u, E); else OK = ExtEcc_PointMultiply(R, S, d, E); } else { OK = ExtEcc_PointMultiplyAndAdd(R, S, d, Q, u, E); } return (OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT); } //***TpmEcc_GenPrivateScalar() // This function gets random values that are the size of the key plus 64 bits. The // value is reduced (mod ('q' - 1)) and incremented by 1 ('q' is the order of the // curve. This produces a value ('d') such that 1 <= 'd' < 'q'. This is the method // of FIPS 186-4 Section B.4.1 ""Key Pair Generation Using Extra Random Bits"". // Return Type: BOOL // TRUE(1) success // FALSE(0) failure generating private key BOOL TpmEcc_GenPrivateScalar( Crypt_Int* dOut, // OUT: the qualified random value const Crypt_EccCurve* E, // IN: curve for which the private key // needs to be appropriate RAND_STATE* rand // IN: state for DRBG ) { TPM_ECC_CURVE curveId = ExtEcc_CurveGetCurveId(E); const Crypt_Int* order = ExtEcc_CurveGetOrder(curveId); BOOL OK; UINT32 orderBits = ExtMath_SizeInBits(order); UINT32 orderBytes = BITS_TO_BYTES(orderBits); CRYPT_INT_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64); CRYPT_INT_VAR(nMinus1, MAX_ECC_KEY_BITS); // OK = TpmMath_GetRandomInteger(bnExtraBits, (orderBytes * 8) + 64, rand); OK = OK && ExtMath_SubtractWord(nMinus1, order, 1); OK = OK && ExtMath_Mod(bnExtraBits, nMinus1); OK = OK && ExtMath_AddWord(dOut, bnExtraBits, 1); return OK && !g_inFailureMode; } //*** TpmEcc_GenerateKeyPair() // This function gets a private scalar from the source of random bits and does // the point multiply to get the public key. BOOL TpmEcc_GenerateKeyPair(Crypt_Int* bnD, // OUT: private scalar Crypt_Point* ecQ, // OUT: public point const Crypt_EccCurve* E, // IN: curve for the point RAND_STATE* rand // IN: DRBG state to use ) { BOOL OK = FALSE; // Get a private scalar OK = TpmEcc_GenPrivateScalar(bnD, E, rand); // Do a point multiply OK = OK && ExtEcc_PointMultiply(ecQ, NULL, bnD, E); return OK; } //***CryptEccNewKeyPair(***) // This function creates an ephemeral ECC. It is ephemeral in that // is expected that the private part of the key will be discarded LIB_EXPORT TPM_RC CryptEccNewKeyPair( TPMS_ECC_POINT* Qout, // OUT: the public point TPM2B_ECC_PARAMETER* dOut, // OUT: the private scalar TPM_ECC_CURVE curveId // IN: the curve for the key ) { CRYPT_CURVE_INITIALIZED(E, curveId); CRYPT_POINT_VAR(ecQ); CRYPT_ECC_NUM(bnD); BOOL OK; if(E == NULL) return TPM_RC_CURVE; TPM_DO_SELF_TEST(TPM_ALG_ECDH); OK = TpmEcc_GenerateKeyPair(bnD, ecQ, E, NULL); if(OK) { TpmEcc_PointTo2B(Qout, ecQ, E); TpmMath_IntTo2B(bnD, &dOut->b, Qout->x.t.size); } else { Qout->x.t.size = Qout->y.t.size = dOut->t.size = 0; } CRYPT_CURVE_FREE(E); return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT; } //*** CryptEccPointMultiply() // This function computes 'R' := ['dIn']'G' + ['uIn']'QIn'. Where 'dIn' and // 'uIn' are scalars, 'G' and 'QIn' are points on the specified curve and 'G' is the // default generator of the curve. // // The 'xOut' and 'yOut' parameters are optional and may be set to NULL if not // used. // // It is not necessary to provide 'uIn' if 'QIn' is specified but one of 'uIn' and // 'dIn' must be provided. If 'dIn' and 'QIn' are specified but 'uIn' is not // provided, then 'R' = ['dIn']'QIn'. // // If the multiply produces the point at infinity, the TPM_RC_NO_RESULT is returned. // // The sizes of 'xOut' and yOut' will be set to be the size of the degree of // the curve // // It is a fatal error if 'dIn' and 'uIn' are both unspecified (NULL) or if 'Qin' // or 'Rout' is unspecified. // // Return Type: TPM_RC // TPM_RC_ECC_POINT the point 'Pin' or 'Qin' is not on the curve // TPM_RC_NO_RESULT the product point is at infinity // TPM_RC_CURVE bad curve // TPM_RC_VALUE 'dIn' or 'uIn' out of range // LIB_EXPORT TPM_RC CryptEccPointMultiply( TPMS_ECC_POINT* Rout, // OUT: the product point R TPM_ECC_CURVE curveId, // IN: the curve to use TPMS_ECC_POINT* Pin, // IN: first point (can be null) TPM2B_ECC_PARAMETER* dIn, // IN: scalar value for [dIn]Qin // the Pin TPMS_ECC_POINT* Qin, // IN: point Q TPM2B_ECC_PARAMETER* uIn // IN: scalar value for the multiplier // of Q ) { CRYPT_CURVE_INITIALIZED(E, curveId); CRYPT_POINT_INITIALIZED(ecP, Pin); CRYPT_ECC_INITIALIZED(bnD, dIn); // If dIn is null, then bnD is null CRYPT_ECC_INITIALIZED(bnU, uIn); CRYPT_POINT_INITIALIZED(ecQ, Qin); CRYPT_POINT_VAR(ecR); TPM_RC retVal; // retVal = TpmEcc_PointMult(ecR, ecP, bnD, ecQ, bnU, E); if(retVal == TPM_RC_SUCCESS) TpmEcc_PointTo2B(Rout, ecR, E); else ClearPoint2B(Rout); CRYPT_CURVE_FREE(E); return retVal; } //*** CryptEccIsPointOnCurve() // 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 + 'a'*'x' + 'b' mod 'p'. // // It is a fatal error if 'Q' is not specified (is NULL). // Return Type: BOOL // TRUE(1) point is on curve // FALSE(0) point is not on curve or curve is not supported LIB_EXPORT BOOL CryptEccIsPointOnCurve( TPM_ECC_CURVE curveId, // IN: the curve selector TPMS_ECC_POINT* Qin // IN: the point. ) { CRYPT_CURVE_INITIALIZED(E, curveId); CRYPT_POINT_INITIALIZED(ecQ, Qin); BOOL OK; // pAssert(Qin != NULL); OK = (E != NULL && (ExtEcc_IsPointOnCurve(ecQ, E))); return OK; } //*** CryptEccGenerateKey() // This function generates an ECC key pair based on the input parameters. // This routine uses KDFa to produce candidate numbers. The method is according // to FIPS 186-3, section B.1.2 "Key Pair Generation by Testing Candidates." // According to the method in FIPS 186-3, the resulting private value 'd' should be // 1 <= 'd' < 'n' where 'n' is the order of the base point. // // It is a fatal error if 'Qout', 'dOut', is not provided (is NULL). // // If the curve is not supported // If 'seed' is not provided, then a random number will be used for the key // Return Type: TPM_RC // TPM_RC_CURVE curve is not supported // TPM_RC_NO_RESULT could not verify key with signature (FIPS only) LIB_EXPORT TPM_RC CryptEccGenerateKey( TPMT_PUBLIC* publicArea, // IN/OUT: The public area template for // the new key. The public key // area will be replaced computed // ECC public key TPMT_SENSITIVE* sensitive, // OUT: the sensitive area will be // updated to contain the private // ECC key and the symmetric // encryption key RAND_STATE* rand // IN: if not NULL, the deterministic // RNG state ) { CRYPT_CURVE_INITIALIZED(E, publicArea->parameters.eccDetail.curveID); CRYPT_ECC_NUM(bnD); CRYPT_POINT_VAR(ecQ); BOOL OK; TPM_RC retVal; // TPM_DO_SELF_TEST(TPM_ALG_ECDSA); // ECDSA is used to verify each key // Validate parameters if(E == NULL) ERROR_EXIT(TPM_RC_CURVE); publicArea->unique.ecc.x.t.size = 0; publicArea->unique.ecc.y.t.size = 0; sensitive->sensitive.ecc.t.size = 0; OK = TpmEcc_GenerateKeyPair(bnD, ecQ, E, rand); if(OK) { TpmEcc_PointTo2B(&publicArea->unique.ecc, ecQ, E); TpmMath_IntTo2B( bnD, &sensitive->sensitive.ecc.b, publicArea->unique.ecc.x.t.size); } # if FIPS_COMPLIANT // See if PWCT is required if(OK && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign)) { CRYPT_ECC_NUM(bnT); CRYPT_ECC_NUM(bnS); TPM2B_DIGEST digest; // TPM_DO_SELF_TEST(TPM_ALG_ECDSA); digest.t.size = MIN(sensitive->sensitive.ecc.t.size, sizeof(digest.t.buffer)); // Get a random value to sign using the built in DRBG state DRBG_Generate(NULL, digest.t.buffer, digest.t.size); if(g_inFailureMode) return TPM_RC_FAILURE; TpmEcc_SignEcdsa(bnT, bnS, E, bnD, &digest, NULL); // and make sure that we can validate the signature OK = TpmEcc_ValidateSignatureEcdsa(bnT, bnS, E, ecQ, &digest) == TPM_RC_SUCCESS; } # endif retVal = (OK) ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT; Exit: CRYPT_CURVE_FREE(E); return retVal; } #endif // ALG_ECC