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)
This commit is contained in:
parent
4660bdea07
commit
8402cd5f75
11 changed files with 398 additions and 30 deletions
|
@ -30,7 +30,7 @@ typedef enum OPTION_choice {
|
||||||
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
|
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
|
||||||
OPT_INFORM, OPT_OUTFORM, OPT_IN, OPT_OUT, OPT_TEXT, OPT_C,
|
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_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
|
OPT_R_ENUM
|
||||||
} OPTION_CHOICE;
|
} OPTION_CHOICE;
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@ const OPTIONS ecparam_options[] = {
|
||||||
{"text", OPT_TEXT, '-', "Print the ec parameters in text form"},
|
{"text", OPT_TEXT, '-', "Print the ec parameters in text form"},
|
||||||
{"C", OPT_C, '-', "Print a 'C' function creating the parameters"},
|
{"C", OPT_C, '-', "Print a 'C' function creating the parameters"},
|
||||||
{"check", OPT_CHECK, '-', "Validate the ec 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, '-',
|
{"list_curves", OPT_LIST_CURVES, '-',
|
||||||
"Prints a list of all curve 'short names'"},
|
"Prints a list of all curve 'short names'"},
|
||||||
{"no_seed", OPT_NO_SEED, '-',
|
{"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 informat = FORMAT_PEM, outformat = FORMAT_PEM, noout = 0, C = 0;
|
||||||
int ret = 1, private = 0;
|
int ret = 1, private = 0;
|
||||||
int list_curves = 0, no_seed = 0, check = 0, new_form = 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);
|
prog = opt_init(argc, argv, ecparam_options);
|
||||||
while ((o = opt_next()) != OPT_EOF) {
|
while ((o = opt_next()) != OPT_EOF) {
|
||||||
|
@ -127,6 +129,9 @@ int ecparam_main(int argc, char **argv)
|
||||||
case OPT_CHECK:
|
case OPT_CHECK:
|
||||||
check = 1;
|
check = 1;
|
||||||
break;
|
break;
|
||||||
|
case OPT_CHECK_NAMED:
|
||||||
|
check_named = 1;
|
||||||
|
break;
|
||||||
case OPT_LIST_CURVES:
|
case OPT_LIST_CURVES:
|
||||||
list_curves = 1;
|
list_curves = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -266,6 +271,16 @@ int ecparam_main(int argc, char **argv)
|
||||||
goto end;
|
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) {
|
if (check) {
|
||||||
BIO_printf(bio_err, "checking elliptic curve parameters: ");
|
BIO_printf(bio_err, "checking elliptic curve parameters: ");
|
||||||
if (!EC_GROUP_check(group, NULL)) {
|
if (!EC_GROUP_check(group, NULL)) {
|
||||||
|
|
|
@ -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
|
* 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
|
* this file except in compliance with the License. You can obtain a copy
|
||||||
|
@ -10,6 +10,16 @@
|
||||||
#include "ec_lcl.h"
|
#include "ec_lcl.h"
|
||||||
#include <openssl/err.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 EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -17,6 +27,11 @@ int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
|
||||||
BN_CTX *new_ctx = NULL;
|
BN_CTX *new_ctx = NULL;
|
||||||
EC_POINT *point = 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 */
|
/* Custom curves assumed to be correct */
|
||||||
if ((group->meth->flags & EC_FLAGS_CUSTOM_CURVE) != 0)
|
if ((group->meth->flags & EC_FLAGS_CUSTOM_CURVE) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <openssl/obj_mac.h>
|
#include <openssl/obj_mac.h>
|
||||||
#include <openssl/opensslconf.h>
|
#include <openssl/opensslconf.h>
|
||||||
#include "internal/nelem.h"
|
#include "internal/nelem.h"
|
||||||
|
#include "internal/o_str.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int field_type, /* either NID_X9_62_prime_field or
|
int field_type, /* either NID_X9_62_prime_field or
|
||||||
|
@ -1136,6 +1137,7 @@ static const struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/* no seed */
|
/* no seed */
|
||||||
|
/* p */
|
||||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
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, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
@ -1209,6 +1211,7 @@ static const struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/* no seed */
|
/* no seed */
|
||||||
|
/* p */
|
||||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
|
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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
@ -1244,6 +1247,7 @@ static const struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/* no seed */
|
/* no seed */
|
||||||
|
/* p */
|
||||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
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, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA1,
|
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
|
NID_X9_62_characteristic_two_field, 20, 36, 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/* no seed */
|
/* seed */
|
||||||
0x77, 0xE2, 0xB0, 0x73, 0x70, 0xEB, 0x0F, 0x83, 0x2A, 0x6D, 0xD5, 0xB6,
|
0x77, 0xE2, 0xB0, 0x73, 0x70, 0xEB, 0x0F, 0x83, 0x2A, 0x6D, 0xD5, 0xB6,
|
||||||
0x2D, 0xFC, 0x88, 0xCD, 0x06, 0xBB, 0x84, 0xBE,
|
0x2D, 0xFC, 0x88, 0xCD, 0x06, 0xBB, 0x84, 0xBE,
|
||||||
/* p */
|
/* p */
|
||||||
|
@ -3197,3 +3201,120 @@ int EC_curve_nist2nid(const char *name)
|
||||||
}
|
}
|
||||||
return NID_undef;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -309,13 +309,10 @@ struct ec_point_st {
|
||||||
static ossl_inline int ec_point_is_compat(const EC_POINT *point,
|
static ossl_inline int ec_point_is_compat(const EC_POINT *point,
|
||||||
const EC_GROUP *group)
|
const EC_GROUP *group)
|
||||||
{
|
{
|
||||||
if (group->meth != point->meth
|
return group->meth == point->meth
|
||||||
|| (group->curve_name != 0
|
&& (group->curve_name == 0
|
||||||
&& point->curve_name != 0
|
|| point->curve_name == 0
|
||||||
&& group->curve_name != point->curve_name))
|
|| group->curve_name == point->curve_name);
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *);
|
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_generate_public_key(EC_KEY *eckey);
|
||||||
int ec_key_simple_check_key(const 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 */
|
/* EC_METHOD definitions */
|
||||||
|
|
||||||
struct ec_key_method_st {
|
struct ec_key_method_st {
|
||||||
|
|
|
@ -284,15 +284,17 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
|
||||||
if (order != NULL) {
|
if (order != NULL) {
|
||||||
if (!BN_copy(group->order, order))
|
if (!BN_copy(group->order, order))
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else {
|
||||||
BN_zero(group->order);
|
BN_zero(group->order);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The cofactor is an optional field, so it should be able to be NULL. */
|
||||||
if (cofactor != NULL) {
|
if (cofactor != NULL) {
|
||||||
if (!BN_copy(group->cofactor, cofactor))
|
if (!BN_copy(group->cofactor, cofactor))
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else {
|
||||||
BN_zero(group->cofactor);
|
BN_zero(group->cofactor);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Some groups have an order with
|
* Some groups have an order with
|
||||||
* factors of two, which makes the Montgomery setup fail.
|
* 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))
|
!b->meth->group_get_curve(b, b1, b2, b3, ctx))
|
||||||
r = 1;
|
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;
|
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),
|
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;
|
r = 1;
|
||||||
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
const BIGNUM *ao, *bo, *ac, *bc;
|
const BIGNUM *ao, *bo, *ac, *bc;
|
||||||
/* compare the order and cofactor */
|
/* compare the order's */
|
||||||
ao = EC_GROUP_get0_order(a);
|
ao = EC_GROUP_get0_order(a);
|
||||||
bo = EC_GROUP_get0_order(b);
|
bo = EC_GROUP_get0_order(b);
|
||||||
|
if (ao == NULL || bo == NULL) {
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 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);
|
ac = EC_GROUP_get0_cofactor(a);
|
||||||
bc = EC_GROUP_get0_cofactor(b);
|
bc = EC_GROUP_get0_cofactor(b);
|
||||||
if (ao == NULL || bo == NULL) {
|
/* Returns 1 (mismatch) if both cofactors are specified and different */
|
||||||
BN_CTX_end(ctx);
|
if (!BN_is_zero(ac) && !BN_is_zero(bc) && BN_cmp(ac, bc) != 0)
|
||||||
BN_CTX_free(ctx_new);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (BN_cmp(ao, bo) || BN_cmp(ac, bc))
|
|
||||||
r = 1;
|
r = 1;
|
||||||
|
/* Returns 0 if the parameters matched */
|
||||||
}
|
}
|
||||||
|
end:
|
||||||
BN_CTX_end(ctx);
|
BN_CTX_end(ctx);
|
||||||
BN_CTX_free(ctx_new);
|
BN_CTX_free(ctx_new);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
ECerr(EC_F_EC_SCALAR_MUL_LADDER, EC_R_UNKNOWN_ORDER);
|
||||||
return 0;
|
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);
|
ECerr(EC_F_EC_SCALAR_MUL_LADDER, EC_R_UNKNOWN_COFACTOR);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_asn1_flag, EC_GROUP_set_point_conversion_form,
|
||||||
EC_GROUP_get_point_conversion_form, EC_GROUP_get0_seed,
|
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_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_basis_type, EC_GROUP_get_trinomial_basis,
|
||||||
EC_GROUP_get_pentanomial_basis, EC_GROUP_get0_field
|
EC_GROUP_get_pentanomial_basis, EC_GROUP_get0_field
|
||||||
- Functions for manipulating EC_GROUP objects
|
- 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_get_degree(const EC_GROUP *group);
|
||||||
|
|
||||||
int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx);
|
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);
|
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
|
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.
|
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.
|
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
|
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
|
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.
|
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_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_order_bits() returns the number of bits in the group order.
|
||||||
EC_GROUP_get0_cofactor() returns an internal pointer to the group cofactor.
|
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_POINT_new(3)>, L<EC_POINT_add(3)>, L<EC_KEY_new(3)>,
|
||||||
L<EC_GFp_simple_method(3)>, L<d2i_ECPKParameters(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
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
Copyright 2013-2017 The OpenSSL Project Authors. All Rights Reserved.
|
Copyright 2013-2017 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
|
|
@ -422,6 +422,7 @@ size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
|
||||||
|
|
||||||
const char *EC_curve_nid2nist(int nid);
|
const char *EC_curve_nid2nist(int nid);
|
||||||
int EC_curve_nist2nid(const char *name);
|
int EC_curve_nist2nid(const char *name);
|
||||||
|
int EC_GROUP_check_named_curve(const EC_GROUP *group, int nist_only);
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
/* EC_POINT functions */
|
/* EC_POINT functions */
|
||||||
|
|
178
test/ectest.c
178
test/ectest.c
|
@ -8,6 +8,7 @@
|
||||||
* https://www.openssl.org/source/license.html
|
* https://www.openssl.org/source/license.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include "internal/nelem.h"
|
#include "internal/nelem.h"
|
||||||
#include "testutil.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,
|
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)
|
static int parameter_test(void)
|
||||||
{
|
{
|
||||||
EC_GROUP *group = NULL, *group2 = NULL;
|
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, crv_len);
|
||||||
ADD_ALL_TESTS(internal_curve_test_method, crv_len);
|
ADD_ALL_TESTS(internal_curve_test_method, crv_len);
|
||||||
ADD_TEST(group_field_test);
|
ADD_TEST(group_field_test);
|
||||||
|
ADD_ALL_TESTS(check_named_curve, crv_len);
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,20 @@ plan skip_all => "EC isn't supported in this build"
|
||||||
my @valid = glob(data_file("valid", "*.pem"));
|
my @valid = glob(data_file("valid", "*.pem"));
|
||||||
my @invalid = glob(data_file("invalid", "*.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) {
|
foreach (@valid) {
|
||||||
ok(run(app([qw{openssl ecparam -noout -check -in}, $_])));
|
ok(run(app([qw{openssl ecparam -noout -check -in}, $_])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (@valid) {
|
||||||
|
ok(run(app([qw{openssl ecparam -noout -check_named -in}, $_])));
|
||||||
|
}
|
||||||
|
|
||||||
foreach (@invalid) {
|
foreach (@invalid) {
|
||||||
ok(!run(app([qw{openssl ecparam -noout -check -in}, $_])));
|
ok(!run(app([qw{openssl ecparam -noout -check -in}, $_])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (@invalid) {
|
||||||
|
ok(!run(app([qw{openssl ecparam -noout -check_named -in}, $_])));
|
||||||
|
}
|
||||||
|
|
|
@ -4795,3 +4795,4 @@ EVP_MD_upref 4742 3_0_0 EXIST::FUNCTION:
|
||||||
EVP_MD_fetch 4743 3_0_0 EXIST::FUNCTION:
|
EVP_MD_fetch 4743 3_0_0 EXIST::FUNCTION:
|
||||||
EVP_set_default_properties 4744 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:
|
OSSL_PARAM_construct_end 4745 3_0_0 EXIST::FUNCTION:
|
||||||
|
EC_GROUP_check_named_curve 4746 3_0_0 EXIST::FUNCTION:EC
|
||||||
|
|
Loading…
Reference in a new issue