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)
master
Shane Lontis 3 years ago
parent a02c715c18
commit c0f39ded68

@ -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)) {

@ -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;

@ -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;
}

@ -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"},

@ -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;
}

@ -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

@ -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;

@ -4,9 +4,10 @@
EC_GROUP_get_ecparameters,
EC_GROUP_get_ecpkparameters,
EC_GROUP_new,
EC_GROUP_new_from_params,
EC_GROUP_new_from_ecparameters,
EC_GROUP_new_from_ecpkparameters,
EC_GROUP_new,
EC_GROUP_free,
EC_GROUP_clear_free,
EC_GROUP_new_curve_GFp,
@ -26,6 +27,8 @@ objects
#include <openssl/ec.h>
EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
OPENSSL_CTX *libctx, const char *propq);
EC_GROUP *EC_GROUP_new_from_ecparameters(const ECPARAMETERS *params);
EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params);
void EC_GROUP_free(EC_GROUP *group);
@ -93,6 +96,14 @@ used.
It is then necessary to call EC_GROUP_set_curve() to set the curve parameters.
Applications should instead use one of the other EC_GROUP_new_* constructors.
EC_GROUP_new_from_params() creates a group with parameters specified by I<params>.
The library context I<libctx> (see L<OPENSSL_CTX(3)>) and property query string
I<propq> are used to fetch algorithms from providers.
I<params> may be either a list of explicit params or a named group,
The values for I<ctx> and I<propq> may be NULL.
The I<params> that can be used are described in
L<B<EVP_PKEY-EC>(7)|EVP_PKEY-EC(7)/Common EC parameters>.
EC_GROUP_new_from_ecparameters() will create a group from the
specified I<params> and
EC_GROUP_new_from_ecpkparameters() will create a group from the specific PK
@ -177,7 +188,7 @@ EC_GROUP_get_curve_GF2m() return 1 on success or 0 on error.
L<crypto(7)>, L<EC_GROUP_copy(3)>,
L<EC_POINT_new(3)>, L<EC_POINT_add(3)>, L<EC_KEY_new(3)>,
L<EC_GFp_simple_method(3)>, L<d2i_ECPKParameters(3)>,
L<OPENSSL_CTX(3)>
L<OPENSSL_CTX(3)>, L<EVP_PKEY-EC(7)>
=head1 HISTORY
@ -187,7 +198,8 @@ L<OPENSSL_CTX(3)>
EC_GROUP_new() was deprecated in OpenSSL 3.0.
EC_GROUP_new_by_curve_name_with_libctx() was added in OpenSSL 3.0.
EC_GROUP_new_by_curve_name_with_libctx() and EC_GROUP_new_from_params() were
added in OpenSSL 3.0.
=item *

