[openssl] master update

shane.lontis at oracle.com shane.lontis at oracle.com
Mon Dec 14 01:33:59 UTC 2020


The branch master has been updated
       via  ac7750bb5ec4238c4f6514eb174c1bd584728f05 (commit)
      from  c739222b5ad68fa23bfdf4807106769f9428506c (commit)


- Log -----------------------------------------------------------------
commit ac7750bb5ec4238c4f6514eb174c1bd584728f05
Author: Shane Lontis <shane.lontis at oracle.com>
Date:   Wed Nov 25 15:21:52 2020 +1000

    Fix Segfault in EVP_PKEY_CTX_dup when the ctx has an undefined operation.
    
    Fixes #12438
    
    Note: This worked in 1.1.1 so just returning an error is not valid.
    
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/13505)

-----------------------------------------------------------------------

Summary of changes:
 crypto/evp/pmeth_lib.c        | 73 +++++++++++++++++++++++++------------------
 doc/man3/EVP_PKEY_CTX_new.pod |  5 +--
 test/evp_pkey_provided_test.c | 66 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+), 33 deletions(-)

diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index 2c2d939538..7364a148a6 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -488,87 +488,79 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx)
             return NULL;
         }
     }
+    rctx->legacy_keytype = pctx->legacy_keytype;
 
     if (EVP_PKEY_CTX_IS_DERIVE_OP(pctx)) {
         if (pctx->op.kex.exchange != NULL) {
             rctx->op.kex.exchange = pctx->op.kex.exchange;
-            if (!EVP_KEYEXCH_up_ref(rctx->op.kex.exchange)) {
-                OPENSSL_free(rctx);
-                return NULL;
-            }
+            if (!EVP_KEYEXCH_up_ref(rctx->op.kex.exchange))
+                goto end;
         }
         if (pctx->op.kex.exchprovctx != NULL) {
             if (!ossl_assert(pctx->op.kex.exchange != NULL))
-                return NULL;
+                goto end;
             rctx->op.kex.exchprovctx
                 = pctx->op.kex.exchange->dupctx(pctx->op.kex.exchprovctx);
             if (rctx->op.kex.exchprovctx == NULL) {
                 EVP_KEYEXCH_free(rctx->op.kex.exchange);
-                OPENSSL_free(rctx);
-                return NULL;
+                goto end;
             }
             return rctx;
         }
     } else if (EVP_PKEY_CTX_IS_SIGNATURE_OP(pctx)) {
         if (pctx->op.sig.signature != NULL) {
             rctx->op.sig.signature = pctx->op.sig.signature;
-            if (!EVP_SIGNATURE_up_ref(rctx->op.sig.signature)) {
-                OPENSSL_free(rctx);
-                return NULL;
-            }
+            if (!EVP_SIGNATURE_up_ref(rctx->op.sig.signature))
+                goto end;
         }
         if (pctx->op.sig.sigprovctx != NULL) {
             if (!ossl_assert(pctx->op.sig.signature != NULL))
-                return NULL;
+                goto end;
             rctx->op.sig.sigprovctx
                 = pctx->op.sig.signature->dupctx(pctx->op.sig.sigprovctx);
             if (rctx->op.sig.sigprovctx == NULL) {
                 EVP_SIGNATURE_free(rctx->op.sig.signature);
-                OPENSSL_free(rctx);
-                return NULL;
+                goto end;
             }
             return rctx;
         }
     } else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(pctx)) {
         if (pctx->op.ciph.cipher != NULL) {
             rctx->op.ciph.cipher = pctx->op.ciph.cipher;
-            if (!EVP_ASYM_CIPHER_up_ref(rctx->op.ciph.cipher)) {
-                OPENSSL_free(rctx);
-                return NULL;
-            }
+            if (!EVP_ASYM_CIPHER_up_ref(rctx->op.ciph.cipher))
+                goto end;
         }
         if (pctx->op.ciph.ciphprovctx != NULL) {
             if (!ossl_assert(pctx->op.ciph.cipher != NULL))
-                return NULL;
+                goto end;
             rctx->op.ciph.ciphprovctx
                 = pctx->op.ciph.cipher->dupctx(pctx->op.ciph.ciphprovctx);
             if (rctx->op.ciph.ciphprovctx == NULL) {
                 EVP_ASYM_CIPHER_free(rctx->op.ciph.cipher);
-                OPENSSL_free(rctx);
-                return NULL;
+                goto end;
             }
             return rctx;
         }
     } else if (EVP_PKEY_CTX_IS_KEM_OP(pctx)) {
         if (pctx->op.encap.kem != NULL) {
             rctx->op.encap.kem = pctx->op.encap.kem;
-            if (!EVP_KEM_up_ref(rctx->op.encap.kem)) {
-                OPENSSL_free(rctx);
-                return NULL;
-            }
+            if (!EVP_KEM_up_ref(rctx->op.encap.kem))
+                goto end;
         }
         if (pctx->op.encap.kemprovctx != NULL) {
             if (!ossl_assert(pctx->op.encap.kem != NULL))
-                return NULL;
+                goto end;
             rctx->op.encap.kemprovctx
                 = pctx->op.encap.kem->dupctx(pctx->op.encap.kemprovctx);
             if (rctx->op.encap.kemprovctx == NULL) {
                 EVP_KEM_free(rctx->op.encap.kem);
-                OPENSSL_free(rctx);
-                return NULL;
+                goto end;
             }
             return rctx;
         }
+    } else if (EVP_PKEY_CTX_IS_GEN_OP(pctx)) {
+        /* Not supported - This would need a gen_dupctx() to work */
+        goto end;
     }
 
     rctx->pmeth = pctx->pmeth;
