PROV: Re-implement all the keypair encoders
authorRichard Levitte <levitte@openssl.org>
Sat, 17 Oct 2020 06:34:47 +0000 (08:34 +0200)
committerRichard Levitte <levitte@openssl.org>
Wed, 11 Nov 2020 11:43:27 +0000 (12:43 +0100)
The base functionality to implement the keypair encoders doesn't
change much, but this results in a more massive amount of
OSSL_DISPATCH and OSSL_ALGORITHM arrays, to support a fine grained
selection of implementation based on what parts of the keypair
structure (combinations of key parameters, public key and private key)
should be output, the output type ("TEXT", "DER" or "PEM") and the
outermost output structure ("pkcs8", "SubjectPublicKeyInfo", key
type specific structures, ...).

We add support for the generic structure name "type-specific", to
allow selecting that without knowing the exact name of that structure.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/13167)

providers/baseprov.c
providers/defltprov.c
providers/encoders.inc
providers/implementations/encode_decode/encode_key2any.c
providers/implementations/include/prov/implementations.h

index 18d664a..c63f1fb 100644 (file)
@@ -69,15 +69,11 @@ static int base_get_params(void *provctx, OSSL_PARAM params[])
 }
 
 static const OSSL_ALGORITHM base_encoder[] = {
-#define ENCODER(name, _fips, _output, func_table)                           \
-    { name,                                                                 \
-      "provider=base,fips=" _fips ",output=" _output,                       \
-      (func_table) }
-
+#define ENCODER_PROVIDER "base"
 #include "encoders.inc"
     { NULL, NULL, NULL }
+#undef ENCODER_PROVIDER
 };