@ -149,7 +149,7 @@ TODO Write a set of cookbook documents and link to them.
0x47
};
const OSSL_PARAM params[] = {
OSSL_PARAM_utf8_string("curve-name", "prime256v1"),
OSSL_PARAM_utf8_string("group", "prime256v1"),
OSSL_PARAM_BN("priv", priv, sizeof(priv)),
OSSL_PARAM_BN("pub", pub, sizeof(pub)),
OSSL_PARAM_END

@ -12,7 +12,15 @@ The B<EC> keytype is implemented in OpenSSL's default provider.
=head2 Common EC parameters
The following Import/Export types are available for the built-in EC algorithm:
The normal way of specifying domain parameters for an EC curve is via the
curve name "group". For curves with no curve name, explicit parameters can be
used that specify "field-type", "p", "a", "b", "generator" and "order".
Explicit parameters are supported for backwards compability reasons, but they
are not compliant with multiple standards (including RFC5915) which only allow
named curves.
The following KeyGen/Gettable/Import/Export types are available for the
built-in EC algorithm:
=over 4
@ -20,12 +28,56 @@ The following Import/Export types are available for the built-in EC algorithm:
The curve name.
=item "field-type" (B<OSSL_PKEY_PARAM_EC_FIELD_TYPE>) <utf8 string>
The value should be either "prime-field" or "characteristic-two-field",
which correspond to prime field Fp and binary field F2^m.
=item "p" (B<OSSL_PKEY_PARAM_EC_P>) <unsigned integer>
For a curve over Fp I<p> is the prime for the field. For a curve over F2^m I<p>
represents the irreducible polynomial - each bit represents a term in the
polynomial. Therefore, there will either be three or five bits set dependent on
whether the polynomial is a trinomial or a pentanomial.
=item "a" (B<OSSL_PKEY_PARAM_EC_A>) <unsigned integer>
=item "b" (B<OSSL_PKEY_PARAM_EC_B>) <unsigned integer>
=item "seed" (B<OSSL_PKEY_PARAM_EC_SEED>) <octet string>
I<a> and I<b> represents the coefficients of the curve
For Fp: y^2 mod p = x^3 +ax + b mod p OR
For F2^m: y^2 + xy = x^3 + ax^2 + b
I<seed> is an optional value that is for information purposes only.
It represents the random number seed used to generate the coefficient I<b> from a
random number.
=item "generator" (B<OSSL_PKEY_PARAM_EC_GENERATOR>) <octet string>
=item "order" (B<OSSL_PKEY_PARAM_EC_ORDER>) <unsigned integer>
=item "cofactor" (B<OSSL_PKEY_PARAM_EC_COFACTOR>) <unsigned integer>
The I<generator> is a well defined point on the curve chosen for cryptographic
operations. The encoding conforms with Sec. 2.3.3 of the SECG SEC 1 ("Elliptic Curve
Cryptography") standard. See EC_POINT_oct2point().
Integers used for point multiplications will be between 0 and
I<order> - 1.
I<cofactor> is an optional value.
I<order> multiplied by the I<cofactor> gives the number of points on the curve.
=item "use-cofactor-flag" (B<OSSL_PKEY_PARAM_USE_COFACTOR_ECDH>) <integer>
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 "encoding" (B<OSSL_PKEY_PARAM_EC_ENCODING>) <utf8 string>
Set the format used for serializing the EC group parameters.
Valid values are "explicit" or "named_curve". The default value is "named_curve".
See also L<EVP_KEYEXCH-ECDH(7)> for the related
B<OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE> parameter that can be set on a
@ -46,6 +98,36 @@ exchange message for the TLS protocol.
=back
The following Gettable types are also available for the built-in EC algorithm:
=over 4
=item "basis-type" (B<OSSL_PKEY_PARAM_EC_CHAR2_TYPE>) <utf8 string>
Supports the values "tpBasis" for a trinomial or "ppBasis" for a pentanomial.
This field is only used for a binary field F2^m.
=item "m" (B<OSSL_PKEY_PARAM_EC_CHAR2_M>) <integer>
=item "tp" (B<OSSL_PKEY_PARAM_EC_CHAR2_TP_BASIS>) <integer>
=item "k1" (B<OSSL_PKEY_PARAM_EC_CHAR2_PP_K1>) <integer>
=item "k2" (B<OSSL_PKEY_PARAM_EC_CHAR2_PP_K2>) <integer>
=item "k3" (B<OSSL_PKEY_PARAM_EC_CHAR2_PP_K3>) <integer>
These fields are only used for a binary field F2^m.
I<m> is the degree of the binary field.
I<tp> is the middle bit of a trinomial so its value must be in the
range m > tp > 0.
I<k1>, I<k2> and I<k3> are used to get the middle bits of a pentanomial such
that m > k3 > k2 > k1 > 0
=back
=head1 EXAMPLES
An B<EVP_PKEY> context can be obtained by calling:

@ -59,10 +59,14 @@ const char *ec_curve_nid2name(int nid);
int ec_curve_name2nid(const char *name);
/* Backend support */
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 ec_group_fromdata(EC_KEY *ec, const OSSL_PARAM params[]);
int ec_key_fromdata(EC_KEY *ecx, const OSSL_PARAM params[], int include_private);
int ec_key_domparams_fromdata(EC_KEY *ecx, const OSSL_PARAM params[]);
int ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[]);
int ec_set_ecdh_cofactor_mode(EC_KEY *ec, int mode);
int ec_encoding_name2id(const char *name);
# endif /* OPENSSL_NO_EC */
#endif

@ -107,18 +107,18 @@ struct ossl_param_st {
# define OSSL_PARAM_REAL 3
/*-
* OSSL_PARAM_UTF8_STRING
* is a printable string. Is expteced to be printed as it is.
* is a printable string. It is expected to be printed as it is.
*/
# define OSSL_PARAM_UTF8_STRING 4
/*-
* OSSL_PARAM_OCTET_STRING
* is a string of bytes with no further specification. Is expected to be
* is a string of bytes with no further specification. It is expected to be
* printed as a hexdump.
*/
# define OSSL_PARAM_OCTET_STRING 5
/*-
* OSSL_PARAM_UTF8_PTR
* is a pointer to a printable string. Is expteced to be printed as it is.
* is a pointer to a printable string. It is expected to be printed as it is.
*
* The difference between this and OSSL_PARAM_UTF8_STRING is that only pointers
* are manipulated for this type.

@ -269,6 +269,22 @@ extern "C" {
#define OSSL_PKEY_PARAM_EC_PUB_X "qx"
#define OSSL_PKEY_PARAM_EC_PUB_Y "qy"
/* Elliptic Curve Explicit Domain Parameters */
#define OSSL_PKEY_PARAM_EC_FIELD_TYPE "field-type"
#define OSSL_PKEY_PARAM_EC_P "p"
#define OSSL_PKEY_PARAM_EC_A "a"
#define OSSL_PKEY_PARAM_EC_B "b"
#define OSSL_PKEY_PARAM_EC_GENERATOR "generator"
#define OSSL_PKEY_PARAM_EC_ORDER "order"
#define OSSL_PKEY_PARAM_EC_COFACTOR "cofactor"
#define OSSL_PKEY_PARAM_EC_SEED "seed"
#define OSSL_PKEY_PARAM_EC_CHAR2_M "m"
#define OSSL_PKEY_PARAM_EC_CHAR2_TYPE "basis-type"
#define OSSL_PKEY_PARAM_EC_CHAR2_TP_BASIS "tp"
#define OSSL_PKEY_PARAM_EC_CHAR2_PP_K1 "k1"
#define OSSL_PKEY_PARAM_EC_CHAR2_PP_K2 "k2"
#define OSSL_PKEY_PARAM_EC_CHAR2_PP_K3 "k3"
/* Elliptic Curve Key Parameters */
#define OSSL_PKEY_PARAM_USE_COFACTOR_FLAG "use-cofactor-flag"
#define OSSL_PKEY_PARAM_USE_COFACTOR_ECDH \
@ -352,6 +368,12 @@ extern "C" {
#define OSSL_PKEY_PARAM_FFC_DIGEST OSSL_PKEY_PARAM_DIGEST
#define OSSL_PKEY_PARAM_FFC_DIGEST_PROPS OSSL_PKEY_PARAM_PROPERTIES
#define OSSL_PKEY_PARAM_EC_ENCODING "encoding" /* utf8_string */
/* OSSL_PKEY_PARAM_EC_ENCODING values */
#define OSSL_PKEY_EC_ENCODING_EXPLICIT "explicit"
#define OSSL_PKEY_EC_ENCODING_GROUP "named_curve"
/* Key Exchange parameters */
#define OSSL_EXCHANGE_PARAM_PAD "pad" /* uint */
#define OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE "ecdh-cofactor-mode" /* int */

@ -47,6 +47,7 @@ typedef enum {
POINT_CONVERSION_HYBRID = 6
} point_conversion_form_t;
# include <openssl/params.h>
# ifndef OPENSSL_NO_DEPRECATED_3_0
typedef struct ec_method_st EC_METHOD;
# endif
@ -379,6 +380,19 @@ EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *ctx);
# endif
/**
* Creates a EC_GROUP object with a curve specified by parameters.
* The parameters may be explicit or a named curve,
* \param params A list of parameters describing the group.
* \param libctx The associated library context or NULL for the default
* context
* \param propq A property query string
* \return newly created EC_GROUP object with specified parameters or NULL
* if an error occurred
*/
EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
OPENSSL_CTX *libctx, const char *propq);
/**
* Creates a EC_GROUP object with a curve specified by a NID
* \param libctx The associated library context or NULL for the default

@ -243,7 +243,10 @@ int ERR_load_EC_strings(void);
# define EC_R_GROUP2PKPARAMETERS_FAILURE 120
# define EC_R_I2D_ECPKPARAMETERS_FAILURE 121
# define EC_R_INCOMPATIBLE_OBJECTS 101
# define EC_R_INVALID_A 168
# define EC_R_INVALID_ARGUMENT 112
# define EC_R_INVALID_B 169
# define EC_R_INVALID_COFACTOR 171
# define EC_R_INVALID_COMPRESSED_POINT 110
# define EC_R_INVALID_COMPRESSION_BIT 109
# define EC_R_INVALID_CURVE 141
@ -252,12 +255,16 @@ int ERR_load_EC_strings(void);
# define EC_R_INVALID_ENCODING 102
# define EC_R_INVALID_FIELD 103
# define EC_R_INVALID_FORM 104
# define EC_R_INVALID_GENERATOR 173
# define EC_R_INVALID_GROUP_ORDER 122
# define EC_R_INVALID_KEY 116
# define EC_R_INVALID_NAMED_GROUP_CONVERSION 174
# define EC_R_INVALID_OUTPUT_LENGTH 161
# define EC_R_INVALID_P 172
# define EC_R_INVALID_PEER_KEY 133
# define EC_R_INVALID_PENTANOMIAL_BASIS 132
# define EC_R_INVALID_PRIVATE_KEY 123
# define EC_R_INVALID_SEED 175
# define EC_R_INVALID_TRINOMIAL_BASIS 137
# define EC_R_KDF_PARAMETER_ERROR 148
# define EC_R_KEYS_NOT_SET 140

@ -23,22 +23,134 @@ void ec_get_new_free_import(OSSL_FUNC_keymgmt_new_fn **ec_new,
*ec_import = ossl_prov_get_keymgmt_import(ec_keymgmt_functions);
}
static int ossl_prov_print_ec_param(BIO *out, const EC_GROUP *group)
static int ossl_prov_print_ec_param_explicit_curve(BIO *out,
const EC_GROUP *group,
BN_CTX *ctx)
{
const char *curve_name;
int curve_nid = EC_GROUP_get_curve_name(group);
const char *plabel = "Prime:";
BIGNUM *p = NULL, *a = NULL, *b = NULL;
/* TODO(3.0): Explicit parameters are currently not supported */
if (curve_nid == NID_undef)
p = BN_CTX_get(ctx);
a = BN_CTX_get(ctx);
b = BN_CTX_get(ctx);
if (b == NULL
|| !EC_GROUP_get_curve(group, p, a, b, ctx))
return 0;
if (BIO_printf(out, "%s: %s\n", "ASN1 OID", OBJ_nid2sn(curve_nid)) <= 0)
if (EC_GROUP_get_field_type(group) == NID_X9_62_characteristic_two_field) {
int basis_type = EC_GROUP_get_basis_type(group);
/* print the 'short name' of the base type OID */
if (basis_type == NID_undef
|| BIO_printf(out, "Basis Type: %s\n", OBJ_nid2sn(basis_type)) <= 0)
return 0;
plabel = "Polynomial:";
}
return ossl_prov_print_labeled_bignum(out, plabel, p)
&& ossl_prov_print_labeled_bignum(out, "A: ", a)
&& ossl_prov_print_labeled_bignum(out, "B: ", b);
}
static int ossl_prov_print_ec_param_explicit_gen(BIO *out,
const EC_GROUP *group,
BN_CTX *ctx)
{
const EC_POINT *point = NULL;
BIGNUM *gen = NULL;
const char *glabel = NULL;
point_conversion_form_t form;
form = EC_GROUP_get_point_conversion_form(group);
point = EC_GROUP_get0_generator(group);
gen = BN_CTX_get(ctx);
if (gen == NULL
|| point == NULL
|| EC_POINT_point2bn(group, point, form, gen, ctx) == NULL)
return 0;
if (gen != NULL) {
switch (form) {
case POINT_CONVERSION_COMPRESSED:
glabel = "Generator (compressed):";
break;
case POINT_CONVERSION_UNCOMPRESSED:
glabel = "Generator (uncompressed):";
break;
case POINT_CONVERSION_HYBRID:
glabel = "Generator (hybrid):";
break;
default:
return 0;
}
return ossl_prov_print_labeled_bignum(out, glabel, gen);
}
return 1;
}
/* Print explicit parameters */
static int ossl_prov_print_ec_param_explicit(BIO *out, const EC_GROUP *group,
OPENSSL_CTX *libctx)
{
int ret = 0, tmp_nid;
BN_CTX *ctx = NULL;
const BIGNUM *order = NULL, *cofactor = NULL;
const unsigned char *seed;
size_t seed_len = 0;
ctx = BN_CTX_new_ex(libctx);
if (ctx == NULL)
return 0;
BN_CTX_start(ctx);
tmp_nid = EC_GROUP_get_field_type(group);
order = EC_GROUP_get0_order(group);
if (order == NULL)
goto err;
seed = EC_GROUP_get0_seed(group);
if (seed != NULL)
seed_len = EC_GROUP_get_seed_len(group);
cofactor = EC_GROUP_get0_cofactor(group);
/* print the 'short name' of the field type */
if (BIO_printf(out, "Field Type: %s\n", OBJ_nid2sn(tmp_nid)) <= 0
|| !ossl_prov_print_ec_param_explicit_curve(out, group, ctx)
|| !ossl_prov_print_ec_param_explicit_gen(out, group, ctx)
|| !ossl_prov_print_labeled_bignum(out, "Order: ", order)
|| (cofactor != NULL
&& !ossl_prov_print_labeled_bignum(out, "Cofactor: ", cofactor))
|| (seed != NULL
&& !ossl_prov_print_labeled_buf(out, "Seed:", seed, seed_len)))
goto err;
ret = 1;
err:
BN_CTX_end(ctx);
BN_CTX_free(ctx);
return ret;
}
static int ossl_prov_print_ec_param(BIO *out, const EC_GROUP *group,
OPENSSL_CTX *libctx)
{
if (EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE) {
const char *curve_name;
int curve_nid = EC_GROUP_get_curve_name(group);
/* TODO(3.0): Only named curves are currently supported */
curve_name = EC_curve_nid2nist(curve_nid);
return (curve_name == NULL
|| BIO_printf(out, "%s: %s\n", "NIST CURVE", curve_name) > 0);
/* Explicit parameters */
if (curve_nid == NID_undef)
return 0;
if (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
|| BIO_printf(out, "%s: %s\n", "NIST CURVE", curve_name) > 0);
} else {
return ossl_prov_print_ec_param_explicit(out, group, libctx);
}
}
int ossl_prov_print_eckey(BIO *out, EC_KEY *eckey, enum ec_print_type type)
@ -94,7 +206,7 @@ int ossl_prov_print_eckey(BIO *out, EC_KEY *eckey, enum ec_print_type type)