From 8402cd5f75f8c2f60d8bd39775b24b03dd8b3b38 Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Thu, 21 Mar 2019 20:09:02 +1000 Subject: [PATCH] added code to validate EC named curve parameters Reviewed-by: Nicola Tuveri Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/8555) --- apps/ecparam.c | 19 +++- crypto/ec/ec_check.c | 17 +++- crypto/ec/ec_curve.c | 123 ++++++++++++++++++++++- crypto/ec/ec_lcl.h | 13 ++- crypto/ec/ec_lib.c | 46 ++++++--- crypto/ec/ec_mult.c | 2 +- doc/man3/EC_GROUP_copy.pod | 18 +++- include/openssl/ec.h | 1 + test/ectest.c | 178 +++++++++++++++++++++++++++++++++ test/recipes/15-test_ecparam.t | 10 +- util/libcrypto.num | 1 + 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 +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 #include #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], ¶m_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 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 (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 is 1 it will only look for NIST approved curves, otherwise it searches all built in curves. + EC_GROUP_cmp compares B and 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, L, L, L, L, L, L +=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 #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 -- 2.25.1