int GetCachedRsaKey()

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;
}