[openssl] master update

Dr. Paul Dale pauli at openssl.org
Sat Aug 1 01:53:48 UTC 2020


The branch master has been updated
       via  790a1b030ac6f968104e17fe5b721c581ebd1d3e (commit)
       via  1dbf4537738d86d8078b74c89e38b6ed0b2b1196 (commit)
       via  3c033c5bfed214b02c0f041239d1cb8a4e27fd82 (commit)
       via  319d0b2be96539f10628c98f37306655fd158f61 (commit)
       via  7c664b1f1b5f60bf896f5fdea5c08c401c541dfe (commit)
       via  3ff8159a8af6ab4e945318c56cd2fffcdd817cf8 (commit)
       via  4701f0a9a0ff08b354142c9f3b4797ff225d7c84 (commit)
       via  a6495479adfb8dc0b500030d4eeb007d9af4572a (commit)
       via  6c6b20d59153cd29e38dfebee0b8a6f998402254 (commit)
       via  86b5ab58aae0bddb93a58e9dcfac5ea3db022f6a (commit)
      from  1202de4481df88d63a2a5cc1e9e0450a7e72f4ac (commit)


- Log -----------------------------------------------------------------
commit 790a1b030ac6f968104e17fe5b721c581ebd1d3e
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 22:11:53 2020 +0200

    DESERIALIZER: Small bugfix in the deser_process()
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 1dbf4537738d86d8078b74c89e38b6ed0b2b1196
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 22:02:07 2020 +0200

    DESERIALIZER: Make OSSL_DESERIALIZER_from_{bio,fp} use BIO_tell() / BIO_seek()
    
    Depending on the BIO used, using BIO_reset() may lead to "interesting"
    results.  For example, a BIO_f_buffer() on top of another BIO that
    handles BIO_reset() as a BIO_seek(bio, 0), the deserialization process
    may find itself with a file that's rewound more than expected.
    
    Therefore, OSSL_DESERIALIZER_from_{bio,fp}'s behaviour is changed to
    rely purely on BIO_tell() / BIO_seek(), and since BIO_s_mem() is used
    internally, it's changed to handle BIO_tell() and BIO_seek() better.
    
    This does currently mean that OSSL_DESERIALIZER can't be easily used
    with streams that don't support BIO_tell() / BIO_seek().
    
    Fixes #12541
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 3c033c5bfed214b02c0f041239d1cb8a4e27fd82
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 21:51:44 2020 +0200

    DESERIALIZER: Refactor the constructor setting API
    
    It's not the best idea to set a whole bunch of parameters in one call,
    that leads to functions that are hard to update.  Better to re-model
    this into several function made to set one parameter each.
    
    This also renames "finalizer" to "constructor", which was suggested
    earlier but got lost at the time.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 319d0b2be96539f10628c98f37306655fd158f61
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 18:40:11 2020 +0200

    TEST: Add testutil tests to compare unterminated strings of different lengths
    
    We use this in test/serdes_test.c, to compare serializations into PEM,
    which aren't necessarily terminated with a NUL byte when they were
    written to a BIO_s_mem().
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 7c664b1f1b5f60bf896f5fdea5c08c401c541dfe
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 18:40:05 2020 +0200

    DESERIALIZER: Add deserializers for the rest of our asymmetric key types
    
    To be able to implement this, there was a need for the standard
    EVP_PKEY_set1_, EVP_PKEY_get0_ and EVP_PKEY_get1_ functions for
    ED25519, ED448, X25519 and X448, as well as the corresponding
    EVP_PKEY_assign_ macros.  There was also a need to extend the list of
    hard coded names that EVP_PKEY_is_a() recognise.
    
    Along with this, OSSL_FUNC_keymgmt_load() are implemented for all
    those key types.
    
    The deserializers for these key types are all implemented generically,
    in providers/implementations/serializers/deserializer_der2key.c.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 3ff8159a8af6ab4e945318c56cd2fffcdd817cf8
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 18:40:02 2020 +0200

    DESERIALIZER: Make it possible to deserialize public keys too
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 4701f0a9a0ff08b354142c9f3b4797ff225d7c84
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 18:39:58 2020 +0200

    DESERIALIZER: Rethink password handling
    
    The OSSL_DESERIALIZER API makes the incorrect assumption that the
    caller must cipher and other pass phrase related parameters to the
    individual desserializer implementations, when the reality is that
    they only need a passphrase callback, and will be able to figure out
    the rest themselves from the input they get.
    
    We simplify it further by never passing any explicit passphrase to the
    provider implementation, and simply have them call the passphrase
    callback unconditionally when they need, leaving it to libcrypto code
    to juggle explicit passphrases, cached passphrases and actual
    passphrase callback calls.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit a6495479adfb8dc0b500030d4eeb007d9af4572a
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 18:39:55 2020 +0200

    RSA: Better synchronisation between ASN1 PSS params and RSA_PSS_PARAMS_30
    
    This is needed so RSA keys created from different code paths have a
    chance to compare as equal.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 6c6b20d59153cd29e38dfebee0b8a6f998402254
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 18:39:51 2020 +0200

    DER writer: Make context-specific tags constructed (i.e. explicit)
    
    For now, that's what we see being used.  It's possible that we will
    have to figure out a way to specific if these should be implicit or
    explicit on a case by case basis.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

commit 86b5ab58aae0bddb93a58e9dcfac5ea3db022f6a
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Jul 27 18:39:44 2020 +0200

    PROV: Fix small logic error in ec_kmgmt.c matching function
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/12544)

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

Summary of changes:
 crypto/bio/bss_mem.c                               |  25 +-
 crypto/der_writer.c                                |   6 +-
 crypto/err/openssl.txt                             |   2 +
 crypto/evp/evp_err.c                               |   2 +
 crypto/evp/p_lib.c                                 |  61 ++++
 crypto/rsa/rsa_ameth.c                             | 114 +++++-
 crypto/serializer/deserializer_lib.c               |  94 +++--
 crypto/serializer/deserializer_meth.c              |   8 +-
 crypto/serializer/deserializer_pkey.c              | 103 +++---
 crypto/serializer/serdes_pass.c                    |   7 +-
 crypto/serializer/serializer_local.h               |  21 +-
 doc/man3/EVP_PKEY_set1_RSA.pod                     |  55 ++-
 doc/man3/OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY.pod |  46 ++-
 doc/man3/OSSL_DESERIALIZER_from_bio.pod            | 135 ++++---
 include/openssl/deserializer.h                     |  41 ++-
 include/openssl/evp.h                              |  21 ++
 include/openssl/evperr.h                           |   2 +
 providers/deserializers.inc                        |  14 +
 .../implementations/include/prov/implementations.h |   7 +
 providers/implementations/keymgmt/dh_kmgmt.c       |  16 +
 providers/implementations/keymgmt/dsa_kmgmt.c      |  16 +
 providers/implementations/keymgmt/ec_kmgmt.c       |  18 +-
 providers/implementations/keymgmt/ecx_kmgmt.c      |  16 +
 providers/implementations/serializers/build.info   |   3 +-
 .../serializers/deserialize_common.c               |  22 +-
 .../serializers/deserialize_der2key.c              | 234 ++++++++++++
 .../serializers/deserialize_der2rsa.c              | 309 ----------------
 .../serializers/deserialize_pem2der.c              |  73 +---
 .../implementations/serializers/serializer_local.h |   2 +-
 test/serdes_test.c                                 | 393 +++++++++++++++------
 test/testutil.h                                    |  10 +-
 test/testutil/tests.c                              |  16 +-
 util/libcrypto.num                                 |  22 +-
 util/other.syms                                    |   8 +-
 34 files changed, 1203 insertions(+), 719 deletions(-)
 create mode 100644 providers/implementations/serializers/deserialize_der2key.c
 delete mode 100644 providers/implementations/serializers/deserialize_der2rsa.c

diff --git a/crypto/bio/bss_mem.c b/crypto/bio/bss_mem.c
index 4043043626..d9580e6d37 100644
--- a/crypto/bio/bss_mem.c
+++ b/crypto/bio/bss_mem.c
@@ -176,6 +176,7 @@ static int mem_buf_free(BIO *a)
 
 /*
  * Reallocate memory buffer if read pointer differs
+ * NOT FOR RDONLY
  */
 static int mem_buf_sync(BIO *b)
 {
@@ -247,12 +248,18 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr)
     long ret = 1;
     char **pptr;
     BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
-    BUF_MEM *bm;
+    BUF_MEM *bm, *bo;            /* bio_mem, bio_other */
+    long off, remain;
 
-    if (b->flags & BIO_FLAGS_MEM_RDONLY)
+    if (b->flags & BIO_FLAGS_MEM_RDONLY) {
         bm = bbm->buf;
-    else
+        bo = bbm->readp;
+    } else {
         bm = bbm->readp;
+        bo = bbm->buf;
+    }
+    off = bm->data - bo->data;
+    remain = bm->length;
 
     switch (cmd) {
     case BIO_CTRL_RESET:
@@ -270,6 +277,18 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr)
             }
         }
         break;
+    case BIO_C_FILE_SEEK:
+        if (num < 0 || num > off + remain)
+            return -1;   /* Can't see outside of the current buffer */
+
+        bm->data = bo->data + num;
+        bm->length = bo->length - num;
+        bm->max = bo->max - num;
+        off = num;
+        /* FALLTHRU */
+    case BIO_C_FILE_TELL:
+        ret = off;
+        break;
     case BIO_CTRL_EOF:
         ret = (long)(bm->length == 0);
         break;
diff --git a/crypto/der_writer.c b/crypto/der_writer.c
index 8762787504..117b5dff90 100644
--- a/crypto/der_writer.c
+++ b/crypto/der_writer.c
@@ -38,10 +38,14 @@ static int int_end_context(WPACKET *pkt, int tag)
         return 1;
     if (!ossl_assert(tag <= 30))
         return 0;
+
+    /* Context specific are normally (?) constructed */
+    tag |= DER_F_CONSTRUCTED | DER_C_CONTEXT;
+
     return WPACKET_get_total_written(pkt, &size1)
         && WPACKET_close(pkt)
         && WPACKET_get_total_written(pkt, &size2)
-        && (size1 == size2 || WPACKET_put_bytes_u8(pkt, DER_C_CONTEXT | tag));
+        && (size1 == size2 || WPACKET_put_bytes_u8(pkt, tag));
 }
 
 int DER_w_precompiled(WPACKET *pkt, int tag,
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 0124d1d3ae..1b4fca9b97 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -875,6 +875,7 @@ EVP_F_EVP_PKEY_ENCRYPT_INIT:139:EVP_PKEY_encrypt_init
 EVP_F_EVP_PKEY_ENCRYPT_OLD:152:EVP_PKEY_encrypt_old
 EVP_F_EVP_PKEY_GET0_DH:119:EVP_PKEY_get0_DH
 EVP_F_EVP_PKEY_GET0_DSA:120:EVP_PKEY_get0_DSA
+EVP_F_EVP_PKEY_GET0_ECX_KEY:222:
 EVP_F_EVP_PKEY_GET0_EC_KEY:131:EVP_PKEY_get0_EC_KEY
 EVP_F_EVP_PKEY_GET0_HMAC:183:EVP_PKEY_get0_hmac
 EVP_F_EVP_PKEY_GET0_POLY1305:184:EVP_PKEY_get0_poly1305
@@ -2532,6 +2533,7 @@ EVP_R_EXPECTING_AN_HMAC_KEY:174:expecting an hmac key
 EVP_R_EXPECTING_AN_RSA_KEY:127:expecting an rsa key
 EVP_R_EXPECTING_A_DH_KEY:128:expecting a dh key
 EVP_R_EXPECTING_A_DSA_KEY:129:expecting a dsa key
+EVP_R_EXPECTING_A_ECX_KEY:219:expecting a ecx key
 EVP_R_EXPECTING_A_EC_KEY:142:expecting a ec key
 EVP_R_EXPECTING_A_POLY1305_KEY:164:expecting a poly1305 key
 EVP_R_EXPECTING_A_SIPHASH_KEY:175:expecting a siphash key
diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c
index 239efaa51a..d13cd05faa 100644
--- a/crypto/evp/evp_err.c
+++ b/crypto/evp/evp_err.c
@@ -61,6 +61,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DH_KEY), "expecting a dh key"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DSA_KEY),
     "expecting a dsa key"},
+    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_ECX_KEY),
+    "expecting a ecx key"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_EC_KEY), "expecting a ec key"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_POLY1305_KEY),
     "expecting a poly1305 key"},
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index a7fd687dd0..3e3f2118a2 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -34,6 +34,7 @@
 
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
+#include "crypto/ecx.h"
 #include "internal/evp.h"
 #include "internal/provider.h"
 #include "evp_local.h"
@@ -855,6 +856,54 @@ EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey)
         EC_KEY_up_ref(ret);
     return ret;
 }
+
+static int EVP_PKEY_set1_ECX_KEY(EVP_PKEY *pkey, int type, ECX_KEY *key)
+{
+    int ret = EVP_PKEY_assign(pkey, type, key);
+    if (ret)
+        ecx_key_up_ref(key);
+    return ret;
+}
+
+static ECX_KEY *EVP_PKEY_get0_ECX_KEY(const EVP_PKEY *pkey, int type)
+{
+    if (!evp_pkey_downgrade((EVP_PKEY *)pkey)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY);
+        return NULL;
+    }
+    if (EVP_PKEY_base_id(pkey) != type) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_EXPECTING_A_ECX_KEY);
+        return NULL;
+    }
+    return pkey->pkey.ecx;
+}
+
+static ECX_KEY *EVP_PKEY_get1_ECX_KEY(EVP_PKEY *pkey, int type)
+{
+    ECX_KEY *ret = EVP_PKEY_get0_ECX_KEY(pkey, type);
+    if (ret != NULL)
+        ecx_key_up_ref(ret);
+    return ret;
+}
+
+#  define IMPLEMENT_ECX_VARIANT(NAME)                                   \
+    int EVP_PKEY_set1_##NAME(EVP_PKEY *pkey, ECX_KEY *key)              \
+    {                                                                   \
+        return EVP_PKEY_set1_ECX_KEY(pkey, EVP_PKEY_##NAME, key);       \
+    }                                                                   \
+    ECX_KEY *EVP_PKEY_get0_##NAME(const EVP_PKEY *pkey)                 \
+    {                                                                   \
+        return EVP_PKEY_get0_ECX_KEY(pkey, EVP_PKEY_##NAME);            \
+    }                                                                   \
+    ECX_KEY *EVP_PKEY_get1_##NAME(EVP_PKEY *pkey)                       \
+    {                                                                   \
+        return EVP_PKEY_get1_ECX_KEY(pkey, EVP_PKEY_##NAME);            \
+    }
+IMPLEMENT_ECX_VARIANT(X25519)
+IMPLEMENT_ECX_VARIANT(X448)
+IMPLEMENT_ECX_VARIANT(ED25519)
+IMPLEMENT_ECX_VARIANT(ED448)
+
 # endif
 
 # ifndef OPENSSL_NO_DH
@@ -940,6 +989,18 @@ int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name)
 #ifndef OPENSSL_NO_EC
         else if (strcasecmp(name, "EC") == 0)
             type = EVP_PKEY_EC;
+        else if (strcasecmp(name, "ED25519") == 0)
+            type = EVP_PKEY_ED25519;
+        else if (strcasecmp(name, "ED448") == 0)
+            type = EVP_PKEY_ED448;
+        else if (strcasecmp(name, "X25519") == 0)
+            type = EVP_PKEY_X25519;
+        else if (strcasecmp(name, "X448") == 0)
+            type = EVP_PKEY_X448;
+#endif
+#ifndef OPENSSL_NO_DH
+        else if (strcasecmp(name, "DH") == 0)
+            type = EVP_PKEY_DH;
 #endif
 #ifndef OPENSSL_NO_DSA
         else if (strcasecmp(name, "DSA") == 0)
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index 22c06a2139..f5911ad233 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -34,6 +34,7 @@ static int rsa_cms_encrypt(CMS_RecipientInfo *ri);
 #endif
 
 static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg);
+static int rsa_sync_to_pss_params_30(RSA *rsa);
 
 /* Set any parameters associated with pkey */
 static int rsa_param_encode(const EVP_PKEY *pkey,
@@ -78,6 +79,8 @@ static int rsa_param_decode(RSA *rsa, const X509_ALGOR *alg)
     rsa->pss = rsa_pss_decode(alg);
     if (rsa->pss == NULL)
         return 0;
+    if (!rsa_sync_to_pss_params_30(rsa))
+        return 0;
     return 1;
 }
 
@@ -118,6 +121,20 @@ static int rsa_pub_decode(EVP_PKEY *pkey, const X509_PUBKEY *pubkey)
         RSA_free(rsa);
         return 0;
     }
+
+    RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK);
+    switch (pkey->ameth->pkey_id) {
+    case EVP_PKEY_RSA:
+        RSA_set_flags(rsa, RSA_FLAG_TYPE_RSA);
+        break;
+    case EVP_PKEY_RSA_PSS:
+        RSA_set_flags(rsa, RSA_FLAG_TYPE_RSASSAPSS);
+        break;
+    default:
+        /* Leave the type bits zero */
+        break;
+    }
+
     if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, rsa)) {
         RSA_free(rsa);
         return 0;
@@ -729,9 +746,34 @@ static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pkctx,
     return rv;
 }
 
