* 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
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);
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;
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;
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;
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;
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"
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;
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;
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;
}
# 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
/* ---------------------------------------------------------------------- */
: 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;
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;
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
/* ---------------------------------------------------------------------- */
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)
{
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);
*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;
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
/* ---------------------------------------------------------------------- */
#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;
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;
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
# 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
/* ---------------------------------------------------------------------- */
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)
{
#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)
{
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;
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;
}
return 0;
EVP_CIPHER_free(ctx->cipher);
+ ctx->cipher = NULL;
ctx->cipher_intent = ciphername != NULL;
if (ciphername != NULL
&& ((ctx->cipher =
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)
{
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 {
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);