Blame SOURCES/0017-openssl-Reimplement-RSA-OAEP-encryption-using-EVP-fu.patch

05e1a9
From 317c1ea1d9893d6f4f837196648c53b7f7dd762f Mon Sep 17 00:00:00 2001
05e1a9
From: Petr Gotthard <petr.gotthard@centrum.cz>
05e1a9
Date: Sun, 15 Aug 2021 17:22:44 +0200
05e1a9
Subject: [PATCH 16/17] openssl: Reimplement RSA OAEP encryption using EVP
05e1a9
 functions
05e1a9
05e1a9
The RSA_padding_add_PKCS1_OAEP_mgf1 is deprecated and the entire
05e1a9
semi-custom implementation of OAEP is unnecessary.
05e1a9
The Part 1, B.10.3 talks about a standard OAEP with a given label,
05e1a9
which can be easily implemented using the standard EVP functions.
05e1a9
Also, the public key retrieval can be replaced by invocation of
05e1a9
convert_pubkey_RSA from lib/tpm2_convert.c
05e1a9
05e1a9
Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
05e1a9
---
05e1a9
 lib/tpm2_identity_util.c | 162 +++++++++++----------------------------
05e1a9
 1 file changed, 43 insertions(+), 119 deletions(-)
05e1a9
05e1a9
diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c
05e1a9
index ba0c0e1c..b04a56d6 100644
05e1a9
--- a/lib/tpm2_identity_util.c
05e1a9
+++ b/lib/tpm2_identity_util.c
05e1a9
@@ -10,6 +10,7 @@
05e1a9
 
05e1a9
 #include "log.h"
05e1a9
 #include "tpm2_alg_util.h"
05e1a9
+#include "tpm2_convert.h"
05e1a9
 #include "tpm2_identity_util.h"
05e1a9
 #include "tpm2_kdfa.h"
05e1a9
 #include "tpm2_kdfe.h"
05e1a9
@@ -17,73 +18,6 @@
05e1a9
 
05e1a9
 // Identity-related functionality that the TPM normally does, but using OpenSSL
05e1a9
 