-int rsa_pss_get_param(const RSA_PSS_PARAMS *pss, const EVP_MD **pmd,
-                      const EVP_MD **pmgf1md, int *psaltlen)
+static int rsa_pss_verify_param(const EVP_MD **pmd, const EVP_MD **pmgf1md,
+                                int *psaltlen, int *ptrailerField)
 {
+    if (psaltlen != NULL && *psaltlen < 0) {
+        ERR_raise(ERR_LIB_RSA, RSA_R_INVALID_SALT_LENGTH);
+        return 0;
+    }
+    /*
+     * low-level routines support only trailer field 0xbc (value 1) and
+     * PKCS#1 says we should reject any other value anyway.
+     */
+    if (ptrailerField != NULL && *ptrailerField != 1) {
+        ERR_raise(ERR_LIB_RSA, RSA_R_INVALID_TRAILER);
+        return 0;
+    }
+    return 1;
+}
+
+static int rsa_pss_get_param_unverified(const RSA_PSS_PARAMS *pss,
+                                        const EVP_MD **pmd,
+                                        const EVP_MD **pmgf1md,
+                                        int *psaltlen, int *ptrailerField)
+{
+    RSA_PSS_PARAMS_30 pss_params;
+
+    /* Get the defaults from the ONE place */
+    (void)rsa_pss_params_30_set_defaults(&pss_params);
+
     if (pss == NULL)
         return 0;
     *pmd = rsa_algor_to_md(pss->hashAlgorithm);
@@ -740,25 +782,65 @@ int rsa_pss_get_param(const RSA_PSS_PARAMS *pss, const EVP_MD **pmd,
     *pmgf1md = rsa_algor_to_md(pss->maskHash);
     if (*pmgf1md == NULL)
         return 0;
-    if (pss->saltLength) {
+    if (pss->saltLength)
         *psaltlen = ASN1_INTEGER_get(pss->saltLength);
-        if (*psaltlen < 0) {
-            RSAerr(RSA_F_RSA_PSS_GET_PARAM, RSA_R_INVALID_SALT_LENGTH);
-            return 0;
-        }
-    } else {
-        *psaltlen = 20;
-    }
+    else
+        *psaltlen = rsa_pss_params_30_saltlen(&pss_params);
+    if (pss->trailerField)
+        *ptrailerField = ASN1_INTEGER_get(pss->trailerField);
+    else
+        *ptrailerField = rsa_pss_params_30_trailerfield(&pss_params);;
+
+    return 1;
+}
 
+int rsa_pss_get_param(const RSA_PSS_PARAMS *pss, const EVP_MD **pmd,
+                      const EVP_MD **pmgf1md, int *psaltlen)
+{
     /*
-     * low-level routines support only trailer field 0xbc (value 1) and
-     * PKCS#1 says we should reject any other value anyway.
+     * Callers do not care about the trailer field, and yet, we must
+     * pass it from get_param to verify_param, since the latter checks
+     * its value.
+     *
+     * When callers start caring, it's a simple thing to add another
+     * argument to this function.
      */
-    if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) {
-        RSAerr(RSA_F_RSA_PSS_GET_PARAM, RSA_R_INVALID_TRAILER);
-        return 0;
-    }
+    int trailerField = 0;
+
+    return rsa_pss_get_param_unverified(pss, pmd, pmgf1md, psaltlen,
+                                        &trailerField)
+        && rsa_pss_verify_param(pmd, pmgf1md, psaltlen, &trailerField);
+}
+
+static int rsa_sync_to_pss_params_30(RSA *rsa)
+{
+    if (rsa != NULL && rsa->pss != NULL) {
+        const EVP_MD *md = NULL, *mgf1md = NULL;
+        int md_nid, mgf1md_nid, saltlen, trailerField;
+        RSA_PSS_PARAMS_30 pss_params;
 
+        /*
+         * We don't care about the validity of the fields here, we just
+         * want to synchronise values.  Verifying here makes it impossible
+         * to even read a key with invalid values, making it hard to test
+         * a bad situation.
+         *
+         * Other routines use rsa_pss_get_param(), so the values will be
+         * checked, eventually.
+         */
+        if (!rsa_pss_get_param_unverified(rsa->pss, &md, &mgf1md,
+                                          &saltlen, &trailerField))
+            return 0;
+        md_nid = EVP_MD_type(md);
+        mgf1md_nid = EVP_MD_type(mgf1md);
+        if (!rsa_pss_params_30_set_defaults(&pss_params)
+            || !rsa_pss_params_30_set_hashalg(&pss_params, md_nid)
+            || !rsa_pss_params_30_set_maskgenhashalg(&pss_params, mgf1md_nid)
+            || !rsa_pss_params_30_set_saltlen(&pss_params, saltlen)
+            || !rsa_pss_params_30_set_trailerfield(&pss_params, trailerField))
+            return 0;
+        rsa->pss_params = pss_params;
+    }
     return 1;
 }
 
diff --git a/crypto/serializer/deserializer_lib.c b/crypto/serializer/deserializer_lib.c
index 2fbb7782cf..aa3b552786 100644
--- a/crypto/serializer/deserializer_lib.c
+++ b/crypto/serializer/deserializer_lib.c
@@ -37,10 +37,11 @@ int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in)
 
     ok = deser_process(NULL, &data);
 
-    /* Clear any cached passphrase */
-    OPENSSL_clear_free(ctx->cached_passphrase, ctx->cached_passphrase_len);
-    ctx->cached_passphrase = NULL;
-    ctx->cached_passphrase_len = 0;
+    /* Clear any internally cached passphrase */
+    if (!ctx->flag_user_passphrase) {
+        OSSL_DESERIALIZER_CTX_set_passphrase(ctx, NULL, 0);
+        ctx->flag_user_passphrase = 0;
+    }
     return ok;
 }
 
@@ -274,21 +275,62 @@ int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx)
     return sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
 }
 
-int OSSL_DESERIALIZER_CTX_set_finalizer(OSSL_DESERIALIZER_CTX *ctx,
-                                        OSSL_DESERIALIZER_FINALIZER *finalizer,
-                                        OSSL_DESERIALIZER_CLEANER *cleaner,
-                                        void *finalize_arg)
+int OSSL_DESERIALIZER_CTX_set_construct(OSSL_DESERIALIZER_CTX *ctx,
+                                        OSSL_DESERIALIZER_CONSTRUCT *construct)
+{
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    ctx->construct = construct;
+    return 1;
+}
+
+int OSSL_DESERIALIZER_CTX_set_construct_data(OSSL_DESERIALIZER_CTX *ctx,
+                                             void *construct_data)
+{
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    ctx->construct_data = construct_data;
+    return 1;
+}
+
+int OSSL_DESERIALIZER_CTX_set_cleanup(OSSL_DESERIALIZER_CTX *ctx,
+                                      OSSL_DESERIALIZER_CLEANUP *cleanup)
 {
     if (!ossl_assert(ctx != NULL)) {
         ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
-    ctx->finalizer = finalizer;
-    ctx->cleaner = cleaner;
-    ctx->finalize_arg = finalize_arg;
+    ctx->cleanup = cleanup;
     return 1;
 }
 
+OSSL_DESERIALIZER_CONSTRUCT *
+OSSL_DESERIALIZER_CTX_get_construct(OSSL_DESERIALIZER_CTX *ctx)
+{
+    if (ctx == NULL)
+        return NULL;
+    return ctx->construct;
+}
+
+void *OSSL_DESERIALIZER_CTX_get_construct_data(OSSL_DESERIALIZER_CTX *ctx)
+{
+    if (ctx == NULL)
+        return NULL;
+    return ctx->construct_data;
+}
+
+OSSL_DESERIALIZER_CLEANUP *
+OSSL_DESERIALIZER_CTX_get_cleanup(OSSL_DESERIALIZER_CTX *ctx)
+{
+    if (ctx == NULL)
+        return NULL;
+    return ctx->cleanup;
+}
+
 int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
                              void *reference, size_t reference_sz,
                              OSSL_CALLBACK *export_cb, void *export_cbarg)
@@ -353,12 +395,13 @@ static int deser_process(const OSSL_PARAM params[], void *arg)
                                                 data->current_deser_inst_index);
         deser = OSSL_DESERIALIZER_INSTANCE_deserializer(deser_inst);
 
-        if (ctx->finalizer(deser_inst, params, ctx->finalize_arg)) {
+        if (ctx->construct != NULL
+            && ctx->construct(deser_inst, params, ctx->construct_data)) {
             ok = 1;
             goto end;
         }
 
-        /* The finalizer didn't return success */
+        /* The constructor didn't return success */
 
         /*
          * so we try to use the object we got and feed it to any next
@@ -400,7 +443,8 @@ static int deser_process(const OSSL_PARAM params[], void *arg)
          * that's the case, we do this extra check.
          */
         if (deser == NULL && ctx->start_input_type != NULL
-            && strcasecmp(ctx->start_input_type, deser_inst->input_type) != 0)
+            && strcasecmp(ctx->start_input_type,
+                          new_deser_inst->input_type) != 0)
             continue;
 
         /*
@@ -413,20 +457,26 @@ static int deser_process(const OSSL_PARAM params[], void *arg)
             && !OSSL_DESERIALIZER_is_a(deser, new_deser_inst->input_type))
             continue;
 
-        if (loc == 0) {
-            if (BIO_reset(bio) <= 0)
-                goto end;
-        } else {
-            if (BIO_seek(bio, loc) <= 0)
-                goto end;
-        }
+        /*
+         * Checking the return value of BIO_reset() or BIO_seek() is unsafe.
+         * Furthermore, BIO_reset() is unsafe to use if the source BIO happens
+         * to be a BIO_s_mem(), because the earlier BIO_tell() gives us zero
+         * no matter where we are in the underlying buffer we're reading from.
+         *
+         * So, we simply do a BIO_seek(), and use BIO_tell() that we're back
+         * at the same position.  This is a best effort attempt, but BIO_seek()
+         * and BIO_tell() should come as a pair...
+         */
+        (void)BIO_seek(bio, loc);
+        if (BIO_tell(bio) != loc)
+            goto end;
 
         /* Recurse */
         new_data.current_deser_inst_index = i;
         ok = new_deser->deserialize(new_deser_inst->deserctx,
                                     (OSSL_CORE_BIO *)bio,
                                     deser_process, &new_data,
-                                    NULL /* ossl_deserializer_passphrase_in_cb */,
+                                    ctx->passphrase_cb,
                                     new_data.ctx);
         if (ok)
             break;
diff --git a/crypto/serializer/deserializer_meth.c b/crypto/serializer/deserializer_meth.c
index 54500716ec..4739c2956d 100644
--- a/crypto/serializer/deserializer_meth.c
+++ b/crypto/serializer/deserializer_meth.c
@@ -490,6 +490,7 @@ OSSL_DESERIALIZER_CTX *OSSL_DESERIALIZER_CTX_new(void)
         return NULL;
     }
 
+    ctx->passphrase_cb = ossl_deserializer_passphrase_in_cb;
     return ctx;
 }
 
@@ -538,11 +539,12 @@ OSSL_DESERIALIZER_INSTANCE_free(OSSL_DESERIALIZER_INSTANCE *deser_inst)
 void OSSL_DESERIALIZER_CTX_free(OSSL_DESERIALIZER_CTX *ctx)
 {
     if (ctx != NULL) {
-        if (ctx->cleaner != NULL)
-            ctx->cleaner(ctx->finalize_arg);
+        if (ctx->cleanup != NULL)
+            ctx->cleanup(ctx->construct_data);
         sk_OSSL_DESERIALIZER_INSTANCE_pop_free(ctx->deser_insts,
                                                OSSL_DESERIALIZER_INSTANCE_free);
-        UI_destroy_method(ctx->allocated_ui_method);
+        OSSL_DESERIALIZER_CTX_set_passphrase_ui(ctx, NULL, NULL);
+        OSSL_DESERIALIZER_CTX_set_passphrase(ctx, NULL, 0);
         OPENSSL_free(ctx);
     }
 }
diff --git a/crypto/serializer/deserializer_pkey.c b/crypto/serializer/deserializer_pkey.c
index 0fafdf31aa..e5e8bfda6f 100644
--- a/crypto/serializer/deserializer_pkey.c
+++ b/crypto/serializer/deserializer_pkey.c
@@ -11,37 +11,37 @@
 #include <openssl/evp.h>
 #include <openssl/ui.h>
 #include <openssl/deserializer.h>
-#include <openssl/core_names.h>
 #include <openssl/safestack.h>
 #include "crypto/evp.h"
 #include "serializer_local.h"
 