-#undef ENCODER
 
 static const OSSL_ALGORITHM base_decoder[] = {
 #define DECODER_PROVIDER "base"
index 8ce6c92..b309ba7 100644 (file)
@@ -442,15 +442,11 @@ static const OSSL_ALGORITHM deflt_keymgmt[] = {
 };
 
 static const OSSL_ALGORITHM deflt_encoder[] = {
-#define ENCODER(name, _fips, _output, func_table)                           \
-    { name,                                                                 \
-      "provider=default,fips=" _fips ",output=" _output,                    \
-      (func_table) }
-
+#define ENCODER_PROVIDER "default"
 #include "encoders.inc"
     { NULL, NULL, NULL }
+#undef ENCODER_PROVIDER
 };
-#undef ENCODER
 
 static const OSSL_ALGORITHM deflt_decoder[] = {
 #define DECODER_PROVIDER "default"
index 1ae0d4f..9330bf4 100644 (file)
  * https://www.openssl.org/source/license.html
  */
 
-#ifndef ENCODER
-# error Macro ENCODER undefined
+#ifndef ENCODER_PROVIDER
+# error Macro ENCODER_PROVIDER undefined
 #endif
 
-    ENCODER("RSA", "yes", "text", ossl_rsa_to_text_encoder_functions),
-    ENCODER("RSA", "yes", "der", ossl_rsa_to_der_encoder_functions),
-    ENCODER("RSA", "yes", "pem", ossl_rsa_to_pem_encoder_functions),
-    ENCODER("RSA-PSS", "yes", "text", ossl_rsapss_to_text_encoder_functions),
-    ENCODER("RSA-PSS", "yes", "der", ossl_rsapss_to_der_encoder_functions),
-    ENCODER("RSA-PSS", "yes", "pem", ossl_rsapss_to_pem_encoder_functions),
+#define ENCODER_STRUCTURE_type_specific_keypair         "type-specific"
+#define ENCODER_STRUCTURE_type_specific_params          "type-specific"
+#define ENCODER_STRUCTURE_type_specific                 "type-specific"
+#define ENCODER_STRUCTURE_type_specific_no_pub          "type-specific"
+#define ENCODER_STRUCTURE_PKCS8                         "pkcs8"
+#define ENCODER_STRUCTURE_SubjectPublicKeyInfo          "SubjectPublicKeyInfo"
+#define ENCODER_STRUCTURE_DH                            "dh"
+#define ENCODER_STRUCTURE_DHX                           "dhx"
+#define ENCODER_STRUCTURE_DSA                           "dsa"
+#define ENCODER_STRUCTURE_EC                            "ec"
+#define ENCODER_STRUCTURE_RSA                           "rsa"
+#define ENCODER_STRUCTURE_PKCS1                         "pkcs1"
+#define ENCODER_STRUCTURE_PKCS3                         "pkcs3"
+#define ENCODER_STRUCTURE_X9_42                         "X9.42"
+#define ENCODER_STRUCTURE_X9_62                         "X9.62"
+
+/* Arguments are prefixed with '_' to avoid build breaks on certain platforms */
+#define ENCODER_TEXT(_name, _sym, _fips)                                \
+    { _name,                                                            \
+      "provider=" ENCODER_PROVIDER ",fips=" #_fips ",output=text",      \
+      (ossl_##_sym##_to_text_encoder_functions) }
+#define ENCODER(_name, _sym, _fips, _output, _structure)                \
+    { _name,                                                            \
+      "provider=" ENCODER_PROVIDER ",fips=" #_fips ",output=" #_output  \
+      ",structure=" ENCODER_STRUCTURE_##_structure,                     \
+      (ossl_##_sym##_to_##_structure##_##_output##_encoder_functions) }
+
+/*
+ * Entries for human text "encoders"
+ */
+ENCODER_TEXT("RSA", rsa, yes),
+ENCODER_TEXT("RSA-PSS", rsapss, yes),
+#ifndef OPENSSL_NO_DH
+ENCODER_TEXT("DH", dh, yes),
+ENCODER_TEXT("DHX", dhx, yes),
+#endif
+#ifndef OPENSSL_NO_DSA
+ENCODER_TEXT("DSA", dsa, yes),
+#endif
+#ifndef OPENSSL_NO_EC
+ENCODER_TEXT("EC", ec, yes),
+ENCODER_TEXT("ED25519", ed25519, yes),
+ENCODER_TEXT("ED448", ed448, yes),
+ENCODER_TEXT("X25519", x25519, yes),
+ENCODER_TEXT("X448", x448, yes),
+#endif
+
+/*
+ * Entries for key type specific output formats.  The structure name on these
+ * is the same as the key type name.  This allows us to say something like:
+ *
+ * To replace i2d_{TYPE}PrivateKey(), i2d_{TYPE}PublicKey() and
+ * i2d_{TYPE}Params(), use OSSL_ENCODER functions with an OSSL_ENCODER_CTX
+ * created like this:
+ *
+ * OSSL_ENCODER_CTX *ctx =
+ *     OSSL_ENCODER_CTX_new_by_EVP_PKEY(pkey, selection, "DER", "type-specific",
+ *                                      NULL, NULL);
+ *
+ * To replace PEM_write_bio_{TYPE}PrivateKey(), PEM_write_bio_{TYPE}PublicKey()
+ * and PEM_write_bio_{TYPE}Params(), use OSSL_ENCODER functions with an
+ * OSSL_ENCODER_CTX created like this:
+ *
+ * OSSL_ENCODER_CTX *ctx =
+ *     OSSL_ENCODER_CTX_new_by_EVP_PKEY(pkey, selection, "PEM", "type-specific",
+ *                                      NULL, NULL);
+ *
+ * We only implement those for which there are current i2d_ and PEM_write_bio
+ * implementations.
+ */
+
+/* The RSA encoders only support private key and public key output */
+ENCODER("RSA", rsa, yes, der, type_specific_keypair),
+ENCODER("RSA", rsa, yes, pem, type_specific_keypair),
+#ifndef OPENSSL_NO_DH
+/* DH and X9.42 DH only support key parameters output. */
+ENCODER("DH", dh, yes, der, type_specific_params),
+ENCODER("DH", dh, yes, pem, type_specific_params),
+ENCODER("DHX", dhx, yes, der, type_specific_params),
+ENCODER("DHX", dhx, yes, pem, type_specific_params),
+#endif
+#ifndef OPENSSL_NO_DSA
+ENCODER("DSA", dsa, yes, der, type_specific),
+ENCODER("DSA", dsa, yes, pem, type_specific),
+#endif
+#ifndef OPENSSL_NO_EC
+/* EC only supports keypair and parameters output. */
+ENCODER("EC", ec, yes, der, type_specific_no_pub),
+ENCODER("EC", ec, yes, pem, type_specific_no_pub),
+#endif
+
+/*
+ * Entries for PKCS#8 and SubjectPublicKeyInfo.
+ * The "der" ones are added convenience for any user that wants to use
+ * OSSL_ENCODER directly.
+ * The "pem" ones also support PEM_write_bio_PrivateKey() and
+ * PEM_write_bio_PUBKEY().
+ */
+ENCODER("RSA", rsa, yes, der, PKCS8),
+ENCODER("RSA", rsa, yes, pem, PKCS8),
+ENCODER("RSA", rsa, yes, der, SubjectPublicKeyInfo),
+ENCODER("RSA", rsa, yes, pem, SubjectPublicKeyInfo),
+
+ENCODER("RSA-PSS", rsapss, yes, der, PKCS8),
+ENCODER("RSA-PSS", rsapss, yes, pem, PKCS8),
+ENCODER("RSA-PSS", rsapss, yes, der, SubjectPublicKeyInfo),
+ENCODER("RSA-PSS", rsapss, yes, pem, SubjectPublicKeyInfo),
 
 #ifndef OPENSSL_NO_DH
-    ENCODER("DH", "yes", "text", ossl_dh_to_text_encoder_functions),
-    ENCODER("DH", "yes", "der", ossl_dh_to_der_encoder_functions),
-    ENCODER("DH", "yes", "pem", ossl_dh_to_pem_encoder_functions),
+ENCODER("DH", dh, yes, der, PKCS8),
+ENCODER("DH", dh, yes, pem, PKCS8),
+ENCODER("DH", dh, yes, der, SubjectPublicKeyInfo),
+ENCODER("DH", dh, yes, pem, SubjectPublicKeyInfo),
 
-    ENCODER("DHX", "yes", "text", ossl_dhx_to_text_encoder_functions),
-    ENCODER("DHX", "yes", "der", ossl_dhx_to_der_encoder_functions),
-    ENCODER("DHX", "yes", "pem", ossl_dhx_to_pem_encoder_functions),
+ENCODER("DHX", dhx, yes, der, PKCS8),
+ENCODER("DHX", dhx, yes, pem, PKCS8),
+ENCODER("DHX", dhx, yes, der, SubjectPublicKeyInfo),
+ENCODER("DHX", dhx, yes, pem, SubjectPublicKeyInfo),
 #endif
 
 #ifndef OPENSSL_NO_DSA
-    ENCODER("DSA", "yes", "text", ossl_dsa_to_text_encoder_functions),
-    ENCODER("DSA", "yes", "der", ossl_dsa_to_der_encoder_functions),
-    ENCODER("DSA", "yes", "pem", ossl_dsa_to_pem_encoder_functions),
+ENCODER("DSA", dsa, yes, der, PKCS8),
+ENCODER("DSA", dsa, yes, pem, PKCS8),
+ENCODER("DSA", dsa, yes, der, SubjectPublicKeyInfo),
+ENCODER("DSA", dsa, yes, pem, SubjectPublicKeyInfo),
 #endif
 
 #ifndef OPENSSL_NO_EC
-    ENCODER("X25519", "yes", "text", ossl_x25519_to_text_encoder_functions),
-    ENCODER("X25519", "yes", "der", ossl_x25519_to_der_encoder_functions),
-    ENCODER("X25519", "yes", "pem", ossl_x25519_to_pem_encoder_functions),
+ENCODER("EC", ec, yes, der, PKCS8),
+ENCODER("EC", ec, yes, pem, PKCS8),
+ENCODER("EC", ec, yes, der, SubjectPublicKeyInfo),
+ENCODER("EC", ec, yes, pem, SubjectPublicKeyInfo),
 
-    ENCODER("X448", "yes", "text", ossl_x448_to_text_encoder_functions),
-    ENCODER("X448", "yes", "der", ossl_x448_to_der_encoder_functions),
-    ENCODER("X448", "yes", "pem", ossl_x448_to_pem_encoder_functions),
+ENCODER("X25519", x25519, yes, der, PKCS8),
+ENCODER("X25519", x25519, yes, pem, PKCS8),
+ENCODER("X25519", x25519, yes, der, SubjectPublicKeyInfo),
+ENCODER("X25519", x25519, yes, pem, SubjectPublicKeyInfo),
 
-    ENCODER("ED25519", "yes", "text", ossl_ed25519_to_text_encoder_functions),
-    ENCODER("ED25519", "yes", "der", ossl_ed25519_to_der_encoder_functions),
-    ENCODER("ED25519", "yes", "pem", ossl_ed25519_to_pem_encoder_functions),
+ENCODER("X448", x448, yes, der, PKCS8),
+ENCODER("X448", x448, yes, pem, PKCS8),
+ENCODER("X448", x448, yes, der, SubjectPublicKeyInfo),
+ENCODER("X448", x448, yes, pem, SubjectPublicKeyInfo),
 
-    ENCODER("ED448", "yes", "text", ossl_ed448_to_text_encoder_functions),
-    ENCODER("ED448", "yes", "der", ossl_ed448_to_der_encoder_functions),
-    ENCODER("ED448", "yes", "pem", ossl_ed448_to_pem_encoder_functions),
+ENCODER("ED25519", ed25519, yes, der, PKCS8),
+ENCODER("ED25519", ed25519, yes, pem, PKCS8),
+ENCODER("ED25519", ed25519, yes, der, SubjectPublicKeyInfo),
+ENCODER("ED25519", ed25519, yes, pem, SubjectPublicKeyInfo),
 
-    ENCODER("EC", "yes", "text", ossl_ec_to_text_encoder_functions),
-    ENCODER("EC", "yes", "der", ossl_ec_to_der_encoder_functions),
-    ENCODER("EC", "yes", "pem", ossl_ec_to_pem_encoder_functions),
+ENCODER("ED448", ed448, yes, der, PKCS8),
+ENCODER("ED448", ed448, yes, pem, PKCS8),
+ENCODER("ED448", ed448, yes, der, SubjectPublicKeyInfo),
+ENCODER("ED448", ed448, yes, pem, SubjectPublicKeyInfo),
+#endif
+
+/*
+ * Entries for key type specific output formats.  These are exactly the
+ * same as the type specific above, except that they use the key type
+ * name as structure name instead of "type-specific", in the call on
+ * OSSL_ENCODER_CTX_new_by_EVP_PKEY().
+ */
+
+/* The RSA encoders only support private key and public key output */
+ENCODER("RSA", rsa, yes, der, RSA),
+ENCODER("RSA", rsa, yes, pem, RSA),
+#ifndef OPENSSL_NO_DH
+/* DH and X9.42 DH only support key parameters output. */
+ENCODER("DH", dh, yes, der, DH),
+ENCODER("DH", dh, yes, pem, DH),
+ENCODER("DHX", dhx, yes, der, DHX),
+ENCODER("DHX", dhx, yes, pem, DHX),
+#endif
+#ifndef OPENSSL_NO_DSA
+ENCODER("DSA", dsa, yes, der, DSA),
+ENCODER("DSA", dsa, yes, pem, DSA),
+#endif
+#ifndef OPENSSL_NO_EC
+ENCODER("EC", ec, yes, der, EC),
+ENCODER("EC", ec, yes, pem, EC),
+#endif
+
+/*
+ * Additional entries with structure names being the standard name.
+ * This is entirely for the convenience of the user that wants to use
+ * OSSL_ENCODER directly with names they may fancy.  These do not impact
+ * on libcrypto functionality in any way.
+ */
+/* PKCS#1 is a well known for plain RSA keys, so we add that too */
+ENCODER("RSA", rsa, yes, der, PKCS1),
+ENCODER("RSA", rsa, yes, pem, PKCS1),
+ENCODER("RSA-PSS", rsapss, yes, der, PKCS1),
+ENCODER("RSA-PSS", rsapss, yes, pem, PKCS1),
+#ifndef OPENSSL_NO_DH
+/* PKCS#3 defines the format for DH parameters */
+ENCODER("DH", dh, yes, der, PKCS3),
+ENCODER("DH", dh, yes, pem, PKCS3),
+/* X9.42 defines the format for DHX parameters */
+ENCODER("DHX", dhx, yes, der, X9_42),
+ENCODER("DHX", dhx, yes, pem, X9_42),
+#endif
+#ifndef OPENSSL_NO_EC
+/* RFC 5915 defines the format for EC keys and parameters */
+ENCODER("EC", ec, yes, der, X9_62),
+ENCODER("EC", ec, yes, pem, X9_62),
 #endif
index ca8f24f..8668588 100644 (file)
@@ -50,7 +50,8 @@ struct key2any_ctx_st {
 typedef int check_key_type_fn(const void *key, int nid);
 typedef int key_to_paramstring_fn(const void *key, int nid,
                                   void **str, int *strtype);
-typedef int key_to_der_fn(BIO *out, const void *key, int key_nid,
+typedef int key_to_der_fn(BIO *out, const void *key,
+                          int key_nid, const char *pemname,
                           key_to_paramstring_fn *p2s, i2d_of_void *k2d,
                           struct key2any_ctx_st *ctx);
 typedef int write_bio_of_void_fn(BIO *bp, const void *x);
@@ -136,9 +137,18 @@ static X509_PUBKEY *key_to_pubkey(const void *key, int key_nid,
     return xpk;
 }
 
-static int key_to_der_pkcs8_bio(BIO *out, const void *key, int key_nid,
-                                key_to_paramstring_fn *p2s, i2d_of_void *k2d,
-                                struct key2any_ctx_st *ctx)
+/*
+ * key_to_pkcs8_* produce encoded output with the key data pkcs8
+ * in a structure.  For private keys, that structure is PKCS#8, and for
+ * public keys, it's X.509 SubjectPublicKeyInfo.  Parameters don't have
+ * any defined envelopment of that kind.
+ */
+static int key_to_pkcs8_der_priv_bio(BIO *out, const void *key,
+                                     int key_nid,
+                                     ossl_unused const char *pemname,
+                                     key_to_paramstring_fn *p2s,
+                                     i2d_of_void *k2d,
+                                     struct key2any_ctx_st *ctx)
 {
     int ret = 0;
     void *str = NULL;
@@ -167,9 +177,12 @@ static int key_to_der_pkcs8_bio(BIO *out, const void *key, int key_nid,
     return ret;
 }
 
-static int key_to_pem_pkcs8_bio(BIO *out, const void *key, int key_nid,
-                                key_to_paramstring_fn *p2s, i2d_of_void *k2d,
-                                struct key2any_ctx_st *ctx)
+static int key_to_pkcs8_pem_priv_bio(BIO *out, const void *key,
+                                     int key_nid,
+                                     ossl_unused const char *pemname,
+                                     key_to_paramstring_fn *p2s,
+                                     i2d_of_void *k2d,
+                                     struct key2any_ctx_st *ctx)
 {
     int ret = 0;
     void *str = NULL;
@@ -198,9 +211,12 @@ static int key_to_pem_pkcs8_bio(BIO *out, const void *key, int key_nid,
     return ret;
 }
 
-static int key_to_der_pubkey_bio(BIO *out, const void *key, int key_nid,
-                                 key_to_paramstring_fn *p2s, i2d_of_void *k2d,
-                                 struct key2any_ctx_st *ctx)
+static int key_to_spki_der_pub_bio(BIO *out, const void *key,
+                                   int key_nid,
+                                   ossl_unused const char *pemname,
+                                   key_to_paramstring_fn *p2s,
+                                   i2d_of_void *k2d,
+                                   struct key2any_ctx_st *ctx)
 {
     int ret = 0;
     void *str = NULL;
@@ -220,9 +236,12 @@ static int key_to_der_pubkey_bio(BIO *out, const void *key, int key_nid,
     return ret;
 }
 
-static int key_to_pem_pubkey_bio(BIO *out, const void *key, int key_nid,
-                                 key_to_paramstring_fn *p2s, i2d_of_void *k2d,
-                                 struct key2any_ctx_st *ctx)
+static int key_to_spki_pem_pub_bio(BIO *out, const void *key,
+                                   int key_nid,
+                                   ossl_unused const char *pemname,
+                                   key_to_paramstring_fn *p2s,
+                                   i2d_of_void *k2d,
+                                   struct key2any_ctx_st *ctx)
 {
     int ret = 0;
     void *str = NULL;
@@ -242,6 +261,85 @@ static int key_to_pem_pubkey_bio(BIO *out, const void *key, int key_nid,
     return ret;
 }
 
+/*
+ * key_to_type_specific_* produce encoded output with type specific key data,
+ * no envelopment; the same kind of output as the type specific i2d_ and
+ * PEM_write_ functions, which is often a simple SEQUENCE of INTEGER.
+ *
+ * OpenSSL tries to discourage production of new keys in this form, because
+ * of the ambiguity when trying to recognise them, but can't deny that PKCS#1
+ * et al still are live standards.
+ *
+ * Note that these functions completely ignore p2s, and rather rely entirely
+ * on k2d to do the complete work.
+ */
+static int key_to_type_specific_der_bio(BIO *out, const void *key,
+                                        int key_nid,
+                                        ossl_unused const char *pemname,
+                                        key_to_paramstring_fn *p2s,
+                                        i2d_of_void *k2d,
+                                        struct key2any_ctx_st *ctx)
+{
+    unsigned char *der = NULL;
+    int derlen;
+    int ret;
+
+    if ((derlen = k2d(key, &der)) <= 0) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    ret = BIO_write(out, der, derlen);
+    OPENSSL_free(der);
+    return ret > 0;
+}
+#define key_to_type_specific_der_priv_bio key_to_type_specific_der_bio
+#define key_to_type_specific_der_pub_bio key_to_type_specific_der_bio
+#define key_to_type_specific_der_param_bio key_to_type_specific_der_bio
+
+static int key_to_type_specific_pem_bio_cb(BIO *out, const void *key,
+                                           int key_nid, const char *pemname,
+                                           key_to_paramstring_fn *p2s,
+                                           i2d_of_void *k2d,
+                                           struct key2any_ctx_st *ctx,
+                                           pem_password_cb *cb, void *cbarg)
+{
+    return
+        PEM_ASN1_write_bio(k2d, pemname, out, key, ctx->cipher,
+                           NULL, 0, ossl_pw_pem_password, &ctx->pwdata) > 0;
+}
+
+static int key_to_type_specific_pem_priv_bio(BIO *out, const void *key,
+                                             int key_nid, const char *pemname,
+                                             key_to_paramstring_fn *p2s,
+                                             i2d_of_void *k2d,
+                                             struct key2any_ctx_st *ctx)
+{
+    return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
+                                           p2s, k2d, ctx,
+                                           ossl_pw_pem_password, &ctx->pwdata);
+}
+
+static int key_to_type_specific_pem_pub_bio(BIO *out, const void *key,
+                                            int key_nid, const char *pemname,
+                                            key_to_paramstring_fn *p2s,
+                                            i2d_of_void *k2d,
+                                            struct key2any_ctx_st *ctx)
+{
+    return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
+                                           p2s, k2d, ctx, NULL, NULL);
+}
+
+static int key_to_type_specific_pem_param_bio(BIO *out, const void *key,
+                                              int key_nid, const char *pemname,
+                                              key_to_paramstring_fn *p2s,
+                                              i2d_of_void *k2d,
+                                              struct key2any_ctx_st *ctx)
+{
+    return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname,
+                                           p2s, k2d, ctx, NULL, NULL);
+}
+
 #define der_output_type         "DER"
 #define pem_output_type         "PEM"
 
@@ -275,7 +373,7 @@ static int prepare_dh_params(const void *dh, int nid,
     return 1;
 }
 
-static int dh_pub_to_der(const void *dh, unsigned char **pder)
+static int dh_spki_pub_to_der(const void *dh, unsigned char **pder)
 {
     const BIGNUM *bn = NULL;
     ASN1_INTEGER *pub_key = NULL;
@@ -296,7 +394,7 @@ static int dh_pub_to_der(const void *dh, unsigned char **pder)
     return ret;
 }
 
-static int dh_priv_to_der(const void *dh, unsigned char **pder)
+static int dh_pkcs8_priv_to_der(const void *dh, unsigned char **pder)
 {
     const BIGNUM *bn = NULL;
     ASN1_INTEGER *priv_key = NULL;
@@ -317,31 +415,24 @@ static int dh_priv_to_der(const void *dh, unsigned char **pder)
     return ret;
 }
 
-static int dh_params_to_der_bio(BIO *out, const void *key)
+static int dh_type_specific_params_to_der(const void *dh, unsigned char **pder)
 {
-    int type =
-        DH_test_flags(key, DH_FLAG_TYPE_DHX) ? EVP_PKEY_DHX : EVP_PKEY_DH;
-
-    if (type == EVP_PKEY_DH)
-        return i2d_DHparams_bio(out, key);
-    return i2d_DHxparams_bio(out, key);
+    if (DH_test_flags(dh, DH_FLAG_TYPE_DHX))
+        return i2d_DHxparams(dh, pder);
+    return i2d_DHparams(dh, pder);
 }
 
-static int dh_params_to_pem_bio(BIO *out, const void *key)
-{
-    int type =
-        DH_test_flags(key, DH_FLAG_TYPE_DHX) ? EVP_PKEY_DHX : EVP_PKEY_DH;
-
-    if (type == EVP_PKEY_DH)
-        return PEM_write_bio_DHparams(out, key);
-
-    return PEM_write_bio_DHxparams(out, key);
-}
+/*
+ * DH doesn't have i2d_DHPrivateKey or i2d_DHPublicKey, so we can't make
+ * corresponding functions here.
+ */
+# define dh_type_specific_priv_to_der   NULL
+# define dh_type_specific_pub_to_der    NULL
 
-static int dh_check_key_type(const void *key, int expected_type)
+static int dh_check_key_type(const void *dh, int expected_type)
 {
     int type =
-        DH_test_flags(key, DH_FLAG_TYPE_DHX) ? EVP_PKEY_DHX : EVP_PKEY_DH;
+        DH_test_flags(dh, DH_FLAG_TYPE_DHX) ? EVP_PKEY_DHX : EVP_PKEY_DH;
 
     return type == expected_type;
 }
@@ -350,6 +441,8 @@ static int dh_check_key_type(const void *key, int expected_type)
 # define dhx_evp_type           EVP_PKEY_DHX
 # define dh_input_type          "DH"
 # define dhx_input_type         "DHX"
+# define dh_pem_type            "DH"
+# define dhx_pem_type           "X9.42 DH"
 #endif
 
 /* ---------------------------------------------------------------------- */
@@ -407,7 +500,7 @@ static int prepare_dsa_params(const void *dsa, int nid,
         :  prepare_some_dsa_params(dsa, nid, pstr, pstrtype);
 }
 
-static int dsa_pub_to_der(const void *dsa, unsigned char **pder)
+static int dsa_spki_pub_to_der(const void *dsa, unsigned char **pder)
 {
     const BIGNUM *bn = NULL;
     ASN1_INTEGER *pub_key = NULL;
@@ -428,7 +521,7 @@ static int dsa_pub_to_der(const void *dsa, unsigned char **pder)
     return ret;
 }
 
-static int dsa_priv_to_der(const void *dsa, unsigned char **pder)
+static int dsa_pkcs8_priv_to_der(const void *dsa, unsigned char **pder)
 {
     const BIGNUM *bn = NULL;
     ASN1_INTEGER *priv_key = NULL;
@@ -449,19 +542,14 @@ static int dsa_priv_to_der(const void *dsa, unsigned char **pder)
     return ret;
 }
 
-static int dsa_params_to_der_bio(BIO *out, const void *key)
-{
-    return i2d_DSAparams_bio(out, key);
-}
-
-static int dsa_params_to_pem_bio(BIO *out, const void *key)
-{
-    return PEM_write_bio_DSAparams(out, key);
-}
+# define dsa_type_specific_priv_to_der   (i2d_of_void *)i2d_DSAPrivateKey
+# define dsa_type_specific_pub_to_der    (i2d_of_void *)i2d_DSAPublicKey
+# define dsa_type_specific_params_to_der (i2d_of_void *)i2d_DSAparams
 
 # define dsa_check_key_type     NULL
 # define dsa_evp_type           EVP_PKEY_DSA
 # define dsa_input_type         "DSA"
+# define dsa_pem_type           "DSA"
 #endif
 
 /* ---------------------------------------------------------------------- */
@@ -489,6 +577,11 @@ static int prepare_ec_explicit_params(const void *eckey,
     return 1;
 }
 
+/*
+ * This implements EcpkParameters, where the CHOICE is based on whether there
+ * is a curve name (curve nid) to be found or not.  See RFC 3279 for details.
+ * TODO: shouldn't we use i2d_ECPKParameters()?
+ */
 static int prepare_ec_params(const void *eckey, int nid,
                              void **pstr, int *pstrtype)
 {
@@ -507,6 +600,7 @@ static int prepare_ec_params(const void *eckey, int nid,
 
     if (curve_nid != NID_undef
         && (EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE)) {
+        /* The CHOICE came to namedCurve */
         if (OBJ_length(params) == 0) {
             /* Some curves might not have an associated OID */
             ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_OID);
@@ -517,26 +611,17 @@ static int prepare_ec_params(const void *eckey, int nid,
         *pstrtype = V_ASN1_OBJECT;
         return 1;
     } else {
+        /* The CHOICE came to ecParameters */
         return prepare_ec_explicit_params(eckey, pstr, pstrtype);
     }
 }
 
-static int ec_params_to_der_bio(BIO *out, const void *eckey)
-{
-    return i2d_ECPKParameters_bio(out, EC_KEY_get0_group(eckey));
-}
-
-static int ec_params_to_pem_bio(BIO *out, const void *eckey)
-{
-    return PEM_write_bio_ECPKParameters(out, EC_KEY_get0_group(eckey));
-}
-
-static int ec_pub_to_der(const void *eckey, unsigned char **pder)
+static int ec_spki_pub_to_der(const void *eckey, unsigned char **pder)
 {
     return i2o_ECPublicKey(eckey, pder);
 }
 
-static int ec_priv_to_der(const void *veckey, unsigned char **pder)
+static int ec_pkcs8_priv_to_der(const void *veckey, unsigned char **pder)
 {
     EC_KEY *eckey = (EC_KEY *)veckey;
     unsigned int old_flags;
@@ -556,9 +641,14 @@ static int ec_priv_to_der(const void *veckey, unsigned char **pder)
     return ret; /* return the length of the der encoded data */
 }
 
+# define ec_type_specific_params_to_der (i2d_of_void *)i2d_ECParameters
+# define ec_type_specific_pub_to_der    (i2d_of_void *)i2o_ECPublicKey
+# define ec_type_specific_priv_to_der   (i2d_of_void *)i2d_ECPrivateKey
+
 # define ec_check_key_type      NULL
 # define ec_evp_type            EVP_PKEY_EC
 # define ec_input_type          "EC"
+# define ec_pem_type            "EC"
 #endif
 
 /* ---------------------------------------------------------------------- */
@@ -566,7 +656,7 @@ static int ec_priv_to_der(const void *veckey, unsigned char **pder)
 #ifndef OPENSSL_NO_EC
 # define prepare_ecx_params NULL
 
-static int ecx_pub_to_der(const void *vecxkey, unsigned char **pder)
+static int ecx_spki_pub_to_der(const void *vecxkey, unsigned char **pder)
 {
     const ECX_KEY *ecxkey = vecxkey;
     unsigned char *keyblob;
@@ -586,7 +676,7 @@ static int ecx_pub_to_der(const void *vecxkey, unsigned char **pder)
     return ecxkey->keylen;
 }
 
-static int ecx_priv_to_der(const void *vecxkey, unsigned char **pder)
+static int ecx_pkcs8_priv_to_der(const void *vecxkey, unsigned char **pder)
 {
     const ECX_KEY *ecxkey = vecxkey;
     ASN1_OCTET_STRING oct;
@@ -610,8 +700,11 @@ static int ecx_priv_to_der(const void *vecxkey, unsigned char **pder)
     return keybloblen;
 }
 
-# define ecx_params_to_der_bio  NULL
-# define ecx_params_to_pem_bio  NULL
+/*
+ * ED25519, ED448, X25519 and X448 only has PKCS#8 / SubjectPublicKeyInfo
+ * representation, so we don't define ecx_type_specific_[priv,pub,params]_to_der.
+ */
+
 # define ecx_check_key_type     NULL
 
 # define ed25519_evp_type       EVP_PKEY_ED25519
@@ -622,6 +715,10 @@ static int ecx_priv_to_der(const void *vecxkey, unsigned char **pder)
 # define ed448_input_type       "ED448"
 # define x25519_input_type      "X25519"
 # define x448_input_type        "X448"
+# define ed25519_pem_type       "ED25519"
+# define ed448_pem_type         "ED448"
+# define x25519_pem_type        "X25519"
+# define x448_pem_type          "X448"
 #endif
 
 /* ---------------------------------------------------------------------- */
@@ -701,10 +798,15 @@ static int prepare_rsa_params(const void *rsa, int nid,
     return 0;
 }
 
-#define rsa_params_to_der_bio   NULL
-#define rsa_params_to_pem_bio   NULL
-#define rsa_priv_to_der         (i2d_of_void *)i2d_RSAPrivateKey
-#define rsa_pub_to_der          (i2d_of_void *)i2d_RSAPublicKey
+/*
+ * RSA is extremely simple, as PKCS#1 is used for the PKCS#8 |privateKey|
+ * field as well as the SubjectPublicKeyInfo |subjectPublicKey| field.
+ */
+#define rsa_pkcs8_priv_to_der           rsa_type_specific_priv_to_der
+#define rsa_spki_pub_to_der             rsa_type_specific_pub_to_der
+#define rsa_type_specific_priv_to_der   (i2d_of_void *)i2d_RSAPrivateKey
+#define rsa_type_specific_pub_to_der    (i2d_of_void *)i2d_RSAPublicKey
+#define rsa_type_specific_params_to_der NULL
 
 static int rsa_check_key_type(const void *rsa, int expected_type)
 {
@@ -723,12 +825,13 @@ static int rsa_check_key_type(const void *rsa, int expected_type)
 #define rsapss_evp_type         EVP_PKEY_RSA_PSS
 #define rsa_input_type          "RSA"
 #define rsapss_input_type       "RSA-PSS"
+#define rsa_pem_type            "RSA"
+#define rsapss_pem_type         "RSA-PSS"
 
 /* ---------------------------------------------------------------------- */
 
 static OSSL_FUNC_decoder_newctx_fn key2any_newctx;
 static OSSL_FUNC_decoder_freectx_fn key2any_freectx;
-static OSSL_FUNC_decoder_gettable_params_fn key2any_gettable_params;
 
 static void *key2any_newctx(void *provctx)
 {
@@ -749,18 +852,27 @@ static void key2any_freectx(void *vctx)
     OPENSSL_free(ctx);
 }
 
-static const OSSL_PARAM *key2any_gettable_params(void *provctx)
+static const OSSL_PARAM *key2any_gettable_params(void *provctx, int structure)
 {
     static const OSSL_PARAM gettables[] = {
+        { OSSL_ENCODER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
+        { OSSL_ENCODER_PARAM_OUTPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
+        OSSL_PARAM_END,
+    };
+
+    static const OSSL_PARAM gettables_w_structure[] = {
+        { OSSL_ENCODER_PARAM_INPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
         { OSSL_ENCODER_PARAM_OUTPUT_TYPE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
+        { OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
         OSSL_PARAM_END,
     };
 
-    return gettables;
+    return structure ? gettables_w_structure : gettables;
 }
 
 static int key2any_get_params(OSSL_PARAM params[], const char *input_type,
-                              const char *output_type)
+                              const char *output_type,
+                              const char *output_struct)
 {
     OSSL_PARAM *p;
 
@@ -772,6 +884,12 @@ static int key2any_get_params(OSSL_PARAM params[], const char *input_type,
     if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, output_type))
         return 0;
 
+    if (output_struct != NULL) {
+        p = OSSL_PARAM_locate(params, OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE);
+        if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, output_struct))
+            return 0;
+    }
+
     return 1;
 }
 
@@ -805,6 +923,7 @@ static int key2any_set_ctx_params(void *vctx, const OSSL_PARAM params[])
             return 0;
 
         EVP_CIPHER_free(ctx->cipher);
+        ctx->cipher = NULL;
         ctx->cipher_intent = ciphername != NULL;
         if (ciphername != NULL
             && ((ctx->cipher =
@@ -814,11 +933,44 @@ static int key2any_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     return 1;
 }
 
+static int key2any_check_selection(int selection, int selection_mask)
+{
+    /*
+     * The selections are kinda sorta "levels", i.e. each selection given
+     * here is assumed to include those following.
+     */
+    int checks[] = {
+        OSSL_KEYMGMT_SELECT_PRIVATE_KEY,
+        OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
+        OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
+    };
+    size_t i;
+
+    /* The decoder implementations made here support guessing */
+    if (selection == 0)
+        return 1;
+
+    for (i = 0; i < OSSL_NELEM(checks); i++) {
+        int check1 = (selection & checks[i]) != 0;
+        int check2 = (selection_mask & checks[i]) != 0;
+
+        /*
+         * If the caller asked for the currently checked bit(s), return
+         * whether the decoder description says it's supported.
+         */
+        if (check1)
+            return check2;
+    }
+
+    /* This should be dead code, but just to be safe... */
+    return 0;
+}
+
 static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout,
-                          const void *key, int type,
+                          const void *key, int type, const char *pemname,
                           check_key_type_fn *checker,
                           key_to_der_fn *writer,
-                          OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg,
+                          OSSL_PASSPHRASE_CALLBACK *pwcb, void *pwcbarg,
                           key_to_paramstring_fn *key2paramstring,
                           i2d_of_void *key2der)
 {
@@ -826,13 +978,15 @@ static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout,
 
     if (key == NULL) {
         ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
-    } else if (checker == NULL || checker(key, type)) {
+    } else if (writer != NULL
+               && (checker == NULL || checker(key, type))) {
         BIO *out = bio_new_from_core_bio(ctx->provctx, cout);
 
         if (out != NULL
-            && writer != NULL
-            && ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, cb, cbarg))
-            ret = writer(out, key, type, key2paramstring, key2der, ctx);
+            && (pwcb == NULL
+                || ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, pwcb, pwcbarg)))
+            ret =
+                writer(out, key, type, pemname, key2paramstring, key2der, ctx);
 
         BIO_free(out);
     } else {
@@ -841,136 +995,395 @@ static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout,
     return ret;
 }
 
-static int key2any_encode_params(struct key2any_ctx_st *ctx,
-                                 OSSL_CORE_BIO *cout,
-                                 const void *key, int type,
-                                 check_key_type_fn *checker,
-                                 write_bio_of_void_fn *writer)
-{
-    int ret = 0;
+#define DO_PRIVATE_KEY_selection_mask OSSL_KEYMGMT_SELECT_PRIVATE_KEY
+#define DO_PRIVATE_KEY(impl, type, kind, output)                            \
+    if ((selection & DO_PRIVATE_KEY_selection_mask) != 0)                   \
+        return key2any_encode(ctx, cout, key, impl##_evp_type,              \
+                              impl##_pem_type " PRIVATE KEY",               \
+                              type##_check_key_type,                        \
+                              key_to_##kind##_##output##_priv_bio,          \
+                              cb, cbarg, prepare_##type##_params,           \
+                              type##_##kind##_priv_to_der);
+
+#define DO_PUBLIC_KEY_selection_mask OSSL_KEYMGMT_SELECT_PUBLIC_KEY
+#define DO_PUBLIC_KEY(impl, type, kind, output)                             \
+    if ((selection & DO_PUBLIC_KEY_selection_mask) != 0)                    \
+        return key2any_encode(ctx, cout, key, impl##_evp_type,              \
+                              impl##_pem_type " PUBLIC KEY",                \
+                              type##_check_key_type,                        \
+                              key_to_##kind##_##output##_pub_bio,           \
+                              cb, cbarg, prepare_##type##_params,           \
+                              type##_##kind##_pub_to_der);
+
+#define DO_PARAMETERS_selection_mask OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
+#define DO_PARAMETERS(impl, type, kind, output)                             \
+    if ((selection & DO_PARAMETERS_selection_mask) != 0)                    \
+        return key2any_encode(ctx, cout, key, impl##_evp_type,              \
+                              impl##_pem_type " PARAMETERS",                \
+                              type##_check_key_type,                        \
+                              key_to_##kind##_##output##_param_bio,         \
+                              NULL, NULL, NULL,                             \
+                              type##_##kind##_params_to_der);
+
+/*-
+ * Implement the kinds of output structure that can be produced.  They are
+ * referred to by name, and for each name, the following macros are defined
+ * (braces not included):
+ *
+ * {kind}_output_structure
+ *
+ *      A string that names the output structure. This is used as a selection
+ *      criterion for each implementation.  It may be NULL, which means that
+ *      there is only one possible output structure for the implemented output
+ *      type.
+ *
+ * DO_{kind}_selection_mask
+ *
+ *      A mask of selection bits that must not be zero.  This is used as a
+ *      selection criterion for each implementation.
+ *      This mask must never be zero.
+ *
+ * DO_{kind}
+ *
+ *      The performing macro.  It must use the DO_ macros defined above,
+ *      always in this order:
+ *
+ *      - DO_PRIVATE_KEY
+ *      - DO_PUBLIC_KEY
+ *      - DO_PARAMETERS
+ *
+ *      Any of those may be omitted, but the relative order must still be
+ *      the same.
+ */
 
-    if (key == NULL) {
-        ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
-    } else if (checker == NULL || checker(key, type)) {
-        BIO *out = bio_new_from_core_bio(ctx->provctx, cout);
+/* PKCS#8 is a structure for private keys only */
+#define PKCS8_output_structure "pkcs8"
+#define DO_PKCS8_selection_mask DO_PRIVATE_KEY_selection_mask
+#define DO_PKCS8(impl, type, output)                                        \
+    DO_PRIVATE_KEY(impl, type, pkcs8, output)
 
-        if (out != NULL && writer != NULL)
-            ret = writer(out, key);
+/* SubjectPublicKeyInfo is a structure for public keys only */
+#define SubjectPublicKeyInfo_output_structure "SubjectPublicKeyInfo"
+#define DO_SubjectPublicKeyInfo_selection_mask DO_PUBLIC_KEY_selection_mask
+#define DO_SubjectPublicKeyInfo(impl, type, output)                         \
+    DO_PUBLIC_KEY(impl, type, spki, output)
 
-        BIO_free(out);
-    } else {
-        ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
-    }
+/*
+ * "type-specific" is a uniform name for key type specific output for private
+ * and public keys as well as key parameters.  This is used internally in
+ * libcrypto so it doesn't have to have special knowledge about select key
+ * types, but also when no better name has been found.  If there are more
+ * expressive DO_ names above, those are preferred.
+ *
+ * Three forms exist:
+ *
+ * - type_specific_keypair              Only supports private and public key
+ * - type_specific_params               Only supports parameters
+ * - type_specific                      Supports all parts of an EVP_PKEY
+ * - type_specific_no_pub               Supports all parts of an EVP_PKEY
+ *                                      except public key
+ */
+#define type_specific_params_output_structure "type-specific"
+#define DO_type_specific_params_selection_mask DO_PARAMETERS_selection_mask
+#define DO_type_specific_params(impl, type, output)                         \
+    DO_PARAMETERS(impl, type, type_specific, output)
+#define type_specific_keypair_output_structure "type-specific"
+#define DO_type_specific_keypair_selection_mask                             \
+    ( DO_PRIVATE_KEY_selection_mask | DO_PUBLIC_KEY_selection_mask )
+#define DO_type_specific_keypair(impl, type, output)                        \
+    DO_PRIVATE_KEY(impl, type, type_specific, output)                       \
+    DO_PUBLIC_KEY(impl, type, type_specific, output)
+#define type_specific_output_structure "type-specific"
+#define DO_type_specific_selection_mask                                     \
+    ( DO_type_specific_keypair_selection_mask                               \
+      | DO_type_specific_params_selection_mask )
+#define DO_type_specific(impl, type, output)                                \
+    DO_type_specific_keypair(impl, type, output)                            \
+    DO_type_specific_params(impl, type, output)
+#define type_specific_no_pub_output_structure "type-specific"
+#define DO_type_specific_no_pub_selection_mask \
+    ( DO_PRIVATE_KEY_selection_mask |  DO_PARAMETERS_selection_mask)
+#define DO_type_specific_no_pub(impl, type, output)                         \
+    DO_PRIVATE_KEY(impl, type, type_specific, output)                       \
+    DO_type_specific_params(impl, type, output)
 
-    return ret;
-}
+/*
+ * Type specific aliases for the cases where we need to refer to them by
+ * type name.
+ * This only covers key types that are represented with i2d_{TYPE}PrivateKey,
+ * i2d_{TYPE}PublicKey and i2d_{TYPE}params / i2d_{TYPE}Parameters.
+ */
+#define RSA_output_structure "rsa"
+#define DO_RSA_selection_mask DO_type_specific_keypair_selection_mask
+#define DO_RSA(impl, type, output) DO_type_specific_keypair(impl, type, output)
+
+#define DH_output_structure "dh"
+#define DO_DH_selection_mask DO_type_specific_params_selection_mask
+#define DO_DH(impl, type, output) DO_type_specific_params(impl, type, output)
+
+#define DHX_output_structure "dhx"
+#define DO_DHX_selection_mask DO_type_specific_params_selection_mask
+#define DO_DHX(impl, type, output) DO_type_specific_params(impl, type, output)
+
+#define DSA_output_structure "dsa"
+#define DO_DSA_selection_mask DO_type_specific_selection_mask
+#define DO_DSA(impl, type, output) DO_type_specific(impl, type, output)
+
+#define EC_output_structure "ec"
+#define DO_EC_selection_mask DO_type_specific_selection_mask
+#define DO_EC(impl, type, output) DO_type_specific(impl, type, output)
+
+/* PKCS#1 defines a structure for RSA private and public keys */
+#define PKCS1_output_structure "pkcs1"
+#define DO_PKCS1_selection_mask DO_RSA_selection_mask
+#define DO_PKCS1(impl, type, output) DO_RSA(impl, type, output)
+
+/* PKCS#3 defines a structure for DH parameters */
+#define PKCS3_output_structure "pkcs3"
+#define DO_PKCS3_selection_mask DO_DH_selection_mask
+#define DO_PKCS3(impl, type, output) DO_DH(impl, type, output)
+/* X9.42 defines a structure for DHx parameters */
+#define X9_42_output_structure "X9.42"
+#define DO_X9_42_selection_mask DO_DHX_selection_mask
+#define DO_X9_42(impl, type, output) DO_DHX(impl, type, output)
+
+/* X9.62 defines a structure for EC keys and parameters */
+#define X9_62_output_structure "X9.62"
+#define DO_X9_62_selection_mask DO_EC_selection_mask
+#define DO_X9_62(impl, type, output) DO_EC(impl, type, output)
 
-#define MAKE_ENCODER(impl, type, evp_type, output)                          \
+/*
+ * MAKE_ENCODER is the single driver for creating OSSL_DISPATCH tables.
+ * It takes the following arguments:
+ *
+ * impl         This is the key type name that's being implemented.
+ * type         This is the type name for the set of functions that implement
+ *              the key type.  For example, ed25519, ed448, x25519 and x448
+ *              are all implemented with the exact same set of functions.
+ * evp_type     The corresponding EVP_PKEY_xxx type macro for each key.
+ *              Necessary because we currently use EVP_PKEY with legacy
+ *              native keys internally.  This will need to be refactored
+ *              when that legacy support goes away.
+ * kind         What kind of support to implement.  These translate into
+ *              the DO_##kind macros above.
+ * output       The output type to implement.  may be der or pem.
+ *
+ * The resulting OSSL_DISPATCH array gets the following name (expressed in
+ * C preprocessor terms) from those arguments:
+ *
+ * ossl_##impl##_to_##kind##_##output##_encoder_functions
+ */
+#define MAKE_ENCODER(impl, type, evp_type, kind, output)                    \
+    static OSSL_FUNC_encoder_gettable_params_fn                             \
+    impl##_to_##kind##_##output##_gettable_params;                          \
     static OSSL_FUNC_encoder_get_params_fn                                  \
-    impl##2##output##_get_params;                                           \
+    impl##_to_##kind##_##output##_get_params;                               \
     static OSSL_FUNC_encoder_import_object_fn                               \
-    impl##2##output##_import_object;                                        \
+    impl##_to_##kind##_##output##_import_object;                            \
     static OSSL_FUNC_encoder_free_object_fn                                 \
-    impl##2##output##_free_object;                                          \
-    static OSSL_FUNC_encoder_encode_fn impl##2##output##_encode;            \
+    impl##_to_##kind##_##output##_free_object;                              \
+    static OSSL_FUNC_encoder_encode_fn                                      \
+    impl##_to_##kind##_##output##_encode;                                   \
                                                                             \
-    static int impl##2##output##_get_params(OSSL_PARAM params[])            \
+    static const OSSL_PARAM *                                               \
+    impl##_to_##kind##_##output##_gettable_params(void *provctx)            \
+    {                                                                       \
+        return key2any_gettable_params(provctx,                             \
+                                       kind##_output_structure != NULL);    \
+    }                                                                       \
+    static int                                                              \
+    impl##_to_##kind##_##output##_get_params(OSSL_PARAM params[])           \
     {                                                                       \
         return key2any_get_params(params, impl##_input_type,                \
-                                  output##_output_type);                    \
+                                  output##_output_type,                     \
+                                  kind##_output_structure);                 \
     }                                                                       \
     static void *                                                           \
-    impl##2##output##_import_object(void *vctx, int selection,              \
-                                    const OSSL_PARAM params[])              \
+    impl##_to_##kind##_##output##_import_object(void *vctx, int selection,  \
+                                                const OSSL_PARAM params[])  \
     {                                                                       \
         struct key2any_ctx_st *ctx = vctx;                                  \
+                                                                            \
         return ossl_prov_import_key(ossl_##impl##_keymgmt_functions,        \
                                     ctx->provctx, selection, params);       \
     }                                                                       \
-    static void impl##2##output##_free_object(void *key)                    \
+    static void impl##_to_##kind##_##output##_free_object(void *key)        \
     {                                                                       \
         ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key);           \
     }                                                                       \
+    static int impl##_to_##kind##_##output##_does_selection(void *ctx,      \
+                                                            int selection)  \
+    {                                                                       \
+        return key2any_check_selection(selection,                           \
+                                       DO_##kind##_selection_mask);         \
+    }                                                                       \
     static int                                                              \
-    impl##2##output##_encode(void *ctx, OSSL_CORE_BIO *cout,                \
-                             const void *key,                               \
-                             const OSSL_PARAM key_abstract[],               \
-                             int selection,                                 \
-                             OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)     \
+    impl##_to_##kind##_##output##_encode(void *ctx, OSSL_CORE_BIO *cout,    \
+                                         const void *key,                   \
+                                         const OSSL_PARAM key_abstract[],   \
+                                         int selection,                     \
+                                         OSSL_PASSPHRASE_CALLBACK *cb,      \
+                                         void *cbarg)                       \
     {                                                                       \
         /* We don't deal with abstract objects */                           \
         if (key_abstract != NULL) {                                         \
             ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);         \
             return 0;                                                       \
         }                                                                   \
-        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)             \
-            return key2any_encode(ctx, cout, key, impl##_evp_type,          \
-                                  type##_check_key_type,                    \
-                                  key_to_##output##_pkcs8_bio,              \
-                                  cb, cbarg,                                \
-                                  prepare_##type##_params,                  \
-                                  type##_priv_to_der);                      \
-        if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)              \
-            return key2any_encode(ctx, cout, key, impl##_evp_type,          \
-                                  type##_check_key_type,                    \
-                                  key_to_##output##_pubkey_bio,             \
-                                  cb, cbarg,                                \
-                                  prepare_##type##_params,                  \
-                                  type##_pub_to_der);                       \
-        if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)          \
-            return key2any_encode_params(ctx, cout, key,                    \
-                                         impl##_evp_type,                   \
-                                         type##_check_key_type,             \
-                                         type##_params_to_##output##_bio);  \
+        DO_##kind(impl, type, output)                                       \
                                                                             \
         ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);             \
         return 0;                                                           \
     }                                                                       \
-    const OSSL_DISPATCH ossl_##impl##_to_##output##_encoder_functions[] = { \
+    const OSSL_DISPATCH                                                     \
+    ossl_##impl##_to_##kind##_##output##_encoder_functions[] = {            \
         { OSSL_FUNC_ENCODER_NEWCTX,                                         \
           (void (*)(void))key2any_newctx },                                 \
         { OSSL_FUNC_ENCODER_FREECTX,                                        \
           (void (*)(void))key2any_freectx },                                \
         { OSSL_FUNC_ENCODER_GETTABLE_PARAMS,                                \
-          (void (*)(void))key2any_gettable_params },                        \
+          (void (*)(void))impl##_to_##kind##_##output##_gettable_params },  \
         { OSSL_FUNC_ENCODER_GET_PARAMS,                                     \
-          (void (*)(void))impl##2##output##_get_params },                   \
+          (void (*)(void))impl##_to_##kind##_##output##_get_params },       \
         { OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS,                            \
           (void (*)(void))key2any_settable_ctx_params },                    \
         { OSSL_FUNC_ENCODER_SET_CTX_PARAMS,                                 \
           (void (*)(void))key2any_set_ctx_params },                         \
+        { OSSL_FUNC_ENCODER_DOES_SELECTION,                                 \
+          (void (*)(void))impl##_to_##kind##_##output##_does_selection },   \
         { OSSL_FUNC_ENCODER_IMPORT_OBJECT,                                  \
-          (void (*)(void))impl##2##output##_import_object },                \
+          (void (*)(void))impl##_to_##kind##_##output##_import_object },    \
         { OSSL_FUNC_ENCODER_FREE_OBJECT,                                    \
-          (void (*)(void))impl##2##output##_free_object },                  \
+          (void (*)(void))impl##_to_##kind##_##output##_free_object },      \
         { OSSL_FUNC_ENCODER_ENCODE,                                         \
-          (void (*)(void))impl##2##output##_encode },                       \
+          (void (*)(void))impl##_to_##kind##_##output##_encode },           \
         { 0, NULL }                                                         \
     }
 
+/*
+ * Replacements for i2d_{TYPE}PrivateKey, i2d_{TYPE}PublicKey,
+ * i2d_{TYPE}params, as they exist.
+ */
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, type_specific_keypair, der);
 #ifndef OPENSSL_NO_DH
-MAKE_ENCODER(dh, dh, EVP_PKEY_DH, der);
-MAKE_ENCODER(dh, dh, EVP_PKEY_DH, pem);
-MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, der);
-MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, pem);
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, type_specific_params, der);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, type_specific_params, der);
 #endif
 #ifndef OPENSSL_NO_DSA
-MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, der);
-MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, pem);
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, type_specific, der);
+#endif
+#ifndef OPENSSL_NO_EC
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, type_specific_no_pub, der);
+#endif
+
+/*
+ * Replacements for PEM_write_bio_{TYPE}PrivateKey,
+ * PEM_write_bio_{TYPE}PublicKey, PEM_write_bio_{TYPE}params, as they exist.
+ */
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, type_specific_keypair, pem);
+#ifndef OPENSSL_NO_DH
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, type_specific_params, pem);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, type_specific_params, pem);
+#endif
+#ifndef OPENSSL_NO_DSA
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, type_specific, pem);
+#endif
+#ifndef OPENSSL_NO_EC
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, type_specific_no_pub, pem);
+#endif
+
+/*
+ * PKCS#8 and SubjectPublicKeyInfo support.  This may duplicate some of the
+ * implementations specified above, but are more specific.
+ * The SubjectPublicKeyInfo implementations also replace the
+ * PEM_write_bio_{TYPE}_PUBKEY functions.
+ * For PEM, these are expected to be used by PEM_write_bio_PrivateKey(),
+ * PEM_write_bio_PUBKEY() and PEM_write_bio_Parameters().
+ */
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS8, der);
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS8, pem);
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, SubjectPublicKeyInfo, pem);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS8, der);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS8, pem);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, SubjectPublicKeyInfo, pem);
+#ifndef OPENSSL_NO_DH
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS8, der);
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS8, pem);
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, SubjectPublicKeyInfo, pem);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PKCS8, der);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, PKCS8, pem);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, SubjectPublicKeyInfo, pem);
+#endif
+#ifndef OPENSSL_NO_DSA
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PKCS8, der);
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, PKCS8, pem);
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, SubjectPublicKeyInfo, pem);
+#endif
+#ifndef OPENSSL_NO_EC
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PKCS8, der);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, PKCS8, pem);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, SubjectPublicKeyInfo, pem);
+MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PKCS8, der);
+MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, PKCS8, pem);
+MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, SubjectPublicKeyInfo, pem);
+MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PKCS8, der);
+MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, PKCS8, pem);
+MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem);
+MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PKCS8, der);
+MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, PKCS8, pem);
+MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, SubjectPublicKeyInfo, pem);
+MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PKCS8, der);
+MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, PKCS8, pem);
+MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, SubjectPublicKeyInfo, pem);
+#endif
+
+/*
+ * Support for key type specific output formats.  Not all key types have
+ * this, we only aim to duplicate what is available in 1.1.1 as
+ * i2d_TYPEPrivateKey(), i2d_TYPEPublicKey() and i2d_TYPEparams().
+ * For example, there are no publicly available i2d_ function for
+ * ED25519, ED448, X25519 or X448, and they therefore only have PKCS#8
+ * and SubjectPublicKeyInfo implementations as implemented above.
+ */
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, RSA, der);
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, RSA, pem);
+#ifndef OPENSSL_NO_DH
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, DH, der);
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, DH, pem);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, DHX, der);
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, DHX, pem);
+#endif
+#ifndef OPENSSL_NO_DSA
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, DSA, der);
+MAKE_ENCODER(dsa, dsa, EVP_PKEY_DSA, DSA, pem);
+#endif
+#ifndef OPENSSL_NO_EC
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EC, der);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, EC, pem);
+#endif
+
+/* Convenience structure names */
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS1, der);
+MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, PKCS1, pem);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS1, der);
+MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA_PSS, PKCS1, pem);
+#ifndef OPENSSL_NO_DH
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS3, der); /* parameters only */
+MAKE_ENCODER(dh, dh, EVP_PKEY_DH, PKCS3, pem); /* parameters only */
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, X9_42, der); /* parameters only */
+MAKE_ENCODER(dhx, dh, EVP_PKEY_DHX, X9_42, pem); /* parameters only */
 #endif
 #ifndef OPENSSL_NO_EC
