From 0a91d1f62d5b6e1cac4d0a7c2ac9f75faad50534 Mon Sep 17 00:00:00 2001
From: Demi Marie Obenour <demi@invisiblethingslab.com>
Date: Fri, 9 Apr 2021 13:34:12 -0400
Subject: [PATCH] Avoid double frees if EVP_PKEY_assign_RSA fails

Previously, the bignums would be left as dangling and double-freed.
---
 rpmio/digest_openssl.c | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/rpmio/digest_openssl.c b/rpmio/digest_openssl.c
index 20c272d..02f34a9 100644
--- a/rpmio/digest_openssl.c
+++ b/rpmio/digest_openssl.c
@@ -292,8 +292,8 @@ struct pgpDigKeyRSA_s {
 
     BIGNUM *n; /* Common Modulus */
     BIGNUM *e; /* Public Exponent */
-
     EVP_PKEY *evp_pkey; /* Fully constructed key */
+    unsigned char immutable; /* if set, this key cannot be mutated */
 };
 
 static int constructRSASigningKey(struct pgpDigKeyRSA_s *key)
@@ -301,33 +301,34 @@ static int constructRSASigningKey(struct pgpDigKeyRSA_s *key)
     if (key->evp_pkey) {
         /* We've already constructed it, so just reuse it */
         return 1;
-    }
+    } else if (key->immutable)
+	return 0;
+    key->immutable = 1;
 
     /* Create the RSA key */
     RSA *rsa = RSA_new();
     if (!rsa) return 0;
 
-    if (!RSA_set0_key(rsa, key->n, key->e, NULL)) {
-        RSA_free(rsa);
-        return 0;
-    }
+    if (RSA_set0_key(rsa, key->n, key->e, NULL) <= 0)
+	goto exit;
+    key->n = key->e = NULL;
 
     /* Create an EVP_PKEY container to abstract the key-type. */
-    key->evp_pkey = EVP_PKEY_new();
-    if (!key->evp_pkey) {
-        RSA_free(rsa);
-        return 0;
-    }
+    if (!(key->evp_pkey = EVP_PKEY_new()))
+	goto exit;
 
     /* Assign the RSA key to the EVP_PKEY structure.
        This will take over memory management of the RSA key */
     if (!EVP_PKEY_assign_RSA(key->evp_pkey, rsa)) {
         EVP_PKEY_free(key->evp_pkey);
         key->evp_pkey = NULL;
-        RSA_free(rsa);
+	goto exit;
     }
 
     return 1;
+exit:
+    RSA_free(rsa);
+    return 0;
 }
 
 static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
@@ -335,9 +336,10 @@ static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
     size_t mlen = pgpMpiLen(p) - 2;
     struct pgpDigKeyRSA_s *key = pgpkey->data;
 
-    if (!key) {
+    if (!key)
         key = pgpkey->data = xcalloc(1, sizeof(*key));
-    }
+    else if (key->immutable)
+	return 1;
 
     switch (num) {
     case 0:
@@ -347,7 +349,7 @@ static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
             return 1;
         }
 
-        key->nbytes = mlen;
+	key->nbytes = mlen;
         /* Create a BIGNUM from the pointer.
            Note: this assumes big-endian data as required by PGP */
         key->n = BN_bin2bn(p+2, mlen, NULL);
-- 
1.8.3.1

