[openssl] master update

tomas at openssl.org tomas at openssl.org
Thu Apr 15 07:23:42 UTC 2021


The branch master has been updated
       via  7e43baed2a4cc050b301650c4a45ebdd54a30b5f (commit)
       via  85fcc3fb777c527a614e58c23609210a9edf893b (commit)
       via  b4f447c038c05260491eb880e4a9c420b476c119 (commit)
       via  4a9fe33c8e12f4fefae0471c0834f8e674dc7e4e (commit)
      from  b9cd82f95bf99eab4e1b0420918e7139db091c4b (commit)


- Log -----------------------------------------------------------------
commit 7e43baed2a4cc050b301650c4a45ebdd54a30b5f
Author: Tomas Mraz <tomas at openssl.org>
Date:   Thu Apr 8 19:27:06 2021 +0200

    Do not allow creating empty RSA keys by duplication
    
    Also avoid crashing in rsa_get_params on empty keys.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/14793)

commit 85fcc3fb777c527a614e58c23609210a9edf893b
Author: Tomas Mraz <tomas at openssl.org>
Date:   Thu Apr 8 19:02:44 2021 +0200

    Remove keymgmt_copy function from the provider API
    
    It is superceded by the keymgmt_dup.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/14793)

commit b4f447c038c05260491eb880e4a9c420b476c119
Author: Tomas Mraz <tomas at openssl.org>
Date:   Thu Apr 8 18:25:26 2021 +0200

    Add selection support to the provider keymgmt_dup function
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/14793)

commit 4a9fe33c8e12f4fefae0471c0834f8e674dc7e4e
Author: Tomas Mraz <tomas at openssl.org>
Date:   Wed Apr 7 19:35:13 2021 +0200

    Implement provider-side keymgmt_dup function
    
    To avoid mutating key data add OSSL_FUNC_KEYMGMT_DUP function
    to the provider API and implement it for all asym-key key
    managements.
    
    Use it when copying everything to an empty EVP_PKEY
    which is the case with EVP_PKEY_dup().
    
    Fixes #14658
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/14793)

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

Summary of changes:
 crypto/dh/dh_ameth.c                          |  42 +----------
 crypto/dh/dh_backend.c                        |  51 +++++++++++++
 crypto/dsa/dsa_ameth.c                        |  41 +---------
 crypto/dsa/dsa_backend.c                      |  50 +++++++++++++
 crypto/ec/ec_backend.c                        |  88 ++++++++++++++++++++++
 crypto/ec/ec_key.c                            |  12 +--
 crypto/ec/ecx_backend.c                       |  45 +++++++++++
 crypto/ec/ecx_key.c                           |   2 +-
 crypto/ec/ecx_meth.c                          |  14 ++--
 crypto/evp/evp_local.h                        |   2 +-
 crypto/evp/keymgmt_lib.c                      |  23 ++----
 crypto/evp/keymgmt_meth.c                     |  19 +++--
 crypto/evp/p_lib.c                            |  13 ++--
 crypto/rsa/rsa_ameth.c                        |  94 +----------------------
 crypto/rsa/rsa_backend.c                      | 103 ++++++++++++++++++++++++++
 doc/man7/provider-keymgmt.pod                 |  19 +++--
 include/crypto/dh.h                           |   1 +
 include/crypto/dsa.h                          |   1 +
 include/crypto/ec.h                           |   1 +
 include/crypto/ecx.h                          |   1 +
 include/crypto/evp.h                          |   5 +-
 include/crypto/rsa.h                          |   1 +
 include/openssl/core_dispatch.h               |   9 +--
 providers/implementations/keymgmt/dh_kmgmt.c  |  12 ++-
 providers/implementations/keymgmt/dsa_kmgmt.c |  11 ++-
 providers/implementations/keymgmt/ec_kmgmt.c  |  10 +++
 providers/implementations/keymgmt/ecx_kmgmt.c |   9 +++
 providers/implementations/keymgmt/rsa_kmgmt.c |  19 ++++-
 test/tls-provider.c                           |  14 ++--
 29 files changed, 459 insertions(+), 253 deletions(-)

diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index 907a867eca..d96b54285b 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -536,46 +536,6 @@ static int dhx_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
     return dh_pkey_import_from_type(params, vpctx, EVP_PKEY_DHX);
 }
 
-static ossl_inline int dh_bn_dup_check(BIGNUM **out, const BIGNUM *f)
-{
-    if (f != NULL && (*out = BN_dup(f)) == NULL)
-        return 0;
-    return 1;
-}
-
-static DH *dh_dup(const DH *dh)
-{
-    DH *dupkey = NULL;
-
-    /* Do not try to duplicate foreign DH keys */
-    if (ossl_dh_get_method(dh) != DH_OpenSSL())
-        return NULL;
-
-    if ((dupkey = ossl_dh_new_ex(dh->libctx)) == NULL)
-        return NULL;
-
-    dupkey->length = DH_get_length(dh);
-    if (!ossl_ffc_params_copy(&dupkey->params, &dh->params))
-        goto err;
-
-    dupkey->flags = dh->flags;
-
-    if (!dh_bn_dup_check(&dupkey->pub_key, dh->pub_key))
-        goto err;
-    if (!dh_bn_dup_check(&dupkey->priv_key, dh->priv_key))
-        goto err;
-
-    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_DH,
-                            &dupkey->ex_data, &dh->ex_data))
-        goto err;
-
-    return dupkey;
-
- err:
-    DH_free(dupkey);
-    return NULL;
-}
-
 static int dh_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
 {
     DH *dh = from->pkey.dh;
@@ -583,7 +543,7 @@ static int dh_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
     int ret;
 
     if (dh != NULL) {
-        dupkey = dh_dup(dh);
+        dupkey = ossl_dh_dup(dh, OSSL_KEYMGMT_SELECT_ALL);
         if (dupkey == NULL)
             return 0;
     }
diff --git a/crypto/dh/dh_backend.c b/crypto/dh/dh_backend.c
index 97f5271a5a..18cf3f5992 100644
--- a/crypto/dh/dh_backend.c
+++ b/crypto/dh/dh_backend.c
@@ -17,6 +17,7 @@
 #include <openssl/core_names.h>
 #include "internal/param_build_set.h"
 #include "crypto/dh.h"
+#include "dh_local.h"
 
 /*
  * The intention with the "backend" source file is to offer backend functions
@@ -117,6 +118,56 @@ int ossl_dh_key_todata(DH *dh, OSSL_PARAM_BLD *bld, OSSL_PARAM params[])
     return 1;
 }
 
+static ossl_inline int dh_bn_dup_check(BIGNUM **out, const BIGNUM *f)
+{
+    if (f != NULL && (*out = BN_dup(f)) == NULL)
+        return 0;
+    return 1;
+}
+
+DH *ossl_dh_dup(const DH *dh, int selection)
+{
+    DH *dupkey = NULL;
+
+#ifndef FIPS_MODULE
+    /* Do not try to duplicate foreign DH keys */
+    if (ossl_dh_get_method(dh) != DH_OpenSSL())
+        return NULL;
+#endif
+
+    if ((dupkey = ossl_dh_new_ex(dh->libctx)) == NULL)
+        return NULL;
+
+    dupkey->length = DH_get_length(dh);
+    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0
+        && !ossl_ffc_params_copy(&dupkey->params, &dh->params))
+        goto err;
+
+    dupkey->flags = dh->flags;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0
+        && ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0
+            || !dh_bn_dup_check(&dupkey->pub_key, dh->pub_key)))
+        goto err;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0
+        && ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0
+            || !dh_bn_dup_check(&dupkey->priv_key, dh->priv_key)))
+        goto err;
+
+#ifndef FIPS_MODULE
+    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_DH,
+                            &dupkey->ex_data, &dh->ex_data))
+        goto err;
+#endif
+
+    return dupkey;
+
+ err:
+    DH_free(dupkey);
+    return NULL;
+}
+
 #ifndef FIPS_MODULE
 DH *ossl_dh_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf,
                            OSSL_LIB_CTX *libctx, const char *propq)
