From f552d900459cbacd82433b688b237cd6870663cd Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Sun, 16 Feb 2020 19:54:08 +1000 Subject: [PATCH] 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 (Merged from https://github.com/openssl/openssl/pull/11107) --- crypto/evp/pmeth_gn.c | 4 +- crypto/evp/pmeth_lib.c | 2 +- doc/man7/provider-keymgmt.pod | 26 ++ providers/defltprov.c | 32 ++- .../include/prov/implementations.h | 12 +- providers/implementations/keymgmt/ec_kmgmt.c | 2 +- providers/implementations/keymgmt/ecx_kmgmt.c | 22 +- .../implementations/serializers/build.info | 2 + .../serializers/serializer_common.c | 28 +- .../serializers/serializer_dh.c | 2 +- .../serializers/serializer_dsa.c | 4 +- .../serializers/serializer_ec.c | 150 ++++++++++ .../serializers/serializer_ec_param.c | 153 ++++++++++ .../serializers/serializer_ec_priv.c | 261 ++++++++++++++++++ .../serializers/serializer_ec_pub.c | 159 +++++++++++ .../serializers/serializer_local.h | 33 ++- .../serializers/serializer_rsa_priv.c | 5 +- test/build.info | 2 +- test/evp_pkey_provided_test.c | 90 +++++- test/recipes/30-test_evp_pkey_provided.t | 3 +- .../30-test_evp_pkey_provided/EC.priv.der | Bin 0 -> 138 bytes .../30-test_evp_pkey_provided/EC.priv.pem | 5 + .../30-test_evp_pkey_provided/EC.priv.txt | 13 + .../30-test_evp_pkey_provided/EC.pub.der | Bin 0 -> 91 bytes .../30-test_evp_pkey_provided/EC.pub.pem | 4 + .../30-test_evp_pkey_provided/EC.pub.txt | 9 + 26 files changed, 955 insertions(+), 68 deletions(-) create mode 100644 providers/implementations/serializers/serializer_ec.c create mode 100644 providers/implementations/serializers/serializer_ec_param.c create mode 100644 providers/implementations/serializers/serializer_ec_priv.c create mode 100644 providers/implementations/serializers/serializer_ec_pub.c create mode 100644 test/recipes/30-test_evp_pkey_provided/EC.priv.der create mode 100644 test/recipes/30-test_evp_pkey_provided/EC.priv.pem create mode 100644 test/recipes/30-test_evp_pkey_provided/EC.priv.txt create mode 100644 test/recipes/30-test_evp_pkey_provided/EC.pub.der create mode 100644 test/recipes/30-test_evp_pkey_provided/EC.pub.pem create mode 100644 test/recipes/30-test_evp_pkey_provided/EC.pub.txt diff --git a/crypto/evp/pmeth_gn.c b/crypto/evp/pmeth_gn.c index 4bea1a1b86..84149fabd7 100644 --- a/crypto/evp/pmeth_gn.c +++ b/crypto/evp/pmeth_gn.c @@ -230,7 +230,7 @@ int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM params[]) if (ctx->operation == EVP_PKEY_OP_PARAMFROMDATA) selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS; else - selection = OSSL_KEYMGMT_SELECT_KEYPAIR; + selection = OSSL_KEYMGMT_SELECT_ALL; keydata = evp_keymgmt_util_fromdata(*ppkey, ctx->keymgmt, selection, params); @@ -261,6 +261,6 @@ const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx) /* We call fromdata_init to get ctx->keymgmt populated */ if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED)) return evp_keymgmt_import_types(ctx->keymgmt, - OSSL_KEYMGMT_SELECT_KEYPAIR); + OSSL_KEYMGMT_SELECT_ALL); return NULL; } diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index c42897c87d..906b08156f 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -938,7 +938,7 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name, else if (strcmp(name, "ecdh_cofactor_mode") == 0) name = OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE; else if (strcmp(name, "ecdh_kdf_md") == 0) - name = OSSL_EXCHANGE_PARAM_KDF_TYPE; + name = OSSL_EXCHANGE_PARAM_KDF_DIGEST; # endif { diff --git a/doc/man7/provider-keymgmt.pod b/doc/man7/provider-keymgmt.pod index 91b87cecdc..0f765f775a 100644 --- a/doc/man7/provider-keymgmt.pod +++ b/doc/man7/provider-keymgmt.pod @@ -354,6 +354,32 @@ The private key value. =back +=head2 Built-in EC Import/Export Types + +The following Import/Export types are available for the built-in EC algorithm: + +=over 4 + +=item "curve-name" (B) + +The EC curve name. + +=item "use-cofactor-flag" (B) + +Enable Cofactor DH (ECC CDH) if this value is 1, otherwise it uses normal EC DH +if the value is zero. The cofactor variant multiplies the shared secret by the +EC curve's cofactor (note for some curves the cofactor is 1). + +=item "pub" (B) + +The public key value in EC point format. + +=item "priv" (B) + +The private key value. + +=back + =head2 Information Parameters See L for further details on the parameters structure. 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 +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#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)) + ok = 1; + ec_free(eckey); + } + return ok; +} + +static int ec_priv_der(void *vctx, void *eckey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ec_priv_ctx_st *ctx = vctx; + + ctx->sc.cb = cb; + ctx->sc.cbarg = cbarg; + + return ossl_prov_write_priv_der_from_obj(out, eckey, EVP_PKEY_EC, + ossl_prov_prepare_ec_params, + ossl_prov_ec_priv_to_der, + &ctx->sc); +} + +/* Private key : PEM */ +static int ec_pem_priv_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_pem_priv(ctx, eckey, out, cb, cbarg)) + ok = 1; + ec_free(eckey); + } + return ok; +} + +static int ec_pem_priv(void *vctx, void *eckey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ec_priv_ctx_st *ctx = vctx; + + ctx->sc.cb = cb; + ctx->sc.cbarg = cbarg; + + return ossl_prov_write_priv_pem_from_obj(out, eckey, EVP_PKEY_EC, + ossl_prov_prepare_ec_params, + ossl_prov_ec_priv_to_der, + &ctx->sc); +} + +/* + * There's no specific print context, so we use the provider context + */ +static void *ec_print_newctx(void *provctx) +{ + return provctx; +} + +static void ec_print_freectx(void *ctx) +{ +} + +static int ec_priv_print_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_print(ctx, eckey, out, cb, cbarg)) + ok = 1; + ec_free(eckey); + } + return ok; +} + +static int ec_priv_print(void *vctx, void *eckey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return ossl_prov_print_eckey(out, eckey, ec_print_priv); +} + +const OSSL_DISPATCH ec_priv_der_serializer_functions[] = { + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_priv_newctx }, + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_priv_freectx }, + { OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS, + (void (*)(void))ec_priv_set_ctx_params }, + { OSSL_FUNC_SERIALIZER_SETTABLE_CTX_PARAMS, + (void (*)(void))ec_priv_settable_ctx_params }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))ec_priv_der_data }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_priv_der }, + { 0, NULL } +}; + +const OSSL_DISPATCH ec_priv_pem_serializer_functions[] = { + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_priv_newctx }, + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_priv_freectx }, + { OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS, + (void (*)(void))ec_priv_set_ctx_params }, + { OSSL_FUNC_SERIALIZER_SETTABLE_CTX_PARAMS, + (void (*)(void))ec_priv_settable_ctx_params }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))ec_pem_priv_data }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_pem_priv }, + { 0, NULL } +}; + +const OSSL_DISPATCH ec_priv_text_serializer_functions[] = { + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_print_newctx }, + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_print_freectx }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_priv_print }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, + (void (*)(void))ec_priv_print_data }, + { 0, NULL } +}; diff --git a/providers/implementations/serializers/serializer_ec_pub.c b/providers/implementations/serializers/serializer_ec_pub.c new file mode 100644 index 0000000000..e9d90f1d20 --- /dev/null +++ b/providers/implementations/serializers/serializer_ec_pub.c @@ -0,0 +1,159 @@ +/* + * 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 +#include +#include +#include +#include +#include "prov/bio.h" +#include "prov/implementations.h" +#include "serializer_local.h" + +static OSSL_OP_serializer_newctx_fn ec_pub_newctx; +static OSSL_OP_serializer_freectx_fn ec_pub_freectx; +static OSSL_OP_serializer_serialize_data_fn ec_pub_der_data; +static OSSL_OP_serializer_serialize_object_fn ec_pub_der; +static OSSL_OP_serializer_serialize_data_fn ec_pub_pem_data; +static OSSL_OP_serializer_serialize_object_fn ec_pub_pem; + +static OSSL_OP_serializer_serialize_data_fn ec_pub_print_data; +static OSSL_OP_serializer_serialize_object_fn ec_pub_print; + +/* Public key : context */ + +/* + * There's no specific implementation context, so we use the provider context + */ +static void *ec_pub_newctx(void *provctx) +{ + return provctx; +} + +static void ec_pub_freectx(void *ctx) +{ +} + +/* Public key : DER */ +static int ec_pub_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_KEYPAIR, params) + && ec_pub_der(vctx, eckey, out, cb, cbarg)) + ok = 1; + ec_free(eckey); + } + return ok; +} + +static int ec_pub_der(void *ctx, void *eckey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return ossl_prov_write_pub_der_from_obj(out, eckey, EVP_PKEY_EC, + ossl_prov_prepare_ec_params, + ossl_prov_ec_pub_to_der); +} + +/* Public key : PEM */ +static int ec_pub_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; + + /* ctx == provctx */ + if ((eckey = ec_new(vctx)) != NULL + && ec_import(eckey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ec_pub_pem(vctx, eckey, out, cb, cbarg)) + ok = 1; + ec_free(eckey); + } + return ok; +} + +static int ec_pub_pem(void *vctx, void *eckey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return ossl_prov_write_pub_pem_from_obj(out, eckey, EVP_PKEY_EC, + ossl_prov_prepare_ec_params, + ossl_prov_ec_pub_to_der); +} + +static int ec_pub_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; + + /* ctx == provctx */ + if ((eckey = ec_new(vctx)) != NULL + && ec_import(eckey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ec_pub_print(vctx, eckey, out, cb, cbarg)) + ok = 1; + ec_free(eckey); + } + return ok; +} + +static int ec_pub_print(void *vctx, void *eckey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return ossl_prov_print_eckey(out, eckey, ec_print_pub); +} + +const OSSL_DISPATCH ec_pub_der_serializer_functions[] = { + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_pub_newctx }, + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_pub_freectx }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))ec_pub_der_data }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_pub_der }, + { 0, NULL } +}; + +const OSSL_DISPATCH ec_pub_pem_serializer_functions[] = { + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_pub_newctx }, + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_pub_freectx }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))ec_pub_pem_data }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_pub_pem }, + { 0, NULL } +}; + +const OSSL_DISPATCH ec_pub_text_serializer_functions[] = { + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))ec_pub_newctx }, + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ec_pub_freectx }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))ec_pub_print }, + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, + (void (*)(void))ec_pub_print_data }, + { 0, NULL } +}; diff --git a/providers/implementations/serializers/serializer_local.h b/providers/implementations/serializers/serializer_local.h index ec27f1443b..3125dc8f74 100644 --- a/providers/implementations/serializers/serializer_local.h +++ b/providers/implementations/serializers/serializer_local.h @@ -50,8 +50,17 @@ OSSL_OP_keymgmt_new_fn *ossl_prov_get_keymgmt_dsa_new(void); OSSL_OP_keymgmt_free_fn *ossl_prov_get_keymgmt_dsa_free(void); OSSL_OP_keymgmt_import_fn *ossl_prov_get_keymgmt_dsa_import(void); +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); + +int ossl_prov_prepare_ec_params(const void *eckey, int nid, + void **pstr, int *pstrtype); +int ossl_prov_ec_pub_to_der(const void *eckey, unsigned char **pder); +int ossl_prov_ec_priv_to_der(const void *eckey, unsigned char **pder); + int ossl_prov_prepare_dh_params(const void *dh, int nid, - ASN1_STRING **pstr, int *pstrtype); + void **pstr, int *pstrtype); int ossl_prov_dh_pub_to_der(const void *dh, unsigned char **pder); int ossl_prov_dh_priv_to_der(const void *dh, unsigned char **pder); @@ -63,14 +72,14 @@ int ossl_prov_ecx_pub_to_der(const void *ecxkey, unsigned char **pder); int ossl_prov_ecx_priv_to_der(const void *ecxkey, unsigned char **pder); int ossl_prov_prepare_dsa_params(const void *dsa, int nid, - ASN1_STRING **pstr, int *pstrtype); + void **pstr, int *pstrtype); /* * Special variant of ossl_prov_prepare_dsa_params() that requires all * three parameters (P, Q and G) to be set. This is used when serializing * the public key. */ int ossl_prov_prepare_all_dsa_params(const void *dsa, int nid, - ASN1_STRING **pstr, int *pstrtype); + void **pstr, int *pstrtype); int ossl_prov_dsa_pub_to_der(const void *dsa, unsigned char **pder); int ossl_prov_dsa_priv_to_der(const void *dsa, unsigned char **pder); @@ -88,6 +97,16 @@ enum dh_print_type { int ossl_prov_print_dh(BIO *out, DH *dh, enum dh_print_type type); +#ifndef OPENSSL_NO_EC +enum ec_print_type { + ec_print_priv, + ec_print_pub, + ec_print_params +}; + +int ossl_prov_print_eckey(BIO *out, EC_KEY *eckey, enum ec_print_type type); +#endif /* OPENSSL_NO_EC */ + enum dsa_print_type { dsa_print_priv, dsa_print_pub, @@ -107,27 +126,27 @@ int ossl_prov_print_ecx(BIO *out, ECX_KEY *ecxkey, enum ecx_print_type type); 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 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 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 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)); diff --git a/providers/implementations/serializers/serializer_rsa_priv.c b/providers/implementations/serializers/serializer_rsa_priv.c index 8ac9f30ad5..23042041de 100644 --- a/providers/implementations/serializers/serializer_rsa_priv.c +++ b/providers/implementations/serializers/serializer_rsa_priv.c @@ -52,7 +52,7 @@ struct rsa_priv_ctx_st { /* Helper functions to prepare RSA-PSS params for serialization */ static int prepare_rsa_params(const void *rsa, int nid, - ASN1_STRING **pstr, int *pstrtype) + void **pstr, int *pstrtype) { const RSA_PSS_PARAMS *pss = RSA_get0_pss_params(rsa); *pstr = NULL; @@ -68,7 +68,8 @@ static int prepare_rsa_params(const void *rsa, int nid, return 1; } /* Encode PSS parameters */ - if (ASN1_item_pack((void *)pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), pstr) + if (ASN1_item_pack((void *)pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), + (ASN1_STRING **)pstr) == NULL) return 0; diff --git a/test/build.info b/test/build.info index 5965616d80..ea350e5d6a 100644 --- a/test/build.info +++ b/test/build.info @@ -144,7 +144,7 @@ IF[{- !$disabled{tests} -}] SOURCE[evp_pkey_provided_test]=evp_pkey_provided_test.c INCLUDE[evp_pkey_provided_test]=../include ../apps/include - DEPEND[evp_pkey_provided_test]=../libcrypto libtestutil.a + DEPEND[evp_pkey_provided_test]=../libcrypto.a libtestutil.a IF[{- !$disabled{'deprecated-3.0'} -}] PROGRAMS{noinst}=igetest bftest casttest diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c index c161698505..6f7f3986e9 100644 --- a/test/evp_pkey_provided_test.c +++ b/test/evp_pkey_provided_test.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 @@ -15,6 +15,7 @@ #include #include "crypto/ecx.h" #include "internal/nelem.h" +#include "internal/param_build.h" #include "crypto/evp.h" /* For the internal API */ #include "testutil.h" @@ -155,7 +156,7 @@ static int test_print_key_type_using_serializer(const char *alg, int type, const char *pq; OSSL_SERIALIZER_CTX *ctx = NULL; BIO *membio = BIO_new(BIO_s_mem()); - int ret = 1; + int ret = 0; switch (type) { case PRIV_TEXT: @@ -187,10 +188,8 @@ static int test_print_key_type_using_serializer(const char *alg, int type, goto err; } - if (!TEST_ptr(membio)) { - ret = 0; + if (!TEST_ptr(membio)) goto err; - } /* Make a context, it's valid for several prints */ TEST_note("Setting up a OSSL_SERIALIZER context with passphrase"); @@ -203,7 +202,7 @@ static int test_print_key_type_using_serializer(const char *alg, int type, TEST_note("Testing with no encryption"); if (!TEST_true(OSSL_SERIALIZER_to_bio(ctx, membio)) || !TEST_true(compare_with_file(alg, type, membio))) - ret = 0; + goto err; if (type == PRIV_PEM) { /* Set a passphrase to be used later */ @@ -216,22 +215,22 @@ static int test_print_key_type_using_serializer(const char *alg, int type, TEST_note("Displaying PEM encrypted with AES-256-CBC"); if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, "AES-256-CBC", NULL)) || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, bio_out))) - ret = 0; + goto err; /* Use an invalid cipher name, which should generate no output */ TEST_note("NOT Displaying PEM encrypted with (invalid) FOO"); if (!TEST_false(OSSL_SERIALIZER_CTX_set_cipher(ctx, "FOO", NULL)) || !TEST_false(OSSL_SERIALIZER_to_bio(ctx, bio_out))) - ret = 0; + goto err; /* Clear the cipher. This should give us an unencrypted PEM again */ TEST_note("Testing with encryption cleared (no encryption)"); if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, NULL, NULL)) || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, membio)) || !TEST_true(compare_with_file(alg, type, membio))) - ret = 0; + goto err; } - + ret = 1; err: BIO_free(membio); OSSL_SERIALIZER_CTX_free(ctx); @@ -479,13 +478,79 @@ static int test_fromdata_ecx(int tst) ret = test_print_key_using_pem(alg, pk) && test_print_key_using_serializer(alg, pk); - err: +err: EVP_PKEY_free(pk); EVP_PKEY_CTX_free(ctx); return ret; } -#endif + +static int test_fromdata_ec(void) +{ + int ret = 0; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pk = NULL; + OSSL_PARAM_BLD bld; + BIGNUM *ec_priv_bn = NULL; + OSSL_PARAM *fromdata_params = NULL; + const char *alg = "EC"; + static const unsigned char ec_pub_keydata[] = { + 0x04, + 0x1b, 0x93, 0x67, 0x55, 0x1c, 0x55, 0x9f, 0x63, + 0xd1, 0x22, 0xa4, 0xd8, 0xd1, 0x0a, 0x60, 0x6d, + 0x02, 0xa5, 0x77, 0x57, 0xc8, 0xa3, 0x47, 0x73, + 0x3a, 0x6a, 0x08, 0x28, 0x39, 0xbd, 0xc9, 0xd2, + 0x80, 0xec, 0xe9, 0xa7, 0x08, 0x29, 0x71, 0x2f, + 0xc9, 0x56, 0x82, 0xee, 0x9a, 0x85, 0x0f, 0x6d, + 0x7f, 0x59, 0x5f, 0x8c, 0xd1, 0x96, 0x0b, 0xdf, + 0x29, 0x3e, 0x49, 0x07, 0x88, 0x3f, 0x9a, 0x29 + }; + static const unsigned char ec_priv_keydata[] = { + 0x33, 0xd0, 0x43, 0x83, 0xa9, 0x89, 0x56, 0x03, + 0xd2, 0xd7, 0xfe, 0x6b, 0x01, 0x6f, 0xe4, 0x59, + 0xcc, 0x0d, 0x9a, 0x24, 0x6c, 0x86, 0x1b, 0x2e, + 0xdc, 0x4b, 0x4d, 0x35, 0x43, 0xe1, 0x1b, 0xad + }; + + ossl_param_bld_init(&bld); + + if (!TEST_ptr(ec_priv_bn = BN_bin2bn(ec_priv_keydata, + sizeof(ec_priv_keydata), NULL))) + goto err; + + if (ossl_param_bld_push_utf8_string(&bld, OSSL_PKEY_PARAM_EC_NAME, + "prime256v1", 0) <= 0) + goto err; + if (ossl_param_bld_push_octet_string(&bld, OSSL_PKEY_PARAM_PUB_KEY, + ec_pub_keydata, + sizeof(ec_pub_keydata)) <= 0) + goto err; + if (ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_PRIV_KEY, ec_priv_bn) <= 0) + goto err; + if (!TEST_ptr(fromdata_params = ossl_param_bld_to_param(&bld))) + goto err; + ctx = EVP_PKEY_CTX_new_from_name(NULL, alg, NULL); + if (!TEST_ptr(ctx)) + goto err; + + if (!TEST_true(EVP_PKEY_key_fromdata_init(ctx)) + || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params)) + || !TEST_int_eq(EVP_PKEY_bits(pk), 256) + || !TEST_int_eq(EVP_PKEY_security_bits(pk), 128) + || !TEST_int_eq(EVP_PKEY_size(pk), 2 + 35 * 2)) + goto err; + + ret = test_print_key_using_pem(alg, pk) + && test_print_key_using_serializer(alg, pk); +err: + BN_free(ec_priv_bn); + ossl_param_bld_free(fromdata_params); + EVP_PKEY_free(pk); + EVP_PKEY_CTX_free(ctx); + return ret; +} + +#endif /* OPENSSL_NO_EC */ int setup_tests(void) @@ -504,6 +569,7 @@ int setup_tests(void) #endif #ifndef OPENSSL_NO_EC ADD_ALL_TESTS(test_fromdata_ecx, 2); + ADD_TEST(test_fromdata_ec); #endif return 1; } diff --git a/test/recipes/30-test_evp_pkey_provided.t b/test/recipes/30-test_evp_pkey_provided.t index 74b366451d..d9efbeaa66 100644 --- a/test/recipes/30-test_evp_pkey_provided.t +++ b/test/recipes/30-test_evp_pkey_provided.t @@ -1,6 +1,5 @@ #! /usr/bin/env perl -# Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. -# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. +# 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 diff --git a/test/recipes/30-test_evp_pkey_provided/EC.priv.der b/test/recipes/30-test_evp_pkey_provided/EC.priv.der new file mode 100644 index 0000000000000000000000000000000000000000..2f74cfc1ae3a6b0db74feff4e3917a5237866068 GIT binary patch literal 138 zcmXqLY-eI*Fc4;A*J|@PXUoLM#sOw9GqSVf8e}suGO{QbUvO?-*%`)s>H5EH#{4Id zXLx6+