-int OSSL_DESERIALIZER_CTX_set_cipher(OSSL_DESERIALIZER_CTX *ctx,
-                                     const char *cipher_name,
-                                     const char *propquery)
-{
-    OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
-
-    params[0] =
-        OSSL_PARAM_construct_utf8_string(OSSL_DESERIALIZER_PARAM_CIPHER,
-                                         (void *)cipher_name, 0);
-    params[1] =
-        OSSL_PARAM_construct_utf8_string(OSSL_DESERIALIZER_PARAM_PROPERTIES,
-                                         (void *)propquery, 0);
-
-    return OSSL_DESERIALIZER_CTX_set_params(ctx, params);
-}
-
 int OSSL_DESERIALIZER_CTX_set_passphrase(OSSL_DESERIALIZER_CTX *ctx,
                                          const unsigned char *kstr,
                                          size_t klen)
 {
-    OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
-
-    params[0] = OSSL_PARAM_construct_octet_string(OSSL_DESERIALIZER_PARAM_PASS,
-                                                  (void *)kstr, klen);
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
 
-    return OSSL_DESERIALIZER_CTX_set_params(ctx, params);
+    OPENSSL_clear_free(ctx->cached_passphrase, ctx->cached_passphrase_len);
+    ctx->cached_passphrase = NULL;
+    ctx->cached_passphrase_len = 0;
+    if (kstr != NULL) {
+        if (klen == 0) {
+            ctx->cached_passphrase = OPENSSL_zalloc(1);
+            ctx->cached_passphrase_len = 0;
+        } else {
+            ctx->cached_passphrase = OPENSSL_memdup(kstr, klen);
+            ctx->cached_passphrase_len = klen;
+        }
+        if (ctx->cached_passphrase == NULL) {
+            ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+    }
+    ctx->flag_user_passphrase = 1;
+    return 1;
 }
 
 static void deserializer_ctx_reset_passphrase_ui(OSSL_DESERIALIZER_CTX *ctx)
@@ -67,27 +67,36 @@ int OSSL_DESERIALIZER_CTX_set_passphrase_ui(OSSL_DESERIALIZER_CTX *ctx,
     return 1;
 }
 
-int OSSL_DESERIALIZER_CTX_set_passphrase_cb(OSSL_DESERIALIZER_CTX *ctx,
-                                            pem_password_cb *cb, void *cbarg)
+int OSSL_DESERIALIZER_CTX_set_pem_password_cb(OSSL_DESERIALIZER_CTX *ctx,
+                                              pem_password_cb *cb, void *cbarg)
 {
+    UI_METHOD *ui_method = NULL;
+
     if (!ossl_assert(ctx != NULL)) {
         ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
 
-    deserializer_ctx_reset_passphrase_ui(ctx);
-    if (cb == NULL)
+    /*
+     * If |cb| is NULL, it means the caller wants to reset previous
+     * password callback info.  Otherwise, we only set the new data
+     * if a new UI_METHOD could be created for this sort of callback.
+     */
+    if (cb == NULL
+        || (ui_method = UI_UTIL_wrap_read_pem_callback(cb, 0)) != NULL) {
+        deserializer_ctx_reset_passphrase_ui(ctx);
+        ctx->ui_method = ctx->allocated_ui_method = ui_method;
+        ctx->ui_data = cbarg;
+        ctx->passphrase_cb = ossl_deserializer_passphrase_in_cb;
         return 1;
-    ctx->ui_method =
-        ctx->allocated_ui_method = UI_UTIL_wrap_read_pem_callback(cb, 0);
-    ctx->ui_data = cbarg;
+    }
 
-    return ctx->ui_method != NULL;
+    return 0;
 }
 
 /*
  * Support for OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY:
- * Handle an object reference
+ * The construct data, and collecting keymgmt information for it
  */
 
 DEFINE_STACK_OF(EVP_KEYMGMT)
@@ -98,11 +107,11 @@ struct deser_EVP_PKEY_data_st {
     STACK_OF(EVP_KEYMGMT) *keymgmts; /* The EVP_KEYMGMTs we handle */
 };
 
-static int deser_finalize_EVP_PKEY(OSSL_DESERIALIZER_INSTANCE *deser_inst,
-                                   const OSSL_PARAM *params,
-                                   void *finalize_arg)
+static int deser_construct_EVP_PKEY(OSSL_DESERIALIZER_INSTANCE *deser_inst,
+                                    const OSSL_PARAM *params,
+                                    void *construct_data)
 {
-    struct deser_EVP_PKEY_data_st *data = finalize_arg;
+    struct deser_EVP_PKEY_data_st *data = construct_data;
     OSSL_DESERIALIZER *deser =
         OSSL_DESERIALIZER_INSTANCE_deserializer(deser_inst);
     void *deserctx = OSSL_DESERIALIZER_INSTANCE_deserializer_ctx(deser_inst);
@@ -216,13 +225,15 @@ static int deser_finalize_EVP_PKEY(OSSL_DESERIALIZER_INSTANCE *deser_inst,
     return (*data->object != NULL);
 }
 
-static void deser_clean_EVP_PKEY(void *finalize_arg)
+static void deser_clean_EVP_PKEY_construct_arg(void *construct_data)
 {
-    struct deser_EVP_PKEY_data_st *data = finalize_arg;
+    struct deser_EVP_PKEY_data_st *data = construct_data;
 
-    sk_EVP_KEYMGMT_pop_free(data->keymgmts, EVP_KEYMGMT_free);
-    OPENSSL_free(data->object_type);
-    OPENSSL_free(data);
+    if (data != NULL) {
+        sk_EVP_KEYMGMT_pop_free(data->keymgmts, EVP_KEYMGMT_free);
+        OPENSSL_free(data->object_type);
+        OPENSSL_free(data);
+    }
 }
 
 DEFINE_STACK_OF_CSTRING()
@@ -344,17 +355,15 @@ OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY(EVP_PKEY **pkey,
     /* Finally, collect extra deserializers based on what we already have */
     (void)OSSL_DESERIALIZER_CTX_add_extra(ctx, libctx, propquery);
 
-    if (!OSSL_DESERIALIZER_CTX_set_finalizer(ctx, deser_finalize_EVP_PKEY,
-                                             deser_clean_EVP_PKEY,
-                                             data->process_data))
+    if (!OSSL_DESERIALIZER_CTX_set_construct(ctx, deser_construct_EVP_PKEY)
+        || !OSSL_DESERIALIZER_CTX_set_construct_data(ctx, data->process_data)
+        || !OSSL_DESERIALIZER_CTX_set_cleanup
+                (ctx, deser_clean_EVP_PKEY_construct_arg))
         goto err;
 
     data->process_data = NULL;
  err:
-    if (data->process_data != NULL)
-        sk_EVP_KEYMGMT_pop_free(data->process_data->keymgmts,
-                                EVP_KEYMGMT_free);
-    OPENSSL_free(data->process_data);
+    deser_clean_EVP_PKEY_construct_arg(data->process_data);
     sk_OPENSSL_CSTRING_free(data->names);
     OPENSSL_free(data);
     return ctx;
diff --git a/crypto/serializer/serdes_pass.c b/crypto/serializer/serdes_pass.c
index 8a33af5e9a..75200955b5 100644
--- a/crypto/serializer/serdes_pass.c
+++ b/crypto/serializer/serdes_pass.c
@@ -48,8 +48,11 @@ static int do_passphrase(char *pass, size_t pass_size, size_t *pass_len,
         return 0;
     }
 
-    UI_set_method(ui, ui_method);
-    UI_add_user_data(ui, ui_data);
+    if (ui_method != NULL) {
+        UI_set_method(ui, ui_method);
+        if (ui_data != NULL)
+            UI_add_user_data(ui, ui_data);
+    }
 
     /* Get an application constructed prompt */
     prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
diff --git a/crypto/serializer/serializer_local.h b/crypto/serializer/serializer_local.h
index acf600c285..d139e402d7 100644
--- a/crypto/serializer/serializer_local.h
+++ b/crypto/serializer/serializer_local.h
@@ -96,17 +96,18 @@ struct ossl_deserializer_ctx_st {
     STACK_OF(OSSL_DESERIALIZER_INSTANCE) *deser_insts;
 
     /*
-     * The finalizer of a deserialization, and its caller argument.
+     * The constructors of a deserialization, and its caller argument.
      */
-    OSSL_DESERIALIZER_FINALIZER *finalizer;
-    OSSL_DESERIALIZER_CLEANER *cleaner;
-    void *finalize_arg;
+    OSSL_DESERIALIZER_CONSTRUCT *construct;
+    OSSL_DESERIALIZER_CLEANUP *cleanup;
+    void *construct_data;
 
     /* For any function that needs a passphrase reader */
+    OSSL_PASSPHRASE_CALLBACK *passphrase_cb;
     const UI_METHOD *ui_method;
     void *ui_data;
     /*
-     * if caller used OSSL_SERIALIZER_CTX_set_passphrase_cb(), we need
+     * if caller used OSSL_SERIALIZER_CTX_set_pem_password_cb(), we need
      * intermediary storage.
      */
     UI_METHOD *allocated_ui_method;
@@ -117,6 +118,16 @@ struct ossl_deserializer_ctx_st {
      */
     unsigned char *cached_passphrase;
     size_t cached_passphrase_len;
+
+    /*
+     * Flag section.  Keep these together
+     */
+
+    /*
+     * The passphrase was passed to us by the user.  In that case, it
+     * should only be freed when freeing this context.
+     */
+    unsigned int flag_user_passphrase:1;
 };
 
 /* Passphrase callbacks, found in serdes_pass.c */
diff --git a/doc/man3/EVP_PKEY_set1_RSA.pod b/doc/man3/EVP_PKEY_set1_RSA.pod
index 10a8e94661..89737a3c8c 100644
--- a/doc/man3/EVP_PKEY_set1_RSA.pod
+++ b/doc/man3/EVP_PKEY_set1_RSA.pod
@@ -3,10 +3,18 @@
 =head1 NAME
 
 EVP_PKEY_set1_RSA, EVP_PKEY_set1_DSA, EVP_PKEY_set1_DH, EVP_PKEY_set1_EC_KEY,
+EVP_PKEY_set1_ED25519, EVP_PKEY_set1_ED448,
+EVP_PKEY_set1_X25519, EVP_PKEY_set1_X448,
 EVP_PKEY_get1_RSA, EVP_PKEY_get1_DSA, EVP_PKEY_get1_DH, EVP_PKEY_get1_EC_KEY,
+EVP_PKEY_get1_ED25519, EVP_PKEY_get1_ED448,
+EVP_PKEY_get1_X25519, EVP_PKEY_get1_X448,
 EVP_PKEY_get0_RSA, EVP_PKEY_get0_DSA, EVP_PKEY_get0_DH, EVP_PKEY_get0_EC_KEY,
+EVP_PKEY_get0_ED25519, EVP_PKEY_get0_ED448,
+EVP_PKEY_get0_X25519, EVP_PKEY_get0_X448,
 EVP_PKEY_assign_RSA, EVP_PKEY_assign_DSA, EVP_PKEY_assign_DH,
 EVP_PKEY_assign_EC_KEY, EVP_PKEY_assign_POLY1305, EVP_PKEY_assign_SIPHASH,
+EVP_PKEY_assign_ED25519, EVP_PKEY_assign_ED448,
+EVP_PKEY_assign_X25519, EVP_PKEY_assign_X448,
 EVP_PKEY_get0_hmac, EVP_PKEY_get0_poly1305, EVP_PKEY_get0_siphash,
 EVP_PKEY_type, EVP_PKEY_id, EVP_PKEY_base_id, EVP_PKEY_set_alias_type,
 EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
@@ -19,11 +27,19 @@ EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
  int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key);
  int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key);
  int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key);
+ int EVP_PKEY_set1_ED25519(EVP_PKEY *pkey, ECX_KEY *key);
+ int EVP_PKEY_set1_ED448(EVP_PKEY *pkey, ECX_KEY *key);
+ int EVP_PKEY_set1_X25519(EVP_PKEY *pkey, ECX_KEY *key);
+ int EVP_PKEY_set1_X448(EVP_PKEY *pkey, ECX_KEY *key);
 
  RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
  DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
  DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey);
  EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get1_ED25519(EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get1_ED448(EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get1_X25519(EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get1_X448(EVP_PKEY *pkey);
 
  const unsigned char *EVP_PKEY_get0_hmac(const EVP_PKEY *pkey, size_t *len);
  const unsigned char *EVP_PKEY_get0_poly1305(const EVP_PKEY *pkey, size_t *len);
@@ -32,11 +48,19 @@ EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
  DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey);
  DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey);
  EC_KEY *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get0_ED25519(EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get0_ED448(EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get0_X25519(EVP_PKEY *pkey);
+ ECX_KEY *EVP_PKEY_get0_X448(EVP_PKEY *pkey);
 
  int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key);
  int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key);
  int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key);
  int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key);
+ int EVP_PKEY_assign_ED25519(EVP_PKEY *pkey, ECX_KEY *key);
+ int EVP_PKEY_assign_ED448(EVP_PKEY *pkey, ECX_KEY *key);
+ int EVP_PKEY_assign_X25519(EVP_PKEY *pkey, ECX_KEY *key);
+ int EVP_PKEY_assign_X448(EVP_PKEY *pkey, ECX_KEY *key);
  int EVP_PKEY_assign_POLY1305(EVP_PKEY *pkey, ASN1_OCTET_STRING *key);
  int EVP_PKEY_assign_SIPHASH(EVP_PKEY *pkey, ASN1_OCTET_STRING *key);
 
@@ -50,24 +74,31 @@ EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
 
 =head1 DESCRIPTION
 
-EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH() and
-EVP_PKEY_set1_EC_KEY() set the key referenced by I<pkey> to I<key>.
+EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH(),
+EVP_PKEY_set1_EC_KEY(), EVP_PKEY_set1_ED25519(), EVP_PKEY_set1_ED448(),
+EVP_PKEY_set1_X25519() and EVP_PKEY_set1_X448() set the key referenced by
+I<pkey> to I<key>.
 
 EVP_PKEY_get1_RSA(), EVP_PKEY_get1_DSA(), EVP_PKEY_get1_DH() and
-EVP_PKEY_get1_EC_KEY() return the referenced key in I<pkey> or
-NULL if the key is not of the correct type.
+EVP_PKEY_get1_EC_KEY(), EVP_PKEY_get1_ED25519(), EVP_PKEY_get1_ED448(),
+EVP_PKEY_get1_X25519() and EVP_PKEY_get1_X448() return the referenced key in
+I<pkey> or NULL if the key is not of the correct type.  The returned key must
+be freed after use.
 
 EVP_PKEY_get0_hmac(), EVP_PKEY_get0_poly1305(), EVP_PKEY_get0_siphash(),
-EVP_PKEY_get0_RSA(), EVP_PKEY_get0_DSA(), EVP_PKEY_get0_DH()
-and EVP_PKEY_get0_EC_KEY() also return the referenced key in I<pkey> or NULL
-if the key is not of the correct type but the reference count of the
-returned key is B<not> incremented and so must not be freed up after use.
+EVP_PKEY_get0_RSA(), EVP_PKEY_get0_DSA(), EVP_PKEY_get0_DH(),
+EVP_PKEY_get0_EC_KEY(), EVP_PKEY_get0_ED25519(), EVP_PKEY_get0_ED448(),
+EVP_PKEY_get0_X25519() and EVP_PKEY_get0_X448() return the referenced
+key in I<pkey> or NULL if the key is not of the correct type but the
+reference count of the returned key is B<not> incremented and so must not be
+freed after use.
 
 EVP_PKEY_assign_RSA(), EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH(),
-EVP_PKEY_assign_EC_KEY(), EVP_PKEY_assign_POLY1305() and
-EVP_PKEY_assign_SIPHASH() also set the referenced key to I<key>
-however these use the supplied I<key> internally and so I<key>
-will be freed when the parent I<pkey> is freed.
+EVP_PKEY_assign_EC_KEY(), EVP_PKEY_assign_ED25519(), EVP_PKEY_assign_ED448(),
+EVP_PKEY_assign_X25519(), EVP_PKEY_assign_X448(), EVP_PKEY_assign_POLY1305() and
+EVP_PKEY_assign_SIPHASH() set the referenced key to I<key> however these use
+the supplied I<key> internally and so I<key> will be freed when the parent
+I<pkey> is freed.
 
 EVP_PKEY_base_id() returns the type of I<pkey>. For example
 an RSA key will return B<EVP_PKEY_RSA>.
diff --git a/doc/man3/OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY.pod b/doc/man3/OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY.pod
index 9ed4e5992e..c8466657c9 100644
--- a/doc/man3/OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY.pod
+++ b/doc/man3/OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY.pod
@@ -3,9 +3,8 @@
 =head1 NAME
 
 OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY,
-OSSL_DESERIALIZER_CTX_set_cipher,
 OSSL_DESERIALIZER_CTX_set_passphrase,
-OSSL_DESERIALIZER_CTX_set_passphrase_cb,
+OSSL_DESERIALIZER_CTX_set_pem_password_cb,
 OSSL_DESERIALIZER_CTX_set_passphrase_ui
 - Deserializer routines to deserialize EVP_PKEYs
 
@@ -19,14 +18,12 @@ OSSL_DESERIALIZER_CTX_set_passphrase_ui
                                        OPENSSL_CTX *libctx,
                                        const char *propquery);
 
- int OSSL_DESERIALIZER_CTX_set_cipher(OSSL_DESERIALIZER_CTX *ctx,
-                                      const char *cipher_name,
-                                      const char *propquery);
  int OSSL_DESERIALIZER_CTX_set_passphrase(OSSL_DESERIALIZER_CTX *ctx,
                                           const unsigned char *kstr,
                                           size_t klen);
- int OSSL_DESERIALIZER_CTX_set_passphrase_cb(OSSL_DESERIALIZER_CTX *ctx,
-                                             pem_password_cb *cb, void *cbarg);
+ int OSSL_DESERIALIZER_CTX_set_pem_password_cb(OSSL_DESERIALIZER_CTX *ctx,
+                                               pem_password_cb *cb,
+                                               void *cbarg);
  int OSSL_DESERIALIZER_CTX_set_passphrase_ui(OSSL_DESERIALIZER_CTX *ctx,
                                              const UI_METHOD *ui_method,
                                              void *ui_data);
@@ -55,38 +52,35 @@ zero).  This helps the caller distinguish between an error when
 creating the B<OSSL_DESERIALIZER_CTX>, and the lack the deserializer
 support and act accordingly.
 
-OSSL_DESERIALIZER_CTX_set_cipher() tells the implementation what cipher
-should be used to decrypt serialized keys.  The cipher is given by
-name I<cipher_name>.  The interpretation of that I<cipher_name> is
-implementation dependent.  The implementation may implement the cipher
-directly itself, or it may choose to fetch it.  If the implementation
-supports fetching the cipher, then it may use I<propquery> as
-properties to be queried for when fetching.  I<cipher_name> may also
-be NULL, which will result in failure if the serialized input is an
-encrypted key.
-
 OSSL_DESERIALIZER_CTX_set_passphrase() gives the implementation a
 pass phrase to use when decrypting the serialized private key.
 Alternatively, a pass phrase callback may be specified with the
 following functions.
 
-OSSL_DESERIALIZER_CTX_set_passphrase_cb() and
-OSSL_DESERIALIZER_CTX_set_passphrase_ui() sets up a callback method that
-the implementation can use to prompt for a pass phrase.
+OSSL_DESERIALIZER_CTX_set_pem_password_cb() and
+OSSL_DESERIALIZER_CTX_set_passphrase_ui() set up a callback method that
+the implementation can use to prompt for a pass phrase, giving the caller
+the choice of prefered pass phrase callback form.  These are called
+indirectly, through an internal B<OSSL_PASSPHRASE_CALLBACK> function.
+
+The internal B<OSSL_PASSPHRASE_CALLBACK> function caches the pass phrase, to
+be re-used in all deserializations that are performed in the same
+deserialization run
+(for example, within one L<OSSL_DESERIALIZER_from_bio(3)> call).
 
-=for comment Note that the callback method is called indirectly,
-through an internal B<OSSL_PASSPHRASE_CALLBACK> function.
+=for comment the name OSSL_DESERIALIZER_CTX_set_pem_password_cb() leaves
+open the future possibility of having a function where the caller can set a
+B<OSSL_PASSPHRASE_CALLBACK> method as another option.
 
 =head1 RETURN VALUES
 
 OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY() returns a pointer to a
 B<OSSL_DESERIALIZER_CTX>, or NULL if it couldn't be created.
 
-OSSL_DESERIALIZER_CTX_set_cipher(),
 OSSL_DESERIALIZER_CTX_set_passphrase(),
-OSSL_DESERIALIZER_CTX_set_passphrase_cb(), and
-OSSL_DESERIALIZER_CTX_set_passphrase_ui() all return 1 on success, or 0
-on failure.
+OSSL_DESERIALIZER_CTX_set_pem_password_cb() and
+OSSL_DESERIALIZER_CTX_set_passphrase_ui()
+all return 1 on success, or 0 on failure.
 
 =head1 NOTES
 
diff --git a/doc/man3/OSSL_DESERIALIZER_from_bio.pod b/doc/man3/OSSL_DESERIALIZER_from_bio.pod
index 8c372a6cf6..1aa54899a5 100644
--- a/doc/man3/OSSL_DESERIALIZER_from_bio.pod
+++ b/doc/man3/OSSL_DESERIALIZER_from_bio.pod
@@ -9,9 +9,14 @@ OSSL_DESERIALIZER_CTX_add_deserializer,
 OSSL_DESERIALIZER_CTX_add_extra,
 OSSL_DESERIALIZER_CTX_num_deserializers,
 OSSL_DESERIALIZER_INSTANCE,
-OSSL_DESERIALIZER_FINALIZER,
-OSSL_DESERIALIZER_CLEANER,
-OSSL_DESERIALIZER_CTX_set_finalizer,
+OSSL_DESERIALIZER_CONSTRUCT,
+OSSL_DESERIALIZER_CLEANUP,
+OSSL_DESERIALIZER_CTX_set_construct,
+OSSL_DESERIALIZER_CTX_set_construct_data,
+OSSL_DESERIALIZER_CTX_set_cleanup,
+OSSL_DESERIALIZER_CTX_get_construct,
+OSSL_DESERIALIZER_CTX_get_construct_data,
+OSSL_DESERIALIZER_CTX_get_cleanup,
 OSSL_DESERIALIZER_export,
 OSSL_DESERIALIZER_INSTANCE_deserializer,
 OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
@@ -32,25 +37,32 @@ OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
  int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx);
 
  typedef struct ossl_deserializer_instance_st OSSL_DESERIALIZER_INSTANCE;
- typedef int (OSSL_DESERIALIZER_FINALIZER)
-     (OSSL_DESERIALIZER_INSTANCE *deser_inst,
-      const OSSL_PARAM *params, void *finalize_arg);
- typedef void (OSSL_DESERIALIZER_CLEANER)(void *finalize_arg);
+ OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
+     (OSSL_DESERIALIZER_INSTANCE *deser_inst);
+ void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
+     (OSSL_DESERIALIZER_INSTANCE *deser_inst);
 