-MAKE_ENCODER(ec, ec, EVP_PKEY_EC, der);
-MAKE_ENCODER(ec, ec, EVP_PKEY_EC, pem);
-MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, der);
-MAKE_ENCODER(ed25519, ecx, EVP_PKEY_ED25519, pem);
-MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, der);
-MAKE_ENCODER(ed448, ecx, EVP_PKEY_ED448, pem);
-MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, der);
-MAKE_ENCODER(x25519, ecx, EVP_PKEY_X25519, pem);
-MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, der);
-MAKE_ENCODER(x448, ecx, EVP_PKEY_ED448, pem);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, X9_62, der);
+MAKE_ENCODER(ec, ec, EVP_PKEY_EC, X9_62, pem);
 #endif
-MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, der);
-MAKE_ENCODER(rsa, rsa, EVP_PKEY_RSA, pem);
-MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA, der);
-MAKE_ENCODER(rsapss, rsa, EVP_PKEY_RSA, pem);
index 23b0f51..ffc23f6 100644 (file)
@@ -321,45 +321,99 @@ extern const OSSL_DISPATCH sm2_asym_cipher_functions[];
 extern const OSSL_DISPATCH ossl_rsa_asym_kem_functions[];
 
 /* Encoders */
-extern const OSSL_DISPATCH ossl_rsa_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_rsa_to_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_PKCS1_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_PKCS1_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_RSA_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_RSA_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_SubjectPublicKeyInfo_pem_encoder_functions[];
 extern const OSSL_DISPATCH ossl_rsa_to_text_encoder_functions[];