05e1a9
-#if defined(LIBRESSL_VERSION_NUMBER)
05e1a9
-static int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
05e1a9
-        const unsigned char *from, int flen, const unsigned char *param, int plen,
05e1a9
-        const EVP_MD *md, const EVP_MD *mgf1md) {
05e1a9
-
05e1a9
-    int ret = 0;
05e1a9
-    int i, emlen = tlen - 1;
05e1a9
-    unsigned char *db, *seed;
05e1a9
-    unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE];
05e1a9
-    int mdlen;
05e1a9
-
05e1a9
-    if (md == NULL)
05e1a9
-    md = EVP_sha1();
05e1a9
-    if (mgf1md == NULL)
05e1a9
-    mgf1md = md;
05e1a9
-
05e1a9
-    mdlen = EVP_MD_size(md);
05e1a9
-
05e1a9
-    if (flen > emlen - 2 * mdlen - 1) {
05e1a9
-        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
05e1a9
-                RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
05e1a9
-        return 0;
05e1a9
-    }
05e1a9
-
05e1a9
-    if (emlen < 2 * mdlen + 1) {
05e1a9
-        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
05e1a9
-                RSA_R_KEY_SIZE_TOO_SMALL);
05e1a9
-        return 0;
05e1a9
-    }
05e1a9
-
05e1a9
-    to[0] = 0;
05e1a9
-    seed = to + 1;
05e1a9
-    db = to + mdlen + 1;
05e1a9
-
05e1a9
-    if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL))
05e1a9
-    return 0;
05e1a9
-    memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1);
05e1a9
-    db[emlen - flen - mdlen - 1] = 0x01;
05e1a9
-    memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen);
05e1a9
-    if (RAND_bytes(seed, mdlen) <= 0)
05e1a9
-    return 0;
05e1a9
-
05e1a9
-    dbmask = OPENSSL_malloc(emlen - mdlen);
05e1a9
-    if (dbmask == NULL) {
05e1a9
-        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE);
05e1a9
-        return 0;
05e1a9
-    }
05e1a9
-
05e1a9
-    if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0)
05e1a9
-    goto err;
05e1a9
-    for (i = 0; i < emlen - mdlen; i++)
05e1a9
-    db[i] ^= dbmask[i];
05e1a9
-
05e1a9
-    if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0)
05e1a9
-    goto err;
05e1a9
-    for (i = 0; i < mdlen; i++)
05e1a9
-    seed[i] ^= seedmask[i];
05e1a9
-
05e1a9
-    ret = 1;
05e1a9
-
05e1a9
-err:
05e1a9
-    OPENSSL_free(dbmask);
05e1a9
-
05e1a9
-    return ret;
05e1a9
-}
05e1a9
-#endif
05e1a9
-
05e1a9
 static TPM2_KEY_BITS get_pub_asym_key_bits(TPM2B_PUBLIC *public) {
05e1a9
 
05e1a9
     TPMU_PUBLIC_PARMS *p = &public->publicArea.parameters;
05e1a9
@@ -102,19 +36,13 @@ static bool share_secret_with_tpm2_rsa_public_key(TPM2B_DIGEST *protection_seed,
05e1a9
         TPM2B_PUBLIC *parent_pub, unsigned char *label, int label_len,
05e1a9
         TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed) {
05e1a9
     bool rval = false;
05e1a9
-    RSA *rsa = NULL;
05e1a9
-
05e1a9
-    // Public modulus (RSA-only!)
05e1a9
-    TPMI_RSA_KEY_BITS mod_size_bits =
05e1a9
-            parent_pub->publicArea.parameters.rsaDetail.keyBits;
05e1a9
-    UINT16 mod_size = mod_size_bits / 8;
05e1a9
-    TPM2B *pub_key_val = (TPM2B *) &parent_pub->publicArea.unique.rsa;
05e1a9
-    unsigned char *pub_modulus = malloc(mod_size);
05e1a9
-    if (pub_modulus == NULL) {
05e1a9
-        LOG_ERR("Failed to allocate memory to store public key's modulus.");
05e1a9
+    EVP_PKEY_CTX *ctx = NULL;
05e1a9
+
05e1a9
+    EVP_PKEY *pkey = convert_pubkey_RSA(&parent_pub->publicArea);
05e1a9
+    if (pkey == NULL) {
05e1a9
+        LOG_ERR("Failed to retrieve public key");
05e1a9
         return false;
05e1a9
     }
05e1a9
-    memcpy(pub_modulus, pub_key_val->buffer, mod_size);
05e1a9
 
05e1a9
     TPMI_ALG_HASH parent_name_alg = parent_pub->publicArea.nameAlg;
05e1a9
 
05e1a9
@@ -122,70 +50,66 @@ static bool share_secret_with_tpm2_rsa_public_key(TPM2B_DIGEST *protection_seed,
05e1a9
      * RSA Secret Sharing uses a randomly generated seed (Part 1, B.10.3).
05e1a9
      */
05e1a9
     protection_seed->size = tpm2_alg_util_get_hash_size(parent_name_alg);
05e1a9
-    int return_code = RAND_bytes(protection_seed->buffer, protection_seed->size);
05e1a9
-    if (return_code != 1) {
05e1a9
+    int rc = RAND_bytes(protection_seed->buffer, protection_seed->size);
05e1a9
+    if (rc != 1) {
05e1a9
         LOG_ERR("Failed to get random bytes");
05e1a9
         goto error;
05e1a9
     }
05e1a9
 
05e1a9
     /*
05e1a9
-     * This is the biggest buffer value, so it should always be sufficient.
05e1a9
+     * The seed value will be OAEP encrypted with a given L parameter.
05e1a9
      */
05e1a9
-    unsigned char encoded[TPM2_MAX_DIGEST_BUFFER];
05e1a9
-    return_code = RSA_padding_add_PKCS1_OAEP_mgf1(encoded, mod_size,
05e1a9
-            protection_seed->buffer, protection_seed->size, label, label_len,
05e1a9
-            tpm2_openssl_md_from_tpmhalg(parent_name_alg), NULL);
05e1a9
-    if (return_code != 1) {
05e1a9
-        LOG_ERR("Failed RSA_padding_add_PKCS1_OAEP_mgf1\n");
05e1a9
-        goto error;
05e1a9
-    }
05e1a9
-    BIGNUM* bne = BN_new();
05e1a9
-    if (!bne) {
05e1a9
-        LOG_ERR("BN_new for bne failed\n");
05e1a9
+    ctx = EVP_PKEY_CTX_new(pkey, NULL);
05e1a9
+    if (!ctx) {
05e1a9
+        LOG_ERR("Failed EVP_PKEY_CTX_new");
05e1a9
         goto error;
05e1a9
     }
05e1a9
-    return_code = BN_set_word(bne, RSA_F4);
05e1a9
-    if (return_code != 1) {
05e1a9
-        LOG_ERR("BN_set_word failed\n");
05e1a9
-        BN_free(bne);
05e1a9
+
05e1a9
+    rc = EVP_PKEY_encrypt_init(ctx);
05e1a9
+    if (rc <= 0) {
05e1a9
+        LOG_ERR("Failed EVP_PKEY_encrypt_init");
05e1a9
         goto error;
05e1a9
     }
05e1a9
-    rsa = RSA_new();
05e1a9
-    if (!rsa) {
05e1a9
-        LOG_ERR("RSA_new failed\n");
05e1a9
-        BN_free(bne);
05e1a9
+
05e1a9
+    rc = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
05e1a9
+    if (rc <= 0) {
05e1a9
+        LOG_ERR("Failed EVP_PKEY_CTX_set_rsa_padding");
05e1a9
         goto error;
05e1a9
     }
05e1a9
-    return_code = RSA_generate_key_ex(rsa, mod_size_bits, bne, NULL);
05e1a9
-    BN_free(bne);
05e1a9
-    if (return_code != 1) {
05e1a9
-        LOG_ERR("RSA_generate_key_ex failed\n");
05e1a9
+
05e1a9
+    rc = EVP_PKEY_CTX_set_rsa_oaep_md(ctx,
05e1a9
+            tpm2_openssl_md_from_tpmhalg(parent_name_alg));
05e1a9
+    if (rc <= 0) {
05e1a9
+        LOG_ERR("Failed EVP_PKEY_CTX_set_rsa_oaep_md");
05e1a9
         goto error;
05e1a9
     }
05e1a9
-    BIGNUM *n = BN_bin2bn(pub_modulus, mod_size, NULL);
05e1a9
-    if (n == NULL) {
05e1a9
-        LOG_ERR("BN_bin2bn failed\n");
05e1a9
+
05e1a9
+    // the library will take ownership of the label
05e1a9
+    char *newlabel = strdup((const char *)label);
05e1a9
+    if (newlabel == NULL) {
05e1a9
+        LOG_ERR("Failed to allocate label");
05e1a9
         goto error;
05e1a9
     }
05e1a9
-    if (!RSA_set0_key(rsa, n, NULL, NULL)) {
05e1a9
-        LOG_ERR("RSA_set0_key failed\n");
05e1a9
-        BN_free(n);
05e1a9
+
05e1a9
+    rc = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, newlabel, label_len);
05e1a9
+    if (rc <= 0) {
05e1a9
+        LOG_ERR("Failed EVP_PKEY_CTX_set0_rsa_oaep_label");
05e1a9
+        free(newlabel);
05e1a9
         goto error;
05e1a9
     }
05e1a9
-    // Encrypting
05e1a9
-    encrypted_protection_seed->size = mod_size;
05e1a9
-    return_code = RSA_public_encrypt(mod_size, encoded,
05e1a9
-            encrypted_protection_seed->secret, rsa, RSA_NO_PADDING);
05e1a9
-    if (return_code < 0) {
05e1a9
-        LOG_ERR("Failed RSA_public_encrypt\n");
05e1a9
+
05e1a9
+    size_t outlen = sizeof(TPMU_ENCRYPTED_SECRET);
05e1a9
+    if (EVP_PKEY_encrypt(ctx, encrypted_protection_seed->secret, &outlen,
05e1a9
+            protection_seed->buffer, protection_seed->size) <= 0) {
05e1a9
+        LOG_ERR("Failed EVP_PKEY_encrypt\n");
05e1a9
         goto error;
05e1a9
     }
05e1a9
-
05e1a9
+    encrypted_protection_seed->size = outlen;
05e1a9
     rval = true;
05e1a9
 
05e1a9
 error:
05e1a9
-    free(pub_modulus);
05e1a9
-    RSA_free(rsa);
05e1a9
+    EVP_PKEY_CTX_free(ctx);
05e1a9
+    EVP_PKEY_free(pkey);
05e1a9
     return rval;
05e1a9
 }
05e1a9
 
05e1a9
-- 
05e1a9
2.31.1
05e1a9