- int OSSL_DESERIALIZER_CTX_set_finalizer(OSSL_DESERIALIZER_CTX *ctx,
-                                         OSSL_DESRIALIZER_FINALIZER *finalizer,
-                                         OSSL_DESERIALIZER_CLEANER *cleaner,
-                                         void *finalize_arg);
+ typedef int (OSSL_DESERIALIZER_CONSTRUCT)
+     (OSSL_DESERIALIZER_INSTANCE *deser_inst,
+      const OSSL_PARAM *params, void *construct_data);
+ typedef void (OSSL_DESERIALIZER_CLEANUP)(void *construct_data);
+
+ int OSSL_DESERIALIZER_CTX_set_construct
+     (OSSL_DESERIALIZER_CTX *ctx, OSSL_DESERIALIZER_CONSTRUCT *construct);
+ int OSSL_DESERIALIZER_CTX_set_construct_data
+     (OSSL_DESERIALIZER_CTX *ctx, void *construct_data);
+ int OSSL_DESERIALIZER_CTX_set_cleanup(OSSL_DESERIALIZER_CTX *ctx,
+                                       OSSL_DESERIALIZER_CLEANUP *cleanup);
+ OSSL_DESERIALIZER_CONSTRUCT *
+ OSSL_DESERIALIZER_CTX_get_construct(OSSL_DESERIALIZER_CTX *ctx);
+ void *OSSL_DESERIALIZER_CTX_get_construct_data(OSSL_DESERIALIZER_CTX *ctx);
+ OSSL_DESERIALIZER_CLEANUP *
+ OSSL_DESERIALIZER_CTX_get_cleanup(OSSL_DESERIALIZER_CTX *ctx);
 
  int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
                               void *reference, size_t reference_sz,
                               OSSL_CALLBACK *export_cb, void *export_cbarg);
 
- OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
-     (OSSL_DESERIALIZER_INSTANCE *deser_inst);
- void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
-     (OSSL_DESERIALIZER_INSTANCE *deser_inst);
-
 Feature availability macros:
 
 =over 4
@@ -83,26 +95,23 @@ what type of input they have.  In this case, OSSL_DESERIALIZER_from_bio()
 will simply try with one deserializer implementation after the other, and
 thereby discover what kind of input the caller gave it.
 
-For every deserialization done, even intermediary, a I<finalizer>
-provided by the caller is used to attempt to "finalize" the current
-deserialization output, which is always a provider side object of some
-sort, by "wrapping" it into some appropriate type or structure that
-the caller knows how to handle.  Exactly what this "wrapping" consists
-of is entirely at the discretion of the I<finalizer>.
+For every deserialization done, even an intermediary one, a constructor
+provided by the caller is called to attempt to construct an appropriate type
+/ structure that the caller knows how to handle from the current
+deserialization result.
+The constructor is set with OSSL_DESERIALIZER_CTX_set_construct().
 
 B<OSSL_DESERIALIZER_INSTANCE> is an opaque structure that contains
 data about the deserializer that was just used, and that may be
-useful for the I<finalizer>.  There are some functions to extract data
+useful for the constructor.  There are some functions to extract data
 from this type, described further down.
 
 =head2 Functions
 
 OSSL_DESERIALIZER_from_bio() runs the deserialization process for the
-context I<ctx>, with the input coming from the B<BIO> I<in>.  The
-application is required to set up the B<BIO> properly, for example to
-have it in text or binary mode if that's appropriate.
-
-=for comment Know your deserializer!
+context I<ctx>, with the input coming from the B<BIO> I<in>.  Should
+it make a difference, it's recommended to have the BIO set in binary
+mode rather than text mode.
 
 OSSL_DESERIALIZER_from_fp() does the same thing as OSSL_DESERIALIZER_from_bio(),
 except that the input is coming from the B<FILE> I<fp>.
@@ -122,17 +131,28 @@ description above.
 OSSL_DESERIALIZER_CTX_num_deserializers() gets the number of
 deserializers currently added to the context I<ctx>.
 
-OSSL_DESERIALIZER_CTX_set_finalizer() sets the I<finalizer> function
-together with the caller argument for the finalizer, I<finalize_arg>,
-as well as I<cleaner>, the function to clean up I<finalize_arg> when
-the deserialization has concluded.
+OSSL_DESERIALIZER_CTX_set_construct() sets the constructor I<construct>.
 
-OSSL_DESERIALIZER_export() is a fallback function for I<finalizers>
-that can't use the data they get directly for diverse reasons.  It
-takes the same deserialize instance I<deser_inst> that the
-I<finalizer> got and an object I<reference>, unpacks the object that
-refers to, and exports it by creating an L<OSSL_PARAM(3)> array that
-it then passes to I<export_cb>, along with I<export_arg>.
+OSSL_DESERIALIZER_CTX_set_construct_data() sets the constructor data that is
+passed to the constructor every time it's called.
+
+OSSL_DESERIALIZER_CTX_set_cleanup() sets the constructor data I<cleanup>
+function.  This is called by L<OSSL_DESERIALIZER_CTX_free(3)>.
+
+OSSL_DESERIALIZER_CTX_get_construct(),
+OSSL_DESERIALIZER_CTX_get_construct_data() and
+OSSL_DESERIALIZER_CTX_get_cleanup()
+return the values that have been set by
+OSSL_DESERIALIZER_CTX_set_construct(),
+OSSL_DESERIALIZER_CTX_set_construct_data() and
+OSSL_DESERIALIZER_CTX_set_cleanup() respectively.
+
+OSSL_DESERIALIZER_export() is a fallback function for constructors that
+cannot use the data they get directly for diverse reasons.  It takes the same
+deserialize instance I<deser_inst> that the constructor got and an object
+I<reference>, unpacks the object which it refers to, and exports it by creating
+an L<OSSL_PARAM(3)> array that it then passes to I<export_cb>, along with
+I<export_arg>.
 
 OSSL_DESERIALIZER_INSTANCE_deserializer() can be used to get the
 deserializer method from a deserializer instance I<deser_inst>.
@@ -141,32 +161,31 @@ OSSL_DESERIALIZER_INSTANCE_deserializer-ctx() can be used to get the
 deserializer method's provider context from a deserializer instance
 I<deser_inst>.
 
-=head2 Finalizer
+=head2 Constructor
 
-The I<finalizer> gets the following arguments:
+A B<OSSL_DESERIALIZER_CONSTRUCT> gets the following arguments:
 
 =over 4
 
 =item I<deser_inst>
 
 The B<OSSL_DESERIALIZER_INSTANCE> for the deserializer from which
-I<finalizer> gets its data.
+the constructor gets its data.
 
 =item I<params>
 
 The data produced by the deserializer, further described below.
 
-=item I<finalize_arg>
+=item I<construct_data>
 
-The pointer that was set with OSSL_DESERIALIZE_CTX_set_finalizer() as
-I<finalize_arg>.
+The pointer that was set with OSSL_DESERIALIZE_CTX_set_construct_data().
 
 =back
 
-The I<finalizer> is expected to return 1 when the data it receives can
-be "finalized", otherwise 0.
+The constructor is expected to return 1 when the data it receives can
+be constructed, otherwise 0.
 
-The globally known parameters that I<finalize> can get in I<params>
+The globally known parameters that the constructor can get in I<params>
 are:
 
 =over 4
@@ -177,7 +196,7 @@ This is a detected content type that some deserializers may provide.
 For example, PEM input sometimes has a type specified in its header,
 and some deserializers may add that information as this parameter.
 This is an optional parameter, but may be useful for extra checks in
-the I<finalizer>.
+the constructor.
 
 =item "data" (B<OSSL_DESERIALIZER_PARAM_DATA>) <octet string>
 
@@ -185,7 +204,7 @@ The deserialized data itself, as an octet string.  This is produced by
 deserializers when it's possible to pass an object in this form.  Most
 often, this is simply meant to be passed to the next deserializer in a
 chain, but could be considered final data as well, at the discretion
-of the I<finalizer>.
+of the constructor.
 
 =item "reference" (B<OSSL_DESERIALIZER_PARAM_DATA>) <octet string>
 
@@ -197,11 +216,12 @@ provides I<deser>.
 =back
 
 At least one of "data" or "reference" must be present, and it's
-possible that both can be.  A I<finalizer> should choose to use the
-"reference" parameter if possible, otherwise the "data" parameter.
+possible that both can be.  A constructor should choose to use the
+"reference" parameter if possible, otherwise it should use the "data"
+parameter.
 
 If it's not possible to use the "reference" parameter, but that's
-still what a I<finalizer> wants to do, it is possible to use
+still what a constructor wants to do, it is possible to use
 OSSL_DESERIALIZER_export() as a fallback.
 
 =head1 RETURN VALUES
@@ -210,10 +230,17 @@ OSSL_DESERIALIZER_from_bio() and OSSL_DESERIALIZER_from_fp() return 1 on
 success, or 0 on failure.
 
 OSSL_DESERIALIZER_CTX_add_deserializer(),
-OSSL_DESERIALIZER_CTX_add_extra(), and
-OSSL_DESERIALIZER_CTX_set_finalizer() return 1 on success, or 0 on
+OSSL_DESERIALIZER_CTX_add_extra(),
+OSSL_DESERIALIZER_CTX_set_construct(),
+OSSL_DESERIALIZER_CTX_set_construct_data() and
+OSSL_DESERIALIZER_CTX_set_cleanup() return 1 on success, or 0 on
 failure.
 
+OSSL_DESERIALIZER_CTX_get_construct(),
+OSSL_DESERIALIZER_CTX_get_construct_data() and
+OSSL_DESERIALIZER_CTX_get_cleanup() return the current pointers to the
+cosntructor, the constructor data and the cleanup functions, respectively.
+
 OSSL_DESERIALIZER_CTX_num_deserializers() returns the current
 number of deserializers.  It returns 0 if I<ctx> is NULL.
 
diff --git a/include/openssl/deserializer.h b/include/openssl/deserializer.h
index d54e47915d..0133785b50 100644
--- a/include/openssl/deserializer.h
+++ b/include/openssl/deserializer.h
@@ -55,14 +55,12 @@ int OSSL_DESERIALIZER_CTX_set_params(OSSL_DESERIALIZER_CTX *ctx,
 void OSSL_DESERIALIZER_CTX_free(OSSL_DESERIALIZER_CTX *ctx);
 
 /* Utilities that help set specific parameters */
-int OSSL_DESERIALIZER_CTX_set_cipher(OSSL_DESERIALIZER_CTX *ctx,
-                                     const char *cipher_name,
-                                     const char *propquery);
 int OSSL_DESERIALIZER_CTX_set_passphrase(OSSL_DESERIALIZER_CTX *ctx,
                                          const unsigned char *kstr,
                                          size_t klen);
-int OSSL_DESERIALIZER_CTX_set_passphrase_cb(OSSL_DESERIALIZER_CTX *ctx,
-                                            pem_password_cb *cb, void *cbarg);
+int OSSL_DESERIALIZER_CTX_set_pem_password_cb(OSSL_DESERIALIZER_CTX *ctx,
+                                              pem_password_cb *cb,
+                                              void *cbarg);
 int OSSL_DESERIALIZER_CTX_set_passphrase_ui(OSSL_DESERIALIZER_CTX *ctx,
                                             const UI_METHOD *ui_method,
                                             void *ui_data);
@@ -81,25 +79,32 @@ int OSSL_DESERIALIZER_CTX_add_extra(OSSL_DESERIALIZER_CTX *ctx,
 int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx);
 
 typedef struct ossl_deserializer_instance_st OSSL_DESERIALIZER_INSTANCE;
-typedef int (OSSL_DESERIALIZER_FINALIZER)
-    (OSSL_DESERIALIZER_INSTANCE *deser_inst,
-     const OSSL_PARAM *params, void *finalize_arg);
-typedef void (OSSL_DESERIALIZER_CLEANER)(void *finalize_arg);
+OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst);
+void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst);
 
-int OSSL_DESERIALIZER_CTX_set_finalizer(OSSL_DESERIALIZER_CTX *ctx,
-                                        OSSL_DESERIALIZER_FINALIZER *finalizer,
-                                        OSSL_DESERIALIZER_CLEANER *cleaner,
-                                        void *finalize_arg);
+typedef int (OSSL_DESERIALIZER_CONSTRUCT)
+    (OSSL_DESERIALIZER_INSTANCE *deser_inst,
+     const OSSL_PARAM *params, void *construct_data);
+typedef void (OSSL_DESERIALIZER_CLEANUP)(void *construct_data);
+
+int OSSL_DESERIALIZER_CTX_set_construct(OSSL_DESERIALIZER_CTX *ctx,
+                                        OSSL_DESERIALIZER_CONSTRUCT *construct);
+int OSSL_DESERIALIZER_CTX_set_construct_data(OSSL_DESERIALIZER_CTX *ctx,
+                                             void *construct_data);
+int OSSL_DESERIALIZER_CTX_set_cleanup(OSSL_DESERIALIZER_CTX *ctx,
+                                      OSSL_DESERIALIZER_CLEANUP *cleanup);
+OSSL_DESERIALIZER_CONSTRUCT *
+OSSL_DESERIALIZER_CTX_get_construct(OSSL_DESERIALIZER_CTX *ctx);
+void *OSSL_DESERIALIZER_CTX_get_construct_data(OSSL_DESERIALIZER_CTX *ctx);
+OSSL_DESERIALIZER_CLEANUP *
+OSSL_DESERIALIZER_CTX_get_cleanup(OSSL_DESERIALIZER_CTX *ctx);
 
 int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
                              void *reference, size_t reference_sz,
                              OSSL_CALLBACK *export_cb, void *export_cbarg);
 
-OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
-    (OSSL_DESERIALIZER_INSTANCE *deser_inst);
-void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
-    (OSSL_DESERIALIZER_INSTANCE *deser_inst);
-
 int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in);
 #ifndef OPENSSL_NO_STDIO
 int OSSL_DESERIALIZER_from_fp(OSSL_DESERIALIZER_CTX *ctx, FILE *in);
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 78771ca251..57b6ff1f7c 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -466,6 +466,14 @@ typedef int (EVP_PBE_KEYGEN) (EVP_CIPHER_CTX *ctx, const char *pass,
 # ifndef OPENSSL_NO_EC
 #  define EVP_PKEY_assign_EC_KEY(pkey,eckey) EVP_PKEY_assign((pkey),EVP_PKEY_EC,\
                                         (eckey))
+#  define EVP_PKEY_assign_X25519(pkey,ecxkey) EVP_PKEY_assign((pkey),EVP_PKEY_X25519,\
+                                        (ecxkey))
+#  define EVP_PKEY_assign_X448(pkey,ecxkey) EVP_PKEY_assign((pkey),EVP_PKEY_X448,\
+                                        (ecxkey))
+#  define EVP_PKEY_assign_ED25519(pkey,ecxkey) EVP_PKEY_assign((pkey),EVP_PKEY_ED25519,\
+                                        (ecxkey))
+#  define EVP_PKEY_assign_ED448(pkey,ecxkey) EVP_PKEY_assign((pkey),EVP_PKEY_ED448,\
+                                        (ecxkey))
 # endif
 # ifndef OPENSSL_NO_SIPHASH
 #  define EVP_PKEY_assign_SIPHASH(pkey,shkey) EVP_PKEY_assign((pkey),\
@@ -1222,6 +1230,19 @@ struct ec_key_st;
 int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key);
 struct ec_key_st *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey);
 struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
+struct ecx_key_st;
+int EVP_PKEY_set1_X25519(EVP_PKEY *pkey, struct ecx_key_st *key);
+struct ecx_key_st *EVP_PKEY_get0_X25519(const EVP_PKEY *pkey);
+struct ecx_key_st *EVP_PKEY_get1_X25519(EVP_PKEY *pkey);
+int EVP_PKEY_set1_X448(EVP_PKEY *pkey, struct ecx_key_st *key);
+struct ecx_key_st *EVP_PKEY_get0_X448(const EVP_PKEY *pkey);
+struct ecx_key_st *EVP_PKEY_get1_X448(EVP_PKEY *pkey);
+int EVP_PKEY_set1_ED25519(EVP_PKEY *pkey, struct ecx_key_st *key);
+struct ecx_key_st *EVP_PKEY_get0_ED25519(const EVP_PKEY *pkey);
+struct ecx_key_st *EVP_PKEY_get1_ED25519(EVP_PKEY *pkey);
+int EVP_PKEY_set1_ED448(EVP_PKEY *pkey, struct ecx_key_st *key);
+struct ecx_key_st *EVP_PKEY_get0_ED448(const EVP_PKEY *pkey);
+struct ecx_key_st *EVP_PKEY_get1_ED448(EVP_PKEY *pkey);
 # endif
 
 EVP_PKEY *EVP_PKEY_new(void);
diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h
index 6bc106812b..5aa002815a 100644
--- a/include/openssl/evperr.h
+++ b/include/openssl/evperr.h
@@ -102,6 +102,7 @@ int ERR_load_EVP_strings(void);
 #  define EVP_F_EVP_PKEY_ENCRYPT_OLD                       0
 #  define EVP_F_EVP_PKEY_GET0_DH                           0
 #  define EVP_F_EVP_PKEY_GET0_DSA                          0
+#  define EVP_F_EVP_PKEY_GET0_ECX_KEY                      0
 #  define EVP_F_EVP_PKEY_GET0_EC_KEY                       0
 #  define EVP_F_EVP_PKEY_GET0_HMAC                         0
 #  define EVP_F_EVP_PKEY_GET0_POLY1305                     0
@@ -185,6 +186,7 @@ int ERR_load_EVP_strings(void);
 # define EVP_R_EXPECTING_AN_RSA_KEY                       127
 # define EVP_R_EXPECTING_A_DH_KEY                         128
 # define EVP_R_EXPECTING_A_DSA_KEY                        129
+# define EVP_R_EXPECTING_A_ECX_KEY                        219
 # define EVP_R_EXPECTING_A_EC_KEY                         142
 # define EVP_R_EXPECTING_A_POLY1305_KEY                   164
 # define EVP_R_EXPECTING_A_SIPHASH_KEY                    175
diff --git a/providers/deserializers.inc b/providers/deserializers.inc
index bab709d31d..ead1c67878 100644
--- a/providers/deserializers.inc
+++ b/providers/deserializers.inc
@@ -11,6 +11,20 @@
 # error Macro DESER undefined
 #endif
 
+#ifndef OPENSSL_NO_DH
+    DESER("DH", "yes", "der", der_to_dh_deserializer_functions),
+#endif
+#ifndef OPENSSL_NO_DSA
+    DESER("DSA", "yes", "der", der_to_dsa_deserializer_functions),
+#endif
+#ifndef OPENSSL_NO_EC
+    DESER("EC", "yes", "der", der_to_ec_deserializer_functions),
+    DESER("ED25519", "yes", "der", der_to_ed25519_deserializer_functions),
+    DESER("ED448", "yes", "der", der_to_ed448_deserializer_functions),
+    DESER("X25519", "yes", "der", der_to_x25519_deserializer_functions),
+    DESER("X448", "yes", "der", der_to_x448_deserializer_functions),
+#endif
     DESER("RSA", "yes", "der", der_to_rsa_deserializer_functions),
     DESER("RSA-PSS", "yes", "der", der_to_rsapss_deserializer_functions),