-
-extern const OSSL_DISPATCH ossl_rsapss_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_rsapss_to_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_type_specific_keypair_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsa_to_type_specific_keypair_pem_encoder_functions[];
+
+extern const OSSL_DISPATCH ossl_rsapss_to_PKCS1_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsapss_to_PKCS1_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsapss_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsapss_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsapss_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_rsapss_to_SubjectPublicKeyInfo_pem_encoder_functions[];
 extern const OSSL_DISPATCH ossl_rsapss_to_text_encoder_functions[];
 
-extern const OSSL_DISPATCH ossl_dh_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_dh_to_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_DH_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_DH_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_PKCS3_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_PKCS3_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_type_specific_params_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dh_to_type_specific_params_pem_encoder_functions[];
 extern const OSSL_DISPATCH ossl_dh_to_text_encoder_functions[];
 
-extern const OSSL_DISPATCH ossl_dhx_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_dhx_to_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_DHX_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_DHX_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_X9_42_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_X9_42_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_type_specific_params_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dhx_to_type_specific_params_pem_encoder_functions[];
 extern const OSSL_DISPATCH ossl_dhx_to_text_encoder_functions[];
 
-extern const OSSL_DISPATCH ossl_dsa_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_dsa_to_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_DSA_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_DSA_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_type_specific_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_dsa_to_type_specific_der_encoder_functions[];
 extern const OSSL_DISPATCH ossl_dsa_to_text_encoder_functions[];
 
