summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorShane Lontis <shane.lontis@oracle.com>2020-08-22 14:55:41 +1000
committerShane Lontis <shane.lontis@oracle.com>2020-08-22 14:55:41 +1000
commitc0f39ded68ba0929698a8773e63e9806ec9e5c74 (patch)
treedce39d009fceac112a1d320b5e072d94e22ca27d /crypto
parenta02c715c183382aa3038fc4d7d463b17e62a24ff (diff)
downloadopenssl-new-c0f39ded68ba0929698a8773e63e9806ec9e5c74.tar.gz
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')
-rw-r--r--crypto/ec/ec_ameth.c62
-rw-r--r--crypto/ec/ec_asn1.c71
-rw-r--r--crypto/ec/ec_backend.c205
-rw-r--r--crypto/ec/ec_err.c8
-rw-r--r--crypto/ec/ec_lib.c411
-rw-r--r--crypto/err/openssl.txt7
-rw-r--r--crypto/evp/pmeth_lib.c20
7 files changed, 613 insertions, 171 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;
+}
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 3a5a5b5692..b530098d2f 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2421,7 +2421,10 @@ EC_R_GF2M_NOT_SUPPORTED:147:gf2m not supported
EC_R_GROUP2PKPARAMETERS_FAILURE:120:group2pkparameters failure
EC_R_I2D_ECPKPARAMETERS_FAILURE:121:i2d ecpkparameters failure
EC_R_INCOMPATIBLE_OBJECTS:101:incompatible objects
+EC_R_INVALID_A:168:invalid a
EC_R_INVALID_ARGUMENT:112:invalid argument
+EC_R_INVALID_B:169:invalid b
+EC_R_INVALID_COFACTOR:171:invalid cofactor
EC_R_INVALID_COMPRESSED_POINT:110:invalid compressed point
EC_R_INVALID_COMPRESSION_BIT:109:invalid compression bit
EC_R_INVALID_CURVE:141:invalid curve
@@ -2430,12 +2433,16 @@ EC_R_INVALID_DIGEST_TYPE:138:invalid digest type
EC_R_INVALID_ENCODING:102:invalid encoding
EC_R_INVALID_FIELD:103:invalid field
EC_R_INVALID_FORM:104:invalid form
+EC_R_INVALID_GENERATOR:173:invalid generator
EC_R_INVALID_GROUP_ORDER:122:invalid group order
EC_R_INVALID_KEY:116:invalid key
+EC_R_INVALID_NAMED_GROUP_CONVERSION:174:invalid named group conversion
EC_R_INVALID_OUTPUT_LENGTH:161:invalid output length
+EC_R_INVALID_P:172:invalid p
EC_R_INVALID_PEER_KEY:133:invalid peer key
EC_R_INVALID_PENTANOMIAL_BASIS:132:invalid pentanomial basis
EC_R_INVALID_PRIVATE_KEY:123:invalid private key
+EC_R_INVALID_SEED:175:invalid seed
EC_R_INVALID_TRINOMIAL_BASIS:137:invalid trinomial basis
EC_R_KDF_PARAMETER_ERROR:148:kdf parameter error
EC_R_KEYS_NOT_SET:140:keys not set
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index fe2cc689f6..7fd5339537 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -1277,24 +1277,6 @@ int EVP_PKEY_CTX_ctrl_uint64(EVP_PKEY_CTX *ctx, int keytype, int optype,
static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
const char *value)
{
-
- /* Special cases that we intercept */
-# ifndef OPENSSL_NO_EC
- /*
- * We don't support encoding settings for providers, i.e. the only
- * possible encoding is "named_curve", so we simply fail when something
- * else is given, and otherwise just pretend all is fine.
- */
- if (strcmp(name, "ec_param_enc") == 0) {
- if (strcmp(value, "named_curve") == 0) {
- return 1;
- } else {
- ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
- return -2;
- }
- }
-# endif
-
if (strcmp(name, "md") == 0)
name = OSSL_ALG_PARAM_DIGEST;
else if (strcmp(name, "rsa_padding_mode") == 0)
@@ -1352,6 +1334,8 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
name = OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE;
else if (strcmp(name, "ecdh_kdf_md") == 0)
name = OSSL_EXCHANGE_PARAM_KDF_DIGEST;
+ else if (strcmp(name, "ec_param_enc") == 0)
+ name = OSSL_PKEY_PARAM_EC_ENCODING;
# endif
else if (strcmp(name, "N") == 0)
name = OSSL_KDF_PARAM_SCRYPT_N;