+
     DESER("DER", "yes", "pem", pem_to_der_deserializer_functions),
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index b02f0c6476..73d4a0225e 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -359,6 +359,13 @@ extern const OSSL_DISPATCH ec_priv_pem_serializer_functions[];
 extern const OSSL_DISPATCH ec_pub_pem_serializer_functions[];
 extern const OSSL_DISPATCH ec_param_pem_serializer_functions[];
 
+extern const OSSL_DISPATCH der_to_dh_deserializer_functions[];
+extern const OSSL_DISPATCH der_to_dsa_deserializer_functions[];
+extern const OSSL_DISPATCH der_to_ec_deserializer_functions[];
+extern const OSSL_DISPATCH der_to_x25519_deserializer_functions[];
+extern const OSSL_DISPATCH der_to_x448_deserializer_functions[];
+extern const OSSL_DISPATCH der_to_ed25519_deserializer_functions[];
+extern const OSSL_DISPATCH der_to_ed448_deserializer_functions[];
 extern const OSSL_DISPATCH der_to_rsa_deserializer_functions[];
 extern const OSSL_DISPATCH der_to_rsapss_deserializer_functions[];
 extern const OSSL_DISPATCH pem_to_der_deserializer_functions[];
diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c
index aa4097766d..2a8b7f8521 100644
--- a/providers/implementations/keymgmt/dh_kmgmt.c
+++ b/providers/implementations/keymgmt/dh_kmgmt.c
@@ -34,6 +34,7 @@ static OSSL_FUNC_keymgmt_gen_set_params_fn dh_gen_set_params;
 static OSSL_FUNC_keymgmt_gen_settable_params_fn dh_gen_settable_params;
 static OSSL_FUNC_keymgmt_gen_fn dh_gen;
 static OSSL_FUNC_keymgmt_gen_cleanup_fn dh_gen_cleanup;
+static OSSL_FUNC_keymgmt_load_fn dh_load;
 static OSSL_FUNC_keymgmt_get_params_fn dh_get_params;
 static OSSL_FUNC_keymgmt_gettable_params_fn dh_gettable_params;
 static OSSL_FUNC_keymgmt_set_params_fn dh_set_params;
@@ -644,6 +645,20 @@ static void dh_gen_cleanup(void *genctx)
     OPENSSL_free(gctx);
 }
 
+void *dh_load(const void *reference, size_t reference_sz)
+{
+    DH *dh = NULL;
+
+    if (reference_sz == sizeof(dh)) {
+        /* The contents of the reference is the address to our object */
+        dh = *(DH **)reference;
+        /* We grabbed, so we detach it */
+        *(DH **)reference = NULL;
+        return dh;
+    }
+    return NULL;
+}
+
 const OSSL_DISPATCH dh_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dh_newdata },
     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dh_gen_init },
@@ -653,6 +668,7 @@ const OSSL_DISPATCH dh_keymgmt_functions[] = {
       (void (*)(void))dh_gen_settable_params },
     { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dh_gen },
     { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dh_gen_cleanup },
+    { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dh_load },
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata },
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c
index 3d38fea44d..58e9fc564f 100644
--- a/providers/implementations/keymgmt/dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/dsa_kmgmt.c
@@ -34,6 +34,7 @@ static OSSL_FUNC_keymgmt_gen_set_params_fn dsa_gen_set_params;
 static OSSL_FUNC_keymgmt_gen_settable_params_fn dsa_gen_settable_params;
 static OSSL_FUNC_keymgmt_gen_fn dsa_gen;
 static OSSL_FUNC_keymgmt_gen_cleanup_fn dsa_gen_cleanup;
+static OSSL_FUNC_keymgmt_load_fn dsa_load;
 static OSSL_FUNC_keymgmt_get_params_fn dsa_get_params;
 static OSSL_FUNC_keymgmt_gettable_params_fn dsa_gettable_params;
 static OSSL_FUNC_keymgmt_has_fn dsa_has;
@@ -557,6 +558,20 @@ static void dsa_gen_cleanup(void *genctx)
     OPENSSL_free(gctx);
 }
 
+void *dsa_load(const void *reference, size_t reference_sz)
+{
+    DSA *dsa = NULL;
+
+    if (reference_sz == sizeof(dsa)) {
+        /* The contents of the reference is the address to our object */
+        dsa = *(DSA **)reference;
+        /* We grabbed, so we detach it */
+        *(DSA **)reference = NULL;
+        return dsa;
+    }
+    return NULL;
+}
+
 const OSSL_DISPATCH dsa_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dsa_newdata },
     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dsa_gen_init },
@@ -566,6 +581,7 @@ const OSSL_DISPATCH dsa_keymgmt_functions[] = {
       (void (*)(void))dsa_gen_settable_params },
     { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dsa_gen },
     { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dsa_gen_cleanup },
+    { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))dsa_load },
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dsa_freedata },
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dsa_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dsa_gettable_params },
diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c
index c1114eee7f..4d040a1902 100644
--- a/providers/implementations/keymgmt/ec_kmgmt.c
+++ b/providers/implementations/keymgmt/ec_kmgmt.c
@@ -33,6 +33,7 @@ static OSSL_FUNC_keymgmt_gen_set_params_fn ec_gen_set_params;
 static OSSL_FUNC_keymgmt_gen_settable_params_fn ec_gen_settable_params;
 static OSSL_FUNC_keymgmt_gen_fn ec_gen;
 static OSSL_FUNC_keymgmt_gen_cleanup_fn ec_gen_cleanup;
+static OSSL_FUNC_keymgmt_load_fn ec_load;
 static OSSL_FUNC_keymgmt_free_fn ec_freedata;
 static OSSL_FUNC_keymgmt_get_params_fn ec_get_params;
 static OSSL_FUNC_keymgmt_gettable_params_fn ec_gettable_params;
@@ -299,7 +300,7 @@ static int ec_match(const void *keydata1, const void *keydata2, int selection)
         const EC_POINT *pa = EC_KEY_get0_public_key(ec1);
         const EC_POINT *pb = EC_KEY_get0_public_key(ec2);
 
-        ok = ok && EC_POINT_cmp(group_b, pa, pb, NULL);
+        ok = ok && EC_POINT_cmp(group_b, pa, pb, NULL) == 0;
     }
     return ok;
 }
@@ -791,6 +792,20 @@ static void ec_gen_cleanup(void *genctx)
     OPENSSL_free(gctx);
 }
 
+void *ec_load(const void *reference, size_t reference_sz)
+{
+    EC_KEY *ec = NULL;
+
+    if (reference_sz == sizeof(ec)) {
+        /* The contents of the reference is the address to our object */
+        ec = *(EC_KEY **)reference;
+        /* We grabbed, so we detach it */
+        *(EC_KEY **)reference = NULL;
+        return ec;
+    }
+    return NULL;
+}
+
 const OSSL_DISPATCH ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata },
     { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))ec_gen_init },
@@ -801,6 +816,7 @@ const OSSL_DISPATCH ec_keymgmt_functions[] = {
       (void (*)(void))ec_gen_settable_params },
     { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))ec_gen },
     { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ec_gen_cleanup },
+    { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))ec_load },
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata },
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))ec_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ec_gettable_params },
diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c
index 542592666e..a1e1edbf5a 100644
--- a/providers/implementations/keymgmt/ecx_kmgmt.c
+++ b/providers/implementations/keymgmt/ecx_kmgmt.c
@@ -41,6 +41,7 @@ static OSSL_FUNC_keymgmt_gen_fn x448_gen;
 static OSSL_FUNC_keymgmt_gen_fn ed25519_gen;
 static OSSL_FUNC_keymgmt_gen_fn ed448_gen;
 static OSSL_FUNC_keymgmt_gen_cleanup_fn ecx_gen_cleanup;
+static OSSL_FUNC_keymgmt_load_fn ecx_load;
 static OSSL_FUNC_keymgmt_get_params_fn x25519_get_params;
 static OSSL_FUNC_keymgmt_get_params_fn x448_get_params;
 static OSSL_FUNC_keymgmt_get_params_fn ed25519_get_params;
@@ -589,6 +590,20 @@ static void ecx_gen_cleanup(void *genctx)
     OPENSSL_free(gctx);
 }
 
+void *ecx_load(const void *reference, size_t reference_sz)
+{
+    ECX_KEY *key = NULL;
+
+    if (reference_sz == sizeof(key)) {
+        /* The contents of the reference is the address to our object */
+        key = *(ECX_KEY **)reference;
+        /* We grabbed, so we detach it */
+        *(ECX_KEY **)reference = NULL;
+        return key;
+    }
+    return NULL;
+}
+
 #define MAKE_KEYMGMT_FUNCTIONS(alg) \
     const OSSL_DISPATCH alg##_keymgmt_functions[] = { \
         { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))alg##_new_key }, \
@@ -609,6 +624,7 @@ static void ecx_gen_cleanup(void *genctx)
           (void (*)(void))ecx_gen_settable_params }, \
         { 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 }, \
         { 0, NULL } \
     };
 
diff --git a/providers/implementations/serializers/build.info b/providers/implementations/serializers/build.info
index bcfe9d4d4b..d660385163 100644
--- a/providers/implementations/serializers/build.info
+++ b/providers/implementations/serializers/build.info
@@ -2,6 +2,7 @@
 # switch each to the Legacy provider when needed.
 
 $SERIALIZER_GOAL=../../libimplementations.a
+$DESERIALIZER_GOAL=../../libimplementations.a
 $RSA_GOAL=../../libimplementations.a
 $FFC_GOAL=../../libimplementations.a
 $DH_GOAL=../../libimplementations.a
@@ -11,7 +12,7 @@ $EC_GOAL=../../libimplementations.a
 
 SOURCE[$SERIALIZER_GOAL]=serializer_common.c deserialize_common.c
 
-SOURCE[$RSA_GOAL]=deserialize_der2rsa.c deserialize_pem2der.c
+SOURCE[$RSA_GOAL]=deserialize_der2key.c deserialize_pem2der.c
 SOURCE[$RSA_GOAL]=serializer_rsa.c serializer_rsa_priv.c serializer_rsa_pub.c
 DEPEND[serializer_rsa.o]=../../common/include/prov/der_rsa.h
 
