| /* Microsoft Reference Implementation for TPM 2.0 | |
| * | |
| * The copyright in this software is being made available under the BSD License, | |
| * included below. This software may be subject to other third party and | |
| * contributor rights, including patent rights, and no such rights are granted | |
| * under this license. | |
| * | |
| * Copyright (c) Microsoft Corporation | |
| * | |
| * All rights reserved. | |
| * | |
| * BSD License | |
| * | |
| * Redistribution and use in source and binary forms, with or without modification, | |
| * are permitted provided that the following conditions are met: | |
| * | |
| * Redistributions of source code must retain the above copyright notice, this list | |
| * of conditions and the following disclaimer. | |
| * | |
| * Redistributions in binary form must reproduce the above copyright notice, this | |
| * list of conditions and the following disclaimer in the documentation and/or | |
| * other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" | |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| //** Includes and Defines | |
| #include "Tpm.h" | |
| #if ALG_ECC | |
| // This version requires that the new format for ECC data be used | |
| #if !USE_BN_ECC_DATA | |
| #error "Need to SET USE_BN_ECC_DATA to YES in Implementaion.h" | |
| #endif | |
| //** 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 ECC_CURVE_DATA | |
| // NULL curve with the indicated TPM_ECC_CURVE is not implemented | |
| // != NULL pointer to the curve data | |
| LIB_EXPORT const ECC_CURVE * | |
| 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 ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); | |
| UINT16 keySizeInBits; | |
| // | |
| keySizeInBits = (curve != NULL) ? curve->keySizeBits : 0; | |
| return keySizeInBits; | |
| } | |
| //*** GetCurveData() | |
| // This function returns the a pointer for the parameter data | |
| // associated with a curve. | |
| const ECC_CURVE_DATA * | |
| GetCurveData( | |
| TPM_ECC_CURVE curveId // IN: the curveID | |
| ) | |
| { | |
| const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); | |
| return (curve != NULL) ? curve->curveData : NULL; | |
| } | |
| //***CryptEccGetOID() | |
| const BYTE * | |
| CryptEccGetOID( | |
| TPM_ECC_CURVE curveId | |
| ) | |
| { | |
| const ECC_CURVE *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; | |
| } | |
| //*** CryptEccGetParameter() | |
| // This function returns an ECC curve parameter. The parameter is | |
| // selected by a single character designator from the set of ""PNABXYH"". | |
| // Return Type: BOOL | |
| // TRUE(1) curve exists and parameter returned | |
| // FALSE(0) curve does not exist or parameter selector | |
| LIB_EXPORT BOOL | |
| CryptEccGetParameter( | |
| TPM2B_ECC_PARAMETER *out, // OUT: place to put parameter | |
| char p, // IN: the parameter selector | |
| TPM_ECC_CURVE curveId // IN: the curve id | |
| ) | |
| { | |
| const ECC_CURVE_DATA *curve = GetCurveData(curveId); | |
| bigConst parameter = NULL; | |
| if(curve != NULL) | |
| { | |
| switch(p) | |
| { | |
| case 'p': | |
| parameter = CurveGetPrime(curve); | |
| break; | |
| case 'n': | |
| parameter = CurveGetOrder(curve); | |
| break; | |
| case 'a': | |
| parameter = CurveGet_a(curve); | |
| break; | |
| case 'b': | |
| parameter = CurveGet_b(curve); | |
| break; | |
| case 'x': | |
| parameter = CurveGetGx(curve); | |
| break; | |
| case 'y': | |
| parameter = CurveGetGy(curve); | |
| break; | |
| case 'h': | |
| parameter = CurveGetCofactor(curve); | |
| break; | |
| default: | |
| FAIL(FATAL_ERROR_INTERNAL); | |
| break; | |
| } | |
| } | |
| // If not debugging and we get here with parameter still NULL, had better | |
| // not try to convert so just return FALSE instead. | |
| return (parameter != NULL) ? BnTo2B(parameter, &out->b, 0) : 0; | |
| } | |
| //*** 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; | |
| } | |
| //*** 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 ECC_CURVE *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(!CryptEccGetParameter(&n, 'n', curveID)) | |
| 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 ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); | |
| const ECC_CURVE_DATA *data; | |
| BOOL found = curve != NULL; | |
| if(found) | |
| { | |
| data = curve->curveData; | |
| parameters->curveID = curve->curveId; | |
| parameters->keySize = curve->keySizeBits; | |
| parameters->kdf = curve->kdf; | |
| parameters->sign = curve->sign; | |
| // BnTo2B(data->prime, ¶meters->p.b, 0); | |
| BnTo2B(data->prime, ¶meters->p.b, parameters->p.t.size); | |
| BnTo2B(data->a, ¶meters->a.b, 0); | |
| BnTo2B(data->b, ¶meters->b.b, 0); | |
| BnTo2B(data->base.x, ¶meters->gX.b, parameters->p.t.size); | |
| BnTo2B(data->base.y, ¶meters->gY.b, parameters->p.t.size); | |
| // BnTo2B(data->base.x, ¶meters->gX.b, 0); | |
| // BnTo2B(data->base.y, ¶meters->gY.b, 0); | |
| BnTo2B(data->order, ¶meters->n.b, 0); | |
| BnTo2B(data->h, ¶meters->h.b, 0); | |
| } | |
| return found; | |
| } | |
| //*** BnGetCurvePrime() | |
| // This function is used to get just the prime modulus associated with a curve. | |
| const bignum_t * | |
| BnGetCurvePrime( | |
| TPM_ECC_CURVE curveId | |
| ) | |
| { | |
| const ECC_CURVE_DATA *C = GetCurveData(curveId); | |
| return (C != NULL) ? CurveGetPrime(C) : NULL; | |
| } | |
| //*** BnGetCurveOrder() | |
| // This function is used to get just the curve order | |
| const bignum_t * | |
| BnGetCurveOrder( | |
| TPM_ECC_CURVE curveId | |
| ) | |
| { | |
| const ECC_CURVE_DATA *C = GetCurveData(curveId); | |
| return (C != NULL) ? CurveGetOrder(C) : NULL; | |
| } | |
| //*** BnIsOnCurve() | |
| // This function checks if a point is on the curve. | |
| BOOL | |
| BnIsOnCurve( | |
| pointConst Q, | |
| const ECC_CURVE_DATA *C | |
| ) | |
| { | |
| BN_VAR(right, (MAX_ECC_KEY_BITS * 3)); | |
| BN_VAR(left, (MAX_ECC_KEY_BITS * 2)); | |
| bigConst prime = CurveGetPrime(C); | |
| // | |
| // Show that point is on the curve y^2 = x^3 + ax + b; | |
| // Or y^2 = x(x^2 + a) + b | |
| // y^2 | |
| BnMult(left, Q->y, Q->y); | |
| BnMod(left, prime); | |
| // x^2 | |
| BnMult(right, Q->x, Q->x); | |
| // x^2 + a | |
| BnAdd(right, right, CurveGet_a(C)); | |
| // BnMod(right, CurveGetPrime(C)); | |
| // x(x^2 + a) | |
| BnMult(right, right, Q->x); | |
| // x(x^2 + a) + b | |
| BnAdd(right, right, CurveGet_b(C)); | |
| BnMod(right, prime); | |
| if(BnUnsignedCmp(left, right) == 0) | |
| return TRUE; | |
| else | |
| return FALSE; | |
| } | |
| //*** BnIsValidPrivateEcc() | |
| // Checks that 0 < 'x' < 'q' | |
| BOOL | |
| BnIsValidPrivateEcc( | |
| bigConst x, // IN: private key to check | |
| bigCurve E // IN: the curve to check | |
| ) | |
| { | |
| BOOL retVal; | |
| retVal = (!BnEqualZero(x) | |
| && (BnUnsignedCmp(x, CurveGetOrder(AccessCurveData(E))) < 0)); | |
| return retVal; | |
| } | |
| LIB_EXPORT BOOL | |
| CryptEccIsValidPrivateKey( | |
| TPM2B_ECC_PARAMETER *d, | |
| TPM_ECC_CURVE curveId | |
| ) | |
| { | |
| BN_INITIALIZED(bnD, MAX_ECC_PARAMETER_BYTES * 8, d); | |
| return !BnEqualZero(bnD) && (BnUnsignedCmp(bnD, BnGetCurveOrder(curveId)) < 0); | |
| } | |
| //*** BnPointMul() | |
| // This function does a point multiply of the form 'R' = ['d']'S' + ['u']'Q' where the | |
| // parameters are bigNum 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 | |
| BnPointMult( | |
| bigPoint R, // OUT: computed point | |
| pointConst S, // IN: optional point to multiply by 'd' | |
| bigConst d, // IN: scalar for [d]S or [d]G | |
| pointConst Q, // IN: optional second point | |
| bigConst u, // IN: optional second scalar | |
| bigCurve E // IN: curve parameters | |
| ) | |
| { | |
| BOOL OK; | |
| // | |
| 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) || BnIsOnCurve(S, AccessCurveData(E)); | |
| OK = OK && ((Q == NULL) || BnIsOnCurve(Q, AccessCurveData(E))); | |
| if(!OK) | |
| return TPM_RC_ECC_POINT; | |
| if((d != NULL) && (S == NULL)) | |
| S = CurveGetG(AccessCurveData(E)); | |
| // If only one scalar, don't need Shamir's trick | |
| if((d == NULL) || (u == NULL)) | |
| { | |
| if(d == NULL) | |
| OK = BnEccModMult(R, Q, u, E); | |
| else | |
| OK = BnEccModMult(R, S, d, E); | |
| } | |
| else | |
| { | |
| OK = BnEccModMult2(R, S, d, Q, u, E); | |
| } | |
| return (OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT); | |
| } | |
| //***BnEccGetPrivate() | |
| // 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 | |
| BnEccGetPrivate( | |
| bigNum dOut, // OUT: the qualified random value | |
| const ECC_CURVE_DATA *C, // IN: curve for which the private key | |
| // needs to be appropriate | |
| RAND_STATE *rand // IN: state for DRBG | |
| ) | |
| { | |
| bigConst order = CurveGetOrder(C); | |
| BOOL OK; | |
| UINT32 orderBits = BnSizeInBits(order); | |
| UINT32 orderBytes = BITS_TO_BYTES(orderBits); | |
| BN_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64); | |
| BN_VAR(nMinus1, MAX_ECC_KEY_BITS); | |
| // | |
| OK = BnGetRandomBits(bnExtraBits, (orderBytes * 8) + 64, rand); | |
| OK = OK && BnSubWord(nMinus1, order, 1); | |
| OK = OK && BnMod(bnExtraBits, nMinus1); | |
| OK = OK && BnAddWord(dOut, bnExtraBits, 1); | |
| return OK && !g_inFailureMode; | |
| } | |
| //*** BnEccGenerateKeyPair() | |
| // This function gets a private scalar from the source of random bits and does | |
| // the point multiply to get the public key. | |
| BOOL | |
| BnEccGenerateKeyPair( | |
| bigNum bnD, // OUT: private scalar | |
| bn_point_t *ecQ, // OUT: public point | |
| bigCurve E, // IN: curve for the point | |
| RAND_STATE *rand // IN: DRBG state to use | |
| ) | |
| { | |
| BOOL OK = FALSE; | |
| // Get a private scalar | |
| OK = BnEccGetPrivate(bnD, AccessCurveData(E), rand); | |
| // Do a point multiply | |
| OK = OK && BnEccModMult(ecQ, NULL, bnD, E); | |
| if(!OK) | |
| BnSetWord(ecQ->z, 0); | |
| else | |
| BnSetWord(ecQ->z, 1); | |
| 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 | |
| ) | |
| { | |
| CURVE_INITIALIZED(E, curveId); | |
| POINT(ecQ); | |
| ECC_NUM(bnD); | |
| BOOL OK; | |
| if(E == NULL) | |
| return TPM_RC_CURVE; | |
| TEST(TPM_ALG_ECDH); | |
| OK = BnEccGenerateKeyPair(bnD, ecQ, E, NULL); | |
| if(OK) | |
| { | |
| BnPointTo2B(Qout, ecQ, E); | |
| BnTo2B(bnD, &dOut->b, Qout->x.t.size); | |
| } | |
| else | |
| { | |
| Qout->x.t.size = Qout->y.t.size = dOut->t.size = 0; | |
| } | |
| 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 | |
| ) | |
| { | |
| CURVE_INITIALIZED(E, curveId); | |
| POINT_INITIALIZED(ecP, Pin); | |
| ECC_INITIALIZED(bnD, dIn); // If dIn is null, then bnD is null | |
| ECC_INITIALIZED(bnU, uIn); | |
| POINT_INITIALIZED(ecQ, Qin); | |
| POINT(ecR); | |
| TPM_RC retVal; | |
| // | |
| retVal = BnPointMult(ecR, ecP, bnD, ecQ, bnU, E); | |
| if(retVal == TPM_RC_SUCCESS) | |
| BnPointTo2B(Rout, ecR, E); | |
| else | |
| ClearPoint2B(Rout); | |
| 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. | |
| ) | |
| { | |
| const ECC_CURVE_DATA *C = GetCurveData(curveId); | |
| POINT_INITIALIZED(ecQ, Qin); | |
| BOOL OK; | |
| // | |
| pAssert(Qin != NULL); | |
| OK = (C != NULL && (BnIsOnCurve(ecQ, C))); | |
| 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 | |
| ) | |
| { | |
| CURVE_INITIALIZED(E, publicArea->parameters.eccDetail.curveID); | |
| ECC_NUM(bnD); | |
| POINT(ecQ); | |
| BOOL OK; | |
| TPM_RC retVal; | |
| // | |
| TEST(TPM_ALG_ECDSA); // ECDSA is used to verify each key | |
| // Validate parameters | |
| if(E == NULL) | |
| ERROR_RETURN(TPM_RC_CURVE); | |
| publicArea->unique.ecc.x.t.size = 0; | |
| publicArea->unique.ecc.y.t.size = 0; | |
| sensitive->sensitive.ecc.t.size = 0; | |
| OK = BnEccGenerateKeyPair(bnD, ecQ, E, rand); | |
| if(OK) | |
| { | |
| BnPointTo2B(&publicArea->unique.ecc, ecQ, E); | |
| BnTo2B(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)) | |
| { | |
| ECC_NUM(bnT); | |
| ECC_NUM(bnS); | |
| TPM2B_DIGEST digest; | |
| // | |
| 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; | |
| BnSignEcdsa(bnT, bnS, E, bnD, &digest, NULL); | |
| // and make sure that we can validate the signature | |
| OK = BnValidateSignatureEcdsa(bnT, bnS, E, ecQ, &digest) == TPM_RC_SUCCESS; | |
| } | |
| #endif | |
| retVal = (OK) ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT; | |
| Exit: | |
| CURVE_FREE(E); | |
| return retVal; | |
| } | |
| #endif // ALG_ECC |