tpm2: EcSM2: Enforce that the random bnK has no leading zeros

Make sure that the value of bnK is not short so that the subsequent
BnEccModMult() runs in constant time. We take the same approach as with
the modifications to BnEccGenerateKeyPair() where we request bnK to have
all bytes set (no leading zeros that will be cut away) in case the order
of the curve is as byte boundary. In the other cases we add the order
to bnK, which creates bnK1, which we then use for BnEccModMult's scalar
parameter.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Suggested-by: Charanjit Jutla <csjutla@us.ibm.com>
Reviewed-by: Charanjit Jutla <csjutla@us.ibm.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2020-10-28 09:49:20 -04:00 committed by Stefan Berger
parent 5c224b8d98
commit 089485035f
3 changed files with 120 additions and 9 deletions

View File

@ -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

View File

@ -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

View File

@ -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);