]> git.proxmox.com Git - libtpms.git/blobdiff - src/tpm2/crypto/openssl/CryptRsa.c
tpm2: Only call EVP_PKEY_CTX_set0_rsa_oaep_label when label != NULL (OSSL 3)
[libtpms.git] / src / tpm2 / crypto / openssl / CryptRsa.c
index 23a449ba4c9ca399e313116aca89b84ad573c886..4ed04384feb0f69c0d9affec47266946a0dc4336 100644 (file)
@@ -3,7 +3,7 @@
 /*             Implementation of cryptographic primitives for RSA              */
 /*                          Written by Ken Goldman                             */
 /*                    IBM Thomas J. Watson Research Center                     */
-/*            $Id: CryptRsa.c 1262 2018-07-11 21:03:43Z kgoldman $             */
+/*            $Id: CryptRsa.c 1658 2021-01-22 23:14:01Z kgoldman $             */
 /*                                                                             */
 /*  Licenses and Notices                                                       */
 /*                                                                             */
 /*    arising in any way out of use or reliance upon this specification or any         */
 /*    information herein.                                                      */
 /*                                                                             */
-/*  (c) Copyright IBM Corp. and others, 2016 - 2018                            */
+/*  (c) Copyright IBM Corp. and others, 2016 - 2021                            */
 /*                                                                             */
 /********************************************************************************/
 
-/* 10.2.19 CryptRsa.c */
-/* 10.2.19.1 Introduction */
+/* 10.2.17 CryptRsa.c */
+/* 10.2.17.1 Introduction */
 /* This file contains implementation of cryptographic primitives for RSA. Vendors may replace the
    implementation in this file with their own library functions. */
-/* 10.2.19.2 Includes */
+/* 10.2.17.2 Includes */
 /* Need this define to get the private defines for this function */
 #define CRYPT_RSA_C
 #include "Tpm.h"
+#include "Helpers_fp.h"  // libtpms added
+
+#include <openssl/rsa.h> // libtpms added
+
 #if ALG_RSA
