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