diff --git a/providers/implementations/serializers/deserialize_common.c b/providers/implementations/serializers/deserialize_common.c
index 449d57b0a3..1a9d3d4a77 100644
--- a/providers/implementations/serializers/deserialize_common.c
+++ b/providers/implementations/serializers/deserialize_common.c
@@ -47,7 +47,7 @@ int ossl_prov_read_pem(PROV_CTX *provctx, OSSL_CORE_BIO *cin,
 
 int ossl_prov_der_from_p8(unsigned char **new_der, long *new_der_len,
                           unsigned char *input_der, long input_der_len,
-                          struct pkcs8_encrypt_ctx_st *ctx)
+                          OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
 {
     const unsigned char *derp;
     X509_SIG *p8 = NULL;
@@ -57,30 +57,20 @@ int ossl_prov_der_from_p8(unsigned char **new_der, long *new_der_len,
         || !ossl_assert(new_der_len != NULL))
         return 0;
 
-    if (ctx->cipher == NULL)
-        return 0;
-
     derp = input_der;
     if ((p8 = d2i_X509_SIG(NULL, &derp, input_der_len)) != NULL) {
         char pbuf[PEM_BUFSIZE];
-        const void *pstr = ctx->cipher_pass;
-        size_t plen = ctx->cipher_pass_length;
-
-        if (pstr == NULL) {
-            pstr = pbuf;
-            if (!ctx->cb(pbuf, sizeof(pbuf), &plen, NULL, ctx->cbarg)) {
-                ERR_raise(ERR_LIB_PROV, PROV_R_READ_KEY);
-                pstr = NULL;
-            }
-        }
+        size_t plen = 0;
 
-        if (pstr != NULL) {
+        if (!pw_cb(pbuf, sizeof(pbuf), &plen, NULL, pw_cbarg)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_READ_KEY);
+        } else {
             const X509_ALGOR *alg = NULL;
             const ASN1_OCTET_STRING *oct = NULL;
             int len = 0;
 
             X509_SIG_get0(p8, &alg, &oct);
-            if (PKCS12_pbe_crypt(alg, pstr, plen, oct->data, oct->length,
+            if (PKCS12_pbe_crypt(alg, pbuf, plen, oct->data, oct->length,
                                  new_der, &len, 0) != NULL)
                 ok = 1;
             *new_der_len = len;
diff --git a/providers/implementations/serializers/deserialize_der2key.c b/providers/implementations/serializers/deserialize_der2key.c
new file mode 100644
index 0000000000..a544d8522c
--- /dev/null
+++ b/providers/implementations/serializers/deserialize_der2key.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/crypto.h>
+#include <openssl/params.h>
+#include <openssl/x509.h>
+#include "prov/bio.h"
+#include "prov/implementations.h"
+#include "serializer_local.h"
+
+static OSSL_FUNC_deserializer_newctx_fn der2rsa_newctx;
+
+static OSSL_FUNC_deserializer_freectx_fn der2key_freectx;
+static OSSL_FUNC_deserializer_gettable_params_fn der2key_gettable_params;
+static OSSL_FUNC_deserializer_get_params_fn der2key_get_params;
+static OSSL_FUNC_deserializer_deserialize_fn der2key_deserialize;
+static OSSL_FUNC_deserializer_export_object_fn der2key_export_object;
+
+typedef void *(extract_key_fn)(EVP_PKEY *);
+typedef void (free_key_fn)(void *);
+struct keytype_desc_st {
+    int type;                 /* EVP key type */
+    const char *name;         /* Keytype */
+    const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */
+
+    /*
+     * These must be the correct EVP_PKEY_get1_{TYPE}() and {TYPE}_free()
+     * function for the key.
+     */
+    extract_key_fn *extract_key;
+    free_key_fn *free_key;
+};
+
+/*
+ * Context used for DER to key deserialization.
+ */
+struct der2key_ctx_st {
+    PROV_CTX *provctx;
+    const struct keytype_desc_st *desc;
+};
+
+static struct der2key_ctx_st *
+der2key_newctx(void *provctx, const struct keytype_desc_st *desc)
+{
+    struct der2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+    if (ctx != NULL) {
+        ctx->provctx = provctx;
+        ctx->desc = desc;
+    }
+    return ctx;
+}
+
+static void der2key_freectx(void *vctx)
+{
+    struct der2key_ctx_st *ctx = vctx;
+
+    OPENSSL_free(ctx);
+}
+
+static const OSSL_PARAM *der2key_gettable_params(void)
+{
+    static const OSSL_PARAM gettables[] = {
+        { OSSL_DESERIALIZER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
+        OSSL_PARAM_END,
+    };
+
+    return gettables;
+}
+
+static int der2key_get_params(OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate(params, OSSL_DESERIALIZER_PARAM_INPUT_TYPE);
+    if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, "DER"))
+        return 0;
+
+    return 1;
+}
+
+static int der2key_deserialize(void *vctx, OSSL_CORE_BIO *cin,
+                               OSSL_CALLBACK *data_cb, void *data_cbarg,
+                               OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
+{
+    struct der2key_ctx_st *ctx = vctx;
+    void *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+    unsigned char *der = NULL;
+    const unsigned char *derp;
+    long der_len = 0;
+    unsigned char *new_der = NULL;
+    long new_der_len;
+    EVP_PKEY *pkey = NULL;
+    void *key = NULL;
+    int ok = 0;
+
+    if (!ossl_prov_read_der(ctx->provctx, cin, &der, &der_len))
+        return 0;
+
+    /*
+     * Opportunistic attempt to decrypt.  If it doesn't work, we try to
+     * decode our input unencrypted.
+     */
+    if (ossl_prov_der_from_p8(&new_der, &new_der_len, der, der_len,
+                              pw_cb, pw_cbarg)) {
+        OPENSSL_free(der);
+        der = new_der;
+        der_len = new_der_len;
+    }
+
+    derp = der;
+    pkey = d2i_PrivateKey_ex(ctx->desc->type, NULL, &derp, der_len,
+                             libctx, NULL);
+    if (pkey == NULL) {
+        derp = der;
+        pkey = d2i_PUBKEY(NULL, &derp, der_len);
+    }
+
+    if (pkey != NULL) {
+        /*
+         * Tear out the low-level key pointer from the pkey,
+         * but only if it matches the expected key type.
+         *
+         * TODO(3.0): The check should be done with EVP_PKEY_is_a(), but
+         * as long as we still have #legacy internal keys, it's safer to
+         * use the type numbers in side the provider.
+         */
+        if (EVP_PKEY_id(pkey) == ctx->desc->type)
+            key = ctx->desc->extract_key(pkey);
+
+        /*
+         * ctx->desc->extract_key() is expected to have incremented |key|'s
+         * reference count, so it should be safe to free |pkey| now.
+         */
+        EVP_PKEY_free(pkey);
+    }
+
+    OPENSSL_free(der);
+
+    if (key != NULL) {
+        OSSL_PARAM params[3];
+
+        params[0] =
+            OSSL_PARAM_construct_utf8_string(OSSL_DESERIALIZER_PARAM_DATA_TYPE,
+                                             (char *)ctx->desc->name, 0);
+        /* The address of the key becomes the octet string */
+        params[1] =
+            OSSL_PARAM_construct_octet_string(OSSL_DESERIALIZER_PARAM_REFERENCE,
+                                              &key, sizeof(key));
+        params[2] = OSSL_PARAM_construct_end();
+
+        ok = data_cb(params, data_cbarg);
+    }
+    ctx->desc->free_key(key);
+
+    return ok;
+}
+
+static int der2key_export_object(void *vctx,
+                                 const void *reference, size_t reference_sz,
+                                 OSSL_CALLBACK *export_cb, void *export_cbarg)
+{
+    struct der2key_ctx_st *ctx = vctx;
+    OSSL_FUNC_keymgmt_export_fn *export =
+        ossl_prov_get_keymgmt_export(ctx->desc->fns);
+    void *keydata;
+
+    if (reference_sz == sizeof(keydata) && export != NULL) {
+        /* The contents of the reference is the address to our object */
+        keydata = *(void **)reference;
+
+        return export(keydata, OSSL_KEYMGMT_SELECT_ALL,
+                      export_cb, export_cbarg);
+    }
+    return 0;
+}
+
+#define IMPLEMENT_NEWCTX(KEYTYPEstr, KEYTYPE, keytype, extract, free)   \
+    static const struct keytype_desc_st keytype##_desc =                \
+        { EVP_PKEY_##KEYTYPE, KEYTYPEstr, keytype##_keymgmt_functions,  \
+          (extract_key_fn *)extract,                                    \
+          (free_key_fn *)free };                                        \
+    static void *der2##keytype##_newctx(void *provctx)                  \
+    {                                                                   \
+        return der2key_newctx(provctx, &keytype##_desc);                \
+    }                                                                   \
+    const OSSL_DISPATCH der_to_##keytype##_deserializer_functions[] = { \
+        { OSSL_FUNC_DESERIALIZER_NEWCTX,                                \
+          (void (*)(void))der2##keytype##_newctx },                     \
+        { OSSL_FUNC_DESERIALIZER_FREECTX,                               \
+          (void (*)(void))der2key_freectx },                            \
+        { OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS,                       \
+          (void (*)(void))der2key_gettable_params },                    \
+        { OSSL_FUNC_DESERIALIZER_GET_PARAMS,                            \
+          (void (*)(void))der2key_get_params },                         \
+        { OSSL_FUNC_DESERIALIZER_DESERIALIZE,                           \
+          (void (*)(void))der2key_deserialize },                        \
+        { OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT,                         \
+          (void (*)(void))der2key_export_object },                      \
+        { 0, NULL }                                                     \
+    }
+
+#ifndef OPENSSL_NO_DH
+IMPLEMENT_NEWCTX("DH", DH, dh, EVP_PKEY_get1_DH, DH_free);
+#endif
+#ifndef OPENSSL_NO_DSA
+IMPLEMENT_NEWCTX("DSA", DSA, dsa, EVP_PKEY_get1_DSA, DSA_free);
+#endif
+#ifndef OPENSSL_NO_EC
+IMPLEMENT_NEWCTX("EC", EC, ec, EVP_PKEY_get1_EC_KEY, EC_KEY_free);
+IMPLEMENT_NEWCTX("X25519", X25519, x25519,
+                 EVP_PKEY_get1_X25519, ecx_key_free);
+IMPLEMENT_NEWCTX("X448", X448, x448,
+                 EVP_PKEY_get1_X448, ecx_key_free);
+IMPLEMENT_NEWCTX("ED25519", ED25519, ed25519,
+                 EVP_PKEY_get1_ED25519, ecx_key_free);
+IMPLEMENT_NEWCTX("ED448", ED448, ed448, EVP_PKEY_get1_ED448, ecx_key_free);
+#endif
+IMPLEMENT_NEWCTX("RSA", RSA, rsa, EVP_PKEY_get1_RSA, RSA_free);
+IMPLEMENT_NEWCTX("RSA-PSS", RSA_PSS, rsapss, EVP_PKEY_get1_RSA, RSA_free);
diff --git a/providers/implementations/serializers/deserialize_der2rsa.c b/providers/implementations/serializers/deserialize_der2rsa.c
deleted file mode 100644
index 75066546ba..0000000000
--- a/providers/implementations/serializers/deserialize_der2rsa.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License").  You may not use
- * this file except in compliance with the License.  You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-/*
- * RSA low level APIs are deprecated for public use, but still ok for
- * internal use.
- */
-#include "internal/deprecated.h"
-
-#include <openssl/core_dispatch.h>
-#include <openssl/core_names.h>
-#include <openssl/crypto.h>
-#include <openssl/err.h>
-#include <openssl/params.h>
-#include <openssl/x509.h>
-#include "prov/bio.h"
-#include "prov/implementations.h"
-#include "prov/providercommonerr.h"
-#include "serializer_local.h"
-
-static OSSL_FUNC_deserializer_newctx_fn der2rsa_newctx;
-static OSSL_FUNC_deserializer_freectx_fn der2rsa_freectx;
-static OSSL_FUNC_deserializer_gettable_params_fn der2rsa_gettable_params;
-static OSSL_FUNC_deserializer_get_params_fn der2rsa_get_params;
-static OSSL_FUNC_deserializer_settable_ctx_params_fn der2rsa_settable_ctx_params;
-static OSSL_FUNC_deserializer_set_ctx_params_fn der2rsa_set_ctx_params;
-static OSSL_FUNC_deserializer_deserialize_fn der2rsa_deserialize;
-static OSSL_FUNC_deserializer_export_object_fn der2rsa_export_object;
-
-/*
- * Context used for DER to RSA key deserialization.
- */
-struct der2rsa_ctx_st {
-    PROV_CTX *provctx;
-
-    int type;
-
-    struct pkcs8_encrypt_ctx_st sc;
-};
-
-static struct der2rsa_ctx_st *der2rsa_newctx_int(void *provctx)
-{
-    struct der2rsa_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
-
-    if (ctx != NULL) {
-        ctx->provctx = provctx;
-        /* -1 is the "whatever" indicator, i.e. the PKCS8 library default PBE */
-        ctx->sc.pbe_nid = -1;
-    }
-    return ctx;
-}
-
-static void *der2rsa_newctx(void *provctx)
-{
-    struct der2rsa_ctx_st *ctx = der2rsa_newctx_int(provctx);
-
-    if (ctx != NULL)
-        ctx->type = EVP_PKEY_RSA;
-    return ctx;
-}
-
-static void *der2rsapss_newctx(void *provctx)
-{
-    struct der2rsa_ctx_st *ctx = der2rsa_newctx_int(provctx);
-
-    if (ctx != NULL)
-        ctx->type = EVP_PKEY_RSA_PSS;
-    return ctx;
-}
-
-static void der2rsa_freectx(void *vctx)
-{
-    struct der2rsa_ctx_st *ctx = vctx;
-
-    EVP_CIPHER_free(ctx->sc.cipher);
-    OPENSSL_clear_free(ctx->sc.cipher_pass, ctx->sc.cipher_pass_length);
-    OPENSSL_free(ctx);
-}
-
-static const OSSL_PARAM *der2rsa_gettable_params(void)
-{
-    static const OSSL_PARAM gettables[] = {
-        { OSSL_DESERIALIZER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
-        OSSL_PARAM_END,
-    };
-
-    return gettables;
-}
-
-static int der2rsa_get_params(OSSL_PARAM params[])
-{
-    OSSL_PARAM *p;
-
-    p = OSSL_PARAM_locate(params, OSSL_DESERIALIZER_PARAM_INPUT_TYPE);
-    if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, "DER"))
-        return 0;
-
-    return 1;
-}
-
-
-static const OSSL_PARAM *der2rsa_settable_ctx_params(void)
-{
-    static const OSSL_PARAM settables[] = {
-        OSSL_PARAM_utf8_string(OSSL_DESERIALIZER_PARAM_CIPHER, NULL, 0),
-        OSSL_PARAM_utf8_string(OSSL_DESERIALIZER_PARAM_PROPERTIES, NULL, 0),
-        OSSL_PARAM_octet_string(OSSL_DESERIALIZER_PARAM_PASS, NULL, 0),
-        OSSL_PARAM_END,
-    };
-
-    return settables;
-}
-
-static int der2rsa_set_ctx_params(void *vctx, const OSSL_PARAM params[])
-{
-    struct der2rsa_ctx_st *ctx = vctx;
-    OPENSSL_CTX *libctx = PROV_CTX_get0_library_context(ctx->provctx);
-    const OSSL_PARAM *p;
-
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_CIPHER))
-        != NULL) {
-        const OSSL_PARAM *propsp =
-            OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_PROPERTIES);
-        const char *props = NULL;
-
-        if (p->data_type != OSSL_PARAM_UTF8_STRING)
-            return 0;
-        if (propsp != NULL && propsp->data_type != OSSL_PARAM_UTF8_STRING)
-            return 0;
-        props = (propsp != NULL ? propsp->data : NULL);
-
-        EVP_CIPHER_free(ctx->sc.cipher);
-        ctx->sc.cipher = NULL;
-        ctx->sc.cipher_intent = p->data != NULL;
-        if (p->data != NULL
-            && ((ctx->sc.cipher = EVP_CIPHER_fetch(libctx, p->data, props))
-                == NULL))
-            return 0;
-    }
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_PASS))
-        != NULL) {
-        OPENSSL_clear_free(ctx->sc.cipher_pass, ctx->sc.cipher_pass_length);
-        ctx->sc.cipher_pass = NULL;
-        if (!OSSL_PARAM_get_octet_string(p, &ctx->sc.cipher_pass, 0,
-                                         &ctx->sc.cipher_pass_length))
-            return 0;
-    }
-    return 1;
-}
-
-static int der2rsa_deserialize(void *vctx, OSSL_CORE_BIO *cin,
-                               OSSL_CALLBACK *data_cb, void *data_cbarg,
-                               OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
-{
-    struct der2rsa_ctx_st *ctx = vctx;
-    void *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
-    RSA *rsa = NULL;
-    unsigned char *der = NULL;
-    const unsigned char *derp;
-    long der_len = 0;
-    unsigned char *new_der = NULL;
-    long new_der_len;
-    EVP_PKEY *pkey = NULL;
-    int ok = 0;
-
-    ctx->sc.cb = pw_cb;
-    ctx->sc.cbarg = pw_cbarg;
-
-    if (!ossl_prov_read_der(ctx->provctx, cin, &der, &der_len))
-        return 0;
-
-    /*
-     * Opportunistic attempt to decrypt.  If it doesn't work, we try to
-     * decode our input unencrypted.
-     */
-    if (ctx->sc.cipher_intent
-        && ossl_prov_der_from_p8(&new_der, &new_der_len, der, der_len,
-                                 &ctx->sc)) {
-        OPENSSL_free(der);
-        der = new_der;
-        der_len = new_der_len;
-    }
-
-    derp = der;
-    if ((pkey = d2i_PrivateKey_ex(ctx->type, NULL, &derp, der_len,
-                                  libctx, NULL)) != NULL) {
-        /* Tear out the RSA pointer from the pkey */
-        rsa = EVP_PKEY_get1_RSA(pkey);
-        EVP_PKEY_free(pkey);
-    }
-
-    OPENSSL_free(der);
-
-    if (rsa != NULL) {
-        OSSL_PARAM params[3];
-        char *object_type = NULL;
-
-        switch (RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK)) {
-        case RSA_FLAG_TYPE_RSA:
-            object_type = "RSA";
-            break;
-        case RSA_FLAG_TYPE_RSASSAPSS:
-            object_type = "RSA-PSS";
-            break;
-        default:
-            ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_RSA_KEY,
-                           "Expected the RSA type to be %d or %d, but got %d",
-                           RSA_FLAG_TYPE_RSA, RSA_FLAG_TYPE_RSASSAPSS,
-                           RSA_test_flags(rsa, RSA_FLAG_TYPE_MASK));
-            goto end;
-        }
-
-
-        params[0] =
-            OSSL_PARAM_construct_utf8_string(OSSL_DESERIALIZER_PARAM_DATA_TYPE,
-                                             object_type, 0);
-        /* The address of the key becomes the octet string */
-        params[1] =
-            OSSL_PARAM_construct_octet_string(OSSL_DESERIALIZER_PARAM_REFERENCE,
-                                              &rsa, sizeof(rsa));
-        params[2] = OSSL_PARAM_construct_end();
-
-        ok = data_cb(params, data_cbarg);
-    }
- end:
-    RSA_free(rsa);
-
-    return ok;
-}
-
-static int der2rsa_export_object_int(void *vctx,
-                                     const void *reference, size_t reference_sz,
-                                     OSSL_FUNC_keymgmt_export_fn *rsa_export,
-                                     OSSL_CALLBACK *export_cb,
-                                     void *export_cbarg)
-{
-    void *keydata;
-
-    if (reference_sz == sizeof(keydata) && rsa_export != NULL) {
-        /* The contents of the reference is the address to our object */
-        keydata = *(RSA **)reference;
-
-        return rsa_export(keydata, OSSL_KEYMGMT_SELECT_ALL,
-                          export_cb, export_cbarg);
-    }
-    return 0;
-}
-
-static int der2rsa_export_object(void *vctx,
-                                 const void *reference, size_t reference_sz,
-                                 OSSL_CALLBACK *export_cb,
-                                 void *export_cbarg)
-{
-    return der2rsa_export_object_int(vctx, reference, reference_sz,
-                                     ossl_prov_get_keymgmt_rsa_export(),
-                                     export_cb, export_cbarg);
-}
-
-static int der2rsapss_export_object(void *vctx,
-                                    const void *reference, size_t reference_sz,
-                                    OSSL_CALLBACK *export_cb,
-                                    void *export_cbarg)
-{
-    return der2rsa_export_object_int(vctx, reference, reference_sz,
-                                     ossl_prov_get_keymgmt_rsapss_export(),
-                                     export_cb, export_cbarg);
-}
-
-const OSSL_DISPATCH der_to_rsa_deserializer_functions[] = {
-    { OSSL_FUNC_DESERIALIZER_NEWCTX, (void (*)(void))der2rsa_newctx },
-    { OSSL_FUNC_DESERIALIZER_FREECTX, (void (*)(void))der2rsa_freectx },
-    { OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS,
-      (void (*)(void))der2rsa_gettable_params },
-    { OSSL_FUNC_DESERIALIZER_GET_PARAMS,
-      (void (*)(void))der2rsa_get_params },
-    { OSSL_FUNC_DESERIALIZER_SETTABLE_CTX_PARAMS,
-      (void (*)(void))der2rsa_settable_ctx_params },
-    { OSSL_FUNC_DESERIALIZER_SET_CTX_PARAMS,
-      (void (*)(void))der2rsa_set_ctx_params },
-    { OSSL_FUNC_DESERIALIZER_DESERIALIZE,
-      (void (*)(void))der2rsa_deserialize },
-    { OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT,
-      (void (*)(void))der2rsa_export_object },
-    { 0, NULL }
-};
-
-const OSSL_DISPATCH der_to_rsapss_deserializer_functions[] = {
-    { OSSL_FUNC_DESERIALIZER_NEWCTX, (void (*)(void))der2rsapss_newctx },
-    { OSSL_FUNC_DESERIALIZER_FREECTX, (void (*)(void))der2rsa_freectx },
-    { OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS,
-      (void (*)(void))der2rsa_gettable_params },
-    { OSSL_FUNC_DESERIALIZER_GET_PARAMS,
-      (void (*)(void))der2rsa_get_params },
-    { OSSL_FUNC_DESERIALIZER_SETTABLE_CTX_PARAMS,
-      (void (*)(void))der2rsa_settable_ctx_params },
-    { OSSL_FUNC_DESERIALIZER_SET_CTX_PARAMS,
-      (void (*)(void))der2rsa_set_ctx_params },
-    { OSSL_FUNC_DESERIALIZER_DESERIALIZE,
-      (void (*)(void))der2rsa_deserialize },
-    { OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT,
-      (void (*)(void))der2rsapss_export_object },
-    { 0, NULL }
-};
diff --git a/providers/implementations/serializers/deserialize_pem2der.c b/providers/implementations/serializers/deserialize_pem2der.c
index a46ec681a1..cbd0867da9 100644
--- a/providers/implementations/serializers/deserialize_pem2der.c
+++ b/providers/implementations/serializers/deserialize_pem2der.c
@@ -37,19 +37,6 @@ static OSSL_FUNC_deserializer_deserialize_fn pem2der_deserialize;
  */
 struct pem2der_ctx_st {
     PROV_CTX *provctx;
-
-    /* Set to 1 if intending to encrypt/decrypt, otherwise 0 */
-    int cipher_intent;
-
-    EVP_CIPHER *cipher;
-
-    /* Passphrase that was passed by the caller */
-    void *cipher_pass;
-    size_t cipher_pass_length;
-
-    /* This callback is only used if |cipher_pass| is NULL */
-    OSSL_PASSPHRASE_CALLBACK *cb;
-    void *cbarg;
 };
 
 static void *pem2der_newctx(void *provctx)
@@ -65,8 +52,6 @@ static void pem2der_freectx(void *vctx)
 {
     struct pem2der_ctx_st *ctx = vctx;
 
-    EVP_CIPHER_free(ctx->cipher);
-    OPENSSL_clear_free(ctx->cipher_pass, ctx->cipher_pass_length);
     OPENSSL_free(ctx);
 }
 
@@ -91,50 +76,22 @@ static int pem2der_get_params(OSSL_PARAM params[])
     return 1;
 }
 
-static const OSSL_PARAM *pem2der_settable_ctx_params(void)
-{
-    static const OSSL_PARAM settables[] = {
-        OSSL_PARAM_octet_string(OSSL_DESERIALIZER_PARAM_PASS, NULL, 0),
-        OSSL_PARAM_END,
-    };
-
-    return settables;
-}
-
-static int pem2der_set_ctx_params(void *vctx, const OSSL_PARAM params[])
-{
-    struct pem2der_ctx_st *ctx = vctx;
-    const OSSL_PARAM *p;
-
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_PASS))
-        != NULL) {
-        OPENSSL_clear_free(ctx->cipher_pass, ctx->cipher_pass_length);
-        ctx->cipher_pass = NULL;
-        if (!OSSL_PARAM_get_octet_string(p, &ctx->cipher_pass, 0,
-                                         &ctx->cipher_pass_length))
-            return 0;
-    }
-    return 1;
-}
-
 /* pem_password_cb compatible function */