-/* 10.2.19.3 Obligatory Initialization Functions */
-/* 10.2.19.3.1 CryptRsaInit() */
+/* 10.2.17.3 Obligatory Initialization Functions */
+/* 10.2.17.3.1 CryptRsaInit() */
 /* Function called at _TPM_Init(). */
 BOOL
 CryptRsaInit(
@@ -78,7 +82,7 @@ CryptRsaInit(
 {
     return TRUE;
 }
-/* 10.2.19.3.2 CryptRsaStartup() */
+/* 10.2.17.3.2 CryptRsaStartup() */
 /* Function called at TPM2_Startup() */
 BOOL
 CryptRsaStartup(
@@ -87,7 +91,7 @@ CryptRsaStartup(
 {
     return TRUE;
 }
-/* 10.2.19.4 Internal Functions */
+/* 10.2.17.4 Internal Functions */
 void
 RsaInitializeExponent(
                      privateExponent_t      *pExp
@@ -102,7 +106,11 @@ RsaInitializeExponent(
     BN_INIT(pExp->qInv);
 #endif
 }
-/* 10.2.19.4.1 ComputePrivateExponent() */
+/* 10.2.17.4.1 ComputePrivateExponent() */
+/* This function computes the private exponent from the primes. */
+/* Return Value        Meaning */
+/* TRUE(1)     success */
+/* FALSE(0)    failure */
 static BOOL
 ComputePrivateExponent(
                       bigNum               P,             // IN: first prime (size is 1/2 of bnN)
@@ -156,9 +164,12 @@ ComputePrivateExponent(
        BnSetWord(Q, 0);
     return pOK && qOK;
 }
-/* 10.2.19.4.2 RsaPrivateKeyOp() */
+/* 10.2.17.4.2 RsaPrivateKeyOp() */
 /* This function is called to do the exponentiation with the private key. Compile options allow use
    of the simple (but slow) private exponent, or the more complex but faster CRT method. */
+/* Return Value        Meaning */
+/* TRUE(1)     success */
+/* FALSE(0)    failure */
 static BOOL
 RsaPrivateKeyOp(
                bigNum               inOut, // IN/OUT: number to be exponentiated
@@ -203,11 +214,12 @@ RsaPrivateKeyOp(
 #endif
     return OK;
 }
-/* 10.2.19.4.3 RSAEP() */
+/* 10.2.17.4.3 RSAEP() */
 /* This function performs the RSAEP operation defined in PKCS#1v2.1. It is an exponentiation of a
    value (m) with the public exponent (e), modulo the public (n). */
 /* Error Returns Meaning */
 /* TPM_RC_VALUE number to exponentiate is larger than the modulus */
+#if !USE_OPENSSL_FUNCTIONS_RSA         // libtpms added
 static TPM_RC
 RSAEP(
       TPM2B       *dInOut,        // IN: size of the encrypted block and the size of
@@ -231,7 +243,7 @@ RSAEP(
                   e.t.size, e.t.buffer, key->publicArea.unique.rsa.t.size,
                   key->publicArea.unique.rsa.t.buffer);
 }
-/* 10.2.19.4.4 RSADP() */
+/* 10.2.17.4.4 RSADP() */
 /* This function performs the RSADP operation defined in PKCS#1v2.1. It is an exponentiation of a
    value (c) with the private exponent (d), modulo the public modulus (n). The decryption is in
    place. */
@@ -261,7 +273,7 @@ RSADP(
     BnTo2B(bnM, inOut, inOut->size);
     return TPM_RC_SUCCESS;
 }
-/* 10.2.19.4.5 OaepEncode() */
+/* 10.2.17.4.5 OaepEncode() */
 /* This function performs OAEP padding. The size of the buffer to receive the OAEP padded data must
    equal the size of the modulus */
 /* Error Returns Meaning */
@@ -280,7 +292,7 @@ OaepEncode(
     INT32        i;
     BYTE         mySeed[MAX_DIGEST_SIZE];
     BYTE        *seed = mySeed;
-    INT32        hLen = CryptHashGetDigestSize(hashAlg);
+    UINT16       hLen = CryptHashGetDigestSize(hashAlg);
     BYTE         mask[MAX_RSA_KEY_BYTES];
     BYTE        *pp;
     BYTE        *pm;
@@ -288,7 +300,7 @@ OaepEncode(
     pAssert(padded != NULL && message != NULL);
     // A value of zero is not allowed because the KDF can't produce a result
     // if the digest size is zero.
-    if(hLen <= 0)
+    if(hLen == 0)
        return TPM_RC_VALUE;
     // Basic size checks
     //  make sure digest isn't too big for key size
@@ -316,14 +328,14 @@ OaepEncode(
     CryptRandomGenerate(hLen, mySeed);
     DRBG_Generate(rand, mySeed, (UINT16)hLen);
     // mask = MGF1 (seed, nSize  hLen  1)
-    CryptMGF1(dbSize, mask, hashAlg, hLen, seed);
+    CryptMGF_KDF(dbSize, mask, hashAlg, hLen, seed, 0);
     // Create the masked db
     pm = mask;
     for(i = dbSize; i > 0; i--)
        *pp++ ^= *pm++;
     pp = &padded->buffer[hLen + 1];
     // Run the masked data through MGF1
-    if(CryptMGF1(hLen, &padded->buffer[1], hashAlg, dbSize, pp) != (unsigned)hLen)
+    if(CryptMGF_KDF(hLen, &padded->buffer[1], hashAlg, dbSize, pp, 0) != (unsigned)hLen)
        ERROR_RETURN(TPM_RC_VALUE);
     // Now XOR the seed to create masked seed
     pp = &padded->buffer[1];
@@ -335,7 +347,7 @@ OaepEncode(
  Exit:
     return retVal;
 }
-/* 10.2.19.4.6 OaepDecode() */
+/* 10.2.17.4.6 OaepDecode() */
 /* This function performs OAEP padding checking. The size of the buffer to receive the recovered
    data. If the padding is not valid, the dSize size is set to zero and the function returns
    TPM_RC_VALUE. */
@@ -365,8 +377,8 @@ OaepDecode(
        ERROR_RETURN(TPM_RC_VALUE);
     // Use the hash size to determine what to put through MGF1 in order
     // to recover the seedMask
-    CryptMGF1(hLen, seedMask, hashAlg, padded->size - hLen - 1,
-             &padded->buffer[hLen + 1]);
+    CryptMGF_KDF(hLen, seedMask, hashAlg, padded->size - hLen - 1,
+                &padded->buffer[hLen + 1], 0);
     // Recover the seed into seedMask
     pAssert(hLen <= sizeof(seedMask));
     pp = &padded->buffer[1];
@@ -374,7 +386,7 @@ OaepDecode(
     for(i = hLen; i > 0; i--)
        *pm++ ^= *pp++;
     // Use the seed to generate the data mask
-    CryptMGF1(padded->size - hLen - 1, mask, hashAlg, hLen, seedMask);
+    CryptMGF_KDF(padded->size - hLen - 1, mask, hashAlg, hLen, seedMask, 0);
     // Use the mask generated from seed to recover the padded data
     pp = &padded->buffer[hLen + 1];
     pm = mask;
@@ -410,7 +422,7 @@ OaepDecode(
        dataOut->size = 0;
     return retVal;
 }
-/* 10.2.19.4.7 PKCS1v1_5Encode() */
+/* 10.2.17.4.7 PKCS1v1_5Encode() */
 /* This function performs the encoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1 */
 /* Error Returns Meaning */
 /* TPM_RC_VALUE message size is too large */
@@ -446,7 +458,7 @@ RSAES_PKCS1v1_5Encode(
        }
     return TPM_RC_SUCCESS;
 }
-/* 10.2.19.4.8 RSAES_Decode() */
+/* 10.2.17.4.8 RSAES_Decode() */
 /* This function performs the decoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1 */
 /* Error Returns Meaning */
 /* TPM_RC_FAIL decoding error or results would no fit into provided buffer */
@@ -469,15 +481,39 @@ RSAES_Decode(
     pSize++;
     // Make sure that pSize has not gone over the end and that there are at least 8
     // bytes of pad data.
-    fail = (pSize >= coded->size) | fail;
-    fail = ((pSize - 2) < 8) | fail;
+    fail = (pSize > coded->size) | fail;
+    fail = ((pSize - 2) <= 8) | fail;
     if((message->size < (UINT16)(coded->size - pSize)) || fail)
        return TPM_RC_VALUE;
     message->size = coded->size - pSize;
     memcpy(message->buffer, &coded->buffer[pSize], coded->size - pSize);
     return TPM_RC_SUCCESS;
 }
-/* 10.2.19.4.9 PssEncode() */
+#endif                                  // libtpms added
+/* 10.2.17.4.13        CryptRsaPssSaltSize() */
+/* This function computes the salt size used in PSS. It is broken out so that the X509 code can get
+   the same value that is used by the encoding function in this module. */
+INT16
+CryptRsaPssSaltSize(
+    INT16              hashSize,
+    INT16               outSize
+)
+{
+    INT16               saltSize;
+    //
+    // (Mask Length) = (outSize - hashSize - 1);
+    // Max saltSize is (Mask Length) - 1
+    saltSize = (outSize - hashSize - 1) - 1;
+    // Use the maximum salt size allowed by FIPS 186-4
+    if (saltSize > hashSize)
+       saltSize = hashSize;
+    else if (saltSize < 0)
+       saltSize = 0;
+    return saltSize;
+}
+
+#if !USE_OPENSSL_FUNCTIONS_RSA         // libtpms added
+/* 10.2.17.4.9 PssEncode() */
 /* This function creates an encoded block of data that is the size of modulus. The function uses the
    maximum salt size that will fit in the encoded block. */
 /* Returns TPM_RC_SUCCESS or goes into failure mode. */
@@ -518,7 +554,7 @@ PssEncode(
     CryptDigestUpdate(&hashState, saltSize, salt);
     CryptHashEnd(&hashState, hLen, &pOut[out->size - hLen - 1]);
     // Create a mask
-    if(CryptMGF1(mLen, pOut, hashAlg, hLen, &pOut[mLen]) != mLen)
+    if(CryptMGF_KDF(mLen, pOut, hashAlg, hLen, &pOut[mLen], 0) != mLen)
        FAIL(FATAL_ERROR_INTERNAL);
     // Since this implementation uses key sizes that are all even multiples of
     // 8, just need to make sure that the most significant bit is CLEAR
@@ -534,7 +570,7 @@ PssEncode(
     // and we are done
     return TPM_RC_SUCCESS;
 }
-/* 10.2.19.4.10 PssDecode() */
+/* 10.2.17.4.10 PssDecode() */
 /* This function checks that the PSS encoded block was built from the provided digest. If the check
    is successful, TPM_RC_SUCCESS is returned. Any other value indicates an error. */
 /* This implementation of PSS decoding is intended for the reference TPM implementation and is not
@@ -574,7 +610,7 @@ PssDecode(
     // Use the hLen bytes at the end of the buffer to generate a mask
     // Doesn't start at the end which is a flag byte
     mLen = eIn->size - hLen - 1;
-    CryptMGF1(mLen, mask, hashAlg, hLen, &pe[mLen]);
+    CryptMGF_KDF(mLen, mask, hashAlg, hLen, &pe[mLen], 0);
     // Clear the MSO of the mask to make it consistent with the encoding.
     mask[0] &= 0x7F;
     pAssert(mLen <= sizeof(mask));
@@ -628,12 +664,57 @@ PssDecode(
  Exit:
     return retVal;
 }
-/* 10.2.19.4.11 () RSASSA_Encode */
-/* Encode a message using PKCS1v1().5 method. */
-/* Error Returns Meaning */
-/* TPM_RC_SCHEME hashAlg is not a supported hash algorithm */
-/* TPM_RC_SIZE eOutSize is not large enough */
-/* TPM_RC_VALUE hInSize does not match the digest size of hashAlg */
+/* 10.2.17.4.16        MakeDerTag() */
+/* Construct the DER value that is used in RSASSA */
+/* Return Value        Meaning */
+/* > 0 size of value */
+/* <= 0        no hash exists */
+INT16
+MakeDerTag(
+          TPM_ALG_ID   hashAlg,
+          INT16        sizeOfBuffer,
+          BYTE        *buffer
+          )
+{
+    //    0x30, 0x31,       // SEQUENCE (2 elements) 1st
+    //        0x30, 0x0D,   // SEQUENCE (2 elements)
+    //            0x06, 0x09,   // HASH OID
+    //                0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+    //             0x05, 0x00,  // NULL
+    //        0x04, 0x20  //  OCTET STRING
+    HASH_DEF   *info = CryptGetHashDef(hashAlg);
+    INT16       oidSize;
+    // If no OID, can't do encode
+    VERIFY(info != NULL);
+    oidSize = 2 + (info->OID)[1];
+    // make sure this fits in the buffer
+    VERIFY(sizeOfBuffer >= (oidSize + 8));
+    *buffer++ = 0x30;  // 1st SEQUENCE
+    // Size of the 1st SEQUENCE is 6 bytes + size of the hash OID + size of the
+    // digest size
+    *buffer++ = (BYTE)(6 + oidSize + info->digestSize);   //
+    *buffer++ = 0x30; // 2nd SEQUENCE
+    // size is 4 bytes of overhead plus the side of the OID
+    *buffer++ = (BYTE)(2 + oidSize);
+    MemoryCopy(buffer, info->OID, oidSize);
+    buffer += oidSize;
+    *buffer++ = 0x05;   // Add a NULL
+    *buffer++ = 0x00;
+    
+    *buffer++ = 0x04;
+    *buffer++ = (BYTE)(info->digestSize);
+    return oidSize + 8;
+ Error:
+    return 0;
+    
+}
+
+/* 10.2.17.4.17        RSASSA_Encode() */
+/* Encode a message using PKCS1v1.5 method. */
+/* Error Returns       Meaning */
+/* TPM_RC_SCHEME       hashAlg is not a supported hash algorithm */
+/* TPM_RC_SIZE eOutSize is not large enough */
+/* TPM_RC_VALUE        hInSize does not match the digest size of hashAlg */
 static TPM_RC
 RSASSA_Encode(
              TPM2B               *pOut,      // IN:OUT on in, the size of the public key
@@ -642,23 +723,28 @@ RSASSA_Encode(
              TPM2B               *hIn        // IN: digest value to encode
              )
 {
-    const BYTE      *der;
+    BYTE             DER[20];
+    BYTE            *der = DER;
+    INT32            derSize = MakeDerTag(hashAlg, sizeof(DER), DER);
     BYTE            *eOut;
-    INT32            derSize = CryptHashGetDer(hashAlg, &der);
     INT32            fillSize;
     TPM_RC           retVal = TPM_RC_SUCCESS;
+    
     // Can't use this scheme if the algorithm doesn't have a DER string defined.
     if(derSize == 0)
        ERROR_RETURN(TPM_RC_SCHEME);
+    
     // If the digest size of 'hashAl' doesn't match the input digest size, then
     // the DER will misidentify the digest so return an error
     if(CryptHashGetDigestSize(hashAlg) != hIn->size)
        ERROR_RETURN(TPM_RC_VALUE);
     fillSize = pOut->size - derSize - hIn->size - 3;
     eOut = pOut->buffer;
+    
     // Make sure that this combination will fit in the provided space
     if(fillSize < 8)
        ERROR_RETURN(TPM_RC_SIZE);
+    
     // Start filling
     *eOut++ = 0; // initial byte of zero
     *eOut++ = 1; // byte of 0x01
@@ -673,11 +759,12 @@ RSASSA_Encode(
  Exit:
     return retVal;
 }
-/* 10.2.19.4.12 RSASSA_Decode() */
+
+/* 10.2.17.4.18        RSASSA_Decode() */
 /* This function performs the RSASSA decoding of a signature. */
-/* Error Returns Meaning */
-/* TPM_RC_VALUE decode unsuccessful */
-/* TPM_RC_SCHEME haslAlg is not supported */
+/* Error Returns       Meaning */
+/* TPM_RC_VALUE        decode unsuccessful */
+/* TPM_RC_SCHEME       haslAlg is not supported */
 static TPM_RC
 RSASSA_Decode(
              TPM_ALG_ID       hashAlg,        // IN: hash algorithm to use for the encoding
@@ -686,25 +773,30 @@ RSASSA_Decode(
              )
 {
     BYTE             fail;
-    const BYTE      *der;
+    BYTE             DER[20];
+    BYTE            *der = DER;
+    INT32            derSize = MakeDerTag(hashAlg, sizeof(DER), DER);
     BYTE            *pe;
-    INT32            derSize = CryptHashGetDer(hashAlg, &der);
     INT32            hashSize = CryptHashGetDigestSize(hashAlg);
     INT32            fillSize;
     TPM_RC           retVal;
     BYTE            *digest;
     UINT16           digestSize;
+    
     pAssert(hIn != NULL && eIn != NULL);
     pe = eIn->buffer;
+    
     // Can't use this scheme if the algorithm doesn't have a DER string
     // defined or if the provided hash isn't the right size
     if(derSize == 0 || (unsigned)hashSize != hIn->size)
        ERROR_RETURN(TPM_RC_SCHEME);
+    
     // Make sure that this combination will fit in the provided space
     // Since no data movement takes place, can just walk though this
     // and accept nearly random values. This can only be called from
     // CryptValidateSignature() so eInSize is known to be in range.
     fillSize = eIn->size - derSize - hashSize - 3;
+    
     // Start checking (fail will become non-zero if any of the bytes do not have
     // the expected value.
     fail = *pe++;                   // initial byte of zero
@@ -722,7 +814,9 @@ RSASSA_Decode(
  Exit:
     return retVal;
 }
-/* 10.2.19.4.13 CryptRsaSelectScheme() */
+#endif                                 // libtpms added
+
+/* 10.2.17.4.13 CryptRsaSelectScheme() */
 /* This function is used by TPM2_RSA_Decrypt() and TPM2_RSA_Encrypt().  It sets up the rules to
    select a scheme between input and object default. This function assume the RSA object is
    loaded. If a default scheme is defined in object, the default scheme should be chosen, otherwise,
@@ -768,7 +862,7 @@ CryptRsaSelectScheme(
     // two different, incompatible schemes specified will return NULL
     return retVal;
 }
-/* 10.2.19.4.14 CryptRsaLoadPrivateExponent() */
+/* 10.2.17.4.14 CryptRsaLoadPrivateExponent() */
 /* Error Returns Meaning */
 /* TPM_RC_BINDING public and private parts of rsaKey are not matched */
 TPM_RC
@@ -786,7 +880,7 @@ CryptRsaLoadPrivateExponent(
     TPM_RC          retVal = TPM_RC_SUCCESS;
     if(!rsaKey->attributes.privateExp)
        {
-           TEST(ALG_NULL_VALUE);
+           TEST(TPM_ALG_NULL);
            // Make sure that the bigNum used for the exponent is properly initialized
            RsaInitializeExponent(&rsaKey->privateExponent);
            // Find the second prime by division
@@ -802,7 +896,8 @@ CryptRsaLoadPrivateExponent(
     rsaKey->attributes.privateExp = (retVal == TPM_RC_SUCCESS);
     return retVal;
 }
-/* 10.2.19.4.15 CryptRsaEncrypt() */
+#if !USE_OPENSSL_FUNCTIONS_RSA         // libtpms added
+/* 10.2.17.4.15 CryptRsaEncrypt() */
 /* This is the entry point for encryption using RSA. Encryption is use of the public exponent. The
    padding parameter determines what padding will be used. */
 /* The cOutSize parameter must be at least as large as the size of the key. */
@@ -843,7 +938,7 @@ CryptRsaEncrypt(
     TEST(scheme->scheme);
     switch(scheme->scheme)
        {
-         case ALG_NULL_VALUE:  // 'raw' encryption
+         case TPM_ALG_NULL:  // 'raw' encryption
              {
                  INT32            i;
                  INT32            dSize = dIn->size;
@@ -862,10 +957,10 @@ CryptRsaEncrypt(
                  // the modulus. If it is, then RSAEP() will catch it.
              }
              break;
-         case ALG_RSAES_VALUE:
+         case TPM_ALG_RSAES:
            retVal = RSAES_PKCS1v1_5Encode(&cOut->b, dIn, rand);
            break;
-         case ALG_OAEP_VALUE:
+         case TPM_ALG_OAEP:
            retVal = OaepEncode(&cOut->b, scheme->details.oaep.hashAlg, label, dIn,
                                rand);
            break;
@@ -881,7 +976,7 @@ CryptRsaEncrypt(
  Exit:
     return retVal;
 }
-/* 10.2.19.4.16 CryptRsaDecrypt() */
+/* 10.2.17.4.16 CryptRsaDecrypt() */
 /* This is the entry point for decryption using RSA. Decryption is use of the private exponent. The
    padType parameter determines what padding was used. */
 /* Error Returns Meaning */
@@ -913,15 +1008,15 @@ CryptRsaDecrypt(
            // Remove padding
            switch(scheme->scheme)
                {
-                 case ALG_NULL_VALUE:
+                 case TPM_ALG_NULL:
                    if(dOut->size < cIn->size)
                        return TPM_RC_VALUE;
                    MemoryCopy2B(dOut, cIn, dOut->size);
                    break;
-                 case ALG_RSAES_VALUE:
+                 case TPM_ALG_RSAES:
                    retVal = RSAES_Decode(dOut, cIn);
                    break;
-                 case ALG_OAEP_VALUE:
+                 case TPM_ALG_OAEP:
                    retVal = OaepDecode(dOut, scheme->details.oaep.hashAlg, label, cIn);
                    break;
                  default:
@@ -932,7 +1027,7 @@ CryptRsaDecrypt(
  Exit:
     return retVal;
 }
-/* 10.2.19.4.17 CryptRsaSign() */
+/* 10.2.17.4.17 CryptRsaSign() */
 /* This function is used to generate an RSA signature of the type indicated in scheme. */
 /* Error Returns Meaning */
 /* TPM_RC_SCHEME scheme or hashAlg are not supported */
@@ -956,14 +1051,14 @@ CryptRsaSign(
     TEST(sigOut->sigAlg);
     switch(sigOut->sigAlg)
        {
-         case ALG_NULL_VALUE:
+         case TPM_ALG_NULL:
            sigOut->signature.rsapss.sig.t.size = 0;
            return TPM_RC_SUCCESS;
-         case ALG_RSAPSS_VALUE:
+         case TPM_ALG_RSAPSS:
            retVal = PssEncode(&sigOut->signature.rsapss.sig.b,
                               sigOut->signature.rsapss.hash, &hIn->b, rand);
            break;
-         case ALG_RSASSA_VALUE:
+         case TPM_ALG_RSASSA:
            retVal = RSASSA_Encode(&sigOut->signature.rsassa.sig.b,
                                   sigOut->signature.rsassa.hash, &hIn->b);
            break;
@@ -977,7 +1072,7 @@ CryptRsaSign(
        }
     return retVal;
 }
-/* 10.2.19.4.18 CryptRsaValidateSignature() */
+/* 10.2.17.4.18 CryptRsaValidateSignature() */
 /* This function is used to validate an RSA signature. If the signature is valid TPM_RC_SUCCESS is
    returned. If the signature is not valid, TPM_RC_SIGNATURE is returned. Other return codes
    indicate either parameter problems or fatal errors. */
@@ -997,8 +1092,8 @@ CryptRsaValidateSignature(
     pAssert(key != NULL && sig != NULL && digest != NULL);
     switch(sig->sigAlg)
        {
-         case ALG_RSAPSS_VALUE:
-         case ALG_RSASSA_VALUE:
+         case TPM_ALG_RSAPSS:
+         case TPM_ALG_RSASSA:
            break;
          default:
            return TPM_RC_SCHEME;
@@ -1013,11 +1108,11 @@ CryptRsaValidateSignature(
        {
            switch(sig->sigAlg)
                {
-                 case ALG_RSAPSS_VALUE:
+                 case TPM_ALG_RSAPSS:
                    retVal = PssDecode(sig->signature.any.hashAlg, &digest->b,
                                       &sig->signature.rsassa.sig.b);
                    break;
-                 case ALG_RSASSA_VALUE:
+                 case TPM_ALG_RSASSA:
                    retVal = RSASSA_Decode(sig->signature.any.hashAlg, &digest->b,
                                           &sig->signature.rsassa.sig.b);
                    break;
@@ -1028,6 +1123,7 @@ CryptRsaValidateSignature(
  Exit:
     return (retVal != TPM_RC_SUCCESS) ? TPM_RC_SIGNATURE : TPM_RC_SUCCESS;
 }
+#endif                                 // libtpms added
 #if SIMULATION && USE_RSA_KEY_CACHE
 extern int s_rsaKeyCacheEnabled;
 int GetCachedRsaKey(OBJECT *key, RAND_STATE *rand);
@@ -1036,7 +1132,7 @@ int GetCachedRsaKey(OBJECT *key, RAND_STATE *rand);
 #else
 #define GET_CACHED_KEY(key, rand)
 #endif
-/* 10.2.19.4.19 CryptRsaGenerateKey() */
+/* 10.2.17.4.19 CryptRsaGenerateKey() */
 /* Generate an RSA key from a provided seed */
 /* Error Returns Meaning */
 /* TPM_RC_CANCELED operation was canceled */
@@ -1086,7 +1182,11 @@ CryptRsaGenerateKey(
        return TPM_RC_SUCCESS;
 #endif
     // Make sure that key generation has been tested
-    TEST(ALG_NULL_VALUE);
+    TEST(TPM_ALG_NULL);
+#if USE_OPENSSL_FUNCTIONS_RSA          // libtpms added begin
+    if (rand == NULL)
+        return OpenSSLCryptRsaGenerateKey(rsaKey, e, keySizeInBits);
+#endif                                 // libtpms added end
     // Need to initialize the privateExponent structure
     RsaInitializeExponent(&rsaKey->privateExponent);
     // The prime is computed in P. When a new prime is found, Q is checked to
@@ -1166,4 +1266,369 @@ CryptRsaGenerateKey(
        rsaKey->attributes.privateExp = SET;
     return retVal;
 }
+
+#if USE_OPENSSL_FUNCTIONS_RSA          // libtpms added begin
+LIB_EXPORT TPM_RC
+CryptRsaEncrypt(
+               TPM2B_PUBLIC_KEY_RSA        *cOut,          // OUT: the encrypted data
+               TPM2B                       *dIn,           // IN: the data to encrypt
+               OBJECT                      *key,           // IN: the key used for encryption
+               TPMT_RSA_DECRYPT            *scheme,        // IN: the type of padding and hash
+               //     if needed
+               const TPM2B                 *label,         // IN: in case it is needed
+               RAND_STATE                  *rand           // IN: random number generator
+               //     state (mostly for testing)
+               )
+{
+    TPM_RC                       retVal;
+    TPM2B_PUBLIC_KEY_RSA         dataIn;
+    TPM2B_PUBLIC_KEY_RSA         scratch;
+    size_t                       outlen;
+    EVP_PKEY                    *pkey = NULL;
+    EVP_PKEY_CTX                *ctx = NULL;
+    const EVP_MD                *md;
+    const char                  *digestname;
+    unsigned char               *tmp = NULL;
+    //
+    // if the input and output buffers are the same, copy the input to a scratch
+    // buffer so that things don't get messed up.
+    if(dIn == &cOut->b)
+       {
+           MemoryCopy2B(&dataIn.b, dIn, sizeof(dataIn.t.buffer));
+           dIn = &dataIn.b;
+       }
+    // All encryption schemes return the same size of data
+    pAssert(sizeof(cOut->t.buffer) >= key->publicArea.unique.rsa.t.size);
+    cOut->t.size = key->publicArea.unique.rsa.t.size;
+    TEST(scheme->scheme);
+
+    retVal = InitOpenSSLRSAPublicKey(key, &pkey);
+    if (retVal != TPM_RC_SUCCESS)
+        return retVal;
+
+    ctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (ctx == NULL ||
+        EVP_PKEY_encrypt_init(ctx) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    switch(scheme->scheme)
+       {
+          case TPM_ALG_NULL:  // 'raw' encryption
+           {
+               INT32                 i;
+               INT32                 dSize = dIn->size;
+               // dIn can have more bytes than cOut as long as the extra bytes
+               // are zero. Note: the more significant bytes of a number in a byte
+               // buffer are the bytes at the start of the array.
+               for(i = 0; (i < dSize) && (dIn->buffer[i] == 0); i++);
+               dSize -= i;
+               scratch.t.size = cOut->t.size;
+               pAssert(scratch.t.size <= sizeof(scratch.t.buffer));
+               if(dSize > scratch.t.size)
+                   ERROR_RETURN(TPM_RC_VALUE);
+               // Pad cOut with zeros if dIn is smaller
+               memset(scratch.t.buffer, 0, scratch.t.size - dSize);
+               // And copy the rest of the value; value is then right-aligned
+               memcpy(&scratch.t.buffer[scratch.t.size - dSize], &dIn->buffer[i], dSize);
+
+               dIn = &scratch.b;
+           }
+            if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0)
+                ERROR_RETURN(TPM_RC_FAILURE);
+            break;
+          case TPM_ALG_RSAES:
+            if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
+                ERROR_RETURN(TPM_RC_FAILURE);
+            break;
+          case TPM_ALG_OAEP:
+            digestname = GetDigestNameByHashAlg(scheme->details.oaep.hashAlg);
+            if (digestname == NULL)
+                ERROR_RETURN(TPM_RC_VALUE);
+
+            md = EVP_get_digestbyname(digestname);
+            if (md == NULL ||
+                EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+                EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0)
+                ERROR_RETURN(TPM_RC_FAILURE);
+
+            if (label->size > 0) {
+                tmp = malloc(label->size);
+                if (tmp == NULL)
+                    ERROR_RETURN(TPM_RC_FAILURE);
+                memcpy(tmp, label->buffer, label->size);
+            }
+            // label->size == 0 is supported
+            if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, tmp, label->size) <= 0)
+                ERROR_RETURN(TPM_RC_FAILURE);
+            tmp = NULL;
+            break;
+          default:
+            ERROR_RETURN(TPM_RC_SCHEME);
+            break;
+       }
+
+    outlen = cOut->t.size;
+
+    if (EVP_PKEY_encrypt(ctx, cOut->t.buffer, &outlen,
+                         dIn->buffer, dIn->size) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    cOut->t.size = outlen;
+
+ Exit:
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_CTX_free(ctx);
+    free(tmp);
+
+    return retVal;
+}
+
+LIB_EXPORT TPM_RC
+CryptRsaDecrypt(
+               TPM2B               *dOut,          // OUT: the decrypted data
+               TPM2B               *cIn,           // IN: the data to decrypt
+               OBJECT              *key,           // IN: the key to use for decryption
+               TPMT_RSA_DECRYPT    *scheme,        // IN: the padding scheme
+               const TPM2B         *label          // IN: in case it is needed for the scheme
+               )
+{
+    TPM_RC                 retVal;
+    EVP_PKEY              *pkey = NULL;
+    EVP_PKEY_CTX          *ctx = NULL;
+    const EVP_MD          *md = NULL;
+    const char            *digestname;
+    size_t                 outlen;
+    unsigned char         *tmp = NULL;
+    unsigned char          buffer[MAX_RSA_KEY_BYTES];
+
+    // Make sure that the necessary parameters are provided
+    pAssert(cIn != NULL && dOut != NULL && key != NULL);
+    // Size is checked to make sure that the encrypted value is the right size
+    if(cIn->size != key->publicArea.unique.rsa.t.size)
+        ERROR_RETURN(TPM_RC_SIZE);
+    TEST(scheme->scheme);
+
+    retVal = InitOpenSSLRSAPrivateKey(key, &pkey);
+    if (retVal != TPM_RC_SUCCESS)
+        return retVal;
+
+    ctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (ctx == NULL ||
+        EVP_PKEY_decrypt_init(ctx) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    switch(scheme->scheme)
+       {
+         case TPM_ALG_NULL:  // 'raw' encryption
+            if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0)
+                ERROR_RETURN(TPM_RC_FAILURE);
+            break;
+         case TPM_ALG_RSAES:
+            if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
+                ERROR_RETURN(TPM_RC_FAILURE);
+            break;
+         case TPM_ALG_OAEP:
+            digestname = GetDigestNameByHashAlg(scheme->details.oaep.hashAlg);
+            if (digestname == NULL)
+                ERROR_RETURN(TPM_RC_VALUE);
+
+            md = EVP_get_digestbyname(digestname);
+            if (md == NULL ||
+                EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+                EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0)
+                ERROR_RETURN(TPM_RC_FAILURE);
+
+            if (label->size > 0) {
+                tmp = malloc(label->size);
+                if (tmp == NULL)
+                    ERROR_RETURN(TPM_RC_FAILURE);
+                memcpy(tmp, label->buffer, label->size);
+
+                if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, tmp, label->size) <= 0)
+                    ERROR_RETURN(TPM_RC_FAILURE);
+                tmp = NULL;
+            }
+            break;
+         default:
+            ERROR_RETURN(TPM_RC_SCHEME);
+            break;
+       }
+
+    /* cannot use cOut->buffer */
+    outlen = sizeof(buffer);
+    if (EVP_PKEY_decrypt(ctx, buffer, &outlen,
+                         cIn->buffer, cIn->size) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    if (outlen > dOut->size)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    memcpy(dOut->buffer, buffer, outlen);
+    dOut->size = outlen;
+
+    retVal = TPM_RC_SUCCESS;
+
+ Exit:
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_CTX_free(ctx);
+    free(tmp);
+
+    return retVal;
+}
+
+LIB_EXPORT TPM_RC
+CryptRsaSign(
+            TPMT_SIGNATURE      *sigOut,
+            OBJECT              *key,           // IN: key to use
+            TPM2B_DIGEST        *hIn,           // IN: the digest to sign
+            RAND_STATE          *rand           // IN: the random number generator
+            //      to use (mostly for testing)
+            )
+{
+    TPM_RC                retVal = TPM_RC_SUCCESS;
+    UINT16                modSize;
+    size_t                outlen;
+    int                   padding;
+    EVP_PKEY             *pkey = NULL;
+    EVP_PKEY_CTX         *ctx = NULL;
+    const EVP_MD         *md;
+    const char           *digestname;
+    TPMI_ALG_HASH         hashAlg;
+
+    // parameter checks
+    pAssert(sigOut != NULL && key != NULL && hIn != NULL);
+    modSize = key->publicArea.unique.rsa.t.size;
+    // for all non-null signatures, the size is the size of the key modulus
+    sigOut->signature.rsapss.sig.t.size = modSize;
+    TEST(sigOut->sigAlg);
+
+    switch(sigOut->sigAlg)
+         {
+          case TPM_ALG_NULL:
+            sigOut->signature.rsapss.sig.t.size = 0;
+            return TPM_RC_SUCCESS;
+          case TPM_ALG_RSAPSS:
+            padding = RSA_PKCS1_PSS_PADDING;
+            hashAlg = sigOut->signature.rsapss.hash;
+            break;
+          case TPM_ALG_RSASSA:
+            padding = RSA_PKCS1_PADDING;
+            hashAlg = sigOut->signature.rsassa.hash;
+            break;
+          default:
+            ERROR_RETURN(TPM_RC_SCHEME);
+         }
+
+    digestname = GetDigestNameByHashAlg(hashAlg);
+    if (digestname == NULL)
+        ERROR_RETURN(TPM_RC_VALUE);
+
+    md = EVP_get_digestbyname(digestname);
+    if (md == NULL)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    retVal = InitOpenSSLRSAPrivateKey(key, &pkey);
+    if (retVal != TPM_RC_SUCCESS)
+        return retVal;
+
+    ctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (ctx == NULL ||
+        EVP_PKEY_sign_init(ctx) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
+        EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    /* careful with PSS padding: Use salt length = hash length (-1) if
+     *   length(digest) + length(hash-to-sign) + 2 <= modSize
+     * otherwise use the max. possible salt length, which is the default (-2)
+     * test case: 1024 bit key PSS signing sha512 hash
+     */
+    if (padding == RSA_PKCS1_PSS_PADDING &&
+        EVP_MD_size(md) + hIn->b.size + 2 <= modSize && /* OSSL: RSA_padding_add_PKCS1_PSS_mgf1 */
+        EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    outlen = sigOut->signature.rsapss.sig.t.size;
+    if (EVP_PKEY_sign(ctx,
+                      sigOut->signature.rsapss.sig.t.buffer, &outlen,
+                      hIn->b.buffer, hIn->b.size) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    sigOut->signature.rsapss.sig.t.size = outlen;
+
+ Exit:
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_CTX_free(ctx);
+
+    return retVal;
+}
+
+LIB_EXPORT TPM_RC
+CryptRsaValidateSignature(
+                         TPMT_SIGNATURE  *sig,           // IN: signature
+                         OBJECT          *key,           // IN: public modulus
+                         TPM2B_DIGEST    *digest         // IN: The digest being validated
+                         )
+{
+    TPM_RC          retVal;
+    int             padding;
+    EVP_PKEY       *pkey = NULL;
+    EVP_PKEY_CTX   *ctx = NULL;
+    const EVP_MD   *md;
+    const char     *digestname;
+
+    //
+    // Fatal programming errors
+    pAssert(key != NULL && sig != NULL && digest != NULL);
+    switch(sig->sigAlg)
+       {
+         case TPM_ALG_RSAPSS:
+           padding = RSA_PKCS1_PSS_PADDING;
+           break;
+         case TPM_ALG_RSASSA:
+           padding = RSA_PKCS1_PADDING;
+           break;
+         default:
+           return TPM_RC_SCHEME;
+       }
+    // Errors that might be caused by calling parameters
+    if(sig->signature.rsassa.sig.t.size != key->publicArea.unique.rsa.t.size)
+       ERROR_RETURN(TPM_RC_SIGNATURE);
+    TEST(sig->sigAlg);
+
+    retVal = InitOpenSSLRSAPublicKey(key, &pkey);
+    if (retVal != TPM_RC_SUCCESS)
+        return retVal;
+
+    digestname = GetDigestNameByHashAlg(sig->signature.any.hashAlg);
+    if (digestname == NULL)
+        ERROR_RETURN(TPM_RC_VALUE);
+
+    md = EVP_get_digestbyname(digestname);
+    ctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (md == NULL || ctx == NULL ||
+        EVP_PKEY_verify_init(ctx) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
+        EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0)
+        ERROR_RETURN(TPM_RC_FAILURE);
+
+    if (EVP_PKEY_verify(ctx,
+                        sig->signature.rsassa.sig.t.buffer, sig->signature.rsassa.sig.t.size,
+                        digest->t.buffer, digest->t.size) <= 0)
+        ERROR_RETURN(TPM_RC_SIGNATURE);
+
+    retVal = TPM_RC_SUCCESS;
+
+ Exit:
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_CTX_free(ctx);
+
+    return (retVal != TPM_RC_SUCCESS) ? TPM_RC_SIGNATURE : TPM_RC_SUCCESS;
+}
+#endif // USE_OPENSSL_FUNCTIONS_RSA    libtpms added end
+
 #endif // TPM_ALG_RSA