@@ -576,17 +568,36 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx)
     rctx->engine = pctx->engine;
 # endif
 
-    if (pctx->peerkey)
+    if (pctx->peerkey != NULL)
         EVP_PKEY_up_ref(pctx->peerkey);
     rctx->peerkey = pctx->peerkey;
 
+    if (pctx->pmeth == NULL) {
+        if (rctx->operation == EVP_PKEY_OP_UNDEFINED) {
+            EVP_KEYMGMT *tmp_keymgmt = pctx->keymgmt;
+            void *provkey;
+
+            provkey = evp_pkey_export_to_provider(pctx->pkey, pctx->libctx,
+                                                  &tmp_keymgmt, pctx->propquery);
+            if (provkey == NULL)
+                goto err;
+            if (!EVP_KEYMGMT_up_ref(tmp_keymgmt))
+                goto err;
+            EVP_KEYMGMT_free(rctx->keymgmt);
+            rctx->keymgmt = tmp_keymgmt;
+            return rctx;
+        }
+        goto err;
+    }
     if (pctx->pmeth->copy(rctx, pctx) > 0)
         return rctx;
-
+err:
     rctx->pmeth = NULL;
     EVP_PKEY_CTX_free(rctx);
     return NULL;
-
+end:
+    OPENSSL_free(rctx);
+    return NULL;
 }
 
 int EVP_PKEY_meth_add0(const EVP_PKEY_METHOD *pmeth)
diff --git a/doc/man3/EVP_PKEY_CTX_new.pod b/doc/man3/EVP_PKEY_CTX_new.pod
index 1b23c2a403..3342386d94 100644
--- a/doc/man3/EVP_PKEY_CTX_new.pod
+++ b/doc/man3/EVP_PKEY_CTX_new.pod
@@ -47,7 +47,8 @@ used when no B<EVP_PKEY> structure is associated with the operations,
 for example during parameter generation or key generation for some
 algorithms.
 
-EVP_PKEY_CTX_dup() duplicates the context I<ctx>.
+EVP_PKEY_CTX_dup() duplicates the context I<ctx>. It is not supported for a
+keygen operation.
 
 EVP_PKEY_CTX_free() frees up the context I<ctx>.
 If I<ctx> is NULL, nothing is done.