diff --git a/crypto/dsa/dsa_ameth.c b/crypto/dsa/dsa_ameth.c
index 69964c053c..2e1ad081dc 100644
--- a/crypto/dsa/dsa_ameth.c
+++ b/crypto/dsa/dsa_ameth.c
@@ -500,45 +500,6 @@ static int dsa_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
     return 1;
 }
 
-static ossl_inline int dsa_bn_dup_check(BIGNUM **out, const BIGNUM *f)
-{
-    if (f != NULL && (*out = BN_dup(f)) == NULL)
-        return 0;
-    return 1;
-}
-
-static DSA *dsa_dup(const DSA *dsa)
-{
-    DSA *dupkey = NULL;
-
-    /* Do not try to duplicate foreign DSA keys */
-    if (DSA_get_method((DSA *)dsa) != DSA_OpenSSL())
-        return NULL;
-
-    if ((dupkey = ossl_dsa_new(dsa->libctx)) == NULL)
-        return NULL;
-
-    if (!ossl_ffc_params_copy(&dupkey->params, &dsa->params))
-        goto err;
-
-    dupkey->flags = dsa->flags;
-
-    if (!dsa_bn_dup_check(&dupkey->pub_key, dsa->pub_key))
-        goto err;
-    if (!dsa_bn_dup_check(&dupkey->priv_key, dsa->priv_key))
-        goto err;
-
-    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_DSA,
-                            &dupkey->ex_data, &dsa->ex_data))
-        goto err;
-
-    return dupkey;
-
- err:
-    DSA_free(dupkey);
-    return NULL;
-}
-
 static int dsa_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
 {
     DSA *dsa = from->pkey.dsa;
@@ -546,7 +507,7 @@ static int dsa_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
     int ret;
 
     if (dsa != NULL) {
-        dupkey = dsa_dup(dsa);
+        dupkey = ossl_dsa_dup(dsa, OSSL_KEYMGMT_SELECT_ALL);
         if (dupkey == NULL)
             return 0;
     }
diff --git a/crypto/dsa/dsa_backend.c b/crypto/dsa/dsa_backend.c
index f3e54aeb13..2ef8cbc9f3 100644
--- a/crypto/dsa/dsa_backend.c
+++ b/crypto/dsa/dsa_backend.c
@@ -16,6 +16,7 @@
 #include <openssl/core_names.h>
 #include <openssl/err.h>
 #include "crypto/dsa.h"
+#include "dsa_local.h"
 
 /*
  * The intention with the "backend" source file is to offer backend support
@@ -56,6 +57,55 @@ int ossl_dsa_key_fromdata(DSA *dsa, const OSSL_PARAM params[])
     return 0;
 }
 
+static ossl_inline int dsa_bn_dup_check(BIGNUM **out, const BIGNUM *f)
+{
+    if (f != NULL && (*out = BN_dup(f)) == NULL)
+        return 0;
+    return 1;
+}
+
+DSA *ossl_dsa_dup(const DSA *dsa, int selection)
+{
+    DSA *dupkey = NULL;
+
+#ifndef FIPS_MODULE
+    /* Do not try to duplicate foreign DSA keys */
+    if (DSA_get_method((DSA *)dsa) != DSA_OpenSSL())
+        return NULL;
+#endif
+
+    if ((dupkey = ossl_dsa_new(dsa->libctx)) == NULL)
+        return NULL;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0
+        && !ossl_ffc_params_copy(&dupkey->params, &dsa->params))
+        goto err;
+
+    dupkey->flags = dsa->flags;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0
+        && ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0
+            || !dsa_bn_dup_check(&dupkey->pub_key, dsa->pub_key)))
+        goto err;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0
+        && ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0
+            || !dsa_bn_dup_check(&dupkey->priv_key, dsa->priv_key)))
+        goto err;
+
+#ifndef FIPS_MODULE
+    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_DSA,
+                            &dupkey->ex_data, &dsa->ex_data))
+        goto err;
+#endif
+
+    return dupkey;
+
+ err:
+    DSA_free(dupkey);
+    return NULL;
+}
+
 #ifndef FIPS_MODULE
 DSA *ossl_dsa_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf,
                              OSSL_LIB_CTX *libctx, const char *propq)
diff --git a/crypto/ec/ec_backend.c b/crypto/ec/ec_backend.c
index 9716ffc2f2..0189a33a91 100644
--- a/crypto/ec/ec_backend.c
+++ b/crypto/ec/ec_backend.c
@@ -17,6 +17,7 @@
 #include <openssl/objects.h>
 #include <openssl/params.h>
 #include <openssl/err.h>
+#include <openssl/engine.h>
 #include "crypto/bn.h"
 #include "crypto/ec.h"
 #include "ec_local.h"
@@ -519,6 +520,93 @@ int ossl_ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
     return 1;
 }
 
