/* 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. */ //** Introduction // The functions in this file provide the low-level interface between the TPM code // and the big number and elliptic curve math routines in OpenSSL. // // Most math on big numbers require a context. The context contains the memory in // which OpenSSL creates and manages the big number values. When a OpenSSL math // function will be called that modifies a BIGNUM value, that value must be created in // an OpenSSL context. The first line of code in such a function must be: // OSSL_ENTER(); and the last operation before returning must be OSSL_LEAVE(). // OpenSSL variables can then be created with BnNewVariable(). Constant values to be // used by OpenSSL are created from the bigNum values passed to the functions in this // file. Space for the BIGNUM control block is allocated in the stack of the // function and then it is initialized by calling BigInitialized(). That function // sets up the values in the BIGNUM structure and sets the data pointer to point to // the data in the bignum_t. This is only used when the value is known to be a // constant in the called function. // // Because the allocations of constants is on the local stack and the // OSSL_ENTER()/OSSL_LEAVE() pair flushes everything created in OpenSSL memory, there // should be no chance of a memory leak. //** Includes and Defines #include "Tpm.h" #ifdef MATH_LIB_OSSL #include "TpmToOsslMath_fp.h" //** Functions //*** OsslToTpmBn() // This function converts an OpenSSL BIGNUM to a TPM bignum. In this implementation // it is assumed that OpenSSL uses a different control structure but the same data // layout -- an array of native-endian words in little-endian order. // Return Type: BOOL // TRUE(1) success // FALSE(0) failure because value will not fit or OpenSSL variable doesn't // exist BOOL OsslToTpmBn( bigNum bn, BIGNUM *osslBn ) { VERIFY(osslBn != NULL); // If the bn is NULL, it means that an output value pointer was NULL meaning that // the results is simply to be discarded. if(bn != NULL) { int i; // VERIFY((unsigned)osslBn->width <= BnGetAllocated(bn)); for(i = 0; i < osslBn->width; i++) bn->d[i] = osslBn->d[i]; BnSetTop(bn, osslBn->width); } return TRUE; Error: return FALSE; } //*** BigInitialized() // This function initializes an OSSL BIGNUM from a TPM bigConst. Do not use this for // values that are passed to OpenSLL when they are not declared as const in the // function prototype. Instead, use BnNewVariable(). BIGNUM * BigInitialized( BIGNUM *toInit, bigConst initializer ) { if(initializer == NULL) FAIL(FATAL_ERROR_PARAMETER); if(toInit == NULL || initializer == NULL) return NULL; toInit->d = (BN_ULONG *)&initializer->d[0]; toInit->dmax = (int)initializer->allocated; toInit->width = (int)initializer->size; toInit->neg = 0; toInit->flags = 0; return toInit; } #ifndef OSSL_DEBUG # define BIGNUM_PRINT(label, bn, eol) # define DEBUG_PRINT(x) #else # define DEBUG_PRINT(x) printf("%s", x) # define BIGNUM_PRINT(label, bn, eol) BIGNUM_print((label), (bn), (eol)) //*** BIGNUM_print() static void BIGNUM_print( const char *label, const BIGNUM *a, BOOL eol ) { BN_ULONG *d; int i; int notZero = FALSE; if(label != NULL) printf("%s", label); if(a == NULL) { printf("NULL"); goto done; } if (a->neg) printf("-"); for(i = a->top, d = &a->d[i - 1]; i > 0; i--) { int j; BN_ULONG l = *d--; for(j = BN_BITS2 - 8; j >= 0; j -= 8) { BYTE b = (BYTE)((l >> j) & 0xFF); notZero = notZero || (b != 0); if(notZero) printf("%02x", b); } if(!notZero) printf("0"); } done: if(eol) printf("\n"); return; } #endif //*** BnNewVariable() // This function allocates a new variable in the provided context. If the context // does not exist or the allocation fails, it is a catastrophic failure. static BIGNUM * BnNewVariable( BN_CTX *CTX ) { BIGNUM *new; // // This check is intended to protect against calling this function without // having initialized the CTX. if((CTX == NULL) || ((new = BN_CTX_get(CTX)) == NULL)) FAIL(FATAL_ERROR_ALLOCATION); return new; } #if LIBRARY_COMPATIBILITY_CHECK //*** MathLibraryCompatibilityCheck() BOOL MathLibraryCompatibilityCheck( void ) { OSSL_ENTER(); BIGNUM *osslTemp = BnNewVariable(CTX); crypt_uword_t i; BYTE test[] = {0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00}; BN_VAR(tpmTemp, sizeof(test) * 8); // allocate some space for a test value // // Convert the test data to a bigNum BnFromBytes(tpmTemp, test, sizeof(test)); // Convert the test data to an OpenSSL BIGNUM BN_bin2bn(test, sizeof(test), osslTemp); // Make sure the values are consistent VERIFY(osslTemp->width == (int)tpmTemp->size); for(i = 0; i < tpmTemp->size; i++) VERIFY(osslTemp->d[i] == tpmTemp->d[i]); OSSL_LEAVE(); return 1; Error: return 0; } #endif //*** BnModMult() // This function does a modular multiply. It first does a multiply and then a divide // and returns the remainder of the divide. // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation LIB_EXPORT BOOL BnModMult( bigNum result, bigConst op1, bigConst op2, bigConst modulus ) { OSSL_ENTER(); BOOL OK = TRUE; BIGNUM *bnResult = BN_NEW(); BIGNUM *bnTemp = BN_NEW(); BIG_INITIALIZED(bnOp1, op1); BIG_INITIALIZED(bnOp2, op2); BIG_INITIALIZED(bnMod, modulus); // VERIFY(BN_mul(bnTemp, bnOp1, bnOp2, CTX)); VERIFY(BN_div(NULL, bnResult, bnTemp, bnMod, CTX)); VERIFY(OsslToTpmBn(result, bnResult)); goto Exit; Error: OK = FALSE; Exit: OSSL_LEAVE(); return OK; } //*** BnMult() // Multiplies two numbers // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation LIB_EXPORT BOOL BnMult( bigNum result, bigConst multiplicand, bigConst multiplier ) { OSSL_ENTER(); BIGNUM *bnTemp = BN_NEW(); BOOL OK = TRUE; BIG_INITIALIZED(bnA, multiplicand); BIG_INITIALIZED(bnB, multiplier); // VERIFY(BN_mul(bnTemp, bnA, bnB, CTX)); VERIFY(OsslToTpmBn(result, bnTemp)); goto Exit; Error: OK = FALSE; Exit: OSSL_LEAVE(); return OK; } //*** BnDiv() // This function divides two bigNum values. The function returns FALSE if // there is an error in the operation. // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation LIB_EXPORT BOOL BnDiv( bigNum quotient, bigNum remainder, bigConst dividend, bigConst divisor ) { OSSL_ENTER(); BIGNUM *bnQ = BN_NEW(); BIGNUM *bnR = BN_NEW(); BOOL OK = TRUE; BIG_INITIALIZED(bnDend, dividend); BIG_INITIALIZED(bnSor, divisor); // if(BnEqualZero(divisor)) FAIL(FATAL_ERROR_DIVIDE_ZERO); VERIFY(BN_div(bnQ, bnR, bnDend, bnSor, CTX)); VERIFY(OsslToTpmBn(quotient, bnQ)); VERIFY(OsslToTpmBn(remainder, bnR)); DEBUG_PRINT("In BnDiv:\n"); BIGNUM_PRINT(" bnDividend: ", bnDend, TRUE); BIGNUM_PRINT(" bnDivisor: ", bnSor, TRUE); BIGNUM_PRINT(" bnQuotient: ", bnQ, TRUE); BIGNUM_PRINT(" bnRemainder: ", bnR, TRUE); goto Exit; Error: OK = FALSE; Exit: OSSL_LEAVE(); return OK; } #if ALG_RSA //*** BnGcd() // Get the greatest common divisor of two numbers // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation LIB_EXPORT BOOL BnGcd( bigNum gcd, // OUT: the common divisor bigConst number1, // IN: bigConst number2 // IN: ) { OSSL_ENTER(); BIGNUM *bnGcd = BN_NEW(); BOOL OK = TRUE; BIG_INITIALIZED(bn1, number1); BIG_INITIALIZED(bn2, number2); // VERIFY(BN_gcd(bnGcd, bn1, bn2, CTX)); VERIFY(OsslToTpmBn(gcd, bnGcd)); goto Exit; Error: OK = FALSE; Exit: OSSL_LEAVE(); return OK; } //***BnModExp() // Do modular exponentiation using bigNum values. The conversion from a bignum_t to // a bigNum is trivial as they are based on the same structure // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation LIB_EXPORT BOOL BnModExp( bigNum result, // OUT: the result bigConst number, // IN: number to exponentiate bigConst exponent, // IN: bigConst modulus // IN: ) { OSSL_ENTER(); BIGNUM *bnResult = BN_NEW(); BOOL OK = TRUE; BIG_INITIALIZED(bnN, number); BIG_INITIALIZED(bnE, exponent); BIG_INITIALIZED(bnM, modulus); // VERIFY(BN_mod_exp(bnResult, bnN, bnE, bnM, CTX)); VERIFY(OsslToTpmBn(result, bnResult)); goto Exit; Error: OK = FALSE; Exit: OSSL_LEAVE(); return OK; } //*** BnModInverse() // Modular multiplicative inverse // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation LIB_EXPORT BOOL BnModInverse( bigNum result, bigConst number, bigConst modulus ) { OSSL_ENTER(); BIGNUM *bnResult = BN_NEW(); BOOL OK = TRUE; BIG_INITIALIZED(bnN, number); BIG_INITIALIZED(bnM, modulus); // VERIFY(BN_mod_inverse(bnResult, bnN, bnM, CTX) != NULL); VERIFY(OsslToTpmBn(result, bnResult)); goto Exit; Error: OK = FALSE; Exit: OSSL_LEAVE(); return OK; } #endif // ALG_RSA #if ALG_ECC //*** PointFromOssl() // Function to copy the point result from an OSSL function to a bigNum // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation static BOOL PointFromOssl( bigPoint pOut, // OUT: resulting point EC_POINT *pIn, // IN: the point to return bigCurve E // IN: the curve ) { BIGNUM *x = NULL; BIGNUM *y = NULL; BOOL OK; BN_CTX_start(E->CTX); // x = BN_CTX_get(E->CTX); y = BN_CTX_get(E->CTX); if(y == NULL) FAIL(FATAL_ERROR_ALLOCATION); // If this returns false, then the point is at infinity OK = EC_POINT_get_affine_coordinates_GFp(E->G, pIn, x, y, E->CTX); if(OK) { OsslToTpmBn(pOut->x, x); OsslToTpmBn(pOut->y, y); BnSetWord(pOut->z, 1); } else BnSetWord(pOut->z, 0); BN_CTX_end(E->CTX); return OK; } //*** EcPointInitialized() // Allocate and initialize a point. static EC_POINT * EcPointInitialized( pointConst initializer, bigCurve E ) { EC_POINT *P = NULL; if(initializer != NULL) { BIG_INITIALIZED(bnX, initializer->x); BIG_INITIALIZED(bnY, initializer->y); if(E == NULL) FAIL(FATAL_ERROR_ALLOCATION); P = EC_POINT_new(E->G); if(!EC_POINT_set_affine_coordinates_GFp(E->G, P, bnX, bnY, E->CTX)) P = NULL; } return P; } //*** BnCurveInitialize() // This function initializes the OpenSSL curve information structure. This // structure points to the TPM-defined values for the curve, to the context for the // number values in the frame, and to the OpenSSL-defined group values. // Return Type: bigCurve * // NULL the TPM_ECC_CURVE is not valid or there was a problem in // in initializing the curve data // non-NULL points to 'E' LIB_EXPORT bigCurve BnCurveInitialize( bigCurve E, // IN: curve structure to initialize TPM_ECC_CURVE curveId // IN: curve identifier ) { const ECC_CURVE_DATA *C = GetCurveData(curveId); if(C == NULL) E = NULL; if(E != NULL) { // This creates the OpenSSL memory context that stays in effect as long as the // curve (E) is defined. OSSL_ENTER(); // if the allocation fails, the TPM fails EC_POINT *P = NULL; BIG_INITIALIZED(bnP, C->prime); BIG_INITIALIZED(bnA, C->a); BIG_INITIALIZED(bnB, C->b); BIG_INITIALIZED(bnX, C->base.x); BIG_INITIALIZED(bnY, C->base.y); BIG_INITIALIZED(bnN, C->order); BIG_INITIALIZED(bnH, C->h); // E->C = C; E->CTX = CTX; // initialize EC group, associate a generator point and initialize the point // from the parameter data // Create a group structure E->G = EC_GROUP_new_curve_GFp(bnP, bnA, bnB, CTX); VERIFY(E->G != NULL); // Allocate a point in the group that will be used in setting the // generator. This is not needed after the generator is set. P = EC_POINT_new(E->G); VERIFY(P != NULL); // Need to use this in case Montgomery method is being used VERIFY(EC_POINT_set_affine_coordinates_GFp(E->G, P, bnX, bnY, CTX)); // Now set the generator VERIFY(EC_GROUP_set_generator(E->G, P, bnN, bnH)); EC_POINT_free(P); goto Exit; Error: EC_POINT_free(P); BnCurveFree(E); E = NULL; } Exit: return E; } //*** BnCurveFree() // This function will free the allocated components of the curve and end the // frame in which the curve data exists LIB_EXPORT void BnCurveFree( bigCurve E ) { if(E) { EC_GROUP_free(E->G); OsslContextLeave(E->CTX); } } //*** BnEccModMult() // This function does a point multiply of the form R = [d]S // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation; treat as result being point at infinity LIB_EXPORT BOOL BnEccModMult( bigPoint R, // OUT: computed point pointConst S, // IN: point to multiply by 'd' (optional) bigConst d, // IN: scalar for [d]S bigCurve E ) { EC_POINT *pR = EC_POINT_new(E->G); EC_POINT *pS = EcPointInitialized(S, E); BIG_INITIALIZED(bnD, d); if(S == NULL) EC_POINT_mul(E->G, pR, bnD, NULL, NULL, E->CTX); else EC_POINT_mul(E->G, pR, NULL, pS, bnD, E->CTX); PointFromOssl(R, pR, E); EC_POINT_free(pR); EC_POINT_free(pS); return !BnEqualZero(R->z); } //*** BnEccModMult2() // This function does a point multiply of the form R = [d]G + [u]Q // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation; treat as result being point at infinity LIB_EXPORT BOOL BnEccModMult2( bigPoint R, // OUT: computed point pointConst S, // IN: optional point bigConst d, // IN: scalar for [d]S or [d]G pointConst Q, // IN: second point bigConst u, // IN: second scalar bigCurve E // IN: curve ) { EC_POINT *pR = EC_POINT_new(E->G); BIG_INITIALIZED(bnD, d); EC_POINT *pQ = EcPointInitialized(Q, E); BIG_INITIALIZED(bnU, u); if(S == NULL || S == (pointConst)&(AccessCurveData(E)->base)) EC_POINT_mul(E->G, pR, bnD, pQ, bnU, E->CTX); else { return FALSE; } PointFromOssl(R, pR, E); EC_POINT_free(pR); EC_POINT_free(pQ); return !BnEqualZero(R->z); } //** BnEccAdd() // This function does addition of two points. // Return Type: BOOL // TRUE(1) success // FALSE(0) failure in operation; treat as result being point at infinity LIB_EXPORT BOOL BnEccAdd( bigPoint R, // OUT: computed point pointConst S, // IN: point to multiply by 'd' pointConst Q, // IN: second point bigCurve E // IN: curve ) { EC_POINT *pR = EC_POINT_new(E->G); EC_POINT *pS = EcPointInitialized(S, E); EC_POINT *pQ = EcPointInitialized(Q, E); // EC_POINT_add(E->G, pR, pS, pQ, E->CTX); PointFromOssl(R, pR, E); EC_POINT_free(pR); EC_POINT_free(pS); EC_POINT_free(pQ); return !BnEqualZero(R->z); } #endif // ALG_ECC #endif // MATHLIB OSSL