summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShane Lontis <shane.lontis@oracle.com>2019-03-21 20:09:02 +1000
committerNicola Tuveri <nic.tuv@gmail.com>2019-04-11 12:05:38 +0300
commit8402cd5f75f8c2f60d8bd39775b24b03dd8b3b38 (patch)
treedd33391c6df2811326b1787ab8fef274d86d8e93
parent4660bdea07e185b96c3b91be3e3b0a38959626ac (diff)
added code to validate EC named curve parameters
Reviewed-by: Nicola Tuveri <nic.tuv@gmail.com> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/8555)
-rw-r--r--apps/ecparam.c19
-rw-r--r--crypto/ec/ec_check.c17
-rw-r--r--crypto/ec/ec_curve.c123
-rw-r--r--crypto/ec/ec_lcl.h13
-rw-r--r--crypto/ec/ec_lib.c46
-rw-r--r--crypto/ec/ec_mult.c2
-rw-r--r--doc/man3/EC_GROUP_copy.pod18
-rw-r--r--include/openssl/ec.h1
-rw-r--r--test/ectest.c178
-rw-r--r--test/recipes/15-test_ecparam.t10
-rw-r--r--util/libcrypto.num1
11 files changed, 398 insertions, 30 deletions
diff --git a/apps/ecparam.c b/apps/ecparam.c
index 24fda049b7..0c893a3977 100644
--- a/apps/ecparam.c
+++ b/apps/ecparam.c
@@ -30,7 +30,7 @@ typedef enum OPTION_choice {
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_C,
OPT_CHECK, OPT_LIST_CURVES, OPT_NO_SEED, OPT_NOOUT, OPT_NAME,
- OPT_CONV_FORM, OPT_PARAM_ENC, OPT_GENKEY, OPT_ENGINE,
+ OPT_CONV_FORM, OPT_PARAM_ENC, OPT_GENKEY, OPT_ENGINE, OPT_CHECK_NAMED,
OPT_R_ENUM
} OPTION_CHOICE;
@@ -43,6 +43,8 @@ const OPTIONS ecparam_options[] = {
{"text", OPT_TEXT, '-', "Print the ec parameters in text form"},
{"C", OPT_C, '-', "Print a 'C' function creating the parameters"},
{"check", OPT_CHECK, '-', "Validate the ec parameters"},
+ {"check_named", OPT_CHECK_NAMED, '-',
+ "Check that named EC curve parameters have not been modified"},
{"list_curves", OPT_LIST_CURVES, '-',
"Prints a list of all curve 'short names'"},
{"no_seed", OPT_NO_SEED, '-',
@@ -90,7 +92,7 @@ int ecparam_main(int argc, char **argv)
int informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0, C = 0;
int ret = 1, private = 0;
int list_curves = 0, no_seed = 0, check = 0, new_form = 0;
- int text = 0, i, genkey = 0;
+ int text = 0, i, genkey = 0, check_named = 0;
prog = opt_init(argc, argv, ecparam_options);
while ((o = opt_next()) != OPT_EOF) {
@@ -127,6 +129,9 @@ int ecparam_main(int argc, char **argv)
case OPT_CHECK:
check = 1;
break;
+ case OPT_CHECK_NAMED:
+ check_named = 1;
+ break;
case OPT_LIST_CURVES:
list_curves = 1;
break;
@@ -266,6 +271,16 @@ int ecparam_main(int argc, char **argv)
goto end;
}
+ if (check_named) {
+ BIO_printf(bio_err, "validating named elliptic curve parameters: ");
+ if (EC_GROUP_check_named_curve(group, 0) <= 0) {
+ BIO_printf(bio_err, "failed\n");
+ ERR_print_errors(bio_err);
+ goto end;
+ }
+ BIO_printf(bio_err, "ok\n");
+ }
+
if (check) {
BIO_printf(bio_err, "checking elliptic curve parameters: ");
if (!EC_GROUP_check(group, NULL)) {
diff --git a/crypto/ec/ec_check.c b/crypto/ec/ec_check.c
index 322d0fe551..09e3deb048 100644
--- a/crypto/ec/ec_check.c
+++ b/crypto/ec/ec_check.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2002-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -10,6 +10,16 @@
#include "ec_lcl.h"
#include <openssl/err.h>
+int EC_GROUP_check_named_curve(const EC_GROUP *group, int nist_only)
+{
+ int nid;
+
+ nid = ec_curve_nid_from_params(group);
+ if (nid > 0 && nist_only && EC_curve_nid2nist(nid) == NULL)
+ nid = 0;
+ return nid;
+}
+
int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
{
int ret = 0;
@@ -17,6 +27,11 @@ int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
BN_CTX *new_ctx = NULL;
EC_POINT *point = NULL;
+ if (group == NULL || group->meth == NULL) {
+ ECerr(EC_F_EC_GROUP_CHECK, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
/* Custom curves assumed to be correct */
if ((group->meth->flags & EC_FLAGS_CUSTOM_CURVE) != 0)
return 1;
diff --git a/crypto/ec/ec_curve.c b/crypto/ec/ec_curve.c
index 641cf3f221..e7a3bd8488 100644
--- a/crypto/ec/ec_curve.c
+++ b/crypto/ec/ec_curve.c
@@ -14,6 +14,7 @@
#include <openssl/obj_mac.h>
#include <openssl/opensslconf.h>
#include "internal/nelem.h"
+#include "internal/o_str.h"
typedef struct {
int field_type, /* either NID_X9_62_prime_field or
@@ -1136,6 +1137,7 @@ static const struct {
},
{
/* no seed */
+ /* p */
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
@@ -1209,6 +1211,7 @@ static const struct {
},
{
/* no seed */
+ /* p */
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
@@ -1244,6 +1247,7 @@ static const struct {
},
{
/* no seed */
+ /* p */
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA1,
@@ -1278,7 +1282,7 @@ static const struct {
NID_X9_62_characteristic_two_field, 20, 36, 2
},
{
- /* no seed */
+ /* seed */
0x77, 0xE2, 0xB0, 0x73, 0x70, 0xEB, 0x0F, 0x83, 0x2A, 0x6D, 0xD5, 0xB6,
0x2D, 0xFC, 0x88, 0xCD, 0x06, 0xBB, 0x84, 0xBE,
/* p */
@@ -3197,3 +3201,120 @@ int EC_curve_nist2nid(const char *name)
}
return NID_undef;
}
+
+#define NUM_BN_FIELDS 6
+/*
+ * Validates EC domain parameter data for known named curves.
+ * This can be used when a curve is loaded explicitly (without a curve
+ * name) or to validate that domain parameters have not been modified.
+ *
+ * Returns: The nid associated with the found named curve, or NID_undef
+ * if not found. If there was an error it returns -1.
+ */
+int ec_curve_nid_from_params(const EC_GROUP *group)
+{
+ int ret = -1, nid, len, field_type, param_len;
+ size_t i, seed_len;
+ const unsigned char *seed, *params_seed, *params;
+ unsigned char *param_bytes = NULL;
+ const EC_CURVE_DATA *data;
+ const EC_POINT *generator = NULL;
+ const EC_METHOD *meth;
+ const BIGNUM *cofactor = NULL;
+ /* An array of BIGNUMs for (p, a, b, x, y, order) */
+ BIGNUM *bn[NUM_BN_FIELDS] = {NULL, NULL, NULL, NULL, NULL, NULL};
+ BN_CTX *ctx = NULL;
+
+ meth = EC_GROUP_method_of(group);
+ if (meth == NULL)
+ return -1;
+ /* Use the optional named curve nid as a search field */
+ nid = EC_GROUP_get_curve_name(group);
+ field_type = EC_METHOD_get_field_type(meth);
+ seed_len = EC_GROUP_get_seed_len(group);
+ seed = EC_GROUP_get0_seed(group);
+ cofactor = EC_GROUP_get0_cofactor(group);
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return -1;
+ BN_CTX_start(ctx);
+
+ /*
+ * The in built curves contains data fields (p, a, b, x, y, order) that are
+ * all zero padded to be the same size. The size of the padding is
+ * determined by either the number of bytes in the field modulus (p) or the
+ * EC group order, whichever is larger.
+ */
+ param_len = BN_num_bytes(group->order);
+ len = BN_num_bytes(group->field);
+ if (len > param_len)
+ param_len = len;
+
+ /* Allocate space to store the padded data for (p, a, b, x, y, order) */
+ param_bytes = OPENSSL_malloc(param_len * NUM_BN_FIELDS);
+ if (param_bytes == NULL)
+ goto end;
+
+ /* Create the bignums */
+ for (i = 0; i < NUM_BN_FIELDS; ++i) {
+ if ((bn[i] = BN_CTX_get(ctx)) == NULL)
+ goto end;
+ }
+ /*
+ * Fill in the bn array with the same values as the internal curves
+ * i.e. the values are p, a, b, x, y, order.
+ */
+ /* Get p, a & b */
+ if (!(EC_GROUP_get_curve(group, bn[0], bn[1], bn[2], ctx)
+ && ((generator = EC_GROUP_get0_generator(group)) != NULL)
+ /* Get x & y */
+ && EC_POINT_get_affine_coordinates(group, generator, bn[3], bn[4], ctx)
+ /* Get order */
+ && EC_GROUP_get_order(group, bn[5], ctx)))
+ goto end;
+
+ /*
+ * Convert the bignum array to bytes that are joined together to form
+ * a single buffer that contains data for all fields.
+ * (p, a, b, x, y, order) are all zero padded to be the same size.
+ */
+ for (i = 0; i < NUM_BN_FIELDS; ++i) {
+ if (BN_bn2binpad(bn[i], &param_bytes[i*param_len], param_len) <= 0)
+ goto end;
+ }
+
+ for (i = 0; i < curve_list_length; i++) {
+ const ec_list_element curve = curve_list[i];
+
+ data = curve.data;
+ /* Get the raw order byte data */
+ params_seed = (const unsigned char *)(data + 1); /* skip header */
+ params = params_seed + data->seed_len;
+
+ /* Look for unique fields in the fixed curve data */
+ if (data->field_type == field_type
+ && param_len == data->param_len
+ && (nid <= 0 || nid == curve.nid)
+ /* check the optional cofactor (ignore if its zero) */
+ && (BN_is_zero(cofactor)
+ || BN_is_word(cofactor, (const BN_ULONG)curve.data->cofactor))
+ /* Check the optional seed (ignore if its not set) */
+ && (data->seed_len == 0 || seed_len == 0
+ || ((size_t)data->seed_len == seed_len
+ && OPENSSL_memcmp(params_seed, seed, seed_len) == 0))
+ /* Check that the groups params match the inbuilt curve params */
+ && OPENSSL_memcmp(param_bytes, params, param_len * NUM_BN_FIELDS)
+ == 0) {
+ ret = curve.nid;
+ goto end;
+ }
+ }
+ /* Gets here if the group was not found */
+ ret = NID_undef;
+end:
+ OPENSSL_free(param_bytes);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h
index 6b90ef3a24..c54789ba6a 100644
--- a/crypto/ec/ec_lcl.h
+++ b/crypto/ec/ec_lcl.h
@@ -309,13 +309,10 @@ struct ec_point_st {
static ossl_inline int ec_point_is_compat(const EC_POINT *point,
const EC_GROUP *group)
{
- if (group->meth != point->meth
- || (group->curve_name != 0
- && point->curve_name != 0
- && group->curve_name != point->curve_name))
- return 0;
-
- return 1;
+ return group->meth == point->meth
+ && (group->curve_name == 0
+ || point->curve_name == 0
+ || group->curve_name == point->curve_name);
}
NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *);
@@ -595,6 +592,8 @@ int ec_key_simple_generate_key(EC_KEY *eckey);
int ec_key_simple_generate_public_key(EC_KEY *eckey);
int ec_key_simple_check_key(const EC_KEY *eckey);
+int ec_curve_nid_from_params(const EC_GROUP *group);
+
/* EC_METHOD definitions */
struct ec_key_method_st {
diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c
index 798382ac29..b2ae11d8ac 100644
--- a/crypto/ec/ec_lib.c
+++ b/crypto/ec/ec_lib.c
@@ -284,15 +284,17 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
if (order != NULL) {
if (!BN_copy(group->order, order))
return 0;
- } else
+ } else {
BN_zero(group->order);
+ }
+ /* The cofactor is an optional field, so it should be able to be NULL. */
if (cofactor != NULL) {
if (!BN_copy(group->cofactor, cofactor))
return 0;
- } else
+ } else {
BN_zero(group->cofactor);
-
+ }
/*
* Some groups have an order with
* factors of two, which makes the Montgomery setup fail.
@@ -530,30 +532,42 @@ int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx)
!b->meth->group_get_curve(b, b1, b2, b3, ctx))
r = 1;
- if (r || BN_cmp(a1, b1) || BN_cmp(a2, b2) || BN_cmp(a3, b3))
+ /* return 1 if the curve parameters are different */
+ if (r || BN_cmp(a1, b1) != 0 || BN_cmp(a2, b2) != 0 || BN_cmp(a3, b3) != 0)
r = 1;
- /* XXX EC_POINT_cmp() assumes that the methods are equal */
+ /* return 1 if the generators are different */
if (r || EC_POINT_cmp(a, EC_GROUP_get0_generator(a),
- EC_GROUP_get0_generator(b), ctx))
+ EC_GROUP_get0_generator(b), ctx) != 0)
r = 1;
if (!r) {
const BIGNUM *ao, *bo, *ac, *bc;
- /* compare the order and cofactor */
+ /* compare the order's */
ao = EC_GROUP_get0_order(a);
bo = EC_GROUP_get0_order(b);
- ac = EC_GROUP_get0_cofactor(a);
- bc = EC_GROUP_get0_cofactor(b);
if (ao == NULL || bo == NULL) {
- BN_CTX_end(ctx);
- BN_CTX_free(ctx_new);
- return -1;
+ /* return an error if either order is NULL */
+ r = -1;
+ goto end;
+ }
+ if (BN_cmp(ao, bo) != 0) {
+ /* return 1 if orders are different */
+ r = 1;
+ goto end;
}
- if (BN_cmp(ao, bo) || BN_cmp(ac, bc))
+ /*
+ * It gets here if the curve parameters and generator matched.
+ * Now check the optional cofactors (if both are present).
+ */
+ ac = EC_GROUP_get0_cofactor(a);
+ bc = EC_GROUP_get0_cofactor(b);
+ /* Returns 1 (mismatch) if both cofactors are specified and different */
+ if (!BN_is_zero(ac) && !BN_is_zero(bc) && BN_cmp(ac, bc) != 0)
r = 1;
+ /* Returns 0 if the parameters matched */
}
-
+end:
BN_CTX_end(ctx);
BN_CTX_free(ctx_new);
@@ -622,8 +636,8 @@ int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src)
}
if (dest->meth != src->meth
|| (dest->curve_name != src->curve_name
- && dest->curve_name != 0
- && src->curve_name != 0)) {
+ && dest->curve_name != 0
+ && src->curve_name != 0)) {
ECerr(EC_F_EC_POINT_COPY, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
diff --git a/crypto/ec/ec_mult.c b/crypto/ec/ec_mult.c
index 755d64400a..76dc524ba9 100644
--- a/crypto/ec/ec_mult.c
+++ b/crypto/ec/ec_mult.c
@@ -156,7 +156,7 @@ int ec_scalar_mul_ladder(const EC_GROUP *group, EC_POINT *r,
ECerr(EC_F_EC_SCALAR_MUL_LADDER, EC_R_UNKNOWN_ORDER);
return 0;
}
- if (BN_is_zero(group->cofactor)) {
+ if (BN_is_zero(group->cofactor) || BN_is_zero(group->cofactor)) {
ECerr(EC_F_EC_SCALAR_MUL_LADDER, EC_R_UNKNOWN_COFACTOR);
return 0;
}
diff --git a/doc/man3/EC_GROUP_copy.pod b/doc/man3/EC_GROUP_copy.pod
index 3f7108d0b8..c25c8f0426 100644
--- a/doc/man3/EC_GROUP_copy.pod
+++ b/doc/man3/EC_GROUP_copy.pod
@@ -9,7 +9,8 @@ EC_GROUP_set_curve_name, EC_GROUP_get_curve_name, EC_GROUP_set_asn1_flag,
EC_GROUP_get_asn1_flag, EC_GROUP_set_point_conversion_form,
EC_GROUP_get_point_conversion_form, EC_GROUP_get0_seed,
EC_GROUP_get_seed_len, EC_GROUP_set_seed, EC_GROUP_get_degree,
-EC_GROUP_check, EC_GROUP_check_discriminant, EC_GROUP_cmp,
+EC_GROUP_check, EC_GROUP_check_named_curve,
+EC_GROUP_check_discriminant, EC_GROUP_cmp,
EC_GROUP_get_basis_type, EC_GROUP_get_trinomial_basis,
EC_GROUP_get_pentanomial_basis, EC_GROUP_get0_field
- Functions for manipulating EC_GROUP objects
@@ -50,6 +51,7 @@ EC_GROUP_get_pentanomial_basis, EC_GROUP_get0_field
int EC_GROUP_get_degree(const EC_GROUP *group);
int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx);
+ int EC_GROUP_check_named_curve(const EC_GROUP *group, int nist_only);
int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx);
@@ -143,6 +145,14 @@ The function EC_GROUP_check performs a number of checks on a curve to verify tha
verifying that the discriminant is non zero; that a generator has been defined; that the generator is on the curve and has
the correct order.
+EC_GROUP_check_named_curve determines if the group's domain parameters match one of the built in curves supported by the library.
+The curve name is returned as a B<NID> if it matches. If the group's domain parameters have been modified then no match will be found.
+If the curve name of the given group is B<NID_undef> (e.g. it has been created by using explicit parameters with no curve name),
+then this method can be used to lookup the name of the curve that matches the group domain parameters. The built in curves contain
+aliases, so that multiple NID's can map to the same domain parameters. For such curves it is unspecified which of the aliases will be
+returned if the curve name of the given group is NID_undef.
+If B<nist_only> is 1 it will only look for NIST approved curves, otherwise it searches all built in curves.
+
EC_GROUP_cmp compares B<a> and B<b> to determine whether they represent the same curve or not.
The functions EC_GROUP_get_basis_type, EC_GROUP_get_trinomial_basis and EC_GROUP_get_pentanomial_basis should only be called for curves
@@ -175,6 +185,8 @@ EC_GROUP_get_order, EC_GROUP_get_cofactor, EC_GROUP_get_curve_name, EC_GROUP_get
and EC_GROUP_get_degree return the order, cofactor, curve name (NID), ASN1 flag, point_conversion_form and degree for the
specified curve respectively. If there is no curve name associated with a curve then EC_GROUP_get_curve_name will return 0.
+EC_GROUP_check_named_curve returns the nid of the matching named curve, otherwise it returns 0 for no match, or -1 on error.
+
EC_GROUP_get0_order() returns an internal pointer to the group order.
EC_GROUP_order_bits() returns the number of bits in the group order.
EC_GROUP_get0_cofactor() returns an internal pointer to the group cofactor.
@@ -198,6 +210,10 @@ L<crypto(7)>, L<EC_GROUP_new(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)>
+=head1 HISTORY
+
+The EC_GROUP_check_named_curve() function was added in OpenSSL 3.0.
+
=head1 COPYRIGHT
Copyright 2013-2017 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/include/openssl/ec.h b/include/openssl/ec.h
index 8d4d1b19ca..af559cb202 100644
--- a/include/openssl/ec.h
+++ b/include/openssl/ec.h
@@ -422,6 +422,7 @@ size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
const char *EC_curve_nid2nist(int nid);
int EC_curve_nist2nid(const char *name);
+int EC_GROUP_check_named_curve(const EC_GROUP *group, int nist_only);
/********************************************************************/
/* EC_POINT functions */
diff --git a/test/ectest.c b/test/ectest.c
index 59c7e99d8c..56c6b6f06d 100644
--- a/test/ectest.c
+++ b/test/ectest.c
@@ -8,6 +8,7 @@
* https://www.openssl.org/source/license.html
*/
+#include <string.h>
#include "internal/nelem.h"
#include "testutil.h"
@@ -1556,6 +1557,182 @@ static const unsigned char p521_explicit[] = {
0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09, 0x02, 0x01, 0x01,
};
+static int check_named_curve(int id)
+{
+ int ret = 0, nid, field_nid, has_seed, rv = 0;
+ EC_GROUP *group = NULL, *gtest = NULL, *galias = NULL;
+ const EC_POINT *group_gen = NULL;
+ EC_POINT *other_gen = NULL;
+ BIGNUM *group_p = NULL, *group_a = NULL, *group_b = NULL;
+ BIGNUM *other_p = NULL, *other_a = NULL, *other_b = NULL;
+ BIGNUM *group_cofactor = NULL, *other_cofactor = NULL;
+ BIGNUM *other_order = NULL;
+ const BIGNUM *group_order = NULL;
+ BN_CTX *bn_ctx = NULL;
+ static const unsigned char invalid_seed[] = "THIS IS NOT A VALID SEED";
+ static size_t invalid_seed_len = sizeof(invalid_seed);
+
+ /* Do some setup */
+ nid = curves[id].nid;
+ if (!TEST_ptr(bn_ctx = BN_CTX_new())
+ || !TEST_ptr(group = EC_GROUP_new_by_curve_name(nid))
+ || !TEST_ptr(gtest = EC_GROUP_dup(group))
+ || !TEST_ptr(group_p = BN_new())
+ || !TEST_ptr(group_a = BN_new())
+ || !TEST_ptr(group_b = BN_new())
+ || !TEST_ptr(group_cofactor = BN_new())
+ || !TEST_ptr(group_gen = EC_GROUP_get0_generator(group))
+ || !TEST_ptr(group_order = EC_GROUP_get0_order(group))
+ || !TEST_true(EC_GROUP_get_cofactor(group, group_cofactor, NULL))
+ || !TEST_true(EC_GROUP_get_curve(group, group_p, group_a, group_b, NULL))
+ || !TEST_ptr(other_gen = EC_POINT_dup(group_gen, group))
+ || !TEST_true(EC_POINT_add(group, other_gen, group_gen, group_gen, NULL))
+ || !TEST_ptr(other_order = BN_dup(group_order))
+ || !TEST_true(BN_add_word(other_order, 1))
+ || !TEST_ptr(other_a = BN_dup(group_a))
+ || !TEST_true(BN_add_word(other_a, 1))
+ || !TEST_ptr(other_b = BN_dup(group_b))
+ || !TEST_true(BN_add_word(other_b, 1))
+ || !TEST_ptr(other_cofactor = BN_dup(group_cofactor))
+ || !TEST_true(BN_add_word(other_cofactor, 1)))
+ goto err;
+
+ /* Determine if the inbuilt curve has a seed field set */
+ has_seed = (EC_GROUP_get_seed_len(group) > 0);
+ field_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
+ if (field_nid == NID_X9_62_characteristic_two_field) {
+ if (!TEST_ptr(other_p = BN_dup(group_p))
+ || !TEST_true(BN_lshift1(other_p, other_p)))
+ goto err;
+ } else {
+ if (!TEST_ptr(other_p = BN_dup(group_p)))
+ goto err;
+ /*
+ * Just choosing any arbitrary prime does not work..
+ * Setting p via ec_GFp_nist_group_set_curve() needs the prime to be a
+ * nist prime. So only select one of these as an alternate prime.
+ */
+ if (!TEST_ptr(BN_copy(other_p,
+ BN_ucmp(BN_get0_nist_prime_192(), other_p) == 0 ?
+ BN_get0_nist_prime_256() :
+ BN_get0_nist_prime_192())))
+ goto err;
+ }
+
+ /* Passes because this is a valid curve */
+ if (!TEST_int_eq(EC_GROUP_check_named_curve(group, 0), nid)
+ /* Only NIST curves pass */
+ || !TEST_int_eq(EC_GROUP_check_named_curve(group, 1),
+ EC_curve_nid2nist(nid) != NULL ? nid : NID_undef))
+ goto err;
+ /*
+ * Pass if the named curve is not known but the parameters are correct.
+ * It is possible to find the wrong alias if there is no curve name.
+ */
+ EC_GROUP_set_curve_name(group, NID_undef);
+ if (!TEST_int_gt(rv = EC_GROUP_check_named_curve(group, 0), 0))
+ goto err;
+#if 0
+ /* This code does not currently work since aliases are not supported
+ * currently.
+ */
+ /* Found an alias */
+ if (rv != nid) {
+ /* Fail if the returned nid is not an alias of the original group */
+ if (!TEST_ptr(galias = EC_GROUP_new_by_curve_name(rv)))
+ goto err;
+ EC_GROUP_set_curve_name(galias, nid);
+ if (!TEST_int_eq(EC_GROUP_check_named_curve(galias, 0), nid))
+ goto err;
+ }
+#endif
+ /* Fail if the curve name doesnt match the parameters */
+ EC_GROUP_set_curve_name(group, nid + 1);
+ if (!TEST_int_le(EC_GROUP_check_named_curve(group, 0), 0))
+ goto err;
+ EC_GROUP_set_curve_name(group, nid);
+
+ if (!TEST_int_eq(EC_GROUP_set_seed(group, invalid_seed, invalid_seed_len),
+ invalid_seed_len))
+ goto err;
+
+ if (has_seed) {
+ /*
+ * If the built in curve has a seed and we set the seed to another value
+ * then it will fail the check.
+ */
+ if (!TEST_int_eq(EC_GROUP_check_named_curve(group, 0), 0))
+ goto err;
+ } else {
+ /*
+ * If the built in curve does not have a seed then setting the seed will
+ * pass the check (as the seed is optional).
+ */
+ if (!TEST_int_eq(EC_GROUP_check_named_curve(group, 0), nid))
+ goto err;
+ }
+ /* Pass if the seed is unknown (as it is optional) */
+ if (!TEST_int_eq(EC_GROUP_set_seed(group, NULL, 0), 1)
+ || !TEST_int_gt(EC_GROUP_check_named_curve(group, 0), 0))
+ goto err;
+
+ /* Check that a duped group passes */
+ if (!TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), nid))
+ goto err;
+
+ /* check that changing any generator parameters fail */
+ if (!TEST_true(EC_GROUP_set_generator(gtest, other_gen, group_order,
+ group_cofactor))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), 0)
+ || !TEST_true(EC_GROUP_set_generator(gtest, group_gen, other_order,
+ group_cofactor))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), 0)
+ /* The order is not an optional field, so this should fail */
+ || !TEST_true(EC_GROUP_set_generator(gtest, group_gen, NULL,
+ group_cofactor))
+ || !TEST_int_le(EC_GROUP_check_named_curve(gtest, 0), 0)
+ || !TEST_true(EC_GROUP_set_generator(gtest, group_gen, group_order,
+ other_cofactor))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), 0)
+ /* Check that if the cofactor is not set then it still passes */
+ || !TEST_true(EC_GROUP_set_generator(gtest, group_gen, group_order,
+ NULL))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), nid)
+ /* check that restoring the generator passes */
+ || !TEST_true(EC_GROUP_set_generator(gtest, group_gen, group_order,
+ group_cofactor))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), nid)
+ /* check that changing any curve parameters fail */
+ || !TEST_true(EC_GROUP_set_curve(gtest, other_p, group_a, group_b, NULL))
+ || !TEST_int_le(EC_GROUP_check_named_curve(gtest, 0), 0)
+ || !TEST_true(EC_GROUP_set_curve(gtest, group_p, other_a, group_b, NULL))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), 0)
+ || !TEST_true(EC_GROUP_set_curve(gtest, group_p, group_a, other_b, NULL))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), 0)
+ /* Check that restoring the curve parameters pass */
+ || !TEST_true(EC_GROUP_set_curve(gtest, group_p, group_a, group_b, NULL))
+ || !TEST_int_eq(EC_GROUP_check_named_curve(gtest, 0), nid))
+ goto err;
+
+ ret = 1;
+err:
+ BN_free(group_p);
+ BN_free(other_p);
+ BN_free(group_a);
+ BN_free(other_a);
+ BN_free(group_b);
+ BN_free(other_b);
+ BN_free(group_cofactor);
+ BN_free(other_cofactor);
+ BN_free(other_order);
+ EC_POINT_free(other_gen);
+ EC_GROUP_free(galias);
+ EC_GROUP_free(gtest);
+ EC_GROUP_free(group);
+ BN_CTX_free(bn_ctx);
+ return ret;
+}
+
static int parameter_test(void)
{
EC_GROUP *group = NULL, *group2 = NULL;
@@ -1621,6 +1798,7 @@ int setup_tests(void)
ADD_ALL_TESTS(internal_curve_test, crv_len);
ADD_ALL_TESTS(internal_curve_test_method, crv_len);
ADD_TEST(group_field_test);
+ ADD_ALL_TESTS(check_named_curve, crv_len);
#endif
return 1;
}
diff --git a/test/recipes/15-test_ecparam.t b/test/recipes/15-test_ecparam.t
index 1d0b59c13e..ee14775747 100644
--- a/test/recipes/15-test_ecparam.t
+++ b/test/recipes/15-test_ecparam.t
@@ -23,12 +23,20 @@ plan skip_all => "EC isn't supported in this build"
my @valid = glob(data_file("valid", "*.pem"));
my @invalid = glob(data_file("invalid", "*.pem"));
-plan tests => scalar @valid + scalar @invalid;
+plan tests => scalar @valid + scalar @invalid + scalar @valid + scalar @invalid;
foreach (@valid) {
ok(run(app([qw{openssl ecparam -noout -check -in}, $_])));
}
+foreach (@valid) {
+ ok(run(app([qw{openssl ecparam -noout -check_named -in}, $_])));
+}
+
foreach (@invalid) {
ok(!run(app([qw{openssl ecparam -noout -check -in}, $_])));
}
+
+foreach (@invalid) {
+ ok(!run(app([qw{openssl ecparam -noout -check_named -in}, $_])));
+}
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 9569bf43f3..3704a63556 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4795,3 +4795,4 @@ EVP_MD_upref 4742 3_0_0 EXIST::FUNCTION:
EVP_MD_fetch 4743 3_0_0 EXIST::FUNCTION:
EVP_set_default_properties 4744 3_0_0 EXIST::FUNCTION:
OSSL_PARAM_construct_end 4745 3_0_0 EXIST::FUNCTION:
+EC_GROUP_check_named_curve 4746 3_0_0 EXIST::FUNCTION:EC