+EC_KEY *ossl_ec_key_dup(const EC_KEY *src, int selection)
+{
+    EC_KEY *ret = ossl_ec_key_new_method_int(src->libctx, src->propq,
+                                             src->engine);
+
+    if (ret == NULL)
+        return NULL;
+
+    if (src == NULL) {
+        ERR_raise(ERR_LIB_EC, ERR_R_PASSED_NULL_PARAMETER);
+        goto err;
+    }
+
+    /* copy the parameters */
+    if (src->group != NULL
+        && (selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
+        ret->group = ossl_ec_group_new_ex(src->libctx, src->propq,
+                                          src->group->meth);
+        if (ret->group == NULL
+            || !EC_GROUP_copy(ret->group, src->group))
+            goto err;
+
+        if (src->meth != NULL) {
+#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE)
+            if (src->engine != NULL && ENGINE_init(src->engine) == 0)
+                goto err;
+            ret->engine = src->engine;
+#endif
+            ret->meth = src->meth;
+        }
+    }
+
+    /*  copy the public key */
+    if (src->pub_key != NULL
+        && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+        if (ret->group == NULL)
+            /* no parameter-less keys allowed */
+            goto err;
+        ret->pub_key = EC_POINT_new(ret->group);
+        if (ret->pub_key == NULL
+            || !EC_POINT_copy(ret->pub_key, src->pub_key))
+                goto err;
+    }
+
+    /* copy the private key */
+    if (src->priv_key != NULL
+        && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+        if (ret->group == NULL)
+            /* no parameter-less keys allowed */
+            goto err;
+        ret->priv_key = BN_new();
+        if (ret->priv_key == NULL || !BN_copy(ret->priv_key, src->priv_key))
+            goto err;
+        if (ret->group->meth->keycopy
+            && ret->group->meth->keycopy(ret, src) == 0)
+            goto err;
+    }
+
+    /* copy the rest */
+    if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0) {
+        ret->enc_flag = src->enc_flag;
+        ret->conv_form = src->conv_form;
+    }
+
+    ret->version = src->version;
+    ret->flags = src->flags;
+
+#ifndef FIPS_MODULE
+    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EC_KEY,
+                            &ret->ex_data, &src->ex_data))
+        goto err;
+#endif
+
+    if (ret->meth != NULL && ret->meth->copy != NULL) {
+        if ((selection
+             & OSSL_KEYMGMT_SELECT_KEYPAIR) != OSSL_KEYMGMT_SELECT_KEYPAIR)
+            goto err;
+        if (ret->meth->copy(ret, src) == 0)
+            goto err;
+    }
+
+    return ret;
+ err:
+    EC_KEY_free(ret);
+    return NULL;
+}
+
 int ossl_ec_encoding_param2id(const OSSL_PARAM *p, int *id)
 {
     const char *name = NULL;
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index 50b53f97ed..f06715fa6b 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -184,17 +184,7 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src)
 
 EC_KEY *EC_KEY_dup(const EC_KEY *ec_key)
 {
-    EC_KEY *ret = ossl_ec_key_new_method_int(ec_key->libctx, ec_key->propq,
-                                             ec_key->engine);
-
-    if (ret == NULL)
-        return NULL;
-
-    if (EC_KEY_copy(ret, ec_key) == NULL) {
-        EC_KEY_free(ret);
-        return NULL;
-    }
-    return ret;
+    return ossl_ec_key_dup(ec_key, OSSL_KEYMGMT_SELECT_ALL);
 }
 
 int EC_KEY_up_ref(EC_KEY *r)
diff --git a/crypto/ec/ecx_backend.c b/crypto/ec/ecx_backend.c
index 8f8fdc7705..3a1314626b 100644
--- a/crypto/ec/ecx_backend.c
+++ b/crypto/ec/ecx_backend.c
@@ -92,6 +92,51 @@ int ossl_ecx_key_fromdata(ECX_KEY *ecx, const OSSL_PARAM params[],
     return 1;
 }
 