+struct pem2der_pass_data_st {
+    OSSL_PASSPHRASE_CALLBACK *cb;
+    void *cbarg;
+};
+
 static int pem2der_pass_helper(char *buf, int num, int w, void *data)
 {
-    struct pem2der_ctx_st *ctx = data;
+    struct pem2der_pass_data_st *pass_data = data;
     size_t plen;
 
-    if (ctx->cipher_pass != NULL) {
-        if (ctx->cipher_pass_length < (size_t)num - 1) {
-            strncpy(buf, ctx->cipher_pass, ctx->cipher_pass_length);
-            buf[ctx->cipher_pass_length] = '\0';
-        } else {
-            OPENSSL_strlcpy(buf, ctx->cipher_pass, num);
-        }
-    } else if (ctx->cb == NULL
-               || !ctx->cb(buf, num, &plen, NULL, ctx->cbarg)) {
+    if (pass_data == NULL
+        || pass_data->cb == NULL
+        || !pass_data->cb(buf, num, &plen, NULL, pass_data->cbarg))
         return -1;
-    }
-    return (int)ctx->cipher_pass_length;
+    return (int)plen;
 }
 
 static int pem2der_deserialize(void *vctx, OSSL_CORE_BIO *cin,
@@ -159,9 +116,13 @@ static int pem2der_deserialize(void *vctx, OSSL_CORE_BIO *cin,
      */
     if (strlen(pem_header) > 10) {
         EVP_CIPHER_INFO cipher;
+        struct pem2der_pass_data_st pass_data;
 
+        pass_data.cb = pw_cb;
+        pass_data.cbarg = pw_cbarg;
         if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher)
-            || !PEM_do_header(&cipher, der, &der_len, pem2der_pass_helper, ctx))
+            || !PEM_do_header(&cipher, der, &der_len,
+                              pem2der_pass_helper, &pass_data))
             goto end;
     }
 
@@ -193,10 +154,6 @@ const OSSL_DISPATCH pem_to_der_deserializer_functions[] = {
       (void (*)(void))pem2der_gettable_params },
     { OSSL_FUNC_DESERIALIZER_GET_PARAMS,
       (void (*)(void))pem2der_get_params },
-    { OSSL_FUNC_DESERIALIZER_SETTABLE_CTX_PARAMS,
-      (void (*)(void))pem2der_settable_ctx_params },
-    { OSSL_FUNC_DESERIALIZER_SET_CTX_PARAMS,
-      (void (*)(void))pem2der_set_ctx_params },
     { OSSL_FUNC_DESERIALIZER_DESERIALIZE, (void (*)(void))pem2der_deserialize },
     { 0, NULL }
 };
diff --git a/providers/implementations/serializers/serializer_local.h b/providers/implementations/serializers/serializer_local.h
index f1d2fe743c..d1359f7f4d 100644
--- a/providers/implementations/serializers/serializer_local.h
+++ b/providers/implementations/serializers/serializer_local.h
@@ -170,5 +170,5 @@ int ossl_prov_read_pem(PROV_CTX *provctx, OSSL_CORE_BIO *cin,
 
 int ossl_prov_der_from_p8(unsigned char **new_der, long *new_der_len,
                           unsigned char *input_der, long input_der_len,
-                          struct pkcs8_encrypt_ctx_st *ctx);
+                          OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg);
 
diff --git a/test/serdes_test.c b/test/serdes_test.c
index 0fc5cb7b4d..85165523ca 100644
--- a/test/serdes_test.c
+++ b/test/serdes_test.c
@@ -12,6 +12,7 @@
 #include <openssl/pem.h>
 #include <openssl/rsa.h>
 #include <openssl/x509.h>
+#include <openssl/params.h>
 #include <openssl/serializer.h>
 #include <openssl/deserializer.h>
 
@@ -27,22 +28,42 @@
  * serializing/deserializing with "traditional" keys.
  */
 
-static EVP_PKEY *key_RSA = NULL;
-static EVP_PKEY *legacy_key_RSA = NULL;
-static EVP_PKEY *key_RSA_PSS = NULL;
-static EVP_PKEY *legacy_key_RSA_PSS = NULL;
+static EVP_PKEY *make_template(const char *type, OSSL_PARAM *genparams)
+{
+    EVP_PKEY *pkey = NULL;
+    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL);
+
+    /*
+     * No real need to check the errors other than for the cascade
+     * effect.  |pkey| will simply remain NULL if something goes wrong.
+     */
+    (void)(ctx != NULL
+           && EVP_PKEY_paramgen_init(ctx) > 0
+           && (genparams == NULL
+               || EVP_PKEY_CTX_set_params(ctx, genparams) > 0)
+           && EVP_PKEY_gen(ctx, &pkey) > 0);
+    EVP_PKEY_CTX_free(ctx);
+
+    return pkey;
+}
 
-static EVP_PKEY *make_RSA(const char *rsa_type, int make_legacy)
+static EVP_PKEY *make_key(const char *type, EVP_PKEY *template,
+                          OSSL_PARAM *genparams, int make_legacy)
 {
     EVP_PKEY *pkey = NULL;
-    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, rsa_type, NULL);
+    EVP_PKEY_CTX *ctx =
+        template != NULL
+        ? EVP_PKEY_CTX_new(template, NULL)
+        : EVP_PKEY_CTX_new_from_name(NULL, type, NULL);
 
     /*
      * No real need to check the errors other than for the cascade
-     * effect.  |pkey| will imply remain NULL if something goes wrong.
+     * effect.  |pkey| will simply remain NULL if something goes wrong.
      */
     (void)(ctx != NULL
            && EVP_PKEY_keygen_init(ctx) > 0
+           && (genparams == NULL
+               || EVP_PKEY_CTX_set_params(ctx, genparams) > 0)
            && EVP_PKEY_keygen(ctx, &pkey) > 0);
     EVP_PKEY_CTX_free(ctx);
     if (make_legacy && EVP_PKEY_get0(pkey) == NULL) {
@@ -53,15 +74,24 @@ static EVP_PKEY *make_RSA(const char *rsa_type, int make_legacy)
     return pkey;
 }
 
+
 /* Main test driver */
 
+/*
+ * TODO(3.0) For better error output, changed the callbacks to take __FILE__
+ * and __LINE__ as first two arguments, and have them use the lower case
+ * functions, such as test_strn_eq(), rather than the uppercase macros
+ * (TEST_strn2_eq(), for example).
+ */
+
 typedef int (serializer)(void **serialized, long *serialized_len,
-                         void *object,
-                         const char *pass, const char *pcipher,
+                         void *object, const char *pass, const char *pcipher,
                          const char *ser_propq);
 typedef int (deserializer)(void **object,
                            void *serialized, long serialized_len,
-                           const char *pass, const char *pcipher);
+                           const char *pass);
+typedef int (tester)(const void *data1, size_t data1_len,
+                     const void *data2, size_t data2_len);
 typedef int (checker)(const char *type, const void *data, size_t data_len);
 typedef void (dumper)(const char *label, const void *data, size_t data_len);
 
@@ -69,6 +99,7 @@ static int test_serialize_deserialize(const char *type, EVP_PKEY *pkey,
                                       const char *pass, const char *pcipher,
                                       serializer *serialize_cb,
                                       deserializer *deserialize_cb,
+                                      tester *test_cb,
                                       checker *check_cb, dumper *dump_cb,
                                       const char *ser_propq, int make_legacy)
 {
@@ -83,7 +114,7 @@ static int test_serialize_deserialize(const char *type, EVP_PKEY *pkey,
                       pass, pcipher, ser_propq)
         || !check_cb(type, serialized, serialized_len)
         || !deserialize_cb((void **)&pkey2, serialized, serialized_len,
-                           pass, pcipher)
+                           pass)
         || !TEST_int_eq(EVP_PKEY_eq(pkey, pkey2), 1))
         goto end;
 
@@ -103,14 +134,18 @@ static int test_serialize_deserialize(const char *type, EVP_PKEY *pkey,
     if ((pass == NULL && pcipher == NULL)
         && (!serialize_cb(&serialized2, &serialized2_len, pkey2,
                           pass, pcipher, ser_propq)
-            || !TEST_mem_eq(serialized, serialized_len,
-                            serialized2, serialized2_len)))
+            || !test_cb(serialized, serialized_len,
+                        serialized2, serialized2_len)))
         goto end;
 
     ok = 1;
  end:
-    if (!ok)
-        dump_cb("serialized result", serialized, serialized_len);
+    if (!ok) {
+        if (serialized != NULL && serialized_len != 0)
+            dump_cb("serialized result", serialized, serialized_len);
+        if (serialized2 != NULL && serialized2_len != 0)
+            dump_cb("re-serialized result", serialized2, serialized2_len);
+    }
 
     OPENSSL_free(serialized);
     OPENSSL_free(serialized2);
