diff --git a/src/tpm2/BnMath.c b/src/tpm2/BnMath.c index db685bf0..f5c8db53 100644 --- a/src/tpm2/BnMath.c +++ b/src/tpm2/BnMath.c @@ -552,3 +552,81 @@ BnGenerateRandomInRange( } return TRUE; } + +// libtpms added begin + +// This version of BnSizeInBits skips any leading zero bytes in bigConst +// and thus calculates the bits that OpenSSL will work with after truncating +// the leading zeros +static LIB_EXPORT unsigned +BnSizeInBitsSkipLeadingZeros( + bigConst n + ) +{ + int firstByte; + unsigned bitSize = BnSizeInBits(n); + crypt_uword_t i; + + if (bitSize <= 8) + return bitSize; + + // search for the first limb that is non-zero + for (i = 0; i < n->size; i++) { + if (n->d[i] != 0) + break; + } + if (i >= n->size) + return 0; // should never happen + + // get the first byte in this limb that is non-zero + firstByte = (RADIX_BITS - 1 - Msb(n->d[i])) >> 3; + + return bitSize - i * sizeof(n->d[0]) - (firstByte << 3); +} + + +/* This is a version of BnGenerateRandomInRange that ensures that the upper most + byte is non-zero, so that the number will not be shortened and subsequent operations + will not have a timing-sidechannel + */ +LIB_EXPORT BOOL +BnGenerateRandomInRangeAllBytes( + bigNum dest, + bigConst limit, + RAND_STATE *rand + ) +{ + BOOL OK; + int repeats = 0; + int maxRepeats; + unsigned requestedBits; + unsigned requestedBytes; + unsigned numBytes; + + if (rand) + return BnGenerateRandomInRange(dest, limit, rand); + + // a 'limit' like 'BN_P638_n' has leading zeros and we only need 73 bytes not 80 + requestedBits = BnSizeInBitsSkipLeadingZeros(limit); + requestedBytes = BITS_TO_BYTES(requestedBits); + maxRepeats = 8; + if (requestedBits & 7) + maxRepeats += (9 - (requestedBits & 7)); + + while (true) { + OK = BnGenerateRandomInRange(dest, limit, rand); + if (!OK) + break; + if (repeats < maxRepeats) { + numBytes = BITS_TO_BYTES(BnSizeInBitsSkipLeadingZeros(dest)); + if (numBytes < requestedBytes) { + repeats++; + continue; + } + } + break; + } + + return OK; +} +// libtpms added end diff --git a/src/tpm2/crypto/openssl/BnMath_fp.h b/src/tpm2/crypto/openssl/BnMath_fp.h index d42a2f6d..62ba7b2d 100644 --- a/src/tpm2/crypto/openssl/BnMath_fp.h +++ b/src/tpm2/crypto/openssl/BnMath_fp.h @@ -151,6 +151,13 @@ BnGenerateRandomInRange( bigConst limit, RAND_STATE *rand ); - +// libtpms added begin +LIB_EXPORT BOOL +BnGenerateRandomInRangeAllBytes( + bigNum dest, + bigConst limit, + RAND_STATE *rand + ); +// libtpms added end #endif diff --git a/src/tpm2/crypto/openssl/CryptEccSignature.c b/src/tpm2/crypto/openssl/CryptEccSignature.c index 3b8853d8..94e33c01 100644 --- a/src/tpm2/crypto/openssl/CryptEccSignature.c +++ b/src/tpm2/crypto/openssl/CryptEccSignature.c @@ -472,6 +472,12 @@ BnSignEcSm2( POINT(Q1); bigConst order = (E != NULL) ? CurveGetOrder(AccessCurveData(E)) : NULL; +// libtpms added begin + UINT32 orderBits = BnSizeInBits(order); + BOOL atByteBoundary = (orderBits & 7) == 0; + ECC_NUM(bnK1); +// libtpms added end + // #ifdef _SM2_SIGN_DEBUG BnFromHex(bnE, "B524F552CD82B8B028476E005C377FB1" @@ -484,16 +490,36 @@ BnSignEcSm2( loop: { // Get a random number 0 < k < n - BnGenerateRandomInRange(bnK, order, rand); + // libtpms modified begin + // + // We take a dual approach here. One for curves whose order is not at + // the byte boundary, e.g. NIST P521, we get a random number bnK and add + // the order to that number to have bnK1. This will not spill over into + // a new byte and we can then use bnK1 to do the do the BnEccModMult + // with a constant number of bytes. For curves whose order is at the + // byte boundary we require that the random number bnK comes back with + // a requested number of bytes. + if (!atByteBoundary) { + BnGenerateRandomInRange(bnK, order, rand); + BnAdd(bnK1, bnK, order); #ifdef _SM2_SIGN_DEBUG - BnFromHex(bnK, "6CB28D99385C175C94F94E934817663F" - "C176D925DD72B727260DBAAE1FB2F96F"); + BnFromHex(bnK1, "6CB28D99385C175C94F94E934817663F" + "C176D925DD72B727260DBAAE1FB2F96F"); #endif - // A4: Figure out the point of elliptic curve (x1, y1)=[k]G, and according - // to details specified in 4.2.7 in Part 1 of this document, transform the - // data type of x1 into an integer; - if(!BnEccModMult(Q1, NULL, bnK, E)) - goto loop; + // A4: Figure out the point of elliptic curve (x1, y1)=[k]G, and according + // to details specified in 4.2.7 in Part 1 of this document, transform the + // data type of x1 into an integer; + if(!BnEccModMult(Q1, NULL, bnK1, E)) + goto loop; + } else { + BnGenerateRandomInRangeAllBytes(bnK, order, rand); +#ifdef _SM2_SIGN_DEBUG + BnFromHex(bnK, "6CB28D99385C175C94F94E934817663F" + "C176D925DD72B727260DBAAE1FB2F96F"); +#endif + if(!BnEccModMult(Q1, NULL, bnK, E)) + goto loop; + } // libtpms modified end // A5: Figure out r = (e + x1) mod n, BnAdd(bnR, bnE, Q1->x); BnMod(bnR, order);