Fix a mem leak in evp_pkey_export_to_provider
authorK1 <dongbeiouba@gmail.com>
Wed, 8 Jun 2022 08:41:16 +0000 (16:41 +0800)
committerTodd Short <todd.short@me.com>
Wed, 15 Jun 2022 14:53:04 +0000 (10:53 -0400)
If keymgmt is NULL, tmp_keymgmt is allocated and will not be freed.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Yang <kaishen.yy@antfin.com>
Reviewed-by: Todd Short <todd.short@me.com>
(Merged from https://github.com/openssl/openssl/pull/18499)

crypto/evp/p_lib.c
test/keymgmt_internal_test.c
test/recipes/02-test_internal_keymgmt.t

index db1822f0d1bce3a922c6045093efaeae61906b5b..8d2eee11f1a94eb0cd620626dc08762b52eb4b5d 100644 (file)
@@ -1853,7 +1853,7 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
 
         if (ctx == NULL)
             goto end;
-        tmp_keymgmt = ctx->keymgmt;
+        allocated_keymgmt = tmp_keymgmt = ctx->keymgmt;
         ctx->keymgmt = NULL;
         EVP_PKEY_CTX_free(ctx);
     }
@@ -1966,8 +1966,10 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
     if (keydata == NULL)
         tmp_keymgmt = NULL;
 
-    if (keymgmt != NULL)
+    if (keymgmt != NULL && tmp_keymgmt != NULL) {
         *keymgmt = tmp_keymgmt;
+        allocated_keymgmt = NULL;
+    }
 
     EVP_KEYMGMT_free(allocated_keymgmt);
     return keydata;
index dd0de2f599277b21aa07d58b432941e51c8064d4..0f2030e61fb729cf051dc5954badc823e2426a25 100644 (file)
@@ -19,6 +19,7 @@
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
 #include <openssl/evp.h>
+#include <openssl/pem.h>
 #include <openssl/provider.h>
 #include <openssl/core_names.h>
 #include "internal/core.h"
@@ -33,6 +34,9 @@ typedef struct {
     OSSL_PROVIDER *prov2;
 } FIXTURE;
 
+/* Collected arguments */
+static const char *cert_filename = NULL;
+
 static void tear_down(FIXTURE *fixture)
 {
     if (fixture != NULL) {
@@ -285,8 +289,70 @@ static int test_pass_key(int n)
     return result;
 }
 
+static int test_evp_pkey_export_to_provider(int n)
+{
+    OSSL_LIB_CTX *libctx = NULL;
+    OSSL_PROVIDER *prov = NULL;
+    X509 *cert = NULL;
+    BIO *bio = NULL;
+    X509_PUBKEY *pubkey = NULL;
+    EVP_KEYMGMT *keymgmt = NULL;
+    EVP_PKEY *pkey = NULL;
+    void *keydata = NULL;
+    int ret = 0;
+
+    if (!TEST_ptr(libctx = OSSL_LIB_CTX_new())
+         || !TEST_ptr(prov = OSSL_PROVIDER_load(libctx, "default")))
+        goto end;
+
+    if ((bio = BIO_new_file(cert_filename, "r")) == NULL) {
+        TEST_error("Couldn't open '%s' for reading\n", cert_filename);
+        TEST_openssl_errors();
+        goto end;
+    }
+
+    if ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) {
+        TEST_error("'%s' doesn't appear to be a X.509 certificate in PEM format\n",
+                   cert_filename);
+        TEST_openssl_errors();
+        goto end;
+    }
+
+    pubkey = X509_get_X509_PUBKEY(cert);
+    pkey = X509_PUBKEY_get0(pubkey);
+
+    if (n == 0) {
+        if (!TEST_ptr(keydata = evp_pkey_export_to_provider(pkey, NULL,
+                                                            NULL, NULL)))
+            goto end;
+    } else if (n == 1) {
+        if (!TEST_ptr(keydata = evp_pkey_export_to_provider(pkey, NULL,
+                                                            &keymgmt, NULL)))
+            goto end;
+    } else {
+        keymgmt = EVP_KEYMGMT_fetch(libctx, "RSA", NULL);
+
+        if (!TEST_ptr(keydata = evp_pkey_export_to_provider(pkey, NULL,
+                                                            &keymgmt, NULL)))
+            goto end;
+    }
+
+    ret = 1;
+ end:
+    BIO_free(bio);
+    X509_free(cert);
+    EVP_KEYMGMT_free(keymgmt);
+    OSSL_PROVIDER_unload(prov);
+    OSSL_LIB_CTX_free(libctx);
+    return ret;
+}
+
 int setup_tests(void)
 {
+    if (!TEST_ptr(cert_filename = test_get_argument(0)))
+        return 0;
+
     ADD_ALL_TESTS(test_pass_key, 1);
+    ADD_ALL_TESTS(test_evp_pkey_export_to_provider, 3);
     return 1;
 }
index 269f624467d85a0227ff03c5630c13dda3e340c9..28f510f1648cee7a0f85b312eab9bddea303c1e5 100644 (file)
@@ -7,12 +7,15 @@
 # https://www.openssl.org/source/license.html
 
 use strict;
-use OpenSSL::Test qw(:DEFAULT bldtop_dir);
-use OpenSSL::Test::Simple;
+use OpenSSL::Test qw(:DEFAULT bldtop_dir srctop_file);
 use OpenSSL::Test::Utils;
 
 setup("test_internal_keymgmt");
 
+plan tests => 1;
+
 $ENV{OPENSSL_MODULES} = bldtop_dir("test");
 
-simple_test("test_internal_keymgmt", "keymgmt_internal_test");
+ok(run(test(["keymgmt_internal_test",
+    srctop_file("test", "certs", "ee-cert.pem")])),
+    "running test_internal_keymgmt");