From: Viktor Dukhovni Date: Tue, 13 May 2025 15:23:25 +0000 (+1000) Subject: Allow keygen after dup of minimal PKEY ctx X-Git-Tag: openssl-3.5.1~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f55c57d1e05a2cc5903a8a3e0f9ca4d8ceb0970;p=thirdparty%2Fopenssl.git Allow keygen after dup of minimal PKEY ctx It should be possible to repeatedly duplicate a PKEY CTX created via EVP_PKEY_CTX_new_from_name() that has not yet been assigned an "operation" (e.g. via EVP_PKEY_CTX_keygen_init()), and then perform keygen_init() and keygen() on the duplicated copies. When the operation is not yet set, all that's needed is to not try to use the key if one isn't set yet. Reviewed-by: Paul Dale Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/27662) (cherry picked from commit 2c74a8d1ef4e9c4b4468afefedb1f72425772a37) --- diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 65e0a0c8206..08c0d6a7b2b 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -590,6 +590,9 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx) EVP_KEYMGMT *tmp_keymgmt = pctx->keymgmt; void *provkey; + if (pctx->pkey == NULL) + return rctx; + provkey = evp_pkey_export_to_provider(pctx->pkey, pctx->libctx, &tmp_keymgmt, pctx->propquery); if (provkey == NULL) diff --git a/doc/man3/EVP_PKEY_CTX_new.pod b/doc/man3/EVP_PKEY_CTX_new.pod index d7ac221f7c1..abf9b67d50d 100644 --- a/doc/man3/EVP_PKEY_CTX_new.pod +++ b/doc/man3/EVP_PKEY_CTX_new.pod @@ -49,8 +49,11 @@ used when no B 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. It is not supported for a -keygen operation. +EVP_PKEY_CTX_dup() duplicates the context I. +It is not supported for a keygen operation. +It is however possible to duplicate a context freshly created via any of the +above C functions, provided L has not yet been +called on the source context, and then use the copy for key generation. EVP_PKEY_CTX_free() frees up the context I. If I is NULL, nothing is done. diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c index a51a4a3c073..ba3d1b82b0a 100644 --- a/test/evp_pkey_provided_test.c +++ b/test/evp_pkey_provided_test.c @@ -2180,6 +2180,53 @@ err: return ret; } +static const char *name_dup_algs[] = { +#ifndef OPENSSL_NO_ECX + "ED25519", +#endif +#ifndef OPENSSL_NO_ML_KEM + "ML-KEM-512", +#endif +#ifndef OPENSSL_NO_ML_DSA + "ML-DSA-44", +#endif + NULL +}; + +static int test_name_dup(int idx) +{ + const char *alg = name_dup_algs[idx]; + EVP_PKEY *key = NULL; + EVP_PKEY_CTX *factory = NULL, *ctx = NULL; + int i, ret = 0; + + if (alg == NULL + || (factory = EVP_PKEY_CTX_new_from_name(NULL, alg, NULL)) == NULL) + return 1; + TEST_info("Testing fresh context dup for: %s", alg); + + /* Run twice to check that *repeated* use works */ + for (i = 0; i < 2; ++i) { + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(key); + key = NULL; + if (!TEST_ptr(ctx = EVP_PKEY_CTX_dup(factory)) + || !TEST_int_gt(EVP_PKEY_keygen_init(ctx), 0) + || !TEST_int_gt(EVP_PKEY_keygen(ctx, &key), 0)) { + ERR_print_errors(bio_err); + goto end; + } + } + ret = 1; + + end: + EVP_PKEY_CTX_free(factory); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(key); + + return ret; +} + int setup_tests(void) { if (!test_skip_common_options()) { @@ -2191,6 +2238,7 @@ int setup_tests(void) return 0; ADD_TEST(test_evp_pkey_ctx_dup_kdf); + ADD_ALL_TESTS(test_name_dup, OSSL_NELEM(name_dup_algs)); ADD_TEST(test_evp_pkey_get_bn_param_large); ADD_TEST(test_fromdata_rsa); ADD_TEST(test_fromdata_rsa_derive_from_pq_sp800);