@@ -96,7 +97,7 @@ documentation for more information.
 
 =head1 RETURN VALUES
 
-EVP_PKEY_CTX_new(), EVP_PKEY_CTX_new_id(), EVP_PKEY_CTX_dup() returns either
+EVP_PKEY_CTX_new(), EVP_PKEY_CTX_new_id() and EVP_PKEY_CTX_dup() return either
 the newly allocated B<EVP_PKEY_CTX> structure or B<NULL> if an error occurred.
 
 EVP_PKEY_CTX_free() does not return a value.
diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c
index a983d3b533..bfc9cd2ebc 100644
--- a/test/evp_pkey_provided_test.c
+++ b/test/evp_pkey_provided_test.c
@@ -1072,6 +1072,70 @@ err:
     return ret;
 }
 
+static int test_ec_dup_no_operation(void)
+{
+    int ret = 0;
+    EVP_PKEY_CTX *pctx = NULL, *ctx = NULL, *kctx = NULL;
+    EVP_PKEY *param = NULL, *pkey = NULL;
+
+    if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))
+        || !TEST_int_gt(EVP_PKEY_paramgen_init(pctx), 0)
+        || !TEST_int_gt(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx,
+                        NID_X9_62_prime256v1), 0)
+        || !TEST_int_gt(EVP_PKEY_paramgen(pctx, &param), 0)
+        || !TEST_ptr(param))
+        goto err;
+
+    EVP_PKEY_CTX_free(pctx);
+    pctx = NULL;
+
+    if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(NULL, param, NULL))
+        || !TEST_ptr(kctx = EVP_PKEY_CTX_dup(ctx))
+        || !TEST_int_gt(EVP_PKEY_keygen_init(kctx), 0)
+        || !TEST_int_gt(EVP_PKEY_keygen(kctx, &pkey), 0))
+        goto err;
+    ret = 1;
+err:
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_free(param);
+    EVP_PKEY_CTX_free(ctx);
+    EVP_PKEY_CTX_free(kctx);
+    EVP_PKEY_CTX_free(pctx);
+    return ret;
+}
+
+/* Test that keygen doesn't support EVP_PKEY_CTX_dup */
+static int test_ec_dup_keygen_operation(void)
+{
+    int ret = 0;
+    EVP_PKEY_CTX *pctx = NULL, *ctx = NULL, *kctx = NULL;
+    EVP_PKEY *param = NULL, *pkey = NULL;
+
+    if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))
+        || !TEST_int_gt(EVP_PKEY_paramgen_init(pctx), 0)
+        || !TEST_int_gt(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx,
+                        NID_X9_62_prime256v1), 0)
+        || !TEST_int_gt(EVP_PKEY_paramgen(pctx, &param), 0)
+        || !TEST_ptr(param))
+        goto err;
+
+    EVP_PKEY_CTX_free(pctx);
+    pctx = NULL;
+
+    if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(NULL, param, NULL))
+        || !TEST_int_gt(EVP_PKEY_keygen_init(ctx), 0)
+        || !TEST_ptr_null(kctx = EVP_PKEY_CTX_dup(ctx)))
+        goto err;
+    ret = 1;
+err:
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_free(param);
+    EVP_PKEY_CTX_free(ctx);
+    EVP_PKEY_CTX_free(kctx);
+    EVP_PKEY_CTX_free(pctx);
+    return ret;
+}
+
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_DSA
@@ -1343,6 +1407,8 @@ int setup_tests(void)
 #ifndef OPENSSL_NO_EC
     ADD_ALL_TESTS(test_fromdata_ecx, 4 * 3);
     ADD_TEST(test_fromdata_ec);
+    ADD_TEST(test_ec_dup_no_operation);
+    ADD_TEST(test_ec_dup_keygen_operation);
 #endif
     return 1;
 }


More information about the openssl-commits mailing list