+ECX_KEY *ossl_ecx_key_dup(const ECX_KEY *key, int selection)
+{
+    ECX_KEY *ret = OPENSSL_zalloc(sizeof(*ret));
+
+    if (ret == NULL) {
+        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    ret->lock = CRYPTO_THREAD_lock_new();
+    if (ret->lock == NULL) {
+        OPENSSL_free(ret);
+        return NULL;
+    }
+
+    ret->libctx = key->libctx;
+    ret->haspubkey = key->haspubkey;
+    ret->keylen = key->keylen;
+    ret->type = key->type;
+    ret->references = 1;
+
+    if (key->propq != NULL) {
+        ret->propq = OPENSSL_strdup(key->propq);
+        if (ret->propq == NULL)
+            goto err;
+    }
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        memcpy(ret->pubkey, key->pubkey, sizeof(ret->pubkey));
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0
+        && key->privkey != NULL) {
+        if (ossl_ecx_key_allocate_privkey(ret) == NULL)
+            goto err;
+        memcpy(ret->privkey, key->privkey, ret->keylen);
+    }
+
+    return ret;
+
+err:
+    ossl_ecx_key_free(ret);
+    ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
+    return NULL;
+}
+
 #ifndef FIPS_MODULE
 ECX_KEY *ossl_ecx_key_op(const X509_ALGOR *palg,
                          const unsigned char *p, int plen,
diff --git a/crypto/ec/ecx_key.c b/crypto/ec/ecx_key.c
index 60d9f3cc9f..dcec26c2e9 100644
--- a/crypto/ec/ecx_key.c
+++ b/crypto/ec/ecx_key.c
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <string.h>
 #include <openssl/err.h>
 #include "crypto/ecx.h"
 
@@ -39,7 +40,6 @@ ECX_KEY *ossl_ecx_key_new(OSSL_LIB_CTX *libctx, ECX_KEY_TYPE type, int haspubkey
 
     if (propq != NULL) {
         ret->propq = OPENSSL_strdup(propq);
-        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
         if (ret->propq == NULL)
             goto err;
     }
diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c
index 609d8609ea..61f062a2f8 100644
--- a/crypto/ec/ecx_meth.c
+++ b/crypto/ec/ecx_meth.c
@@ -406,16 +406,18 @@ static int ecx_generic_import_from(const OSSL_PARAM params[], void *vpctx,
 
 static int ecx_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
 {
-    ECX_KEY *ecx = from->pkey.ecx;
+    ECX_KEY *ecx = from->pkey.ecx, *dupkey = NULL;
     int ret;
 
-    /* We can do just up-ref as ECX keys are immutable */
-    if (ecx != NULL && !ossl_ecx_key_up_ref(ecx))
-        return 0;
+    if (ecx != NULL) {
+        dupkey = ossl_ecx_key_dup(ecx, OSSL_KEYMGMT_SELECT_ALL);
+        if (dupkey == NULL)
+            return 0;
+    }
 
-    ret = EVP_PKEY_assign(to, from->type, ecx);
+    ret = EVP_PKEY_assign(to, from->type, dupkey);
     if (!ret)
-        ossl_ecx_key_free(ecx);
+        ossl_ecx_key_free(dupkey);
     return ret;
 }
 
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index 72caf86aaf..9473d54817 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -112,7 +112,7 @@ struct evp_keymgmt_st {
     OSSL_FUNC_keymgmt_import_types_fn *import_types;
     OSSL_FUNC_keymgmt_export_fn *export;
     OSSL_FUNC_keymgmt_export_types_fn *export_types;
-    OSSL_FUNC_keymgmt_copy_fn *copy;
+    OSSL_FUNC_keymgmt_dup_fn *dup;
 } /* EVP_KEYMGMT */ ;
 
 struct evp_keyexch_st {
diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c
index 872a63ae47..80aea65e88 100644
--- a/crypto/evp/keymgmt_lib.c
+++ b/crypto/evp/keymgmt_lib.c
@@ -441,24 +441,13 @@ int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
     if (to_keymgmt == NULL)
         to_keymgmt = from->keymgmt;
 
-    if (to_keymgmt == from->keymgmt && to_keymgmt->copy != NULL) {
-        /* Make sure there's somewhere to copy to */
-        if (to_keydata == NULL
-            && ((to_keydata = alloc_keydata = evp_keymgmt_newdata(to_keymgmt))
-                == NULL)) {
-            ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
-            return 0;
-        }
-
-        /*
-         * |to| and |from| have the same keymgmt, and the copy function is
-         * implemented, so just copy and be done
-         */
-        if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata,
-                              selection)) {
-            evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
+    if (to_keymgmt == from->keymgmt && to_keymgmt->dup != NULL
+        && to_keydata == NULL) {
+        to_keydata = alloc_keydata = evp_keymgmt_dup(to_keymgmt,
+                                                     from->keydata,
+                                                     selection);
+        if (to_keydata == NULL)
             return 0;
-        }
     } else if (match_type(to_keymgmt, from->keymgmt)) {
         struct evp_keymgmt_util_try_import_data_st import_data;
 
diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c
index cdd7c70ed9..937faa99d6 100644
--- a/crypto/evp/keymgmt_meth.c
+++ b/crypto/evp/keymgmt_meth.c
@@ -129,9 +129,9 @@ static void *keymgmt_from_algorithm(int name_id,
             if (keymgmt->has == NULL)
                 keymgmt->has = OSSL_FUNC_keymgmt_has(fns);
             break;
-        case OSSL_FUNC_KEYMGMT_COPY:
-            if (keymgmt->copy == NULL)
-                keymgmt->copy = OSSL_FUNC_keymgmt_copy(fns);
+        case OSSL_FUNC_KEYMGMT_DUP:
+            if (keymgmt->dup == NULL)
+                keymgmt->dup = OSSL_FUNC_keymgmt_dup(fns);
             break;
         case OSSL_FUNC_KEYMGMT_VALIDATE:
             if (keymgmt->validate == NULL)
@@ -463,12 +463,11 @@ const OSSL_PARAM *evp_keymgmt_export_types(const EVP_KEYMGMT *keymgmt,
     return keymgmt->export_types(selection);
 }
 
-int evp_keymgmt_copy(const EVP_KEYMGMT *keymgmt,
-                     void *keydata_to, const void *keydata_from,
-                     int selection)
+void *evp_keymgmt_dup(const EVP_KEYMGMT *keymgmt, const void *keydata_from,
+                      int selection)
 {
-    /* We assume no copy if the implementation doesn't have a function */
-    if (keymgmt->copy == NULL)
-        return 0;
-    return keymgmt->copy(keydata_to, keydata_from, selection);
+    /* We assume no dup if the implementation doesn't have a function */
+    if (keymgmt->dup == NULL)
+        return NULL;
+    return keymgmt->dup(keydata_from, selection);
 }
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 0fc3af494f..de4f1811c1 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -180,10 +180,12 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
 
     /*
      * If |to| is provided, we know that |from| is legacy at this point.
-     * Try exporting |from| to |to|'s keymgmt, then use evp_keymgmt_copy()
+     * Try exporting |from| to |to|'s keymgmt, then use evp_keymgmt_dup()
      * to copy the appropriate data to |to|'s keydata.
+     * We cannot override existing data so do it only if there is no keydata
+     * in |to| yet.
      */
-    if (to->keymgmt != NULL) {
+    if (to->keymgmt != NULL && to->keydata == NULL) {
         EVP_KEYMGMT *to_keymgmt = to->keymgmt;
         void *from_keydata =
             evp_pkey_export_to_provider((EVP_PKEY *)from, NULL, &to_keymgmt,
@@ -196,8 +198,9 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
         if (from_keydata == NULL)
             ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
         else
-            ok = evp_keymgmt_copy(to->keymgmt, to->keydata, from_keydata,
-                                  SELECT_PARAMETERS);
+            ok = (to->keydata = evp_keymgmt_dup(to->keymgmt,
+                                                from_keydata,
+                                                SELECT_PARAMETERS)) != NULL;
         goto end;
     }
 
@@ -1857,7 +1860,7 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
 
         /* Synchronize the dirty count */
         pk->dirty_cnt_copy = pk->ameth->dirty_cnt(pk);
-    
+
         CRYPTO_THREAD_unlock(pk->lock);
         goto end;
     }
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index e633fa5c93..2f9d60a7b3 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -884,98 +884,6 @@ static int rsa_pss_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
     return rsa_int_import_from(params, vpctx, RSA_FLAG_TYPE_RSASSAPSS);
 }
 
-static ossl_inline int rsa_bn_dup_check(BIGNUM **out, const BIGNUM *f)
-{
-    if (f != NULL && (*out = BN_dup(f)) == NULL)
-        return 0;
-    return 1;
-}
-
-static RSA *rsa_dup(const RSA *rsa)
-{
-    RSA *dupkey = NULL;
-    int pnum, i;
-
-    /* Do not try to duplicate foreign RSA keys */
-    if (RSA_get_method(rsa) != RSA_PKCS1_OpenSSL())
-        return NULL;
-
-    if ((dupkey = ossl_rsa_new_with_ctx(rsa->libctx)) == NULL)
-        return NULL;
-
-    /* private and public key */
-    if (!rsa_bn_dup_check(&dupkey->n, rsa->n))
-        goto err;
-    if (!rsa_bn_dup_check(&dupkey->e, rsa->e))
-        goto err;
-    if (!rsa_bn_dup_check(&dupkey->d, rsa->d))
-        goto err;
-
-    /* factors and crt params */
-    if (!rsa_bn_dup_check(&dupkey->p, rsa->p))
-        goto err;
-    if (!rsa_bn_dup_check(&dupkey->q, rsa->q))
-        goto err;
-    if (!rsa_bn_dup_check(&dupkey->dmp1, rsa->dmp1))
-        goto err;
-    if (!rsa_bn_dup_check(&dupkey->dmq1, rsa->dmq1))
-        goto err;
-    if (!rsa_bn_dup_check(&dupkey->iqmp, rsa->iqmp))
-        goto err;
-
-    /* multiprime */
-    pnum = sk_RSA_PRIME_INFO_num(rsa->prime_infos);
-    if (pnum > 0) {
-        dupkey->prime_infos = sk_RSA_PRIME_INFO_new_reserve(NULL, pnum);
-        for (i = 0; i < pnum; i++) {
-            const RSA_PRIME_INFO *pinfo = NULL;
-            RSA_PRIME_INFO *duppinfo = NULL;
-
-            if ((duppinfo = OPENSSL_zalloc(sizeof(*duppinfo))) == NULL) {
-                ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-            /* push first so cleanup in error case works */
-            (void)sk_RSA_PRIME_INFO_push(dupkey->prime_infos, duppinfo);
-
-            pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
-            if (!rsa_bn_dup_check(&duppinfo->r, pinfo->r))
-                goto err;
-            if (!rsa_bn_dup_check(&duppinfo->d, pinfo->d))
-                goto err;
-            if (!rsa_bn_dup_check(&duppinfo->t, pinfo->t))
-                goto err;
-        }
-        if (!ossl_rsa_multip_calc_product(dupkey))
-            goto err;
-    }
-
-    dupkey->version = rsa->version;
-    dupkey->flags = rsa->flags;
-
-    dupkey->pss_params = rsa->pss_params;
-
-    if (rsa->pss != NULL) {
-        dupkey->pss = RSA_PSS_PARAMS_dup(rsa->pss);
-        if (rsa->pss->maskGenAlgorithm != NULL
-            && dupkey->pss->maskGenAlgorithm == NULL) {
-            dupkey->pss->maskHash = ossl_x509_algor_mgf1_decode(rsa->pss->maskGenAlgorithm);
-            if (dupkey->pss->maskHash == NULL)
-                goto err;
-        }
-    }
-
-    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_RSA,
-                            &dupkey->ex_data, &rsa->ex_data))
-        goto err;
-
-    return dupkey;
-
- err:
-    RSA_free(dupkey);
-    return NULL;
-}
-
 static int rsa_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
 {
     RSA *rsa = from->pkey.rsa;
@@ -983,7 +891,7 @@ static int rsa_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
     int ret;
 
     if (rsa != NULL) {
-        dupkey = rsa_dup(rsa);
+        dupkey = ossl_rsa_dup(rsa, OSSL_KEYMGMT_SELECT_ALL);
         if (dupkey == NULL)
             return 0;
     }
diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c
index 01ee875058..192b3fdbf7 100644
--- a/crypto/rsa/rsa_backend.c
+++ b/crypto/rsa/rsa_backend.c
@@ -22,6 +22,7 @@
 #include "internal/param_build_set.h"
 #include "crypto/asn1.h"
 #include "crypto/rsa.h"
+#include "rsa_local.h"
 
 #include "e_os.h"                /* strcasecmp for Windows() */
 
@@ -322,6 +323,108 @@ int ossl_rsa_pss_params_30_fromdata(RSA_PSS_PARAMS_30 *pss_params,
     return ret;
 }
 
+static ossl_inline int rsa_bn_dup_check(BIGNUM **out, const BIGNUM *f)
+{
+    if (f != NULL && (*out = BN_dup(f)) == NULL)
+        return 0;
+    return 1;
+}
+
+RSA *ossl_rsa_dup(const RSA *rsa, int selection)
+{
+    RSA *dupkey = NULL;
+#ifndef FIPS_MODULE
+    int pnum, i;
+
+    /* Do not try to duplicate foreign RSA keys */
+    if (RSA_get_method(rsa) != RSA_PKCS1_OpenSSL())
+        return NULL;
+#endif
+
+    if ((dupkey = ossl_rsa_new_with_ctx(rsa->libctx)) == NULL)
+        return NULL;
+
+    /* public key */
+    if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
+        if (!rsa_bn_dup_check(&dupkey->n, rsa->n))
+            goto err;
+        if (!rsa_bn_dup_check(&dupkey->e, rsa->e))
+            goto err;
+    }
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+
+        /* private key */
+        if (!rsa_bn_dup_check(&dupkey->d, rsa->d))
+            goto err;
+
+        /* factors and crt params */
+        if (!rsa_bn_dup_check(&dupkey->p, rsa->p))
+            goto err;
+        if (!rsa_bn_dup_check(&dupkey->q, rsa->q))
+            goto err;
+        if (!rsa_bn_dup_check(&dupkey->dmp1, rsa->dmp1))
+            goto err;
+        if (!rsa_bn_dup_check(&dupkey->dmq1, rsa->dmq1))
+            goto err;
+        if (!rsa_bn_dup_check(&dupkey->iqmp, rsa->iqmp))
+            goto err;
+    }
+
+    dupkey->version = rsa->version;
+    dupkey->flags = rsa->flags;
+    /* we always copy the PSS parameters regardless of selection */
+    dupkey->pss_params = rsa->pss_params;
+
+#ifndef FIPS_MODULE
+    /* multiprime */
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0
+        && (pnum = sk_RSA_PRIME_INFO_num(rsa->prime_infos)) > 0) {
+        dupkey->prime_infos = sk_RSA_PRIME_INFO_new_reserve(NULL, pnum);
+        for (i = 0; i < pnum; i++) {
+            const RSA_PRIME_INFO *pinfo = NULL;
+            RSA_PRIME_INFO *duppinfo = NULL;
+
+            if ((duppinfo = OPENSSL_zalloc(sizeof(*duppinfo))) == NULL) {
+                ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            /* push first so cleanup in error case works */
+            (void)sk_RSA_PRIME_INFO_push(dupkey->prime_infos, duppinfo);
+
+            pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
+            if (!rsa_bn_dup_check(&duppinfo->r, pinfo->r))
+                goto err;
+            if (!rsa_bn_dup_check(&duppinfo->d, pinfo->d))
+                goto err;
+            if (!rsa_bn_dup_check(&duppinfo->t, pinfo->t))
+                goto err;
+        }
+        if (!ossl_rsa_multip_calc_product(dupkey))
+            goto err;
+    }
+
+    if (rsa->pss != NULL) {
+        dupkey->pss = RSA_PSS_PARAMS_dup(rsa->pss);
+        if (rsa->pss->maskGenAlgorithm != NULL
+            && dupkey->pss->maskGenAlgorithm == NULL) {
+            dupkey->pss->maskHash = ossl_x509_algor_mgf1_decode(rsa->pss->maskGenAlgorithm);
+            if (dupkey->pss->maskHash == NULL)
+                goto err;
+        }
+    }
+    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_RSA,
+                            &dupkey->ex_data, &rsa->ex_data))
+        goto err;
+#endif
+
+    return dupkey;
+
+ err:
+    RSA_free(dupkey);
+    return NULL;
+}
+
 #ifndef FIPS_MODULE
 RSA_PSS_PARAMS *ossl_rsa_pss_decode(const X509_ALGOR *alg)
 {
diff --git a/doc/man7/provider-keymgmt.pod b/doc/man7/provider-keymgmt.pod
index 9a11b316c2..c9280bc8ef 100644
--- a/doc/man7/provider-keymgmt.pod
+++ b/doc/man7/provider-keymgmt.pod
@@ -52,8 +52,8 @@ provider-keymgmt - The KEYMGMT library E<lt>-E<gt> provider functions
                               OSSL_CALLBACK *param_cb, void *cbarg);
  const OSSL_PARAM *OSSL_FUNC_keymgmt_export_types(int selection);
 
- /* Key object copy */
- int OSSL_FUNC_keymgmt_copy(void *keydata_to, const void *keydata_from, int selection);
+ /* Key object duplication, a constructor */
+ void *OSSL_FUNC_keymgmt_dup(const void *keydata_from, int selection);
 
  /* Key object validation */
  int OSSL_FUNC_keymgmt_validate(const void *keydata, int selection, int checktype);
@@ -118,7 +118,7 @@ macros in L<openssl-core_dispatch.h(7)>, as follows:
  OSSL_FUNC_keymgmt_export               OSSL_FUNC_KEYMGMT_EXPORT
  OSSL_FUNC_keymgmt_export_types         OSSL_FUNC_KEYMGMT_EXPORT_TYPES
 
- OSSL_FUNC_keymgmt_copy                 OSSL_FUNC_KEYMGMT_COPY
+ OSSL_FUNC_keymgmt_dup                  OSSL_FUNC_KEYMGMT_DUP
 
 =head2 Key Objects
 
@@ -320,7 +320,7 @@ I<selection> in I<keydata1> and I<keydata2> match.  It is assumed that
 the caller has ensured that I<keydata1> and I<keydata2> are both owned
 by the implementation of this function.
 
-=head2 Key Object Import, Export and Copy Functions
+=head2 Key Object Import, Export and Duplication Functions
 
 OSSL_FUNC_keymgmt_import() should import data indicated by I<selection> into
 I<keydata> with values taken from the B<OSSL_PARAM> array I<params>.
@@ -337,10 +337,9 @@ OSSL_FUNC_keymgmt_export_types() should return a constant array of descriptor
 B<OSSL_PARAM> for data indicated by I<selection>, that the
 OSSL_FUNC_keymgmt_export() callback can expect to receive.
 
-OSSL_FUNC_keymgmt_copy() should copy data subsets indicated by I<selection>
-from I<keydata_from> to I<keydata_to>.  It is assumed that the caller
-has ensured that I<keydata_to> and I<keydata_from> are both owned by
-the implementation of this function.
+OSSL_FUNC_keymgmt_dup() should duplicate data subsets indicated by
+I<selection> or the whole key data I<keydata_from> and create a new
+provider side key object with the data.
 
 =head2 Common Information Parameters
 
@@ -379,8 +378,8 @@ Bits of security is defined in SP800-57.
 
 =head1 RETURN VALUES
 
-OSSL_FUNC_keymgmt_new() should return a valid reference to the newly created provider
-side key object, or NULL on failure.
+OSSL_FUNC_keymgmt_new() and OSSL_FUNC_keymgmt_dup() should return a valid
+reference to the newly created provider side key object, or NULL on failure.
 
 OSSL_FUNC_keymgmt_import(), OSSL_FUNC_keymgmt_export(), OSSL_FUNC_keymgmt_get_params() and
 OSSL_FUNC_keymgmt_set_params() should return 1 for success or 0 on error.
diff --git a/include/crypto/dh.h b/include/crypto/dh.h
index ab6115d986..291e008c9c 100644
--- a/include/crypto/dh.h
+++ b/include/crypto/dh.h
@@ -56,5 +56,6 @@ int ossl_dh_kdf_X9_42_asn1(unsigned char *out, size_t outlen,
                            const unsigned char *ukm, size_t ukmlen,
                            const EVP_MD *md,
                            OSSL_LIB_CTX *libctx, const char *propq);
+DH *ossl_dh_dup(const DH *dh, int selection);
 
 #endif  /* OSSL_CRYPTO_DH_H */
diff --git a/include/crypto/dsa.h b/include/crypto/dsa.h
index 38c49c3295..ed0c887b83 100644
--- a/include/crypto/dsa.h
+++ b/include/crypto/dsa.h
@@ -43,5 +43,6 @@ int ossl_dsa_check_pub_key_partial(const DSA *dsa, const BIGNUM *pub_key,
                                    int *ret);
 int ossl_dsa_check_priv_key(const DSA *dsa, const BIGNUM *priv_key, int *ret);
 int ossl_dsa_check_pairwise(const DSA *dsa);
+DSA *ossl_dsa_dup(const DSA *dsa, int selection);
 
 #endif
diff --git a/include/crypto/ec.h b/include/crypto/ec.h
index c679fd8d11..80b5ce0735 100644
--- a/include/crypto/ec.h
+++ b/include/crypto/ec.h
@@ -79,6 +79,7 @@ int ossl_ec_group_set_params(EC_GROUP *group, const OSSL_PARAM params[]);
 int ossl_ec_key_fromdata(EC_KEY *ecx, const OSSL_PARAM params[],
                          int include_private);
 int ossl_ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[]);
