in TPMCmd/tpm/src/crypt/CryptRsa.c [1303:1487]
int GetCachedRsaKey(TPMT_PUBLIC *publicArea, TPMT_SENSITIVE *sensitive,
RAND_STATE *rand);
#define GET_CACHED_KEY(publicArea, sensitive, rand) \
(s_rsaKeyCacheEnabled && GetCachedRsaKey(publicArea, sensitive, rand))
#else
#define GET_CACHED_KEY(key, rand)
#endif
//*** CryptRsaGenerateKey()
// Generate an RSA key from a provided seed
/*(See part 1 specification)
// The formulation is:
// KDFa(hash, seed, label, Name, Counter, bits)
// Where:
// hash the nameAlg from the public template
// seed a seed (will be a primary seed for a primary key)
// label a distinguishing label including vendor ID and
// vendor-assigned part number for the TPM.
// Name the nameAlg from the template and the hash of the template
// using nameAlg.
// Counter a 32-bit integer that is incremented each time the KDF is
// called in order to produce a specific key. This value
// can be a 32-bit integer in host format and does not need
// to be put in canonical form.
// bits the number of bits needed for the key.
// The following process is implemented to find a RSA key pair:
// 1. pick a random number with enough bits from KDFa as a prime candidate
// 2. set the first two significant bits and the least significant bit of the
// prime candidate
// 3. check if the number is a prime. if not, pick another random number
// 4. Make sure the difference between the two primes are more than 2^104.
// Otherwise, restart the process for the second prime
// 5. If the counter has reached its maximum but we still can not find a valid
// RSA key pair, return an internal error. This is an artificial bound.
// Other implementation may choose a smaller number to indicate how many
// times they are willing to try.
*/
// Return Type: TPM_RC
// TPM_RC_CANCELED operation was canceled
// TPM_RC_RANGE public exponent is not supported
// TPM_RC_VALUE could not find a prime using the provided parameters
LIB_EXPORT TPM_RC
CryptRsaGenerateKey(
TPMT_PUBLIC *publicArea,
TPMT_SENSITIVE *sensitive,
RAND_STATE *rand // IN: if not NULL, the deterministic
// RNG state
)
{
UINT32 i;
BN_RSA(bnD);
BN_RSA(bnN);
BN_WORD(bnPubExp);
UINT32 e = publicArea->parameters.rsaDetail.exponent;
int keySizeInBits;
TPM_RC retVal = TPM_RC_NO_RESULT;
NEW_PRIVATE_EXPONENT(Z);
//
// Need to make sure that the caller did not specify an exponent that is
// not supported
e = publicArea->parameters.rsaDetail.exponent;
if(e == 0)
e = RSA_DEFAULT_PUBLIC_EXPONENT;
else
{
if(e < 65537)
ERROR_RETURN(TPM_RC_RANGE);
// Check that e is prime
if(!IsPrimeInt(e))
ERROR_RETURN(TPM_RC_RANGE);
}
BnSetWord(bnPubExp, e);
// check for supported key size.
keySizeInBits = publicArea->parameters.rsaDetail.keyBits;
if(((keySizeInBits % 1024) != 0)
|| (keySizeInBits > MAX_RSA_KEY_BITS) // this might be redundant, but...
|| (keySizeInBits == 0))
ERROR_RETURN(TPM_RC_VALUE);
// Set the prime size for instrumentation purposes
INSTRUMENT_SET(PrimeIndex, PRIME_INDEX(keySizeInBits / 2));
#if SIMULATION && USE_RSA_KEY_CACHE
if(GET_CACHED_KEY(publicArea, sensitive, rand))
return TPM_RC_SUCCESS;
#endif
// Make sure that key generation has been tested
TEST(TPM_ALG_NULL);
// The prime is computed in P. When a new prime is found, Q is checked to
// see if it is zero. If so, P is copied to Q and a new P is found.
// When both P and Q are non-zero, the modulus and
// private exponent are computed and a trial encryption/decryption is
// performed. If the encrypt/decrypt fails, assume that at least one of the
// primes is composite. Since we don't know which one, set Q to zero and start
// over and find a new pair of primes.
for(i = 1; (retVal == TPM_RC_NO_RESULT) && (i != 100); i++)
{
if(_plat__IsCanceled())
ERROR_RETURN(TPM_RC_CANCELED);
if(BnGeneratePrimeForRSA(Z->P, keySizeInBits / 2, e, rand) == TPM_RC_FAILURE)
{
retVal = TPM_RC_FAILURE;
goto Exit;
}
INSTRUMENT_INC(PrimeCounts[PrimeIndex]);
// If this is the second prime, make sure that it differs from the
// first prime by at least 2^100
if(BnEqualZero(Z->Q))
{
// copy p to q and compute another prime in p
BnCopy(Z->Q, Z->P);
continue;
}
// Make sure that the difference is at least 100 bits. Need to do it this
// way because the big numbers are only positive values
if(BnUnsignedCmp(Z->P, Z->Q) < 0)
BnSub(bnD, Z->Q, Z->P);
else
BnSub(bnD, Z->P, Z->Q);
if(BnMsb(bnD) < 100)
continue;
//Form the public modulus and set the unique value
BnMult(bnN, Z->P, Z->Q);
BnTo2B(bnN, &publicArea->unique.rsa.b,
(NUMBYTES)BITS_TO_BYTES(keySizeInBits));
// Make sure everything came out right. The MSb of the values must be one
if(((publicArea->unique.rsa.t.buffer[0] & 0x80) == 0)
|| (publicArea->unique.rsa.t.size
!= (NUMBYTES)BITS_TO_BYTES(keySizeInBits)))
FAIL(FATAL_ERROR_INTERNAL);
// Make sure that we can form the private exponent values
if(ComputePrivateExponent(bnPubExp, Z) != TRUE)
{
// If ComputePrivateExponent could not find an inverse for
// Q, then copy P and recompute P. This might
// cause both to be recomputed if P is also zero
if(BnEqualZero(Z->Q))
BnCopy(Z->Q, Z->P);
continue;
}
// Pack the private exponent into the sensitive area
PackExponent(&sensitive->sensitive.rsa, Z);
// Make sure everything came out right. The MSb of the values must be one
if(((publicArea->unique.rsa.t.buffer[0] & 0x80) == 0)
|| ((sensitive->sensitive.rsa.t.buffer[0] & 0x80) == 0))
FAIL(FATAL_ERROR_INTERNAL);
retVal = TPM_RC_SUCCESS;
// Do a trial encryption decryption if this is a signing key
if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign))
{
BN_RSA(temp1);
BN_RSA(temp2);
BnGenerateRandomInRange(temp1, bnN, rand);
// Encrypt with public exponent...
BnModExp(temp2, temp1, bnPubExp, bnN);
// ... then decrypt with private exponent
RsaPrivateKeyOp(temp2, Z);
// If the starting and ending values are not the same,
// start over )-;
if(BnUnsignedCmp(temp2, temp1) != 0)
{
BnSetWord(Z->Q, 0);
retVal = TPM_RC_NO_RESULT;
}
}
}
Exit:
return retVal;
}