summaryrefslogtreecommitdiffstats
path: root/providers
diff options
context:
space:
mode:
authorShane Lontis <shane.lontis@oracle.com>2020-02-16 19:54:08 +1000
committerShane Lontis <shane.lontis@oracle.com>2020-03-04 07:48:45 +1000
commitf552d900459cbacd82433b688b237cd6870663cd (patch)
tree8fca1cf5a0274525e750cf74e890a3ac7f7eb671 /providers
parent4a98ad086a6db9a8646244bd6e6517f9fff11762 (diff)
Add Serializers for EC
Provide EC serializers for text, pem and der. EC parameters use ANS1 'CHOICE' - which means they are more embedded than other parameters used by other KEY types (which normally have a SEQUENCE at the top level). For this reason the ANS1_STRING type that was being passed around has been changed to a void so that the code can still be shared with EC. The EC serializer only supports named curves currently. NOTE the serializer code assumes PKCS8 format - if the older encode methods are needed they will need to be added in another PR. (Probably when deserialization is considered). EVP_PKEY_key_fromdata_init was changed from using a keypair selection to all bits of a key. A side effect of this was that the very restrictive checks in the ecx code needed to be relaxed as it was assuming all selection flags were non optional. As this is not the case for any other key the code has been modified. Fixed a bug in legacy_ctrl_str_to_params() - "ecdh_cofactor_mode" was being incorrectly converted to the wrong keyname. Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/11107)
Diffstat (limited to 'providers')
-rw-r--r--providers/defltprov.c32
-rw-r--r--providers/implementations/include/prov/implementations.h12
-rw-r--r--providers/implementations/keymgmt/ec_kmgmt.c2
-rw-r--r--providers/implementations/keymgmt/ecx_kmgmt.c22
-rw-r--r--providers/implementations/serializers/build.info2
-rw-r--r--providers/implementations/serializers/serializer_common.c28
-rw-r--r--providers/implementations/serializers/serializer_dh.c2
-rw-r--r--providers/implementations/serializers/serializer_dsa.c4
-rw-r--r--providers/implementations/serializers/serializer_ec.c150
-rw-r--r--providers/implementations/serializers/serializer_ec_param.c153
-rw-r--r--providers/implementations/serializers/serializer_ec_priv.c261
-rw-r--r--providers/implementations/serializers/serializer_ec_pub.c159
-rw-r--r--providers/implementations/serializers/serializer_local.h33
-rw-r--r--providers/implementations/serializers/serializer_rsa_priv.c5
14 files changed, 815 insertions, 50 deletions
diff --git a/providers/defltprov.c b/providers/defltprov.c
index 9400eee0c9..0f66aa2b71 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -471,17 +471,17 @@ static const OSSL_ALGORITHM deflt_serializer[] = {
#endif
#ifndef OPENSSL_NO_EC
- { "X25519", "provider=default,format=text,type=private",
+ { "X25519", "provider=default,fips=yes,format=text,type=private",
x25519_priv_print_serializer_functions },
- { "X25519", "provider=default,format=text,type=public",
+ { "X25519", "provider=default,fips=yes,format=text,type=public",
x25519_pub_print_serializer_functions },
- { "X25519", "provider=default,format=der,type=private",
+ { "X25519", "provider=default,fips=yes,format=der,type=private",
x25519_priv_der_serializer_functions },
- { "X25519", "provider=default,format=der,type=public",
+ { "X25519", "provider=default,fips=yes,format=der,type=public",
x25519_pub_der_serializer_functions },
- { "X25519", "provider=default,format=pem,type=private",
+ { "X25519", "provider=default,fips=yes,format=pem,type=private",
x25519_priv_pem_serializer_functions },
- { "X25519", "provider=default,format=pem,type=public",
+ { "X25519", "provider=default,fips=yes,format=pem,type=public",
x25519_pub_pem_serializer_functions },
{ "X448", "provider=default,format=text,type=private",
@@ -496,8 +496,26 @@ static const OSSL_ALGORITHM deflt_serializer[] = {
x448_priv_pem_serializer_functions },
{ "X448", "provider=default,format=pem,type=public",
x448_pub_pem_serializer_functions },
-#endif
+ { "EC", "provider=default,fips=yes,format=text,type=private",
+ ec_priv_text_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=text,type=public",
+ ec_pub_text_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=text,type=parameters",
+ ec_param_text_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=der,type=private",
+ ec_priv_der_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=der,type=public",
+ ec_pub_der_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=der,type=parameters",
+ ec_param_der_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=pem,type=private",
+ ec_priv_pem_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=pem,type=public",
+ ec_pub_pem_serializer_functions },
+ { "EC", "provider=default,fips=yes,format=pem,type=parameters",
+ ec_param_pem_serializer_functions },
+#endif
{ NULL, NULL, NULL }
};
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index a98d1139d3..ea33bedfd8 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -315,3 +315,13 @@ extern const OSSL_DISPATCH x448_priv_der_serializer_functions[];
extern const OSSL_DISPATCH x448_pub_der_serializer_functions[];
extern const OSSL_DISPATCH x448_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH x448_pub_pem_serializer_functions[];
+
+extern const OSSL_DISPATCH ec_priv_text_serializer_functions[];
+extern const OSSL_DISPATCH ec_pub_text_serializer_functions[];
+extern const OSSL_DISPATCH ec_param_text_serializer_functions[];
+extern const OSSL_DISPATCH ec_priv_der_serializer_functions[];
+extern const OSSL_DISPATCH ec_pub_der_serializer_functions[];
+extern const OSSL_DISPATCH ec_param_der_serializer_functions[];
+extern const OSSL_DISPATCH ec_priv_pem_serializer_functions[];
+extern const OSSL_DISPATCH ec_pub_pem_serializer_functions[];
+extern const OSSL_DISPATCH ec_param_pem_serializer_functions[];
diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c
index 6a358aa93b..107ab1b594 100644
--- a/providers/implementations/keymgmt/ec_kmgmt.c
+++ b/providers/implementations/keymgmt/ec_kmgmt.c
@@ -473,7 +473,7 @@ static
int ec_import(void *keydata, int selection, const OSSL_PARAM params[])
{
EC_KEY *ec = keydata;
- int ok = 0;
+ int ok = 1;
if (ec == NULL)
return 0;
diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c
index fe0193d944..d3aa9ba1f9 100644
--- a/providers/implementations/keymgmt/ecx_kmgmt.c
+++ b/providers/implementations/keymgmt/ecx_kmgmt.c
@@ -27,6 +27,8 @@ static OSSL_OP_keymgmt_import_types_fn ecx_imexport_types;
static OSSL_OP_keymgmt_export_fn ecx_export;
static OSSL_OP_keymgmt_export_types_fn ecx_imexport_types;
+#define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
+
static void *x25519_new_key(void *provctx)
{
return ecx_key_new(X25519_KEYLEN, 0);
@@ -40,12 +42,9 @@ static void *x448_new_key(void *provctx)
static int ecx_has(void *keydata, int selection)
{
ECX_KEY *key = keydata;
- const int ecx_selections = OSSL_KEYMGMT_SELECT_PUBLIC_KEY
- | OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
int ok = 1;
- if ((selection & ~ecx_selections) != 0
- || (selection & ecx_selections) == 0)
+ if ((selection & ECX_POSSIBLE_SELECTIONS) == 0)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
@@ -63,29 +62,24 @@ static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[])
size_t privkeylen = 0, pubkeylen;
const OSSL_PARAM *param_priv_key = NULL, *param_pub_key;
unsigned char *pubkey;
- const int ecx_selections = OSSL_KEYMGMT_SELECT_PUBLIC_KEY
- | OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
if (key == NULL)
return 0;
- if ((selection & ~ecx_selections) != 0
- || (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
return 0;
- if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
- param_priv_key =
- OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
param_pub_key =
OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+ if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+ param_priv_key =
+ OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
/*
* If a private key is present then a public key must also be present.
* Alternatively we've just got a public key.
*/
- if (param_pub_key == NULL
- || (param_priv_key == NULL
- && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0))
+ if (param_pub_key == NULL)
return 0;
if (param_priv_key != NULL
diff --git a/providers/implementations/serializers/build.info b/providers/implementations/serializers/build.info
index d5873d1052..66502c76aa 100644
--- a/providers/implementations/serializers/build.info
+++ b/providers/implementations/serializers/build.info
@@ -6,6 +6,7 @@ $RSA_GOAL=../../libimplementations.a
$DH_GOAL=../../libimplementations.a
$DSA_GOAL=../../libimplementations.a
$ECX_GOAL=../../libimplementations.a
+$EC_GOAL=../../libimplementations.a
SOURCE[$SERIALIZER_GOAL]=serializer_common.c
SOURCE[$RSA_GOAL]=serializer_rsa.c serializer_rsa_priv.c serializer_rsa_pub.c
@@ -17,4 +18,5 @@ IF[{- !$disabled{dsa} -}]
ENDIF
IF[{- !$disabled{ec} -}]
SOURCE[$ECX_GOAL]=serializer_ecx.c serializer_ecx_priv.c serializer_ecx_pub.c
+ SOURCE[$EC_GOAL]=serializer_ec.c serializer_ec_priv.c serializer_ec_pub.c serializer_ec_param.c
ENDIF
diff --git a/providers/implementations/serializers/serializer_common.c b/providers/implementations/serializers/serializer_common.c
index b1ad523b71..0b99f4939b 100644
--- a/providers/implementations/serializers/serializer_common.c
+++ b/providers/implementations/serializers/serializer_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -21,7 +21,7 @@
static PKCS8_PRIV_KEY_INFO *
ossl_prov_p8info_from_obj(const void *obj, int obj_nid,
- ASN1_STRING *params,
+ void *params,
int params_type,
int (*k2d)(const void *obj,
unsigned char **pder))
@@ -72,7 +72,7 @@ static X509_SIG *ossl_prov_encp8_from_p8info(PKCS8_PRIV_KEY_INFO *p8info,
}
static X509_SIG *ossl_prov_encp8_from_obj(const void *obj, int obj_nid,
- ASN1_STRING *params,
+ void *params,
int params_type,
int (*k2d)(const void *obj,
unsigned char **pder),
@@ -87,7 +87,7 @@ static X509_SIG *ossl_prov_encp8_from_obj(const void *obj, int obj_nid,
}
static X509_PUBKEY *ossl_prov_pubkey_from_obj(const void *obj, int obj_nid,
- ASN1_STRING *params,
+ void *params,
int params_type,
int (*k2d)(const void *obj,
unsigned char **pder))
@@ -272,18 +272,17 @@ int ossl_prov_print_labeled_buf(BIO *out, const char *label,
return 1;
}
-
-/* p2s = param to asn1_string, k2d = key to der */
+/* p2s = param to asn1, k2d = key to der */
int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid,
int (*p2s)(const void *obj, int nid,
- ASN1_STRING **str,
+ void **str,
int *strtype),
int (*k2d)(const void *obj,
unsigned char **pder),
struct pkcs8_encrypt_ctx_st *ctx)
{
int ret = 0;
- ASN1_STRING *str = NULL;
+ void *str = NULL;
int strtype = V_ASN1_UNDEF;
if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype))
@@ -312,14 +311,14 @@ int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid,
int ossl_prov_write_priv_pem_from_obj(BIO *out, const void *obj, int obj_nid,
int (*p2s)(const void *obj, int nid,
- ASN1_STRING **str,
+ void **str,
int *strtype),
int (*k2d)(const void *obj,
unsigned char **pder),
struct pkcs8_encrypt_ctx_st *ctx)
{
int ret = 0;
- ASN1_STRING *str = NULL;
+ void *str = NULL;
int strtype = V_ASN1_UNDEF;
if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype))
@@ -348,13 +347,13 @@ int ossl_prov_write_priv_pem_from_obj(BIO *out, const void *obj, int obj_nid,
int ossl_prov_write_pub_der_from_obj(BIO *out, const void *obj, int obj_nid,
int (*p2s)(const void *obj, int nid,
- ASN1_STRING **str,
+ void **str,
int *strtype),
int (*k2d)(const void *obj,
unsigned char **pder))
{
int ret = 0;
- ASN1_STRING *str = NULL;
+ void *str = NULL;
int strtype = V_ASN1_UNDEF;
X509_PUBKEY *xpk = NULL;
@@ -373,13 +372,13 @@ int ossl_prov_write_pub_der_from_obj(BIO *out, const void *obj, int obj_nid,
int ossl_prov_write_pub_pem_from_obj(BIO *out, const void *obj, int obj_nid,
int (*p2s)(const void *obj, int nid,
- ASN1_STRING **str,
+ void **str,
int *strtype),
int (*k2d)(const void *obj,
unsigned char **pder))
{
int ret = 0;
- ASN1_STRING *str = NULL;
+ void *str = NULL;
int strtype = V_ASN1_UNDEF;
X509_PUBKEY *xpk = NULL;
@@ -395,4 +394,3 @@ int ossl_prov_write_pub_pem_from_obj(BIO *out, const void *obj, int obj_nid,
X509_PUBKEY_free(xpk);
return ret;
}
-
diff --git a/providers/implementations/serializers/serializer_dh.c b/providers/implementations/serializers/serializer_dh.c
index 31ba175dd7..b2517ed947 100644
--- a/providers/implementations/serializers/serializer_dh.c
+++ b/providers/implementations/serializers/serializer_dh.c
@@ -107,7 +107,7 @@ int ossl_prov_print_dh(BIO *out, DH *dh, enum dh_print_type type)
}
int ossl_prov_prepare_dh_params(const void *dh, int nid,
- ASN1_STRING **pstr, int *pstrtype)
+ void **pstr, int *pstrtype)
{
ASN1_STRING *params = ASN1_STRING_new();
diff --git a/providers/implementations/serializers/serializer_dsa.c b/providers/implementations/serializers/serializer_dsa.c
index 16ecb0d952..c26be47e66 100644
--- a/providers/implementations/serializers/serializer_dsa.c
+++ b/providers/implementations/serializers/serializer_dsa.c
@@ -98,7 +98,7 @@ int ossl_prov_print_dsa(BIO *out, DSA *dsa, enum dsa_print_type type)
}
int ossl_prov_prepare_dsa_params(const void *dsa, int nid,
- ASN1_STRING **pstr, int *pstrtype)
+ void **pstr, int *pstrtype)
{
ASN1_STRING *params = ASN1_STRING_new();
@@ -121,7 +121,7 @@ int ossl_prov_prepare_dsa_params(const void *dsa, int nid,
}
int ossl_prov_prepare_all_dsa_params(const void *dsa, int nid,
- ASN1_STRING **pstr, int *pstrtype)
+ void **pstr, int *pstrtype)
{
const BIGNUM *p = DSA_get0_p(dsa);
const BIGNUM *q = DSA_get0_q(dsa);
diff --git a/providers/implementations/serializers/serializer_ec.c b/providers/implementations/serializers/serializer_ec.c
new file mode 100644
index 0000000000..3d455f1507
--- /dev/null
+++ b/providers/implementations/serializers/serializer_ec.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include "crypto/ec.h"
+#include "prov/bio.h" /* ossl_prov_bio_printf() */
+#include "prov/implementations.h" /* ec_keymgmt_functions */
+#include "serializer_local.h"
+
+void ec_get_new_free_import(OSSL_OP_keymgmt_new_fn **ec_new,
+ OSSL_OP_keymgmt_free_fn **ec_free,
+ OSSL_OP_keymgmt_import_fn **ec_import)
+{
+ *ec_new = ossl_prov_get_keymgmt_new(ec_keymgmt_functions);
+ *ec_free = ossl_prov_get_keymgmt_free(ec_keymgmt_functions);
+ *ec_import = ossl_prov_get_keymgmt_import(ec_keymgmt_functions);
+}
+
+static int ossl_prov_print_ec_param(BIO *out, const EC_GROUP *group)
+{
+ const char *curve_name;
+ int curve_nid = EC_GROUP_get_curve_name(group);
+
+ /* TODO(3.0): Explicit parameters are currently not supported */
+ if (curve_nid == NID_undef)
+ return 0;
+
+ if (ossl_prov_bio_printf(out, "%s: %s\n", "ASN1 OID",
+ OBJ_nid2sn(curve_nid)) <= 0)
+ return 0;
+
+ /* TODO(3.0): Only named curves are currently supported */
+ curve_name = EC_curve_nid2nist(curve_nid);
+ return (curve_name == NULL
+ || ossl_prov_bio_printf(out, "%s: %s\n", "NIST CURVE",
+ curve_name) > 0);
+}
+
+int ossl_prov_print_eckey(BIO *out, EC_KEY *eckey, enum ec_print_type type)
+{
+ int ret = 0;
+ const char *type_label = NULL;
+ unsigned char *priv = NULL, *pub = NULL;
+ size_t priv_len = 0, pub_len = 0;
+ const EC_GROUP *group;
+
+ if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL)
+ goto null_err;
+
+ switch (type) {
+ case ec_print_priv:
+ type_label = "Private-Key";
+ break;
+ case ec_print_pub:
+ type_label = "Public-Key";
+ break;
+ case ec_print_params:
+ type_label = "EC-Parameters";
+ break;
+ }
+
+ if (type == ec_print_priv) {
+ const BIGNUM *priv_key = EC_KEY_get0_private_key(eckey);
+
+ if (priv_key == NULL)
+ goto null_err;
+ priv_len = EC_KEY_priv2buf(eckey, &priv);
+ if (priv_len == 0)
+ goto err;
+ }
+
+ if (type == ec_print_priv || type == ec_print_pub) {
+ const EC_POINT *pub_pt = EC_KEY_get0_public_key(eckey);
+
+ if (pub_pt == NULL)
+ goto null_err;
+
+ pub_len = EC_KEY_key2buf(eckey, EC_KEY_get_conv_form(eckey), &pub, NULL);
+ if (pub_len == 0)
+ goto err;
+ }
+
+ if (ossl_prov_bio_printf(out, "%s: (%d bit)\n", type_label,
+ EC_GROUP_order_bits(group)) <= 0)
+ goto err;
+ if (priv != NULL
+ && !ossl_prov_print_labeled_buf(out, "priv:", priv, priv_len))
+ goto err;
+ if (pub != NULL
+ && !ossl_prov_print_labeled_buf(out, "pub:", pub, pub_len))
+ goto err;
+ ret = ossl_prov_print_ec_param(out, group);
+err:
+ OPENSSL_clear_free(priv, priv_len);
+ OPENSSL_free(pub);
+ return ret;
+null_err:
+ ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
+ goto err;
+}
+
+int ossl_prov_prepare_ec_params(const void *eckey, int nid,
+ void **pstr, int *pstrtype)
+{
+ int curve_nid;
+ const EC_GROUP *group = EC_KEY_get0_group(eckey);
+ ASN1_OBJECT *params;
+
+ if (group == NULL
+ || ((curve_nid = EC_GROUP_get_curve_name(group)) == NID_undef)
+ || ((params = OBJ_nid2obj(curve_nid)) == NULL)) {
+ /* TODO(3.0): Explicit curves are not supported */
+ return 0;
+ }
+
+ *pstr = params;
+ *pstrtype = V_ASN1_OBJECT;
+ return 1;
+}
+
+int ossl_prov_ec_pub_to_der(const void *eckey, unsigned char **pder)
+{
+ return i2o_ECPublicKey(eckey, pder);
+}
+
+int ossl_prov_ec_priv_to_der(const void *veckey, unsigned char **pder)
+{
+ EC_KEY *eckey = (EC_KEY *)veckey;
+ unsigned int old_flags;
+ int ret = 0;
+
+ /*
+ * For PKCS8 the curve name appears in the PKCS8_PRIV_KEY_INFO object
+ * as the pkeyalg->parameter field. (For a named curve this is an OID)
+ * The pkey field is an octet string that holds the encoded
+ * ECPrivateKey SEQUENCE with the optional parameters field omitted.
+ * We omit this by setting the EC_PKEY_NO_PARAMETERS flag.
+ */
+ old_flags = EC_KEY_get_enc_flags(eckey); /* save old flags */
+ EC_KEY_set_enc_flags(eckey, old_flags | EC_PKEY_NO_PARAMETERS);
+ ret = i2d_ECPrivateKey(eckey, pder);
+ EC_KEY_set_enc_flags(eckey, old_flags); /* restore old flags */
+ return ret; /* return the length of the der encoded data */
+}
diff --git a/providers/implementations/serializers/serializer_ec_param.c b/providers/implementations/serializers/serializer_ec_param.c
new file mode 100644
index 0000000000..fdeedb5dff
--- /dev/null
+++ b/providers/implementations/serializers/serializer_ec_param.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_numbers.h>
+#include <openssl/pem.h>
+#include <openssl/ec.h>
+#include <openssl/types.h>
+#include <openssl/params.h>
+#include "prov/bio.h"
+#include "prov/implementations.h"
+#include "prov/providercommonerr.h"
+#include "serializer_local.h"
+
+static OSSL_OP_serializer_newctx_fn ec_param_newctx;
+static OSSL_OP_serializer_freectx_fn ec_param_freectx;
+static OSSL_OP_serializer_serialize_data_fn ec_param_der_data;
+static OSSL_OP_serializer_serialize_object_fn ec_param_der;
+static OSSL_OP_serializer_serialize_data_fn ec_param_pem_data;
+static OSSL_OP_serializer_serialize_object_fn ec_param_pem;
+
+static OSSL_OP_serializer_serialize_data_fn ec_param_print_data;
+static OSSL_OP_serializer_serialize_object_fn ec_param_print;
+
+
+/* There is no specific implementation context, so use the provider context */
+static void *ec_param_newctx(void *provctx)
+{
+ return provctx;
+}
+
+static void ec_param_freectx(void *vctx)
+{
+}
+
+/* Public key : DER */
+static int ec_param_der_data(void *vctx, const OSSL_PARAM params[], BIO *out,
+ OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
+{
+ OSSL_OP_keymgmt_new_fn *ec_new;
+ OSSL_OP_keymgmt_free_fn *ec_free;
+ OSSL_OP_keymgmt_import_fn *ec_import;
+ int ok = 0;
+
+ ec_get_new_free_import(&ec_new, &ec_free, &ec_import);
+
+ if (ec_import != NULL) {
+ EC_KEY *eckey;
+
+ /* vctx == provctx */
+ if ((eckey = ec_new(vctx)) != NULL
+ && ec_import(eckey, OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, params)
+ && ec_param_der(vctx, eckey, out, cb, cbarg))
+ ok = 1;
+ ec_free(eckey);
+ }
+ return ok;
+}
+
+static int ec_param_der(void *vctx, void *eckey, BIO *out,
+ OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
+{
+ return i2d_ECPKParameters_bio(out, EC_KEY_get0_group(eckey));
+}
+
+/* Public key : PEM */
+static int ec_param_pem_data(void *vctx, const OSSL_PARAM params[], BIO *out,
+ OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
+{
+ OSSL_OP_keymgmt_new_fn *ec_new;
+ OSSL_OP_keymgmt_free_fn *ec_free;
+ OSSL_OP_keymgmt_import_fn *ec_import;
+ int ok = 0;
+
+ ec_get_new_free_import(&ec_new, &ec_free, &ec_import);
+
+ if (ec_import != NULL) {
+ EC_KEY *eckey;
+
+ /* vctx == provctx */
+ if ((eckey = ec_new(vctx)) != NULL
+ && ec_import(eckey, OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, params)
+ && ec_param_pem(vctx, eckey, out, cb, cbarg))
+ ok = 1;
+ ec_free(eckey);
+ }
+ return ok;
+}
+
+static int ec_param_pem(void *vctx, void *eckey, BIO *out,
+ OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
+{
+ return PEM_write_bio_ECPKParameters(out, EC_KEY_get0_group(eckey));
+}
+
+static int ec_param_print_data(void *vctx, const OSSL_PARAM params[], BIO *out,
+ OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
+{
+ OSSL_OP_keymgmt_new_fn *ec_new;
+ OSSL_OP_keymgmt_free_fn *ec_free;
+ OSSL_OP_keymgmt_import_fn *ec_import;
+ int ok = 0;
+
+ ec_get_new_free_import(&ec_new, &ec_free, &ec_import);
+
+ if (ec_import != NULL) {
+ EC_KEY *eckey;
+
+ /* vctx == provctx */
+ if ((eckey = ec_new(vctx)) != NULL
+ && ec_import(eckey, OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, params)
+ && ec_param_print(vctx, eckey, out, cb, cbarg))
+ ok = 1;
+ ec_free(eckey);
+ }
+ return ok;
+}
+
+static int ec_param_print(void *vctx, void *eckey, BIO *out,
+ OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
+{
+ return ossl_prov_print_eckey(out, eckey, ec_print_params);
+}
+
+const OSSL_DISPATCH ec_param_der_serializer_functions[] = {
+ { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_param_newctx },
+ { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_param_freectx },
+ { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))ec_param_der_data },
+ { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_param_der },
+ { 0, NULL }
+};
+
+const OSSL_DISPATCH ec_param_pem_serializer_functions[] = {
+ { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_param_newctx },
+ { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_param_freectx },
+ { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))ec_param_pem_data },
+ { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_param_pem },
+ { 0, NULL }
+};
+
+const OSSL_DISPATCH ec_param_text_serializer_functions[] = {
+ { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_param_newctx },
+ { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_param_freectx },
+ { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_param_print },
+ { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA,
+ (void (*)(void))ec_param_print_data },
+ { 0, NULL }
+};
diff --git a/providers/implementations/serializers/serializer_ec_priv.c b/providers/implementations/serializers/serializer_ec_priv.c
new file mode 100644
index 0000000000..14ff2ae60e
--- /dev/null
+++ b/providers/implementations/serializers/serializer_ec_priv.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_numbers.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ec.h>
+#include <openssl/types.h>
+#include <openssl/params.h>
+#include "prov/bio.h"
+#include "prov/implementations.h"
+#include "serializer_local.h"
+
+static OSSL_OP_serializer_newctx_fn ec_priv_newctx;
+static OSSL_OP_serializer_freectx_fn ec_priv_freectx;
+static OSSL_OP_serializer_set_ctx_params_fn ec_priv_set_ctx_params;
+static OSSL_OP_serializer_settable_ctx_params_fn ec_priv_settable_ctx_params;
+static OSSL_OP_serializer_serialize_data_fn ec_priv_der_data;
+static OSSL_OP_serializer_serialize_object_fn ec_priv_der;
+static OSSL_OP_serializer_serialize_data_fn ec_pem_priv_data;
+static OSSL_OP_serializer_serialize_object_fn ec_pem_priv;
+
+static OSSL_OP_serializer_newctx_fn ec_print_newctx;
+static OSSL_OP_serializer_freectx_fn ec_print_freectx;
+static OSSL_OP_serializer_serialize_data_fn ec_priv_print_data;
+static OSSL_OP_serializer_serialize_object_fn ec_priv_print;
+
+ /*
+ * Context used for private key serialization.
+ */
+struct ec_priv_ctx_st {
+ void *provctx;
+
+ struct pkcs8_encrypt_ctx_st sc;
+};
+
+/* Private key : context */
+static void *ec_priv_newctx(void *provctx)
+{
+ struct ec_priv_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL) {
+ ctx->provctx = provctx;
+
+ /* -1 is the "whatever" indicator, i.e. the PKCS8 library default PBE */
+ ctx->sc.pbe_nid = -1;
+ }
+ return ctx;
+}
+
+static void ec_priv_freectx(void *vctx)
+{
+ struct ec_priv_ctx_st *ctx = vctx;
+
+ EVP_CIPHER_free(ctx->sc.cipher);
+ OPENSSL_free(ctx->sc.cipher_pass);
+ OPENSSL_free(ctx);
+}
+
+static const OSSL_PARAM *ec_priv_settable_ctx_params(void)
+{
+ static const OSSL_PARAM settables[] = {
+ OSSL_PARAM_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_SERIALIZER_PARAM_PASS, NULL, 0),
+ OSSL_PARAM_END,
+ };
+
+ return settables;
+}
+
+static int ec_priv_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ struct ec_priv_ctx_st *ctx = vctx;
+ const OSSL_PARAM *p;
+
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_CIPHER))
+ != NULL) {
+ const OSSL_PARAM *propsp =
+ OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PROPERTIES);
+ const char *props = NULL;
+
+ if (p->data_type != OSSL_PARAM_UTF8_STRING)
+ return 0;
+ if (propsp != NULL && propsp->data_type != OSSL_PARAM_UTF8_STRING)
+ return 0;
+ props = (propsp != NULL ? propsp->data : NULL);
+
+ EVP_CIPHER_free(ctx->sc.cipher);
+ ctx->sc.cipher_intent = p->data != NULL;
+ if (p->data != NULL
+ && ((ctx->sc.cipher = EVP_CIPHER_fetch(NULL, p->data, props))
+ == NULL))
+ return 0;
+ }
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PASS))
+ != NULL) {
+ OPENSSL_free(ctx->sc.cipher_pass);
+ ctx->sc.cipher_pass = NULL;
+ if (!OSSL_PARAM_get_octet_string(p, &ctx->sc.cipher_pass, 0,
+ &ctx->sc.cipher_pass_length))
+ return 0;
+ }
+ return 1;
+}
+
+/* Private key : DER */
+static int ec_priv_der_data(void *vctx, const OSSL_PARAM params[], BIO *out,
+ OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
+{
+ struct ec_priv_ctx_st *ctx = vctx;
+ OSSL_OP_keymgmt_new_fn *ec_new;
+ OSSL_OP_keymgmt_free_fn *ec_free;
+ OSSL_OP_keymgmt_import_fn *ec_import;
+ int ok = 0;
+
+ ec_get_new_free_import(&ec_new, &ec_free, &ec_import);
+
+ if (ec_import != NULL) {
+ EC_KEY *eckey;
+
+ if ((eckey = ec_new(ctx->provctx)) != NULL
+ && ec_import(eckey, OSSL_KEYMGMT_SELECT_KEYPAIR, params)
+ && ec_priv_der(ctx, eckey, out, cb, cbarg))