+EC_KEY *ossl_ec_key_dup(const EC_KEY *key, int selection);
 EC_KEY *ossl_ec_key_param_from_x509_algor(const X509_ALGOR *palg,
                                           OSSL_LIB_CTX *libctx,
                                           const char *propq);
diff --git a/include/crypto/ecx.h b/include/crypto/ecx.h
index 656ee94f09..82671a8f4d 100644
--- a/include/crypto/ecx.h
+++ b/include/crypto/ecx.h
@@ -83,6 +83,7 @@ void ossl_ecx_key_set0_libctx(ECX_KEY *key, OSSL_LIB_CTX *libctx);
 unsigned char *ossl_ecx_key_allocate_privkey(ECX_KEY *key);
 void ossl_ecx_key_free(ECX_KEY *key);
 int ossl_ecx_key_up_ref(ECX_KEY *key);
+ECX_KEY *ossl_ecx_key_dup(const ECX_KEY *key, int selection);
 
 int ossl_x25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
                 const uint8_t peer_public_value[32]);
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index 8ea5a2bf35..88a1c3d857 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -810,9 +810,8 @@ int evp_keymgmt_export(const EVP_KEYMGMT *keymgmt, void *keydata,
                        int selection, OSSL_CALLBACK *param_cb, void *cbarg);
 const OSSL_PARAM *evp_keymgmt_export_types(const EVP_KEYMGMT *keymgmt,
                                            int selection);
