diff options
author | Shane Lontis <shane.lontis@oracle.com> | 2020-08-22 14:55:41 +1000 |
---|---|---|
committer | Shane Lontis <shane.lontis@oracle.com> | 2020-08-22 14:55:41 +1000 |
commit | c0f39ded68ba0929698a8773e63e9806ec9e5c74 (patch) | |
tree | dce39d009fceac112a1d320b5e072d94e22ca27d /crypto/ec | |
parent | a02c715c183382aa3038fc4d7d463b17e62a24ff (diff) |
Add Explicit EC parameter support to providers.
This was added for backward compatability.
Added EC_GROUP_new_from_params() that supports explicit curve parameters.
This fixes the 15-test_genec.t TODO.
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/12604)
Diffstat (limited to 'crypto/ec')
-rw-r--r-- | crypto/ec/ec_ameth.c | 62 | ||||
-rw-r--r-- | crypto/ec/ec_asn1.c | 71 | ||||
-rw-r--r-- | crypto/ec/ec_backend.c | 205 | ||||
-rw-r--r-- | crypto/ec/ec_err.c | 8 | ||||
-rw-r--r-- | crypto/ec/ec_lib.c | 411 |
5 files changed, 604 insertions, 153 deletions
diff --git a/crypto/ec/ec_ameth.c b/crypto/ec/ec_ameth.c index 6cd0bf6279..8840d57188 100644 --- a/crypto/ec/ec_ameth.c +++ b/crypto/ec/ec_ameth.c @@ -606,43 +606,6 @@ size_t ec_pkey_dirty_cnt(const EVP_PKEY *pkey) return pkey->pkey.ec->dirty_cnt; } -static ossl_inline -int ecparams_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl) -{ - const EC_GROUP *ecg; - int curve_nid; - - if (eckey == NULL) - return 0; - - ecg = EC_KEY_get0_group(eckey); - if (ecg == NULL) - return 0; - - curve_nid = EC_GROUP_get_curve_name(ecg); - - if (curve_nid == NID_undef) { - /* explicit parameters */ - - /* - * TODO(3.0): should we support explicit parameters curves? - */ - return 0; - } else { - /* named curve */ - const char *curve_name = NULL; - - if ((curve_name = OBJ_nid2sn(curve_nid)) == NULL) - return 0; - - if (!OSSL_PARAM_BLD_push_utf8_string(tmpl, OSSL_PKEY_PARAM_GROUP_NAME, - curve_name, 0)) - return 0; - } - - return 1; -} - static int ec_pkey_export_to(const EVP_PKEY *from, void *to_keydata, EVP_KEYMGMT *to_keymgmt, OPENSSL_CTX *libctx, @@ -650,7 +613,7 @@ int ec_pkey_export_to(const EVP_PKEY *from, void *to_keydata, { const EC_KEY *eckey = NULL; const EC_GROUP *ecg = NULL; - unsigned char *pub_key_buf = NULL; + unsigned char *pub_key_buf = NULL, *gen_buf = NULL; size_t pub_key_buflen; OSSL_PARAM_BLD *tmpl; OSSL_PARAM *params = NULL; @@ -676,8 +639,17 @@ int ec_pkey_export_to(const EVP_PKEY *from, void *to_keydata, if (tmpl == NULL) return 0; + /* + * EC_POINT_point2buf() can generate random numbers in some + * implementations so we need to ensure we use the correct libctx. + */ + bnctx = BN_CTX_new_ex(libctx); + if (bnctx == NULL) + goto err; + BN_CTX_start(bnctx); + /* export the domain parameters */ - if (!ecparams_to_params(eckey, tmpl)) + if (!ec_group_todata(ecg, tmpl, NULL, libctx, propq, bnctx, &gen_buf)) goto err; selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; @@ -685,14 +657,6 @@ int ec_pkey_export_to(const EVP_PKEY *from, void *to_keydata, pub_point = EC_KEY_get0_public_key(eckey); if (pub_point != NULL) { - /* - * EC_POINT_point2buf() can generate random numbers in some - * implementations so we need to ensure we use the correct libctx. - */ - bnctx = BN_CTX_new_ex(libctx); - if (bnctx == NULL) - goto err; - /* convert pub_point to a octet string according to the SECG standard */ if ((pub_key_buflen = EC_POINT_point2buf(ecg, pub_point, POINT_CONVERSION_COMPRESSED, @@ -779,6 +743,8 @@ int ec_pkey_export_to(const EVP_PKEY *from, void *to_keydata, OSSL_PARAM_BLD_free(tmpl); OSSL_PARAM_BLD_free_params(params); OPENSSL_free(pub_key_buf); + OPENSSL_free(gen_buf); + BN_CTX_end(bnctx); BN_CTX_free(bnctx); return rv; } @@ -794,7 +760,7 @@ static int ec_pkey_import_from(const OSSL_PARAM params[], void *vpctx) return 0; } - if (!ec_key_domparams_fromdata(ec, params) + if (!ec_group_fromdata(ec, params) || !ec_key_otherparams_fromdata(ec, params) || !ec_key_fromdata(ec, params, 1) || !EVP_PKEY_assign_EC_KEY(pkey, ec)) { diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c index 654a12ad60..879ff9faa2 100644 --- a/crypto/ec/ec_asn1.c +++ b/crypto/ec/ec_asn1.c @@ -23,75 +23,6 @@ #ifndef FIPS_MODULE -int EC_GROUP_get_basis_type(const EC_GROUP *group) -{ - int i; - - if (EC_GROUP_get_field_type(group) != NID_X9_62_characteristic_two_field) - /* everything else is currently not supported */ - return 0; - - /* Find the last non-zero element of group->poly[] */ - for (i = 0; - i < (int)OSSL_NELEM(group->poly) && group->poly[i] != 0; - i++) - continue; - - if (i == 4) - return NID_X9_62_ppBasis; - else if (i == 2) - return NID_X9_62_tpBasis; - else - /* everything else is currently not supported */ - return 0; -} - -#ifndef OPENSSL_NO_EC2M -int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k) -{ - if (group == NULL) - return 0; - - if (EC_GROUP_get_field_type(group) != NID_X9_62_characteristic_two_field - || !((group->poly[0] != 0) && (group->poly[1] != 0) - && (group->poly[2] == 0))) { - ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS, - ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - - if (k) - *k = group->poly[1]; - - return 1; -} - -int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1, - unsigned int *k2, unsigned int *k3) -{ - if (group == NULL) - return 0; - - if (EC_GROUP_get_field_type(group) != NID_X9_62_characteristic_two_field - || !((group->poly[0] != 0) && (group->poly[1] != 0) - && (group->poly[2] != 0) && (group->poly[3] != 0) - && (group->poly[4] == 0))) { - ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS, - ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - - if (k1) - *k1 = group->poly[3]; - if (k2) - *k2 = group->poly[2]; - if (k3) - *k3 = group->poly[1]; - - return 1; -} -#endif - /* some structures needed for the asn1 encoding */ typedef struct x9_62_pentanomial_st { int32_t k1; @@ -444,7 +375,7 @@ static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve) } ECPARAMETERS *EC_GROUP_get_ecparameters(const EC_GROUP *group, - ECPARAMETERS *params) + ECPARAMETERS *params) { size_t len = 0; ECPARAMETERS *ret = NULL; diff --git a/crypto/ec/ec_backend.c b/crypto/ec/ec_backend.c index 2277c2c724..1599e2b1f3 100644 --- a/crypto/ec/ec_backend.c +++ b/crypto/ec/ec_backend.c @@ -10,15 +10,178 @@ #include <openssl/core_names.h> #include <openssl/objects.h> #include <openssl/params.h> +#include <openssl/err.h> #include "crypto/bn.h" #include "crypto/ec.h" +#include "ec_local.h" +#include "e_os.h" +#include "internal/param_build_set.h" + +/* Mapping between a flag and a name */ +static const OSSL_ITEM encoding_nameid_map[] = { + { OPENSSL_EC_EXPLICIT_CURVE, OSSL_PKEY_EC_ENCODING_EXPLICIT }, + { OPENSSL_EC_NAMED_CURVE, OSSL_PKEY_EC_ENCODING_GROUP }, +}; + +int ec_encoding_name2id(const char *name) +{ + size_t i, sz; + + /* Return the default value if there is no name */ + if (name == NULL) + return OPENSSL_EC_NAMED_CURVE; + + for (i = 0, sz = OSSL_NELEM(encoding_nameid_map); i < sz; i++) { + if (strcasecmp(name, encoding_nameid_map[i].ptr) == 0) + return encoding_nameid_map[i].id; + } + return -1; +} + +static char *ec_param_encoding_id2name(int id) +{ + size_t i, sz; + + for (i = 0, sz = OSSL_NELEM(encoding_nameid_map); i < sz; i++) { + if (id == (int)encoding_nameid_map[i].id) + return encoding_nameid_map[i].ptr; + } + return NULL; +} + +int ec_group_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl, + OSSL_PARAM params[], OPENSSL_CTX *libctx, const char *propq, + BN_CTX *bnctx, unsigned char **genbuf) +{ + int ret = 0, curve_nid, encoding_flag; + const char *field_type, *encoding_name; + const BIGNUM *cofactor, *order; + BIGNUM *p = NULL, *a = NULL, *b = NULL; + point_conversion_form_t genform; + const EC_POINT *genpt; + unsigned char *seed = NULL; + size_t genbuf_len, seed_len; + + if (group == NULL) { + ECerr(0,EC_R_PASSED_NULL_PARAMETER); + return 0; + } + + encoding_flag = EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE; + encoding_name = ec_param_encoding_id2name(encoding_flag); + if (encoding_name == NULL + || !ossl_param_build_set_utf8_string(tmpl, params, + OSSL_PKEY_PARAM_EC_ENCODING, + encoding_name)) { + ECerr(0, EC_R_INVALID_ENCODING); + return 0; + } + + curve_nid = EC_GROUP_get_curve_name(group); + if (curve_nid == NID_undef) { + /* explicit curve */ + int fid = EC_GROUP_get_field_type(group); + + if (fid == NID_X9_62_prime_field) { + field_type = SN_X9_62_prime_field; + } else if (fid == NID_X9_62_characteristic_two_field) { + field_type = SN_X9_62_characteristic_two_field; + } else { + ECerr(0, EC_R_INVALID_FIELD); + return 0; + } + + p = BN_CTX_get(bnctx); + a = BN_CTX_get(bnctx); + b = BN_CTX_get(bnctx); + if (b == NULL) { + ECerr(0, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_GROUP_get_curve(group, p, a, b, bnctx)) { + ECerr(0, EC_R_INVALID_CURVE); + goto err; + } + + order = EC_GROUP_get0_order(group); + if (order == NULL) { + ECerr(0, EC_R_INVALID_GROUP_ORDER); + goto err; + } + genpt = EC_GROUP_get0_generator(group); + if (genpt == NULL) { + ECerr(0, EC_R_INVALID_GENERATOR); + goto err; + } + genform = EC_GROUP_get_point_conversion_form(group); + genbuf_len = EC_POINT_point2buf(group, genpt, genform, genbuf, bnctx); + if (genbuf_len == 0) { + ECerr(0, EC_R_INVALID_GENERATOR); + goto err; + } + + if (!ossl_param_build_set_utf8_string(tmpl, params, + OSSL_PKEY_PARAM_EC_FIELD_TYPE, + field_type) + || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_P, p) + || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_A, a) + || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_B, b) + || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_ORDER, + order) + || !ossl_param_build_set_octet_string(tmpl, params, + OSSL_PKEY_PARAM_EC_GENERATOR, + *genbuf, genbuf_len)) { + ECerr(0, ERR_R_MALLOC_FAILURE); + goto err; + } + + cofactor = EC_GROUP_get0_cofactor(group); + if (cofactor != NULL + && !ossl_param_build_set_bn(tmpl, params, + OSSL_PKEY_PARAM_EC_COFACTOR, cofactor)) { + ECerr(0, ERR_R_MALLOC_FAILURE); + goto err; + } + + seed = EC_GROUP_get0_seed(group); + seed_len = EC_GROUP_get_seed_len(group); + if (seed != NULL + && seed_len > 0 + && !ossl_param_build_set_octet_string(tmpl, params, + OSSL_PKEY_PARAM_EC_SEED, + seed, seed_len)) { + ECerr(0, ERR_R_MALLOC_FAILURE); + goto err; + } +#ifdef OPENSSL_NO_EC2M + if (fid == NID_X9_62_characteristic_two_field) { + ECerr(0, EC_R_GF2M_NOT_SUPPORTED); + goto err; + } +#endif + } else { + /* named curve */ + const char *curve_name = curve_name = ec_curve_nid2name(curve_nid); + + if (curve_name == NULL + || !ossl_param_build_set_utf8_string(tmpl, params, + OSSL_PKEY_PARAM_GROUP_NAME, + curve_name)) { + ECerr(0, EC_R_INVALID_CURVE); + goto err; + } + } + ret = 1; +err: + return ret; +} /* * The intention with the "backend" source file is to offer backend support * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider * implementations alike. */ - int ec_set_ecdh_cofactor_mode(EC_KEY *ec, int mode) { const EC_GROUP *ecg = EC_KEY_get0_group(ec); @@ -163,52 +326,27 @@ int ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private) return ok; } -int ec_key_domparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[]) +int ec_group_fromdata(EC_KEY *ec, const OSSL_PARAM params[]) { - const OSSL_PARAM *param_ec_name; - EC_GROUP *ecg = NULL; - char *curve_name = NULL; int ok = 0; + EC_GROUP *group = NULL; if (ec == NULL) return 0; - param_ec_name = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); - if (param_ec_name == NULL) { - /* explicit parameters */ - - /* - * TODO(3.0): should we support explicit parameters curves? - */ - return 0; - } else { - /* named curve */ - int curve_nid; - - if (!OSSL_PARAM_get_utf8_string(param_ec_name, &curve_name, 0) - || curve_name == NULL - || (curve_nid = ec_curve_name2nid(curve_name)) == NID_undef) - goto err; - - if ((ecg = EC_GROUP_new_by_curve_name_with_libctx(ec_key_get_libctx(ec), - ec_key_get0_propq(ec), - curve_nid)) == NULL) - goto err; - } + group = EC_GROUP_new_from_params(params, ec_key_get_libctx(ec), + ec_key_get0_propq(ec)); - if (!EC_KEY_set_group(ec, ecg)) + if (!EC_KEY_set_group(ec, group)) goto err; /* * TODO(3.0): if the group has changed, should we invalidate the private and * public key? */ - ok = 1; - - err: - OPENSSL_free(curve_name); - EC_GROUP_free(ecg); +err: + EC_GROUP_free(group); return ok; } @@ -227,5 +365,6 @@ int ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[]) || !ec_set_ecdh_cofactor_mode(ec, mode)) return 0; } + return 1; } diff --git a/crypto/ec/ec_err.c b/crypto/ec/ec_err.c index afb2696285..7112cbc21f 100644 --- a/crypto/ec/ec_err.c +++ b/crypto/ec/ec_err.c @@ -44,7 +44,10 @@ static const ERR_STRING_DATA EC_str_reasons[] = { "i2d ecpkparameters failure"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INCOMPATIBLE_OBJECTS), "incompatible objects"}, + {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_A), "invalid a"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_ARGUMENT), "invalid argument"}, + {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_B), "invalid b"}, + {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_COFACTOR), "invalid cofactor"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_COMPRESSED_POINT), "invalid compressed point"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_COMPRESSION_BIT), @@ -55,14 +58,19 @@ static const ERR_STRING_DATA EC_str_reasons[] = { {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_ENCODING), "invalid encoding"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_FIELD), "invalid field"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_FORM), "invalid form"}, + {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_GENERATOR), "invalid generator"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_GROUP_ORDER), "invalid group order"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_KEY), "invalid key"}, + {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_NAMED_GROUP_CONVERSION), + "invalid named group conversion"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_OUTPUT_LENGTH), "invalid output length"}, + {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_P), "invalid p"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_PEER_KEY), "invalid peer key"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_PENTANOMIAL_BASIS), "invalid pentanomial basis"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_PRIVATE_KEY), "invalid private key"}, + {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_SEED), "invalid seed"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_TRINOMIAL_BASIS), "invalid trinomial basis"}, {ERR_PACK(ERR_LIB_EC, 0, EC_R_KDF_PARAMETER_ERROR), "kdf parameter error"}, diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c index a0c007a13e..d9298f62d0 100644 --- a/crypto/ec/ec_lib.c +++ b/crypto/ec/ec_lib.c @@ -15,11 +15,14 @@ #include "internal/deprecated.h" #include <string.h> - +#include <openssl/params.h> +#include <openssl/core_names.h> #include <openssl/err.h> #include <openssl/opensslv.h> - +#include "crypto/ec.h" +#include "internal/nelem.h" #include "ec_local.h" +#include "e_os.h" /* strcasecmp */ /* functions for EC_GROUP objects */ @@ -1317,3 +1320,407 @@ int ec_point_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx) return group->meth->blind_coordinates(group, p, ctx); } + +int EC_GROUP_get_basis_type(const EC_GROUP *group) +{ + int i; + + if (EC_GROUP_get_field_type(group) != NID_X9_62_characteristic_two_field) + /* everything else is currently not supported */ + return 0; + + /* Find the last non-zero element of group->poly[] */ + for (i = 0; + i < (int)OSSL_NELEM(group->poly) && group->poly[i] != 0; + i++) + continue; + + if (i == 4) + return NID_X9_62_ppBasis; + else if (i == 2) + return NID_X9_62_tpBasis; + else + /* everything else is currently not supported */ + return 0; +} + +#ifndef OPENSSL_NO_EC2M +int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k) +{ + if (group == NULL) + return 0; + + if (EC_GROUP_get_field_type(group) != NID_X9_62_characteristic_two_field + || !((group->poly[0] != 0) && (group->poly[1] != 0) + && (group->poly[2] == 0))) { + ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (k) + *k = group->poly[1]; + + return 1; +} + +int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1, + unsigned int *k2, unsigned int *k3) +{ + if (group == NULL) + return 0; + + if (EC_GROUP_get_field_type(group) != NID_X9_62_characteristic_two_field + || !((group->poly[0] != 0) && (group->poly[1] != 0) + && (group->poly[2] != 0) && (group->poly[3] != 0) + && (group->poly[4] == 0))) { + ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (k1) + *k1 = group->poly[3]; + if (k2) + *k2 = group->poly[2]; + if (k3) + *k3 = group->poly[1]; + + return 1; +} +#endif + +/* + * Check if the explicit parameters group matches any built-in curves. + * + * We create a copy of the group just built, so that we can remove optional + * fields for the lookup: we do this to avoid the possibility that one of + * the optional parameters is used to force the library into using a less + * performant and less secure EC_METHOD instead of the specialized one. + * In any case, `seed` is not really used in any computation, while a + * cofactor different from the one in the built-in table is just + * mathematically wrong anyway and should not be used. + */ +static EC_GROUP *ec_group_explicit_to_named(const EC_GROUP *group, + OPENSSL_CTX *libctx, + const char *propq, + BN_CTX *ctx) +{ + EC_GROUP *ret_group = NULL, *dup = NULL; + int curve_name_nid; + + const EC_POINT *point = EC_GROUP_get0_generator(group); + const BIGNUM *order = EC_GROUP_get0_order(group); + int no_seed = (EC_GROUP_get0_seed(group) == NULL); + + if ((dup = EC_GROUP_dup(group)) == NULL + || EC_GROUP_set_seed(dup, NULL, 0) != 1 + || !EC_GROUP_set_generator(dup, point, order, NULL)) + goto err; + if ((curve_name_nid = ec_curve_nid_from_params(dup, ctx)) != NID_undef) { + /* + * The input explicit parameters successfully matched one of the + * built-in curves: often for built-in curves we have specialized + * methods with better performance and hardening. + * + * In this case we replace the `EC_GROUP` created through explicit + * parameters with one created from a named group. + */ + +#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 + /* + * NID_wap_wsg_idm_ecid_wtls12 and NID_secp224r1 are both aliases for + * the same curve, we prefer the SECP nid when matching explicit + * parameters as that is associated with a specialized EC_METHOD. + */ + if (curve_name_nid == NID_wap_wsg_idm_ecid_wtls12) + curve_name_nid = NID_secp224r1; +#endif /* !def(OPENSSL_NO_EC_NISTP_64_GCC_128) */ + + ret_group = EC_GROUP_new_by_curve_name_with_libctx(libctx, propq, + curve_name_nid); + if (ret_group == NULL) + goto err; + + /* + * Set the flag so that EC_GROUPs created from explicit parameters are + * serialized using explicit parameters by default. + */ + EC_GROUP_set_asn1_flag(ret_group, OPENSSL_EC_EXPLICIT_CURVE); + + /* + * If the input params do not contain the optional seed field we make + * sure it is not added to the returned group. + * + * The seed field is not really used inside libcrypto anyway, and + * adding it to parsed explicit parameter keys would alter their DER + * encoding output (because of the extra field) which could impact + * applications fingerprinting keys by their DER encoding. + */ + if (no_seed) { + if (EC_GROUP_set_seed(ret_group, NULL, 0) != 1) + goto err; + } + } else { + ret_group = (EC_GROUP *)group; + } + EC_GROUP_free(dup); + return ret_group; +err: + EC_GROUP_free(dup); + EC_GROUP_free(ret_group); + return NULL; +} + +static int ec_encoding_param2id(const OSSL_PARAM *p, int *id) +{ + const char *name = NULL; + int status = 0; + + switch (p->data_type) { + case OSSL_PARAM_UTF8_STRING: + /* The OSSL_PARAM functions have no support for this */ + name = p->data; + status = (name != NULL); + break; + case OSSL_PARAM_UTF8_PTR: + status = OSSL_PARAM_get_utf8_ptr(p, &name); + break; + } + if (status) { + int i = ec_encoding_name2id(name); + + if (i >= 0) { + *id = i; + return 1; + } + } + return 0; +} + +static EC_GROUP *group_new_from_name(const OSSL_PARAM *p, + OPENSSL_CTX *libctx, const char *propq) +{ + int ok = 0, nid; + const char *curve_name = NULL; + + switch (p->data_type) { + case OSSL_PARAM_UTF8_STRING: + /* The OSSL_PARAM functions have no support for this */ + curve_name = p->data; + ok = (curve_name != NULL); + break; + case OSSL_PARAM_UTF8_PTR: + ok = OSSL_PARAM_get_utf8_ptr(p, &curve_name); + break; + } + + if (ok) { + nid = ec_curve_name2nid(curve_name); + if (nid == NID_undef) { + ECerr(0, EC_R_INVALID_CURVE); + return NULL; + } else { + return EC_GROUP_new_by_curve_name_with_libctx(libctx, propq, nid); + } + } + return NULL; +} + +EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[], + OPENSSL_CTX *libctx, const char *propq) +{ + const OSSL_PARAM *ptmp, *pa, *pb; + int ok = 0; + EC_GROUP *group = NULL, *named_group = NULL; + BIGNUM *p = NULL, *a = NULL, *b = NULL, *order = NULL, *cofactor = NULL; + EC_POINT *point = NULL; + int field_bits = 0; + int is_prime_field = 1; + BN_CTX *bnctx = NULL; + const unsigned char *buf = NULL; + int encoding_flag = -1; + + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_ENCODING); + if (ptmp != NULL && !ec_encoding_param2id(ptmp, &encoding_flag)) { + ECerr(0, EC_R_INVALID_ENCODING); + return 0; + } + + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); + if (ptmp != NULL) { + group = group_new_from_name(ptmp, libctx, propq); + if (group != NULL) + EC_GROUP_set_asn1_flag(group, encoding_flag); + else + ECerr(0, ERR_R_EC_LIB); + return group; + } + bnctx = BN_CTX_new_ex(libctx); + if (bnctx == NULL) { + ECerr(0, ERR_R_MALLOC_FAILURE); + return 0; + } + BN_CTX_start(bnctx); + + p = BN_CTX_get(bnctx); + a = BN_CTX_get(bnctx); + b = BN_CTX_get(bnctx); + order = BN_CTX_get(bnctx); + if (order == NULL) { + ECerr(0, ERR_R_MALLOC_FAILURE); + goto err; + } + + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_FIELD_TYPE); + if (ptmp == NULL || ptmp->data_type != OSSL_PARAM_UTF8_STRING) { + ECerr(0, EC_R_INVALID_FIELD); + goto err; + } + if (strcasecmp(ptmp->data, SN_X9_62_prime_field) == 0) { + is_prime_field = 1; + } else if (strcasecmp(ptmp->data, SN_X9_62_characteristic_two_field) == 0) { + is_prime_field = 0; + } else { + /* Invalid field */ + ECerr(0, EC_R_UNSUPPORTED_FIELD); + goto err; + } + + pa = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_A); + if (!OSSL_PARAM_get_BN(pa, &a)) { + ECerr(0, EC_R_INVALID_A); + goto err; + } + pb = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_B); + if (!OSSL_PARAM_get_BN(pb, &b)) { + ECerr(0, EC_R_INVALID_B); + goto err; + } + + /* extract the prime number or irreducible polynomial */ + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_P); + if (!OSSL_PARAM_get_BN(ptmp, &p)) { + ECerr(0, EC_R_INVALID_P); + goto err; + } + + if (is_prime_field) { + if (BN_is_negative(p) || BN_is_zero(p)) { + ECerr(0, EC_R_INVALID_P); + goto err; + } + field_bits = BN_num_bits(p); + if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) { + ECerr(0, EC_R_FIELD_TOO_LARGE); + goto err; + } + + /* create the EC_GROUP structure */ + group = EC_GROUP_new_curve_GFp(p, a, b, bnctx); + } else { +#ifdef OPENSSL_NO_EC2M + ECerr(0, EC_R_GF2M_NOT_SUPPORTED); + goto err; +#else + /* create the EC_GROUP structure */ + group = EC_GROUP_new_curve_GF2m(p, a, b, NULL); + if (group != NULL) { + field_bits = EC_GROUP_get_degree(group); + if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) { + ECerr(0, EC_R_FIELD_TOO_LARGE); + goto err; + } + } +#endif /* OPENSSL_NO_EC2M */ + } + + if (group == NULL) { + ECerr(0, ERR_R_EC_LIB); + goto err; + } + + /* Optional seed */ + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_SEED); + if (ptmp != NULL) { + if (ptmp->data_type != OSSL_PARAM_OCTET_STRING) { + ECerr(0, EC_R_INVALID_SEED); + goto err; + } + if (!EC_GROUP_set_seed(group, ptmp->data, ptmp->data_size)) + goto err; + } + + /* generator base point */ + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_GENERATOR); + if (ptmp == NULL + || ptmp->data_type != OSSL_PARAM_OCTET_STRING) { + ECerr(0, EC_R_INVALID_GENERATOR); + goto err; + } + buf = (const unsigned char *)(ptmp->data); + if ((point = EC_POINT_new(group)) == NULL) + goto err; + EC_GROUP_set_point_conversion_form(group, + (point_conversion_form_t)buf[0] & ~0x01); + if (!EC_POINT_oct2point(group, point, buf, ptmp->data_size, bnctx)) { + ECerr(0, EC_R_INVALID_GENERATOR); + goto err; + } + + /* order */ + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_ORDER); + if (!OSSL_PARAM_get_BN(ptmp, &order) + || (BN_is_negative(order) || BN_is_zero(order)) + || (BN_num_bits(order) > (int)field_bits + 1)) { /* Hasse bound */ + ECerr(0, EC_R_INVALID_GROUP_ORDER); + goto err; + } + + /* Optional cofactor */ + ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_COFACTOR); + if (ptmp != NULL) { + cofactor = BN_CTX_get(bnctx); + if (cofactor == NULL || !OSSL_PARAM_get_BN(ptmp, &cofactor)) { + ECerr(0, EC_R_INVALID_COFACTOR); + goto err; + } + } + + /* set the generator, order and cofactor (if present) */ + if (!EC_GROUP_set_generator(group, point, order, cofactor)) { + ECerr(0, EC_R_INVALID_GENERATOR); + goto err; + } + + named_group = ec_group_explicit_to_named(group, libctx, propq, bnctx); + if (named_group == NULL) { + ECerr(0, EC_R_INVALID_NAMED_GROUP_CONVERSION); + goto err; + } + if (named_group == group) { + /* + * If we did not find a named group then the encoding should be explicit + * if it was specified + */ + if (encoding_flag == OPENSSL_EC_NAMED_CURVE) { + ECerr(0, EC_R_INVALID_ENCODING); + goto err; + } + EC_GROUP_set_asn1_flag(group, OPENSSL_EC_EXPLICIT_CURVE); + } else { + EC_GROUP_free(group); + group = named_group; + } + ok = 1; + err: + if (!ok) { + EC_GROUP_free(group); + group = NULL; + } + EC_POINT_free(point); + BN_CTX_end(bnctx); + BN_CTX_free(bnctx); + + return group; +} |