-extern const OSSL_DISPATCH ossl_x25519_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_x25519_to_pem_encoder_functions[];
-extern const OSSL_DISPATCH ossl_x25519_to_text_encoder_functions[];
-
-extern const OSSL_DISPATCH ossl_x448_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_x448_to_pem_encoder_functions[];
-extern const OSSL_DISPATCH ossl_x448_to_text_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_EC_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_EC_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_X9_62_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_X9_62_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_type_specific_no_pub_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_type_specific_no_pub_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ec_to_text_encoder_functions[];
 
-extern const OSSL_DISPATCH ossl_ed25519_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_ed25519_to_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed25519_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed25519_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed25519_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed25519_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed25519_to_OSSL_current_der_encoder_functions[];
 extern const OSSL_DISPATCH ossl_ed25519_to_text_encoder_functions[];
 
-extern const OSSL_DISPATCH ossl_ed448_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_ed448_to_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed448_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed448_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed448_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed448_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ed448_to_OSSL_current_der_encoder_functions[];
 extern const OSSL_DISPATCH ossl_ed448_to_text_encoder_functions[];
 
-extern const OSSL_DISPATCH ossl_ec_to_der_encoder_functions[];
-extern const OSSL_DISPATCH ossl_ec_to_pem_encoder_functions[];
-extern const OSSL_DISPATCH ossl_ec_to_text_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x25519_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x25519_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x25519_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x25519_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x25519_to_OSSL_current_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x25519_to_text_encoder_functions[];
+
+extern const OSSL_DISPATCH ossl_x448_to_PKCS8_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x448_to_PKCS8_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x448_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x448_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x448_to_OSSL_current_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_x448_to_text_encoder_functions[];
 
 /* Decoders */
 extern const OSSL_DISPATCH ossl_PKCS8_der_to_dh_decoder_functions[];