-int evp_keymgmt_copy(const EVP_KEYMGMT *keymgmt,
-                     void *keydata_to, const void *keydata_from,
-                     int selection);
+void *evp_keymgmt_dup(const EVP_KEYMGMT *keymgmt,
+                      const void *keydata_from, int selection);
 
 /* Pulling defines out of C source files */
 
diff --git a/include/crypto/rsa.h b/include/crypto/rsa.h
index 73bf03f615..f252363465 100644
--- a/include/crypto/rsa.h
+++ b/include/crypto/rsa.h
@@ -63,6 +63,7 @@ int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes,
 int ossl_rsa_get0_all_params(RSA *r, STACK_OF(BIGNUM_const) *primes,
                              STACK_OF(BIGNUM_const) *exps,
                              STACK_OF(BIGNUM_const) *coeffs);
+RSA *ossl_rsa_dup(const RSA *rsa, int selection);
 
 int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[]);
 int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[]);
diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h
index 1cc2ebcc57..5385b65169 100644
--- a/include/openssl/core_dispatch.h
+++ b/include/openssl/core_dispatch.h
@@ -595,11 +595,10 @@ OSSL_CORE_MAKE_FUNC(int, keymgmt_export,
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, keymgmt_export_types,
                     (int selection))
 
-/* Copy function, only works for matching keymgmt */
-# define OSSL_FUNC_KEYMGMT_COPY                       44
-OSSL_CORE_MAKE_FUNC(int, keymgmt_copy,
-                    ( void *keydata_to, const void *keydata_from,
-                     int selection))
+/* Dup function, constructor */
+# define OSSL_FUNC_KEYMGMT_DUP                        44
+OSSL_CORE_MAKE_FUNC(void *, keymgmt_dup,
+                    (const void *keydata_from, int selection))
 
 /* Key Exchange */
 
diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c
index ba56abe04a..b3678c5e2a 100644
--- a/providers/implementations/keymgmt/dh_kmgmt.c
+++ b/providers/implementations/keymgmt/dh_kmgmt.c
@@ -45,6 +45,7 @@ static OSSL_FUNC_keymgmt_import_fn dh_import;
 static OSSL_FUNC_keymgmt_import_types_fn dh_import_types;
 static OSSL_FUNC_keymgmt_export_fn dh_export;
 static OSSL_FUNC_keymgmt_export_types_fn dh_export_types;
+static OSSL_FUNC_keymgmt_dup_fn dh_dup;
 
 #define DH_POSSIBLE_SELECTIONS                                                 \
     (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
@@ -707,7 +708,7 @@ static void dh_gen_cleanup(void *genctx)
     OPENSSL_free(gctx);
 }
 
-void *dh_load(const void *reference, size_t reference_sz)
+static void *dh_load(const void *reference, size_t reference_sz)
 {
     DH *dh = NULL;
 
@@ -721,6 +722,13 @@ void *dh_load(const void *reference, size_t reference_sz)
     return NULL;
 }
 
+static void *dh_dup(const void *keydata_from, int selection)
+{
+    if (ossl_prov_is_running())
+        return ossl_dh_dup(keydata_from, selection);
+    return NULL;
+}
+
 const OSSL_DISPATCH ossl_dh_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dh_newdata },
     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dh_gen_init },
@@ -743,6 +751,7 @@ const OSSL_DISPATCH ossl_dh_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types },
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export },
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup },
     { 0, NULL }
 };
 
@@ -776,5 +785,6 @@ const OSSL_DISPATCH ossl_dhx_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dh_export_types },
     { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
       (void (*)(void))dhx_query_operation_name },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dh_dup },
     { 0, NULL }
 };
diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c
index 15a40df260..38e682f3b6 100644
--- a/providers/implementations/keymgmt/dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/dsa_kmgmt.c
@@ -44,6 +44,7 @@ static OSSL_FUNC_keymgmt_import_fn dsa_import;
 static OSSL_FUNC_keymgmt_import_types_fn dsa_import_types;
 static OSSL_FUNC_keymgmt_export_fn dsa_export;
 static OSSL_FUNC_keymgmt_export_types_fn dsa_export_types;
+static OSSL_FUNC_keymgmt_dup_fn dsa_dup;
 
 #define DSA_DEFAULT_MD "SHA256"
 #define DSA_POSSIBLE_SELECTIONS                                                \
@@ -597,7 +598,7 @@ static void dsa_gen_cleanup(void *genctx)
     OPENSSL_free(gctx);
 }
 
-void *dsa_load(const void *reference, size_t reference_sz)
+static void *dsa_load(const void *reference, size_t reference_sz)
 {
     DSA *dsa = NULL;
 
@@ -611,6 +612,13 @@ void *dsa_load(const void *reference, size_t reference_sz)
     return NULL;
 }
 
+static void *dsa_dup(const void *keydata_from, int selection)
+{
+    if (ossl_prov_is_running())
+        return ossl_dsa_dup(keydata_from, selection);
+    return NULL;
+}
+
 const OSSL_DISPATCH ossl_dsa_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dsa_newdata },
     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dsa_gen_init },
@@ -631,5 +639,6 @@ const OSSL_DISPATCH ossl_dsa_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dsa_import_types },
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dsa_export },
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))dsa_export_types },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))dsa_dup },
     { 0, NULL }
 };
diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c
index fe5bd7a28a..f563d920c4 100644
--- a/providers/implementations/keymgmt/ec_kmgmt.c
+++ b/providers/implementations/keymgmt/ec_kmgmt.c
@@ -55,6 +55,7 @@ static OSSL_FUNC_keymgmt_import_types_fn ec_import_types;
 static OSSL_FUNC_keymgmt_export_fn ec_export;
 static OSSL_FUNC_keymgmt_export_types_fn ec_export_types;
 static OSSL_FUNC_keymgmt_query_operation_name_fn ec_query_operation_name;
+static OSSL_FUNC_keymgmt_dup_fn ec_dup;
 #ifndef FIPS_MODULE
 # ifndef OPENSSL_NO_SM2
 static OSSL_FUNC_keymgmt_new_fn sm2_newdata;
@@ -1361,6 +1362,13 @@ static void *sm2_load(const void *reference, size_t reference_sz)
 # endif
 #endif
 
+static void *ec_dup(const void *keydata_from, int selection)
+{
+    if (ossl_prov_is_running())
+        return ossl_ec_key_dup(keydata_from, selection);
+    return NULL;
+}
+
 const OSSL_DISPATCH ossl_ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata },
     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))ec_gen_init },
@@ -1386,6 +1394,7 @@ const OSSL_DISPATCH ossl_ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_export_types },
     { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
       (void (*)(void))ec_query_operation_name },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ec_dup },
     { 0, NULL }
 };
 
