From 398c8da5c8c3cf3369ac7e8883823e0c94735ca7 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 21 Aug 2020 14:50:52 +0200 Subject: EC_KEY: add EC_KEY_decoded_from_explicit_params() The function returns 1 when the encoding of a decoded EC key used explicit encoding of the curve parameters. Reviewed-by: David von Oheimb Reviewed-by: Nicola Tuveri (Merged from https://github.com/openssl/openssl/pull/12909) --- crypto/ec/ec_asn1.c | 31 +++++++++++---- crypto/ec/ec_key.c | 7 ++++ crypto/ec/ec_lib.c | 1 + crypto/ec/ec_local.h | 2 + doc/man3/EC_KEY_new.pod | 8 +++- include/openssl/ec.h | 2 + test/ec_internal_test.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ util/libcrypto.num | 1 + 8 files changed, 144 insertions(+), 9 deletions(-) diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c index 96e7d83ea7..7b7c75ce84 100644 --- a/crypto/ec/ec_asn1.c +++ b/crypto/ec/ec_asn1.c @@ -137,6 +137,12 @@ struct ec_parameters_st { ASN1_INTEGER *cofactor; } /* ECPARAMETERS */ ; +typedef enum { + ECPKPARAMETERS_TYPE_NAMED = 0, + ECPKPARAMETERS_TYPE_EXPLICIT, + ECPKPARAMETERS_TYPE_IMPLICIT +} ecpk_parameters_type_t; + struct ecpk_parameters_st { int type; union { @@ -535,9 +541,10 @@ ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group, return NULL; } } else { - if (ret->type == 0) + if (ret->type == ECPKPARAMETERS_TYPE_NAMED) ASN1_OBJECT_free(ret->value.named_curve); - else if (ret->type == 1 && ret->value.parameters) + else if (ret->type == ECPKPARAMETERS_TYPE_EXPLICIT + && ret->value.parameters != NULL) ECPARAMETERS_free(ret->value.parameters); } @@ -554,7 +561,7 @@ ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group, ECerr(EC_F_EC_GROUP_GET_ECPKPARAMETERS, EC_R_MISSING_OID); ok = 0; } else { - ret->type = 0; + ret->type = ECPKPARAMETERS_TYPE_NAMED; ret->value.named_curve = asn1obj; } } else @@ -562,7 +569,7 @@ ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group, ok = 0; } else { /* use the ECPARAMETERS structure */ - ret->type = 1; + ret->type = ECPKPARAMETERS_TYPE_EXPLICIT; if ((ret->value.parameters = EC_GROUP_get_ecparameters(group, NULL)) == NULL) ok = 0; @@ -901,7 +908,8 @@ EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params) return NULL; } - if (params->type == 0) { /* the curve is given by an OID */ + if (params->type == ECPKPARAMETERS_TYPE_NAMED) { + /* the curve is given by an OID */ tmp = OBJ_obj2nid(params->value.named_curve); if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, @@ -909,15 +917,16 @@ EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params) return NULL; } EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE); - } else if (params->type == 1) { /* the parameters are given by a - * ECPARAMETERS structure */ + } else if (params->type == ECPKPARAMETERS_TYPE_EXPLICIT) { + /* the parameters are given by an ECPARAMETERS structure */ ret = EC_GROUP_new_from_ecparameters(params->value.parameters); if (!ret) { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, ERR_R_EC_LIB); return NULL; } EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_EXPLICIT_CURVE); - } else if (params->type == 2) { /* implicitlyCA */ + } else if (params->type == ECPKPARAMETERS_TYPE_IMPLICIT) { + /* implicit parameters inherited from CA - unsupported */ return NULL; } else { ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, EC_R_ASN1_ERROR); @@ -947,6 +956,9 @@ EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len) return NULL; } + if (params->type == ECPKPARAMETERS_TYPE_EXPLICIT) + group->decoded_from_explicit_params = 1; + if (a) { EC_GROUP_free(*a); *a = group; @@ -998,6 +1010,9 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len) if (priv_key->parameters) { EC_GROUP_free(ret->group); ret->group = EC_GROUP_new_from_ecpkparameters(priv_key->parameters); + if (ret->group != NULL + && priv_key->parameters->type == ECPKPARAMETERS_TYPE_EXPLICIT) + ret->group->decoded_from_explicit_params = 1; } if (ret->group == NULL) { diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index 261087ce23..23efbd015c 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -564,6 +564,13 @@ void EC_KEY_clear_flags(EC_KEY *key, int flags) key->flags &= ~flags; } +int EC_KEY_decoded_from_explicit_params(const EC_KEY *key) +{ + if (key == NULL || key->group == NULL) + return -1; + return key->group->decoded_from_explicit_params; +} + size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form, unsigned char **pbuf, BN_CTX *ctx) { diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c index 6832383cad..08db89fcee 100644 --- a/crypto/ec/ec_lib.c +++ b/crypto/ec/ec_lib.c @@ -211,6 +211,7 @@ int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src) dest->asn1_flag = src->asn1_flag; dest->asn1_form = src->asn1_form; + dest->decoded_from_explicit_params = src->decoded_from_explicit_params; if (src->seed) { OPENSSL_free(dest->seed); diff --git a/crypto/ec/ec_local.h b/crypto/ec/ec_local.h index e656fbd5e7..6ea26193e1 100644 --- a/crypto/ec/ec_local.h +++ b/crypto/ec/ec_local.h @@ -209,6 +209,8 @@ struct ec_group_st { BIGNUM *order, *cofactor; int curve_name; /* optional NID for named curve */ int asn1_flag; /* flag to control the asn1 encoding */ + int decoded_from_explicit_params; /* set if decoded from explicit + * curve parameters encoding */ point_conversion_form_t asn1_form; unsigned char *seed; /* optional seed for parameters (appears in * ASN1) */ diff --git a/doc/man3/EC_KEY_new.pod b/doc/man3/EC_KEY_new.pod index 21663a032e..530979833d 100644 --- a/doc/man3/EC_KEY_new.pod +++ b/doc/man3/EC_KEY_new.pod @@ -9,7 +9,8 @@ EC_KEY_get0_engine, EC_KEY_get0_group, EC_KEY_set_group, EC_KEY_get0_private_key, EC_KEY_set_private_key, EC_KEY_get0_public_key, EC_KEY_set_public_key, EC_KEY_get_conv_form, -EC_KEY_set_conv_form, EC_KEY_set_asn1_flag, EC_KEY_precompute_mult, +EC_KEY_set_conv_form, EC_KEY_set_asn1_flag, +EC_KEY_decoded_from_explicit_params, EC_KEY_precompute_mult, EC_KEY_generate_key, EC_KEY_check_key, EC_KEY_set_public_key_affine_coordinates, EC_KEY_oct2key, EC_KEY_key2buf, EC_KEY_oct2priv, EC_KEY_priv2oct, EC_KEY_priv2buf - Functions for creating, destroying and manipulating @@ -38,6 +39,7 @@ EC_KEY objects point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key); void EC_KEY_set_conv_form(EC_KEY *eckey, point_conversion_form_t cform); void EC_KEY_set_asn1_flag(EC_KEY *eckey, int asn1_flag); + int EC_KEY_decoded_from_explicit_params(const EC_KEY *key); int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx); int EC_KEY_generate_key(EC_KEY *key); int EC_KEY_check_key(const EC_KEY *key); @@ -118,6 +120,10 @@ EC_KEY_set_asn1_flag() sets the asn1_flag on the underlying EC_GROUP object (if set). Refer to L for further information on the asn1_flag. +EC_KEY_decoded_from_explicit_params() returns 1 if the group of the I was +decoded from data with explicitly encoded group parameters, -1 if the I +is NULL or the group parameters are missing, and 0 otherwise. + EC_KEY_precompute_mult() stores multiples of the underlying EC_GROUP generator for faster point multiplication. See also L. diff --git a/include/openssl/ec.h b/include/openssl/ec.h index 5af9ebdc7f..ca86ec15c5 100644 --- a/include/openssl/ec.h +++ b/include/openssl/ec.h @@ -829,6 +829,8 @@ void EC_KEY_set_flags(EC_KEY *key, int flags); void EC_KEY_clear_flags(EC_KEY *key, int flags); +int EC_KEY_decoded_from_explicit_params(const EC_KEY *key); + /** Creates a new EC_KEY object using a named curve as underlying * EC_GROUP object. * \param nid NID of the named curve. diff --git a/test/ec_internal_test.c b/test/ec_internal_test.c index 4b849312be..d1eede3a7f 100644 --- a/test/ec_internal_test.c +++ b/test/ec_internal_test.c @@ -183,6 +183,106 @@ static int field_tests_default(int n) return ret; } +/* + * Tests behavior of the decoded_from_explicit_params flag and API + */ +static int decoded_flag_test(void) +{ + EC_GROUP *grp; + EC_GROUP *grp_copy = NULL; + ECPARAMETERS *ecparams = NULL; + ECPKPARAMETERS *ecpkparams = NULL; + EC_KEY *key = NULL; + unsigned char *encodedparams = NULL; + const unsigned char *encp; + int encodedlen; + int testresult = 0; + + /* Test EC_GROUP_new not setting the flag */ + grp = EC_GROUP_new(EC_GFp_simple_method()); + if (!TEST_ptr(grp) + || !TEST_int_eq(grp->decoded_from_explicit_params, 0)) + goto err; + EC_GROUP_free(grp); + + /* Test EC_GROUP_new_by_curve_name not setting the flag */ + grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + if (!TEST_ptr(grp) + || !TEST_int_eq(grp->decoded_from_explicit_params, 0)) + goto err; + + /* Test EC_GROUP_new_from_ecparameters not setting the flag */ + if (!TEST_ptr(ecparams = EC_GROUP_get_ecparameters(grp, NULL)) + || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecparameters(ecparams)) + || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0)) + goto err; + EC_GROUP_free(grp_copy); + grp_copy = NULL; + ECPARAMETERS_free(ecparams); + ecparams = NULL; + + /* Test EC_GROUP_new_from_ecpkparameters not setting the flag */ + if (!TEST_int_eq(EC_GROUP_get_asn1_flag(grp), OPENSSL_EC_NAMED_CURVE) + || !TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL)) + || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams)) + || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0) + || !TEST_ptr(key = EC_KEY_new()) + /* Test EC_KEY_decoded_from_explicit_params on key without a group */ + || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), -1) + || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1) + /* Test EC_KEY_decoded_from_explicit_params negative case */ + || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 0)) + goto err; + EC_GROUP_free(grp_copy); + grp_copy = NULL; + ECPKPARAMETERS_free(ecpkparams); + ecpkparams = NULL; + + /* Test d2i_ECPKParameters with named params not setting the flag */ + if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0) + || !TEST_ptr(encp = encodedparams) + || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen)) + || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0)) + goto err; + EC_GROUP_free(grp_copy); + grp_copy = NULL; + OPENSSL_free(encodedparams); + encodedparams = NULL; + + /* Asn1 flag stays set to explicit with EC_GROUP_new_from_ecpkparameters */ + EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_EXPLICIT_CURVE); + if (!TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL)) + || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams)) + || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE) + || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0)) + goto err; + EC_GROUP_free(grp_copy); + grp_copy = NULL; + + /* Test d2i_ECPKParameters with explicit params setting the flag */ + if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0) + || !TEST_ptr(encp = encodedparams) + || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen)) + || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE) + || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 1) + || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1) + /* Test EC_KEY_decoded_from_explicit_params positive case */ + || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 1)) + goto err; + + testresult = 1; + + err: + EC_KEY_free(key); + EC_GROUP_free(grp); + EC_GROUP_free(grp_copy); + ECPARAMETERS_free(ecparams); + ECPKPARAMETERS_free(ecpkparams); + OPENSSL_free(encodedparams); + + return testresult; +} + int setup_tests(void) { crv_len = EC_get_builtin_curves(NULL, 0); @@ -196,6 +296,7 @@ int setup_tests(void) ADD_TEST(field_tests_ec2_simple); #endif ADD_ALL_TESTS(field_tests_default, crv_len); + ADD_TEST(decoded_flag_test); return 1; } diff --git a/util/libcrypto.num b/util/libcrypto.num index e16b836eb2..436f799bca 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4590,3 +4590,4 @@ RSA_get0_pss_params 4543 1_1_1e EXIST::FUNCTION:RSA X509_ALGOR_copy 4544 1_1_1h EXIST::FUNCTION: X509_REQ_set0_signature 4545 1_1_1h EXIST::FUNCTION: X509_REQ_set1_signature_algo 4546 1_1_1h EXIST::FUNCTION: +EC_KEY_decoded_from_explicit_params 4547 1_1_1h EXIST::FUNCTION:EC -- cgit v1.2.3