summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Mraz <tomas@openssl.org>2021-03-19 18:45:43 +0100
committerPauli <pauli@openssl.org>2021-03-28 16:38:57 +1000
commit2145ba5e8383184d7f212500ec2f759bdf08503a (patch)
treea862106cc508e75f170b3105e3b5919fb38219d3
parentc464583483df70ad8df9907168bf015d672742bd (diff)
Implement EVP_PKEY_dup() function
Fixes #14501 Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14624)
-rw-r--r--crypto/dh/dh_ameth.c60
-rw-r--r--crypto/dsa/dsa_ameth.c62
-rw-r--r--crypto/ec/ec_ameth.c22
-rw-r--r--crypto/ec/ecx_meth.c19
-rw-r--r--crypto/evp/p_lib.c55
-rw-r--r--crypto/ffc/ffc_params.c1
-rw-r--r--crypto/rsa/rsa_ameth.c116
-rw-r--r--crypto/rsa/rsa_asn1.c1
-rw-r--r--crypto/x509/x509_att.c24
-rw-r--r--doc/man3/EVP_PKEY_new.pod11
-rw-r--r--doc/man3/X509_dup.pod1
-rw-r--r--include/crypto/asn1.h1
-rw-r--r--include/crypto/x509.h2
-rw-r--r--include/openssl/evp.h1
-rw-r--r--include/openssl/rsa.h1
-rw-r--r--test/ecdsatest.c7
-rw-r--r--test/evp_extra_test.c36
-rw-r--r--test/evp_libctx_test.c20
-rw-r--r--test/evp_pkey_provided_test.c627
-rw-r--r--test/keymgmt_internal_test.c67
-rw-r--r--util/libcrypto.num2
21 files changed, 854 insertions, 282 deletions
diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index ffaf41d802..0ed057dd8d 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -536,6 +536,64 @@ 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;
+ DH *dupkey = NULL;
+ int ret;
+
+ if (dh != NULL) {
+ dupkey = dh_dup(dh);
+ if (dupkey == NULL)
+ return 0;
+ }
+
+ ret = EVP_PKEY_assign(to, from->type, dupkey);
+ if (!ret)
+ DH_free(dupkey);
+ return ret;
+}
+
const EVP_PKEY_ASN1_METHOD ossl_dh_asn1_meth = {
EVP_PKEY_DH,
EVP_PKEY_DH,
@@ -579,6 +637,7 @@ const EVP_PKEY_ASN1_METHOD ossl_dh_asn1_meth = {
dh_pkey_dirty_cnt,
dh_pkey_export_to,
dh_pkey_import_from,
+ dh_pkey_copy
};
const EVP_PKEY_ASN1_METHOD ossl_dhx_asn1_meth = {
@@ -622,4 +681,5 @@ const EVP_PKEY_ASN1_METHOD ossl_dhx_asn1_meth = {
dh_pkey_dirty_cnt,
dh_pkey_export_to,
dhx_pkey_import_from,
+ dh_pkey_copy
};
diff --git a/crypto/dsa/dsa_ameth.c b/crypto/dsa/dsa_ameth.c
index e4c739daf9..1009f1a5c7 100644
--- a/crypto/dsa/dsa_ameth.c
+++ b/crypto/dsa/dsa_ameth.c
@@ -475,7 +475,7 @@ static int dsa_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
rv = evp_keymgmt_import(to_keymgmt, to_keydata, selection, params);
OSSL_PARAM_BLD_free_params(params);
-err:
+ err:
OSSL_PARAM_BLD_free(tmpl);
return rv;
}
@@ -500,6 +500,63 @@ 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;
+ DSA *dupkey = NULL;
+ int ret;
+
+ if (dsa != NULL) {
+ dupkey = dsa_dup(dsa);
+ if (dupkey == NULL)
+ return 0;
+ }
+
+ ret = EVP_PKEY_assign_DSA(to, dupkey);
+ if (!ret)
+ DSA_free(dupkey);
+ return ret;
+}
+
/* NB these are sorted in pkey_id order, lowest first */
const EVP_PKEY_ASN1_METHOD ossl_dsa_asn1_meths[5] = {
@@ -564,6 +621,7 @@ const EVP_PKEY_ASN1_METHOD ossl_dsa_asn1_meths[5] = {
dsa_pkey_dirty_cnt,
dsa_pkey_export_to,
- dsa_pkey_import_from
+ dsa_pkey_import_from,
+ dsa_pkey_copy
}
};
diff --git a/crypto/ec/ec_ameth.c b/crypto/ec/ec_ameth.c
index 69370d6bc1..273663d89e 100644
--- a/crypto/ec/ec_ameth.c
+++ b/crypto/ec/ec_ameth.c
@@ -640,6 +640,27 @@ static int ec_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
return 1;
}
+static int ec_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
+{
+ EC_KEY *eckey = from->pkey.ec;
+ EC_KEY *dupkey = NULL;
+ int ret;
+
+ if (eckey != NULL) {
+ dupkey = EC_KEY_dup(eckey);
+ if (dupkey == NULL)
+ return 0;
+ } else {
+ /* necessary to properly copy empty SM2 keys */
+ return EVP_PKEY_set_type(to, from->type);
+ }
+
+ ret = EVP_PKEY_assign_EC_KEY(to, dupkey);
+ if (!ret)
+ EC_KEY_free(dupkey);
+ return ret;
+}
+
const EVP_PKEY_ASN1_METHOD ossl_eckey_asn1_meth = {
EVP_PKEY_EC,
EVP_PKEY_EC,
@@ -687,6 +708,7 @@ const EVP_PKEY_ASN1_METHOD ossl_eckey_asn1_meth = {
ec_pkey_dirty_cnt,
ec_pkey_export_to,
ec_pkey_import_from,
+ ec_pkey_copy,
eckey_priv_decode_ex
};
diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c
index 00896f4186..c4d534e48c 100644
--- a/crypto/ec/ecx_meth.c
+++ b/crypto/ec/ecx_meth.c
@@ -404,6 +404,21 @@ static int ecx_generic_import_from(const OSSL_PARAM params[], void *vpctx,
return 1;
}
+static int ecx_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
+{
+ ECX_KEY *ecx = from->pkey.ecx;
+ int ret;
+
+ /* We can do just up-ref as ECX keys are immutable */
+ if (ecx != NULL && !ossl_ecx_key_up_ref(ecx))
+ return 0;
+
+ ret = EVP_PKEY_assign(to, from->type, ecx);
+ if (!ret)
+ ossl_ecx_key_free(ecx);
+ return ret;
+}
+
static int x25519_import_from(const OSSL_PARAM params[], void *vpctx)
{
return ecx_generic_import_from(params, vpctx, EVP_PKEY_X25519);
@@ -453,6 +468,7 @@ const EVP_PKEY_ASN1_METHOD ossl_ecx25519_asn1_meth = {
ecx_pkey_dirty_cnt,
ecx_pkey_export_to,
x25519_import_from,
+ ecx_pkey_copy,
ecx_priv_decode_ex
};
@@ -506,6 +522,7 @@ const EVP_PKEY_ASN1_METHOD ossl_ecx448_asn1_meth = {
ecx_pkey_dirty_cnt,
ecx_pkey_export_to,
x448_import_from,
+ ecx_pkey_copy,
ecx_priv_decode_ex
};
@@ -632,6 +649,7 @@ const EVP_PKEY_ASN1_METHOD ossl_ed25519_asn1_meth = {
ecx_pkey_dirty_cnt,
ecx_pkey_export_to,
ed25519_import_from,
+ ecx_pkey_copy,
ecx_priv_decode_ex
};
@@ -684,6 +702,7 @@ const EVP_PKEY_ASN1_METHOD ossl_ed448_asn1_meth = {
ecx_pkey_dirty_cnt,
ecx_pkey_export_to,
ed448_import_from,
+ ecx_pkey_copy,
ecx_priv_decode_ex
};
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 94a83c4804..d424106360 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -39,6 +39,7 @@
#include "crypto/evp.h"
#include "crypto/ec.h"
#include "crypto/ecx.h"
+#include "crypto/x509.h"
#include "internal/provider.h"
#include "evp_local.h"
@@ -1578,6 +1579,60 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey)
}
#ifndef FIPS_MODULE
+EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey)
+{
+ EVP_PKEY *dup_pk;
+
+ if (pkey == NULL) {
+ ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
+ }
+
+ if ((dup_pk = EVP_PKEY_new()) == NULL)
+ return NULL;
+
+ if (evp_pkey_is_blank(pkey))
+ goto done;
+
+ if (evp_pkey_is_provided(pkey)) {
+ if (!evp_keymgmt_util_copy(dup_pk, pkey,
+ OSSL_KEYMGMT_SELECT_ALL))
+ goto err;
+ goto done;
+ }
+
+ if (evp_pkey_is_legacy(pkey)) {
+ const EVP_PKEY_ASN1_METHOD *ameth = pkey->ameth;
+
+ if (ameth == NULL || ameth->copy == NULL) {
+ if (pkey->pkey.ptr == NULL /* empty key, just set type */
+ && EVP_PKEY_set_type(dup_pk, pkey->type) != 0)
+ goto done;
+ ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_TYPE);
+ goto err;
+ }
+ if (!ameth->copy(dup_pk, pkey))
+ goto err;
+ goto done;
+ }
+
+ goto err;
+done:
+ /* copy auxiliary data */
+ if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EVP_PKEY,
+ &dup_pk->ex_data, &pkey->ex_data))
+ goto err;
+
+ if (pkey->attributes != NULL) {
+ if ((dup_pk->attributes = ossl_x509at_dup(pkey->attributes)) == NULL)
+ goto err;
+ }
+ return dup_pk;
+err:
+ EVP_PKEY_free(dup_pk);
+ return NULL;
+}
+
void evp_pkey_free_legacy(EVP_PKEY *x)
{
const EVP_PKEY_ASN1_METHOD *ameth = x->ameth;
diff --git a/crypto/ffc/ffc_params.c b/crypto/ffc/ffc_params.c
index 43064c0222..1bdee0bb6b 100644
--- a/crypto/ffc/ffc_params.c
+++ b/crypto/ffc/ffc_params.c
@@ -196,6 +196,7 @@ int ossl_ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src)
dst->pcounter = src->pcounter;
dst->h = src->h;
dst->gindex = src->gindex;
+ dst->flags = src->flags;
return 1;
}
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index 7a747a33ef..2155eaccd6 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -884,6 +884,116 @@ 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;
+ RSA *dupkey = NULL;
+ int ret;
+
+ if (rsa != NULL) {
+ dupkey = rsa_dup(rsa);
+ if (dupkey == NULL)
+ return 0;
+ }
+
+ ret = EVP_PKEY_assign(to, from->type, dupkey);
+ if (!ret)
+ RSA_free(dupkey);
+ return ret;
+}
+
const EVP_PKEY_ASN1_METHOD ossl_rsa_asn1_meths[2] = {
{
EVP_PKEY_RSA,
@@ -923,7 +1033,8 @@ const EVP_PKEY_ASN1_METHOD ossl_rsa_asn1_meths[2] = {
rsa_pkey_dirty_cnt,
rsa_pkey_export_to,
- rsa_pkey_import_from
+ rsa_pkey_import_from,
+ rsa_pkey_copy
},
{
@@ -969,5 +1080,6 @@ const EVP_PKEY_ASN1_METHOD ossl_rsa_pss_asn1_meth = {
rsa_pkey_dirty_cnt,
rsa_pss_pkey_export_to,
- rsa_pss_pkey_import_from
+ rsa_pss_pkey_import_from,
+ rsa_pkey_copy
};
diff --git a/crypto/rsa/rsa_asn1.c b/crypto/rsa/rsa_asn1.c
index c5799d8e4d..42fa20b6f0 100644
--- a/crypto/rsa/rsa_asn1.c
+++ b/crypto/rsa/rsa_asn1.c
@@ -92,6 +92,7 @@ ASN1_SEQUENCE_cb(RSA_PSS_PARAMS, rsa_pss_cb) = {
} ASN1_SEQUENCE_END_cb(RSA_PSS_PARAMS, RSA_PSS_PARAMS)
IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
+IMPLEMENT_ASN1_DUP_FUNCTION(RSA_PSS_PARAMS)
/* Free up maskHash */
static int rsa_oaep_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c
index 6a949f190e..52cad9a047 100644
--- a/crypto/x509/x509_att.c
+++ b/crypto/x509/x509_att.c
@@ -15,6 +15,7 @@
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "crypto/x509.h"
#include "x509_local.h"
int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
@@ -84,8 +85,9 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
if (*x == NULL) {
if ((sk = sk_X509_ATTRIBUTE_new_null()) == NULL)
goto err;
- } else
+ } else {
sk = *x;
+ }
if ((new_attr = X509_ATTRIBUTE_dup(attr)) == NULL)
goto err2;
@@ -98,7 +100,8 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
err2:
X509_ATTRIBUTE_free(new_attr);
- sk_X509_ATTRIBUTE_free(sk);
+ if (*x == NULL)
+ sk_X509_ATTRIBUTE_free(sk);
return NULL;
}
@@ -165,6 +168,23 @@ void *X509at_get0_data_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *x,
return X509_ATTRIBUTE_get0_data(at, 0, type, NULL);
}
+STACK_OF(X509_ATTRIBUTE) *ossl_x509at_dup(const STACK_OF(X509_ATTRIBUTE) *x)
+{
+ int i, n;
+ STACK_OF(X509_ATTRIBUTE) *sk = NULL;
+
+ n = sk_X509_ATTRIBUTE_num(x);
+ for (i = 0; i < n; ++i) {
+ X509_ATTRIBUTE *attr = sk_X509_ATTRIBUTE_value(x, i);
+
+ if (X509at_add1_attr(&sk, attr) == NULL) {
+ sk_X509_ATTRIBUTE_pop_free(sk, X509_ATTRIBUTE_free);
+ return NULL;
+ }
+ }
+ return sk;
+}
+
X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
int atrtype, const void *data,
int len)
diff --git a/doc/man3/EVP_PKEY_new.pod b/doc/man3/EVP_PKEY_new.pod
index 4eaedba44d..ee55396de3 100644
--- a/doc/man3/EVP_PKEY_new.pod
+++ b/doc/man3/EVP_PKEY_new.pod
@@ -5,6 +5,7 @@
EVP_PKEY,
EVP_PKEY_new,
EVP_PKEY_up_ref,
+EVP_PKEY_dup,
EVP_PKEY_free,
EVP_PKEY_new_raw_private_key_ex,
EVP_PKEY_new_raw_private_key,
@@ -24,6 +25,7 @@ EVP_PKEY_get_raw_public_key
EVP_PKEY *EVP_PKEY_new(void);
int EVP_PKEY_up_ref(EVP_PKEY *key);
+ EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *key);
void EVP_PKEY_free(EVP_PKEY *key);
EVP_PKEY *EVP_PKEY_new_raw_private_key_ex(OSSL_LIB_CTX *libctx,
@@ -82,6 +84,9 @@ B<1>.
EVP_PKEY_up_ref() increments the reference count of I<key>.
+EVP_PKEY_dup() duplicates the I<key>. The I<key> must not be ENGINE based or
+a raw key, otherwise the duplication will fail.
+
EVP_PKEY_free() decrements the reference count of I<key> and, if the reference
count is zero, frees it up. If I<key> is NULL, nothing is done.
@@ -169,7 +174,9 @@ L<EVP_PKEY_set1_EC_KEY(3)>.
EVP_PKEY_new(), EVP_PKEY_new_raw_private_key(), EVP_PKEY_new_raw_public_key(),
EVP_PKEY_new_CMAC_key() and EVP_PKEY_new_mac_key() return either the newly
-allocated B<EVP_PKEY> structure or B<NULL> if an error occurred.
+allocated B<EVP_PKEY> structure or NULL if an error occurred.
+
+EVP_PKEY_dup() returns the key duplicate or NULL if an error occurred.
EVP_PKEY_up_ref(), EVP_PKEY_get_raw_private_key() and
EVP_PKEY_get_raw_public_key() return 1 for success and 0 for failure.
@@ -191,7 +198,7 @@ EVP_PKEY_new_raw_private_key(), EVP_PKEY_new_raw_public_key(),
EVP_PKEY_new_CMAC_key(), EVP_PKEY_new_raw_private_key() and
EVP_PKEY_get_raw_public_key() functions were added in OpenSSL 1.1.1.
-The EVP_PKEY_new_raw_private_key_ex() and
+The EVP_PKEY_dup(), EVP_PKEY_new_raw_private_key_ex(), and
EVP_PKEY_new_raw_public_key_ex()
functions were added in OpenSSL 3.0.
diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod
index 5bf96bb575..65df06c830 100644
--- a/doc/man3/X509_dup.pod
+++ b/doc/man3/X509_dup.pod
@@ -231,6 +231,7 @@ RSA_OAEP_PARAMS_free,
RSA_OAEP_PARAMS_new,
RSA_PSS_PARAMS_free,
RSA_PSS_PARAMS_new,
+RSA_PSS_PARAMS_dup,
SCRYPT_PARAMS_free,
SCRYPT_PARAMS_new,
SXNETID_free,
diff --git a/include/crypto/asn1.h b/include/crypto/asn1.h
index b812bdd614..17d5f637ef 100644
--- a/include/crypto/asn1.h
+++ b/include/crypto/asn1.h
@@ -83,6 +83,7 @@ struct evp_pkey_asn1_method_st {
EVP_KEYMGMT *to_keymgmt, OSSL_LIB_CTX *libctx,
const char *propq);
OSSL_CALLBACK *import_from;
+ int (*copy) (EVP_PKEY *to, EVP_PKEY *from);
int (*priv_decode_ex) (EVP_PKEY *pk,
const PKCS8_PRIV_KEY_INFO *p8inf,
diff --git a/include/crypto/x509.h b/include/crypto/x509.h
index 3ff903541f..936ab790de 100644
--- a/include/crypto/x509.h
+++ b/include/crypto/x509.h
@@ -325,6 +325,8 @@ int ossl_x509_add_cert_new(STACK_OF(X509) **sk, X509 *cert, int flags);
int ossl_x509_add_certs_new(STACK_OF(X509) **p_sk, STACK_OF(X509) *certs,
int flags);
+STACK_OF(X509_ATTRIBUTE) *ossl_x509at_dup(const STACK_OF(X509_ATTRIBUTE) *x);
+
int ossl_x509_PUBKEY_get0_libctx(OSSL_LIB_CTX **plibctx, const char **ppropq,
const X509_PUBKEY *key);
/* Calculate default key identifier according to RFC 5280 section 4.2.1.2 (1) */
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 9f3efbd2f5..26a97008ba 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -1318,6 +1318,7 @@ struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
EVP_PKEY *EVP_PKEY_new(void);
int EVP_PKEY_up_ref(EVP_PKEY *pkey);
+EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey);
void EVP_PKEY_free(EVP_PKEY *pkey);
EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp,
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h
index 8822345d5a..573ba003cc 100644
--- a/include/openssl/rsa.h
+++ b/include/openssl/rsa.h
@@ -319,6 +319,7 @@ struct rsa_pss_params_st {
};
DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
+DECLARE_ASN1_DUP_FUNCTION(RSA_PSS_PARAMS)
typedef struct rsa_oaep_params_st {
X509_ALGOR *hashFunc;
diff --git a/test/ecdsatest.c b/test/ecdsatest.c
index 38486f5955..2cd7b970a2 100644
--- a/test/ecdsatest.c
+++ b/test/ecdsatest.c
@@ -190,7 +190,7 @@ static int test_builtin(int n, int as)
EC_KEY *eckey_neg = NULL, *eckey = NULL;
unsigned char dirt, offset, tbs[128];
unsigned char *sig = NULL;
- EVP_PKEY *pkey_neg = NULL, *pkey = NULL;
+ EVP_PKEY *pkey_neg = NULL, *pkey = NULL, *dup_pk = NULL;
EVP_MD_CTX *mctx = NULL;
size_t sig_len;
int nid, ret = 0;
@@ -237,6 +237,10 @@ static int test_builtin(int n, int as)
|| !TEST_true(EVP_PKEY_assign_EC_KEY(pkey_neg, eckey_neg)))
goto err;
+ if (!TEST_ptr(dup_pk = EVP_PKEY_dup(pkey))
+ || !TEST_int_eq(EVP_PKEY_eq(pkey, dup_pk), 1))
+ goto err;
+
temp = ECDSA_size(eckey);
/*
@@ -337,6 +341,7 @@ static int test_builtin(int n, int as)
err:
EVP_PKEY_free(pkey);
EVP_PKEY_free(pkey_neg);
+ EVP_PKEY_free(dup_pk);
EVP_MD_CTX_free(mctx);
OPENSSL_free(sig);
return ret;
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 859ef4cb91..a3d0a319e8 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -752,7 +752,7 @@ static int test_EC_priv_only_legacy(void)
BIGNUM *priv = NULL;
int ret = 0;
EC_KEY *eckey = NULL;
- EVP_PKEY *pkey = NULL;
+ EVP_PKEY *pkey = NULL, *dup_pk = NULL;
EVP_MD_CTX *ctx = NULL;
/* Create the low level EC_KEY */
@@ -774,19 +774,31 @@ static int test_EC_priv_only_legacy(void)
goto err;
eckey = NULL;
- ctx = EVP_MD_CTX_new();
- if (!TEST_ptr(ctx))
- goto err;
+ while (dup_pk == NULL) {
+ ret = 0;
+ ctx = EVP_MD_CTX_new();
+ if (!TEST_ptr(ctx))
+ goto err;
- /*
- * The EVP_DigestSignInit function should create the key on the provider
- * side which is sufficient for this test.
- */
- if (!TEST_true(EVP_DigestSignInit_ex(ctx, NULL, NULL, testctx, testpropq,
- pkey, NULL)))
- goto err;
+ /*
+ * The EVP_DigestSignInit function should create the key on the
+ * provider side which is sufficient for this test.
+ */
+ if (!TEST_true(EVP_DigestSignInit_ex(ctx, NULL, NULL, testctx,
+ testpropq, pkey, NULL)))
+ goto err;
+ EVP_MD_CTX_free(ctx);
+ ctx = NULL;
- ret = 1;
+ if (!TEST_ptr(dup_pk = EVP_PKEY_dup(pkey)))
+ goto err;
+ /* EVP_PKEY_eq() returns -2 with missing public keys */
+ ret = TEST_int_eq(EVP_PKEY_eq(pkey, dup_pk), -2);
+ EVP_PKEY_free(pkey);
+ pkey = dup_pk;
+ if (!ret)
+ goto err;
+ }
err:
EVP_MD_CTX_free(ctx);
diff --git a/test/evp_libctx_test.c b/test/evp_libctx_test.c
index f5d652ebc0..c5cc6bb0d7 100644
--- a/test/evp_libctx_test.c
+++ b/test/evp_libctx_test.c
@@ -83,7 +83,7 @@ static int test_dsa_param_keygen(int tstid)
int expected;
EVP_PKEY_CTX *gen_ctx = NULL;
EVP_PKEY *pkey_parm = NULL;
- EVP_PKEY *pkey = NULL;
+ EVP_PKEY *pkey = NULL, *dup_pk = NULL;
DSA *dsa = NULL;
int pind, qind, gind;
BIGNUM *p = NULL, *q = NULL, *g = NULL;
@@ -127,9 +127,17 @@ static int test_dsa_param_keygen(int tstid)
|| !TEST_int_gt(EVP_PKEY_keygen_init(gen_ctx), 0)
|| !TEST_int_eq(EVP_PKEY_keygen(gen_ctx, &pkey), expected))
goto err;
+
+ if (expected) {
+ if (!TEST_ptr(dup_pk = EVP_PKEY_dup(pkey))
+ || !TEST_int_eq(EVP_PKEY_eq(pkey, dup_pk), 1))
+ goto err;
+ }
+
ret = 1;
err:
EVP_PKEY_free(pkey);
+ EVP_PKEY_free(dup_pk);
EVP_PKEY_CTX_free(gen_ctx);
EVP_PKEY_free(pkey_parm);
DSA_free(dsa);
@@ -147,7 +155,7 @@ static int do_dh_param_keygen(int tstid, const BIGNUM **bn)
int expected;
EVP_PKEY_CTX *gen_ctx = NULL;
EVP_PKEY *pkey_parm = NULL;
- EVP_PKEY *pkey = NULL;
+ EVP_PKEY *pkey = NULL, *dup_pk = NULL;
DH *dh = NULL;
int pind, qind, gind;
BIGNUM *p = NULL, *q = NULL, *g = NULL;
@@ -182,9 +190,17 @@ static int do_dh_param_keygen(int tstid, const BIGNUM **bn)
|| !TEST_int_gt(EVP_PKEY_keygen_init(gen_ctx), 0)
|| !TEST_int_eq(EVP_PKEY_keygen(gen_ctx, &pkey), expected))
goto err;
+
+ if (expected) {
+ if (!TEST_ptr(dup_pk = EVP_PKEY_dup(pkey))
+ || !TEST_int_eq(EVP_PKEY_eq(pkey, dup_pk), 1))
+ goto err;
+ }
+
ret = 1;
err:
EVP_PKEY_free(pkey);
+ EVP_PKEY_free(dup_pk);
EVP_PKEY_CTX_free(gen_ctx);
EVP_PKEY_free(pkey_parm);
DH_free(dh);
diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c
index c89bb36628..6aa566cac4 100644
--- a/test/evp_pkey_provided_test.c
+++ b/test/evp_pkey_provided_test.c
@@ -305,7 +305,7 @@ static int test_fromdata_rsa(void)
{
int ret = 0, i;
EVP_PKEY_CTX *ctx = NULL, *key_ctx = NULL;
- EVP_PKEY *pk = NULL, *copy_pk = NULL;
+ EVP_PKEY *pk = NULL, *copy_pk = NULL, *dup_pk = NULL;
/*
* 32-bit RSA key, extracted from this command,
* executed with OpenSSL 1.0.2:
@@ -341,29 +341,45 @@ static int test_fromdata_rsa(void)
if (!TEST_true(EVP_PKEY_fromdata_init(ctx))
|| !TEST_true(EVP_PKEY_fromdata(ctx, &pk, EVP_PKEY_KEYPAIR,
- fromdata_params))
- || !TEST_int_eq(EVP_PKEY_bits(pk), 32)
- || !TEST_int_eq(EVP_PKEY_security_bits(pk), 8)
- || !TEST_int_eq(EVP_PKEY_size(pk), 4)
- || !TEST_false(EVP_PKEY_missing_parameters(pk)))
+ fromdata_params)))
goto err;
- if (!TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, "")))
- goto err;
+ while (dup_pk == NULL) {
+ ret = 0;
+ if (!TEST_int_eq(EVP_PKEY_bits(pk), 32)
+ || !TEST_int_eq(EVP_PKEY_security_bits(pk), 8)
+ || !TEST_int_eq(EVP_PKEY_size(pk), 4)
+ || !TEST_false(EVP_PKEY_missing_parameters(pk)))
+ goto err;
- if (!TEST_true(EVP_PKEY_check(key_ctx))
- || !TEST_true(EVP_PKEY_public_check(key_ctx))
- || !TEST_true(EVP_PKEY_private_check(key_ctx))
- || !TEST_true(EVP_PKEY_pairwise_check(key_ctx)))
- goto err;
+ EVP_PKEY_CTX_free(key_ctx);
+ if (!TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, "")))
+ goto err;
- /* EVP_PKEY_copy_parameters() should fail for RSA */
- if (!TEST_ptr(copy_pk = EVP_PKEY_new())
- || !TEST_false(EVP_PKEY_copy_parameters(copy_pk, pk)))
- goto err;
+ if (!TEST_true(EVP_PKEY_check(key_ctx))
+ || !TEST_true(EVP_PKEY_public_check(key_ctx))
+ || !TEST_true(EVP_PKEY_private_check(key_ctx))
+ || !TEST_true(EVP_PKEY_pairwise_check(key_ctx)))
+ goto err;
+
+ /* EVP_PKEY_copy_parameters() should fail for RSA */
+ if (!TEST_ptr(copy_pk = EVP_PKEY_new())
+ || !TEST_false(EVP_PKEY_copy_parameters(copy_pk, pk)))
+ goto err;
+ EVP_PKEY_free(copy_pk);
+ copy_pk = NULL;
- ret = test_print_key_using_pem("RSA", pk)
- && test_print_key_using_encoder("RSA", pk);
+ ret = test_print_key_using_pem("RSA", pk)
+ && test_print_key_using_encoder("RSA", pk);
+
+ if (!ret || !TEST_ptr(dup_pk = EVP_PKEY_dup(pk)))
+ goto err;
+ ret = ret && TEST_int_eq(EVP_PKEY_eq(pk, dup_pk), 1);
<