@@ -1416,6 +1425,7 @@ const OSSL_DISPATCH ossl_sm2_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_export_types },
     { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
       (void (*)(void))sm2_query_operation_name },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ec_dup },
     { 0, NULL }
 };
 # endif
diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c
index a0284325cc..45593be544 100644
--- a/providers/implementations/keymgmt/ecx_kmgmt.c
+++ b/providers/implementations/keymgmt/ecx_kmgmt.c
@@ -71,6 +71,7 @@ static OSSL_FUNC_keymgmt_import_fn ecx_import;
 static OSSL_FUNC_keymgmt_import_types_fn ecx_imexport_types;
 static OSSL_FUNC_keymgmt_export_fn ecx_export;
 static OSSL_FUNC_keymgmt_export_types_fn ecx_imexport_types;
+static OSSL_FUNC_keymgmt_dup_fn ecx_dup;
 
 #define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
 
@@ -691,6 +692,13 @@ void *ecx_load(const void *reference, size_t reference_sz)
     return NULL;
 }
 
+static void *ecx_dup(const void *keydata_from, int selection)
+{
+    if (ossl_prov_is_running())
+        return ossl_ecx_key_dup(keydata_from, selection);
+    return NULL;
+}
+
 static int ecx_key_pairwise_check(const ECX_KEY *ecx, int type)
 {
     uint8_t pub[64];
@@ -788,6 +796,7 @@ static int ed448_validate(const void *keydata, int selection, int checktype)
         { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))alg##_gen }, \
         { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ecx_gen_cleanup }, \
         { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))ecx_load }, \
+        { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ecx_dup }, \
         { 0, NULL } \
     };
 
diff --git a/providers/implementations/keymgmt/rsa_kmgmt.c b/providers/implementations/keymgmt/rsa_kmgmt.c
index fbd99e3dc8..a075c54487 100644
--- a/providers/implementations/keymgmt/rsa_kmgmt.c
+++ b/providers/implementations/keymgmt/rsa_kmgmt.c
@@ -49,6 +49,7 @@ static OSSL_FUNC_keymgmt_import_types_fn rsa_import_types;
 static OSSL_FUNC_keymgmt_export_fn rsa_export;
 static OSSL_FUNC_keymgmt_export_types_fn rsa_export_types;
 static OSSL_FUNC_keymgmt_query_operation_name_fn rsa_query_operation_name;
+static OSSL_FUNC_keymgmt_dup_fn rsa_dup;
 
 #define RSA_DEFAULT_MD "SHA256"
 #define RSA_PSS_DEFAULT_MD OSSL_DIGEST_NAME_SHA1
@@ -305,15 +306,16 @@ static int rsa_get_params(void *key, OSSL_PARAM params[])
     const RSA_PSS_PARAMS_30 *pss_params = ossl_rsa_get0_pss_params_30(rsa);
     int rsa_type = RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK);
     OSSL_PARAM *p;
+    int empty = RSA_get0_n(rsa) == NULL;
 
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
-        && !OSSL_PARAM_set_int(p, RSA_bits(rsa)))
+        && (empty || !OSSL_PARAM_set_int(p, RSA_bits(rsa))))
         return 0;
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL
-        && !OSSL_PARAM_set_int(p, RSA_security_bits(rsa)))
+        && (empty || !OSSL_PARAM_set_int(p, RSA_security_bits(rsa))))
         return 0;
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
-        && !OSSL_PARAM_set_int(p, RSA_size(rsa)))
+        && (empty || !OSSL_PARAM_set_int(p, RSA_size(rsa))))
         return 0;
 
     /*
@@ -645,6 +647,15 @@ static void *rsapss_load(const void *reference, size_t reference_sz)
     return common_load(reference, reference_sz, RSA_FLAG_TYPE_RSASSAPSS);
 }
 
+static void *rsa_dup(const void *keydata_from, int selection)
+{
+    if (ossl_prov_is_running()
+        /* do not allow creating empty keys by duplication */
+        && (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
+        return ossl_rsa_dup(keydata_from, selection);
+    return NULL;
+}
+
 /* For any RSA key, we use the "RSA" algorithms regardless of sub-type. */
 static const char *rsa_query_operation_name(int operation_id)
 {
@@ -671,6 +682,7 @@ const OSSL_DISPATCH ossl_rsa_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))rsa_import_types },
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))rsa_export },
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))rsa_export_types },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))rsa_dup },
     { 0, NULL }
 };
 
@@ -695,5 +707,6 @@ const OSSL_DISPATCH ossl_rsapss_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))rsa_export_types },
     { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
       (void (*)(void))rsa_query_operation_name },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))rsa_dup },
     { 0, NULL }
 };
diff --git a/test/tls-provider.c b/test/tls-provider.c
index 1085273a32..482c3aa0da 100644
--- a/test/tls-provider.c
+++ b/test/tls-provider.c
@@ -52,7 +52,7 @@ typedef struct xorkey_st {
 static OSSL_FUNC_keymgmt_new_fn xor_newdata;
 static OSSL_FUNC_keymgmt_free_fn xor_freedata;
 static OSSL_FUNC_keymgmt_has_fn xor_has;
-static OSSL_FUNC_keymgmt_copy_fn xor_copy;
+static OSSL_FUNC_keymgmt_dup_fn xor_dup;
 static OSSL_FUNC_keymgmt_gen_init_fn xor_gen_init;
 static OSSL_FUNC_keymgmt_gen_set_params_fn xor_gen_set_params;
 static OSSL_FUNC_keymgmt_gen_settable_params_fn xor_gen_settable_params;
@@ -440,9 +440,9 @@ static int xor_has(const void *vkey, int selection)
     return ok;
 }
 
-static int xor_copy(void *vtokey, const void *vfromkey, int selection)
+static void *xor_dup(const void *vfromkey, int selection)
 {
-    XORKEY *tokey = vtokey;
+    XORKEY *tokey = xor_newdata(NULL);
     const XORKEY *fromkey = vfromkey;
     int ok = 0;
 
@@ -466,7 +466,11 @@ static int xor_copy(void *vtokey, const void *vfromkey, int selection)
             }
         }
     }
-    return ok;
+    if (!ok) {
+        xor_freedata(tokey);
+        tokey = NULL;
+    }
+    return tokey;
 }
 
 static ossl_inline int xor_get_params(void *vkey, OSSL_PARAM params[])
@@ -706,7 +710,7 @@ static const OSSL_DISPATCH xor_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))xor_set_params },
     { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))xor_settable_params },
     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))xor_has },
-    { OSSL_FUNC_KEYMGMT_COPY, (void (*)(void))xor_copy },
+    { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))xor_dup },
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))xor_freedata },
     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))xor_import },
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))xor_import_types },


More information about the openssl-commits mailing list