@@ -157,7 +192,7 @@ static int serialize_EVP_PKEY_prov(void **serialized, long *serialized_len,
 
 static int deserialize_EVP_PKEY_prov(void **object,
                                      void *serialized, long serialized_len,
-                                     const char *pass, const char *pcipher)
+                                     const char *pass)
 {
     EVP_PKEY *pkey = NULL;
     OSSL_DESERIALIZER_CTX *dctx = NULL;
@@ -170,8 +205,6 @@ static int deserialize_EVP_PKEY_prov(void **object,
         || (pass != NULL
             && !OSSL_DESERIALIZER_CTX_set_passphrase(dctx, upass,
                                                      strlen(pass)))
-        || (pcipher != NULL
-            && !OSSL_DESERIALIZER_CTX_set_cipher(dctx, pcipher, NULL))
         || !TEST_ptr(mem_deser = BIO_new_mem_buf(serialized, serialized_len))
         || !TEST_true(OSSL_DESERIALIZER_from_bio(dctx, mem_deser)))
         goto end;
@@ -222,6 +255,18 @@ static int serialize_EVP_PKEY_legacy_PEM(void **serialized,
     return ok;
 }
 
+static int test_text(const void *data1, size_t data1_len,
+                     const void *data2, size_t data2_len)
+{
+    return TEST_strn2_eq(data1, data1_len, data2, data2_len);
+}
+
+static int test_mem(const void *data1, size_t data1_len,
+                    const void *data2, size_t data2_len)
+{
+    return TEST_mem_eq(data1, data1_len, data2, data2_len);
+}
+
 /* Test cases and their dumpers / checkers */
 
 static void dump_der(const char *label, const void *data, size_t data_len)
@@ -252,21 +297,12 @@ static int check_unprotected_PKCS8_DER(const char *type,
     return ok;
 }
 
-static int test_unprotected_RSA_via_DER(void)
+static int test_unprotected_via_DER(const char *type, EVP_PKEY *key)
 {
-    return test_serialize_deserialize("RSA", key_RSA, NULL, NULL,
-                                      serialize_EVP_PKEY_prov,
-                                      deserialize_EVP_PKEY_prov,
-                                      check_unprotected_PKCS8_DER, dump_der,
-                                      OSSL_SERIALIZER_PrivateKey_TO_DER_PQ,
-                                      0);
-}
-
-static int test_unprotected_RSA_PSS_via_DER(void)
-{
-    return test_serialize_deserialize("RSA-PSS", key_RSA_PSS, NULL, NULL,
+    return test_serialize_deserialize(type, key, NULL, NULL,
                                       serialize_EVP_PKEY_prov,
                                       deserialize_EVP_PKEY_prov,
+                                      test_mem,
                                       check_unprotected_PKCS8_DER, dump_der,
                                       OSSL_SERIALIZER_PrivateKey_TO_DER_PQ,
                                       0);
@@ -280,21 +316,12 @@ static int check_unprotected_PKCS8_PEM(const char *type,
     return TEST_strn_eq(data, pem_header, sizeof(pem_header) - 1);
 }
 
-static int test_unprotected_RSA_via_PEM(void)
+static int test_unprotected_via_PEM(const char *type, EVP_PKEY *key)
 {
-    return test_serialize_deserialize("RSA", key_RSA, NULL, NULL,
-                                      serialize_EVP_PKEY_prov,
-                                      deserialize_EVP_PKEY_prov,
-                                      check_unprotected_PKCS8_PEM, dump_pem,
-                                      OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ,
-                                      0);
-}
-
-static int test_unprotected_RSA_PSS_via_PEM(void)
-{
-    return test_serialize_deserialize("RSA-PSS", key_RSA_PSS, NULL, NULL,
+    return test_serialize_deserialize(type, key, NULL, NULL,
                                       serialize_EVP_PKEY_prov,
                                       deserialize_EVP_PKEY_prov,
+                                      test_text,
                                       check_unprotected_PKCS8_PEM, dump_pem,
                                       OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ,
                                       0);
@@ -311,20 +338,12 @@ static int check_unprotected_legacy_PEM(const char *type,
         && TEST_strn_eq(data, pem_header, strlen(pem_header));
 }
 
-static int test_unprotected_RSA_via_legacy_PEM(void)
+static int test_unprotected_via_legacy_PEM(const char *type, EVP_PKEY *key)
 {
-    return test_serialize_deserialize("RSA", legacy_key_RSA, NULL, NULL,
-                                      serialize_EVP_PKEY_legacy_PEM,
-                                      deserialize_EVP_PKEY_prov,
-                                      check_unprotected_legacy_PEM, dump_pem,
-                                      NULL, 1);
-}
-
-static int test_unprotected_RSA_PSS_via_legacy_PEM(void)
-{
-    return test_serialize_deserialize("RSA-PSS", legacy_key_RSA_PSS, NULL, NULL,
+    return test_serialize_deserialize(type, key, NULL, NULL,
                                       serialize_EVP_PKEY_legacy_PEM,
                                       deserialize_EVP_PKEY_prov,
+                                      test_text,
                                       check_unprotected_legacy_PEM, dump_pem,
                                       NULL, 1);
 }
@@ -343,21 +362,12 @@ static int check_protected_PKCS8_DER(const char *type,
     return ok;
 }
 
-static int test_protected_RSA_via_DER(void)
+static int test_protected_via_DER(const char *type, EVP_PKEY *key)
 {
-    return test_serialize_deserialize("RSA", key_RSA, pass, pass_cipher,
-                                      serialize_EVP_PKEY_prov,
-                                      deserialize_EVP_PKEY_prov,
-                                      check_protected_PKCS8_DER, dump_der,
-                                      OSSL_SERIALIZER_PrivateKey_TO_DER_PQ,
-                                      0);
-}
-
-static int test_protected_RSA_PSS_via_DER(void)
-{
-    return test_serialize_deserialize("RSA", key_RSA, pass, pass_cipher,
+    return test_serialize_deserialize(type, key, pass, pass_cipher,
                                       serialize_EVP_PKEY_prov,
                                       deserialize_EVP_PKEY_prov,
+                                      test_mem,
                                       check_protected_PKCS8_DER, dump_der,
                                       OSSL_SERIALIZER_PrivateKey_TO_DER_PQ,
                                       0);
@@ -371,21 +381,12 @@ static int check_protected_PKCS8_PEM(const char *type,
     return TEST_strn_eq(data, pem_header, sizeof(pem_header) - 1);
 }
 
-static int test_protected_RSA_via_PEM(void)
+static int test_protected_via_PEM(const char *type, EVP_PKEY *key)
 {
-    return test_serialize_deserialize("RSA", key_RSA, pass, pass_cipher,
-                                      serialize_EVP_PKEY_prov,
-                                      deserialize_EVP_PKEY_prov,
-                                      check_protected_PKCS8_PEM, dump_pem,
-                                      OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ,
-                                      0);
-}
-
-static int test_protected_RSA_PSS_via_PEM(void)
-{
-    return test_serialize_deserialize("RSA-PSS", key_RSA_PSS, pass, pass_cipher,
+    return test_serialize_deserialize(type, key, pass, pass_cipher,
                                       serialize_EVP_PKEY_prov,
                                       deserialize_EVP_PKEY_prov,
+                                      test_text,
                                       check_protected_PKCS8_PEM, dump_pem,
                                       OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ,
                                       0);
@@ -403,52 +404,230 @@ static int check_protected_legacy_PEM(const char *type,
         && TEST_ptr(strstr(data, "\nDEK-Info: "));
 }
 
-static int test_protected_RSA_via_legacy_PEM(void)
+static int test_protected_via_legacy_PEM(const char *type, EVP_PKEY *key)
 {
-    return test_serialize_deserialize("RSA", legacy_key_RSA, pass, pass_cipher,
+    return test_serialize_deserialize(type, key, pass, pass_cipher,
                                       serialize_EVP_PKEY_legacy_PEM,
                                       deserialize_EVP_PKEY_prov,
+                                      test_text,
                                       check_protected_legacy_PEM, dump_pem,
                                       NULL, 1);
 }
 
-static int test_protected_RSA_PSS_via_legacy_PEM(void)
+static int check_public_DER(const char *type, const void *data, size_t data_len)
 {
-    return test_serialize_deserialize("RSA-PSS", legacy_key_RSA_PSS,
-                                      pass, pass_cipher,
-                                      serialize_EVP_PKEY_legacy_PEM,
+    const unsigned char *datap = data;
+    EVP_PKEY *pkey = d2i_PUBKEY(NULL, &datap, data_len);
+    int ok = (TEST_ptr(pkey) && TEST_true(EVP_PKEY_is_a(pkey, type)));
+
+    EVP_PKEY_free(pkey);
+    return ok;
+}
+
+static int test_public_via_DER(const char *type, EVP_PKEY *key)
+{
+    return test_serialize_deserialize(type, key, NULL, NULL,
+                                      serialize_EVP_PKEY_prov,
                                       deserialize_EVP_PKEY_prov,
-                                      check_protected_legacy_PEM, dump_pem,
-                                      NULL, 1);
+                                      test_mem,
+                                      check_public_DER, dump_der,
+                                      OSSL_SERIALIZER_PUBKEY_TO_DER_PQ,
+                                      0);
+}
+
+static int check_public_PEM(const char *type, const void *data, size_t data_len)
+{
+    static const char pem_header[] = "-----BEGIN " PEM_STRING_PUBLIC "-----";
+
+    return
+        TEST_strn_eq(data, pem_header, sizeof(pem_header) - 1);
 }
 
+static int test_public_via_PEM(const char *type, EVP_PKEY *key)
+{
+    return test_serialize_deserialize(type, key, NULL, NULL,
+                                      serialize_EVP_PKEY_prov,
+                                      deserialize_EVP_PKEY_prov,
+                                      test_text,
+                                      check_public_PEM, dump_pem,
+                                      OSSL_SERIALIZER_PUBKEY_TO_PEM_PQ,
+                                      0);
+}
+
+#define KEYS(KEYTYPE)                           \
+    static EVP_PKEY *key_##KEYTYPE = NULL;      \
+    static EVP_PKEY *legacy_key_##KEYTYPE = NULL
+#define MAKE_KEYS(KEYTYPE, KEYTYPEstr, params)                          \
+    ok = ok                                                             \
+        && TEST_ptr(key_##KEYTYPE =                                     \
+                    make_key(KEYTYPEstr, NULL, params, 0))              \
+        && TEST_ptr(legacy_key_##KEYTYPE =                              \
+                    make_key(KEYTYPEstr, NULL, params, 1))
+#define FREE_KEYS(KEYTYPE)                                              \
+    EVP_PKEY_free(key_##KEYTYPE);                                       \
+    EVP_PKEY_free(legacy_key_##KEYTYPE)
+
+#define DOMAIN_KEYS(KEYTYPE)                    \
+    static EVP_PKEY *template_##KEYTYPE = NULL; \
+    static EVP_PKEY *key_##KEYTYPE = NULL;      \
+    static EVP_PKEY *legacy_key_##KEYTYPE = NULL
+#define MAKE_DOMAIN_KEYS(KEYTYPE, KEYTYPEstr, params)                   \
+    ok = ok                                                             \
+        && TEST_ptr(template_##KEYTYPE =                                \
+                    make_template(KEYTYPEstr, params))                  \
+        && TEST_ptr(key_##KEYTYPE =                                     \
+                    make_key(KEYTYPEstr, template_##KEYTYPE, NULL, 0))  \
+        && TEST_ptr(legacy_key_##KEYTYPE =                              \
+                    make_key(KEYTYPEstr, template_##KEYTYPE, NULL, 1))
+#define FREE_DOMAIN_KEYS(KEYTYPE)                                       \
+    EVP_PKEY_free(template_##KEYTYPE);                                  \
+    EVP_PKEY_free(key_##KEYTYPE);                                       \
+    EVP_PKEY_free(legacy_key_##KEYTYPE)
+
+#define IMPLEMENT_TEST_SUITE(KEYTYPE, KEYTYPEstr)                       \
+    static int test_unprotected_##KEYTYPE##_via_DER(void)               \
+    {                                                                   \
+        return test_unprotected_via_DER(KEYTYPEstr, key_##KEYTYPE);     \
+    }                                                                   \
+    static int test_unprotected_##KEYTYPE##_via_PEM(void)               \
+    {                                                                   \
+        return test_unprotected_via_PEM(KEYTYPEstr, key_##KEYTYPE);     \
+    }                                                                   \
+    static int test_unprotected_##KEYTYPE##_via_legacy_PEM(void)        \
+    {                                                                   \
+        return test_unprotected_via_legacy_PEM(KEYTYPEstr,              \
+                                               legacy_key_##KEYTYPE);   \
+    }                                                                   \
+    static int test_protected_##KEYTYPE##_via_DER(void)                 \
+    {                                                                   \
+        return test_protected_via_DER(KEYTYPEstr, key_##KEYTYPE);       \
+    }                                                                   \
+    static int test_protected_##KEYTYPE##_via_PEM(void)                 \
+    {                                                                   \
+        return test_protected_via_PEM(KEYTYPEstr, key_##KEYTYPE);       \
+    }                                                                   \
+    static int test_protected_##KEYTYPE##_via_legacy_PEM(void)          \
+    {                                                                   \
+        return test_protected_via_legacy_PEM(KEYTYPEstr,                \
+                                             legacy_key_##KEYTYPE);     \
+    }                                                                   \
+    static int test_public_##KEYTYPE##_via_DER(void)                    \
+    {                                                                   \
+        return test_public_via_DER(KEYTYPEstr, key_##KEYTYPE);          \
+    }                                                                   \
+    static int test_public_##KEYTYPE##_via_PEM(void)                    \
+    {                                                                   \
+        return test_public_via_PEM(KEYTYPEstr, key_##KEYTYPE);          \
+    }
+
+#define ADD_TEST_SUITE(KEYTYPE)                                 \
+    ADD_TEST(test_unprotected_##KEYTYPE##_via_DER);             \
+    ADD_TEST(test_unprotected_##KEYTYPE##_via_PEM);             \
+    ADD_TEST(test_unprotected_##KEYTYPE##_via_legacy_PEM);      \
+    ADD_TEST(test_protected_##KEYTYPE##_via_DER);               \
+    ADD_TEST(test_protected_##KEYTYPE##_via_PEM);               \
+    ADD_TEST(test_protected_##KEYTYPE##_via_legacy_PEM);        \
+    ADD_TEST(test_public_##KEYTYPE##_via_DER);                  \
+    ADD_TEST(test_public_##KEYTYPE##_via_PEM)
+
+#ifndef OPENSSL_NO_DH
+DOMAIN_KEYS(DH);
+IMPLEMENT_TEST_SUITE(DH, "DH")
+#endif
+#ifndef OPENSSL_NO_DSA
+DOMAIN_KEYS(DSA);
+IMPLEMENT_TEST_SUITE(DSA, "DSA")
+#endif
+#ifndef OPENSSL_NO_EC
+DOMAIN_KEYS(EC);
+IMPLEMENT_TEST_SUITE(EC, "EC")
+KEYS(ED25519);
+IMPLEMENT_TEST_SUITE(ED25519, "ED25519")
+KEYS(ED448);
+IMPLEMENT_TEST_SUITE(ED448, "ED448")
+KEYS(X25519);
+IMPLEMENT_TEST_SUITE(X25519, "X25519")
+KEYS(X448);
+IMPLEMENT_TEST_SUITE(X448, "X448")
+#endif
+KEYS(RSA);
+IMPLEMENT_TEST_SUITE(RSA, "RSA")
+KEYS(RSA_PSS);
+IMPLEMENT_TEST_SUITE(RSA_PSS, "RSA-PSS")
+
 int setup_tests(void)
 {
+    int ok = 1;
+
+#ifndef OPENSSL_NO_EC
+    static char groupname[] = "prime256v1";
+    OSSL_PARAM EC_params[] = {
+        OSSL_PARAM_utf8_string("group", groupname, sizeof(groupname) - 1),
+        OSSL_PARAM_END
+    };
+#endif
+
+    /* 7 is the default magic number */
+    static unsigned int rsapss_min_saltlen = 7;
+    OSSL_PARAM RSA_PSS_params[] = {
+        OSSL_PARAM_uint("saltlen", &rsapss_min_saltlen),
+        OSSL_PARAM_END
+    };
+
     TEST_info("Generating keys...");
-    if (!TEST_ptr(key_RSA = make_RSA("RSA", 0))
-        || !TEST_ptr(legacy_key_RSA = make_RSA("RSA", 1))
-        || !TEST_ptr(key_RSA_PSS = make_RSA("RSA-PSS", 0))
-        || !TEST_ptr(legacy_key_RSA_PSS = make_RSA("RSA-PSS", 1))) {
-        EVP_PKEY_free(key_RSA);
-        EVP_PKEY_free(legacy_key_RSA);
-        EVP_PKEY_free(key_RSA_PSS);
-        EVP_PKEY_free(legacy_key_RSA_PSS);
-        return 0;
-    }
+#ifndef OPENSSL_NO_DH
+    MAKE_DOMAIN_KEYS(DH, "DH", NULL);
+#endif
+#ifndef OPENSSL_NO_DSA
+    MAKE_DOMAIN_KEYS(DSA, "DSA", NULL);
+#endif
+#ifndef OPENSSL_NO_EC
+    MAKE_DOMAIN_KEYS(EC, "EC", EC_params);
+    MAKE_KEYS(ED25519, "ED25519", NULL);
+    MAKE_KEYS(ED448, "ED448", NULL);
+    MAKE_KEYS(X25519, "X25519", NULL);
+    MAKE_KEYS(X448, "X448", NULL);
+#endif
+    MAKE_KEYS(RSA, "RSA", NULL);
+    MAKE_KEYS(RSA_PSS, "RSA-PSS", RSA_PSS_params);
     TEST_info("Generating key... done");
 
-    ADD_TEST(test_unprotected_RSA_via_DER);
-    ADD_TEST(test_unprotected_RSA_via_PEM);
-    ADD_TEST(test_unprotected_RSA_via_legacy_PEM);
-    ADD_TEST(test_protected_RSA_via_DER);
-    ADD_TEST(test_protected_RSA_via_PEM);
-    ADD_TEST(test_protected_RSA_via_legacy_PEM);
-    ADD_TEST(test_unprotected_RSA_PSS_via_DER);
-    ADD_TEST(test_unprotected_RSA_PSS_via_PEM);
-    ADD_TEST(test_unprotected_RSA_PSS_via_legacy_PEM);
-    ADD_TEST(test_protected_RSA_PSS_via_DER);
-    ADD_TEST(test_protected_RSA_PSS_via_PEM);
-    ADD_TEST(test_protected_RSA_PSS_via_legacy_PEM);
+    if (ok) {
+#ifndef OPENSSL_NO_DH
+        ADD_TEST_SUITE(DH);
+#endif
+#ifndef OPENSSL_NO_DSA
+        ADD_TEST_SUITE(DSA);
+#endif
+#ifndef OPENSSL_NO_EC
+        ADD_TEST_SUITE(EC);
+        ADD_TEST_SUITE(ED25519);
+        ADD_TEST_SUITE(ED448);
+        ADD_TEST_SUITE(X25519);
+        ADD_TEST_SUITE(X448);
+#endif
+        ADD_TEST_SUITE(RSA);
+        ADD_TEST_SUITE(RSA_PSS);
+    }
 
     return 1;
 }
+
+void cleanup_tests(void)
+{
+#ifndef OPENSSL_NO_DH
+    FREE_DOMAIN_KEYS(DH);
+#endif
+#ifndef OPENSSL_NO_DSA
+    FREE_DOMAIN_KEYS(DSA);
+#endif
+#ifndef OPENSSL_NO_EC
+    FREE_DOMAIN_KEYS(EC);
+    FREE_KEYS(ED25519);
+    FREE_KEYS(ED448);
+    FREE_KEYS(X25519);
+    FREE_KEYS(X448);
+#endif
+    FREE_KEYS(RSA);
+    FREE_KEYS(RSA_PSS);
+}
diff --git a/test/testutil.h b/test/testutil.h
index 69869e2601..88a3cbc9a8 100644
--- a/test/testutil.h
+++ b/test/testutil.h
@@ -296,9 +296,9 @@ DECLARE_COMPARISON(char *, str, ne)
  * Same as above, but for strncmp.
  */
 int test_strn_eq(const char *file, int line, const char *, const char *,
-                 const char *a, const char *b, size_t s);
+                 const char *a, size_t an, const char *b, size_t bn);
 int test_strn_ne(const char *file, int line, const char *, const char *,
-                 const char *a, const char *b, size_t s);
+                 const char *a, size_t an, const char *b, size_t bn);
 
 /*
  * Equality test for memory blocks where NULL is a legitimate value.
@@ -438,8 +438,10 @@ void test_perror(const char *s);
 
 # define TEST_str_eq(a, b)    test_str_eq(__FILE__, __LINE__, #a, #b, a, b)
 # define TEST_str_ne(a, b)    test_str_ne(__FILE__, __LINE__, #a, #b, a, b)
-# define TEST_strn_eq(a, b, n) test_strn_eq(__FILE__, __LINE__, #a, #b, a, b, n)
-# define TEST_strn_ne(a, b, n) test_strn_ne(__FILE__, __LINE__, #a, #b, a, b, n)
+# define TEST_strn_eq(a, b, n) test_strn_eq(__FILE__, __LINE__, #a, #b, a, n, b, n)
+# define TEST_strn_ne(a, b, n) test_strn_ne(__FILE__, __LINE__, #a, #b, a, n, b, n)
+# define TEST_strn2_eq(a, m, b, n) test_strn_eq(__FILE__, __LINE__, #a, #b, a, m, b, n)
+# define TEST_strn2_ne(a, m, b, n) test_strn_ne(__FILE__, __LINE__, #a, #b, a, m, b, n)
 
 # define TEST_mem_eq(a, m, b, n) test_mem_eq(__FILE__, __LINE__, #a, #b, a, m, b, n)
 # define TEST_mem_ne(a, m, b, n) test_mem_ne(__FILE__, __LINE__, #a, #b, a, m, b, n)
diff --git a/test/testutil/tests.c b/test/testutil/tests.c
index 56177cd999..c1605ca8eb 100644
--- a/test/testutil/tests.c
+++ b/test/testutil/tests.c
@@ -302,28 +302,28 @@ int test_str_ne(const char *file, int line, const char *st1, const char *st2,
 }
 
 int test_strn_eq(const char *file, int line, const char *st1, const char *st2,
-                 const char *s1, const char *s2, size_t len)
+                 const char *s1, size_t n1, const char *s2, size_t n2)
 {
     if (s1 == NULL && s2 == NULL)
       return 1;
-    if (s1 == NULL || s2 == NULL || strncmp(s1, s2, len) != 0) {
+    if (n1 != n2 || s1 == NULL || s2 == NULL || strncmp(s1, s2, n1) != 0) {
         test_fail_string_message(NULL, file, line, "string", st1, st2, "==",
-                                 s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, len),
-                                 s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, len));
+                                 s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, n1),
+                                 s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, n2));
         return 0;
     }
     return 1;
 }
 
 int test_strn_ne(const char *file, int line, const char *st1, const char *st2,
-                 const char *s1, const char *s2, size_t len)
+                 const char *s1, size_t n1, const char *s2, size_t n2)
 {
     if ((s1 == NULL) ^ (s2 == NULL))
       return 1;
-    if (s1 == NULL || strncmp(s1, s2, len) == 0) {
+    if (n1 != n2 || s1 == NULL || strncmp(s1, s2, n1) == 0) {
         test_fail_string_message(NULL, file, line, "string", st1, st2, "!=",
-                                 s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, len),
-                                 s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, len));
+                                 s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, n1),
+                                 s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, n2));
         return 0;
     }
     return 1;
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 1a59d81624..b1c7947b86 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5163,16 +5163,14 @@ OSSL_DESERIALIZER_settable_ctx_params   ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_new               ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_set_params        ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_free              ?	3_0_0	EXIST::FUNCTION:
-OSSL_DESERIALIZER_CTX_set_cipher        ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_set_passphrase    ?	3_0_0	EXIST::FUNCTION:
-OSSL_DESERIALIZER_CTX_set_passphrase_cb ?	3_0_0	EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_pem_password_cb ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_set_passphrase_ui ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_from_bio              ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_from_fp               ?	3_0_0	EXIST::FUNCTION:STDIO
 OSSL_DESERIALIZER_CTX_add_deserializer  ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_add_extra         ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_num_deserializers ?	3_0_0	EXIST::FUNCTION:
-OSSL_DESERIALIZER_CTX_set_finalizer     ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_set_input_type    ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_export                ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_INSTANCE_deserializer ?	3_0_0	EXIST::FUNCTION:
@@ -5181,3 +5179,21 @@ ERR_load_OSSL_DESERIALIZER_strings      ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_gettable_params       ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_get_params            ?	3_0_0	EXIST::FUNCTION:
 OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY   ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_set1_X25519                    ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get0_X25519                    ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get1_X25519                    ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_set1_X448                      ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get0_X448                      ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get1_X448                      ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_set1_ED25519                   ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get0_ED25519                   ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get1_ED25519                   ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_set1_ED448                     ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get0_ED448                     ?	3_0_0	EXIST::FUNCTION:EC
+EVP_PKEY_get1_ED448                     ?	3_0_0	EXIST::FUNCTION:EC
+OSSL_DESERIALIZER_CTX_set_construct     ?	3_0_0	EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_construct_data ?	3_0_0	EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_set_cleanup       ?	3_0_0	EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_get_construct     ?	3_0_0	EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_get_construct_data ?	3_0_0	EXIST::FUNCTION:
+OSSL_DESERIALIZER_CTX_get_cleanup       ?	3_0_0	EXIST::FUNCTION:
diff --git a/util/other.syms b/util/other.syms
index 38ad3d3a33..bfe320396b 100644
--- a/util/other.syms
+++ b/util/other.syms
@@ -43,8 +43,8 @@ OPENSSL_CTX                             datatype
 NAMING_AUTHORITY                        datatype
 OSSL_DESERIALIZER                       datatype
 OSSL_DESERIALIZER_CTX                   datatype
-OSSL_DESERIALIZER_FINALIZER             datatype
-OSSL_DESERIALIZER_CLEANER               datatype
+OSSL_DESERIALIZER_CONSTRUCT             datatype
+OSSL_DESERIALIZER_CLEANUP               datatype
 OSSL_DESERIALIZER_INSTANCE              datatype
 OSSL_DESERIALIZER_CTX                   datatype
 OSSL_HTTP_bio_cb_t                      datatype
@@ -305,6 +305,10 @@ EVP_PKEY_CTX_set_tls1_prf_md            define
 EVP_PKEY_assign_DH                      define
 EVP_PKEY_assign_DSA                     define
 EVP_PKEY_assign_EC_KEY                  define
+EVP_PKEY_assign_ED25519                 define
+EVP_PKEY_assign_ED448                   define
+EVP_PKEY_assign_X25519                  define
+EVP_PKEY_assign_X448                    define
 EVP_PKEY_assign_POLY1305                define
 EVP_PKEY_assign_RSA                     define
 EVP_PKEY_assign_SIPHASH                 define


More information about the openssl-commits mailing list