From d72e2842715ada993157540e121f8030e158857b Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Wed, 13 May 2015 14:48:39 -0700 Subject: [PATCH] Support arbitrary elliptic curve groups. This change exposes the functions needed to support arbitrary elliptic curve groups. The Java API[1] doesn't allow a provider to only provide certain elliptic curve groups. So if BoringSSL is an ECC provider on Android, we probably need to support arbitrary groups because someone out there is going to be using it for Bitcoin I'm sure. Perhaps in time we can remove this support, but not yet. [1] https://docs.oracle.com/javase/7/docs/api/java/security/spec/ECParameterSpec.html Change-Id: Ic1d76de96f913c9ca33c46b451cddc08c5b93d80 Reviewed-on: https://boringssl-review.googlesource.com/4740 Reviewed-by: David Benjamin Reviewed-by: Adam Langley --- crypto/ec/ec.c | 46 +++++++++++++++++++++++++++++++++++++---- crypto/err/ec.errordata | 2 ++ include/openssl/ec.h | 20 ++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c index 5426b8ff..f38eba66 100644 --- a/crypto/ec/ec.c +++ b/crypto/ec/ec.c @@ -265,8 +265,8 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) { return ret; } -static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, - const BIGNUM *b, BN_CTX *ctx) { +EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { const EC_METHOD *meth = EC_GFp_mont_method(); EC_GROUP *ret; @@ -276,7 +276,7 @@ static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, } if (ret->meth->group_set_curve == 0) { - OPENSSL_PUT_ERROR(EC, ec_group_new_curve_GFp, + OPENSSL_PUT_ERROR(EC, EC_GROUP_new_curve_GFp, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } @@ -287,6 +287,44 @@ static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, return ret; } +int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, + const BIGNUM *order, const BIGNUM *cofactor) { + if (group->curve_name != NID_undef) { + /* |EC_GROUP_set_generator| should only be used with |EC_GROUP|s returned + * by |EC_GROUP_new_curve_GFp|. */ + return 0; + } + + if (group->generator == NULL) { + group->generator = EC_POINT_new(group); + if (group->generator == NULL) { + return 0; + } + } + + if (!EC_POINT_copy(group->generator, generator)) { + return 0; + } + + if (order != NULL) { + if (!BN_copy(&group->order, order)) { + return 0; + } + } else { + BN_zero(&group->order); + } + + if (cofactor != NULL) { + if (!BN_copy(&group->cofactor, cofactor)) { + return 0; + } + } else { + BN_zero(&group->cofactor); + } + + return 1; +} + static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) { EC_GROUP *group = NULL; EC_POINT *P = NULL; @@ -322,7 +360,7 @@ static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) { goto err; } } else { - if ((group = ec_group_new_curve_GFp(p, a, b, ctx)) == NULL) { + if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) { OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_EC_LIB); goto err; } diff --git a/crypto/err/ec.errordata b/crypto/err/ec.errordata index 3b815c8a..252f7ab2 100644 --- a/crypto/err/ec.errordata +++ b/crypto/err/ec.errordata @@ -3,9 +3,11 @@ EC,function,100,EC_GROUP_copy EC,function,101,EC_GROUP_get_curve_GFp EC,function,102,EC_GROUP_get_degree EC,function,103,EC_GROUP_new_by_curve_name +EC,function,166,EC_GROUP_new_curve_GFp EC,function,104,EC_KEY_check_key EC,function,105,EC_KEY_copy EC,function,106,EC_KEY_generate_key +EC,function,165,EC_KEY_new_by_curve_name EC,function,107,EC_KEY_new_method EC,function,108,EC_KEY_set_public_key_affine_coordinates EC,function,109,EC_POINT_add diff --git a/include/openssl/ec.h b/include/openssl/ec.h index 633b11b4..25b45518 100644 --- a/include/openssl/ec.h +++ b/include/openssl/ec.h @@ -286,6 +286,25 @@ OPENSSL_EXPORT int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, /* Deprecated functions. */ +/* EC_GROUP_new_curve_GFp creates a new, arbitrary elliptic curve group based + * on the equation y² = x³ + a·x + b. It returns the new group or NULL on + * error. + * + * |EC_GROUP|s returned by this function will always compare as unequal via + * |EC_GROUP_cmp| (even to themselves). |EC_GROUP_get_curve_name| will always + * return |NID_undef|. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, + const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); + +/* EC_GROUP_set_generator sets the generator for |group| to |generator|, which + * must have the given order and cofactor. This should only be used with + * |EC_GROUP| objects returned by |EC_GROUP_new_curve_GFp|. */ +OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group, + const EC_POINT *generator, + const BIGNUM *order, + const BIGNUM *cofactor); + /* EC_GROUP_set_asn1_flag does nothing. */ OPENSSL_EXPORT void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag); @@ -381,6 +400,7 @@ OPENSSL_EXPORT void EC_GROUP_set_point_conversion_form( #define EC_F_ec_group_copy 163 #define EC_F_nistp256_pre_comp_new 164 #define EC_F_EC_KEY_new_by_curve_name 165 +#define EC_F_EC_GROUP_new_curve_GFp 166 #define EC_R_BUFFER_TOO_SMALL 100 #define EC_R_COORDINATES_OUT_OF_RANGE 101 #define EC_R_D2I_ECPKPARAMETERS_FAILURE 102