From 0533e0bcba55a201e437d7b9833a9ef96bd2fba9 Mon Sep 17 00:00:00 2001 From: slontis Date: Wed, 9 Apr 2025 10:05:09 +1000 Subject: [PATCH] Fix EVP_PKEY_CTX_dup() so that it copies the keymanager. A call to EVP_PKEY_CTX_new() creates a keymgmt pointer internally, but EVP_PKEY_CTX_dup() does not copy this field. Calling EVP_PKEY_derive_set_peer_ex() after EVP_PKEY_CTX_dup() resulted in a segfault because it tried to access this pointer. EVP_PKEY_CTX_dup() has been updated to copy the keymanager (and upref it). Reported by Eamon ODea (Oracle). Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/27304) (cherry picked from commit 3c22da73465f5dd211299e64f0de8786dcaf86c3) --- crypto/evp/pmeth_lib.c | 6 ++++++ test/ectest.c | 10 ++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 245ca2d41d7..b7253f11505 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -501,6 +501,12 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx) } rctx->legacy_keytype = pctx->legacy_keytype; + if (pctx->keymgmt != NULL) { + if (!EVP_KEYMGMT_up_ref(pctx->keymgmt)) + goto err; + rctx->keymgmt = pctx->keymgmt; + } + if (EVP_PKEY_CTX_IS_DERIVE_OP(pctx)) { if (pctx->op.kex.exchange != NULL) { rctx->op.kex.exchange = pctx->op.kex.exchange; diff --git a/test/ectest.c b/test/ectest.c index 946973c2f4d..0318bc9eae7 100644 --- a/test/ectest.c +++ b/test/ectest.c @@ -2707,7 +2707,7 @@ static int custom_params_test(int id) int is_prime = 0; EC_KEY *eckey1 = NULL, *eckey2 = NULL; EVP_PKEY *pkey1 = NULL, *pkey2 = NULL; - EVP_PKEY_CTX *pctx1 = NULL, *pctx2 = NULL; + EVP_PKEY_CTX *pctx1 = NULL, *pctx2 = NULL, *dctx = NULL; size_t sslen, t; unsigned char *pub1 = NULL , *pub2 = NULL; OSSL_PARAM_BLD *param_bld = NULL; @@ -2930,11 +2930,12 @@ static int custom_params_test(int id) EVP_PKEY_CTX_free(pctx1); if (!TEST_ptr(pctx1 = EVP_PKEY_CTX_new(pkey1, NULL)) || !TEST_int_eq(EVP_PKEY_derive_init(pctx1), 1) - || !TEST_int_eq(EVP_PKEY_derive_set_peer(pctx1, pkey2), 1) - || !TEST_int_eq(EVP_PKEY_derive(pctx1, NULL, &t), 1) + || !TEST_ptr(dctx = EVP_PKEY_CTX_dup(pctx1)) + || !TEST_int_eq(EVP_PKEY_derive_set_peer_ex(dctx, pkey2, 1), 1) + || !TEST_int_eq(EVP_PKEY_derive(dctx, NULL, &t), 1) || !TEST_int_gt(bsize, t) || !TEST_int_le(sslen, t) - || !TEST_int_eq(EVP_PKEY_derive(pctx1, buf1, &t), 1) + || !TEST_int_eq(EVP_PKEY_derive(dctx, buf1, &t), 1) /* compare with previous result */ || !TEST_mem_eq(buf1, t, buf2, sslen)) goto err; @@ -2962,6 +2963,7 @@ static int custom_params_test(int id) EVP_PKEY_free(pkey2); EVP_PKEY_CTX_free(pctx1); EVP_PKEY_CTX_free(pctx2); + EVP_PKEY_CTX_free(dctx); return ret; } -- 2.47.2