From a173cc9c388cbe8105f78ba5a8fdfbf20a35be1a Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Thu, 16 Jan 2020 17:18:26 +1000 Subject: [PATCH] Add EC key validation to default provider Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/10861) --- crypto/ec/ec_check.c | 19 +-- crypto/ec/ec_key.c | 152 +++++++++++++------ crypto/ec/ec_lib.c | 5 + include/crypto/ec.h | 4 + providers/implementations/keymgmt/ec_kmgmt.c | 33 +++- 5 files changed, 156 insertions(+), 57 deletions(-) diff --git a/crypto/ec/ec_check.c b/crypto/ec/ec_check.c index bb39177d64..1283d8404f 100644 --- a/crypto/ec/ec_check.c +++ b/crypto/ec/ec_check.c @@ -20,26 +20,27 @@ int EC_GROUP_check_named_curve(const EC_GROUP *group, int nist_only, BN_CTX *ctx) { int nid = NID_undef; -#ifndef FIPS_MODE BN_CTX *new_ctx = NULL; + if (group == NULL) { + ECerr(0, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + if (ctx == NULL) { - ctx = new_ctx = BN_CTX_new(); + ctx = new_ctx = BN_CTX_new_ex(NULL); if (ctx == NULL) { - ECerr(EC_F_EC_GROUP_CHECK_NAMED_CURVE, ERR_R_MALLOC_FAILURE); - goto err; + ECerr(0, ERR_R_MALLOC_FAILURE); + return NID_undef; } } -#endif nid = ec_curve_nid_from_params(group, ctx); if (nid > 0 && nist_only && EC_curve_nid2nist(nid) == NULL) nid = NID_undef; -#ifndef FIPS_MODE - err: - BN_CTX_free(ctx); -#endif +err: + BN_CTX_free(new_ctx); return nid; } diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index 18b544b9d3..ae3e974231 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -419,93 +419,151 @@ err: /* * ECC Key validation as specified in SP800-56A R3. - * Section 5.6.2.3.3 ECC Full Public-Key Validation - * Section 5.6.2.1.2 Owner Assurance of Private-Key Validity - * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency - * NOTES: - * Before calling this method in fips mode, there should be an assurance that - * an approved elliptic-curve group is used. - * Returns 1 if the key is valid, otherwise it returns 0. + * Section 5.6.2.3.3 ECC Full Public-Key Validation. */ -int ec_key_simple_check_key(const EC_KEY *eckey) +int ec_key_public_check(const EC_KEY *eckey, BN_CTX *ctx) { - int ok = 0; - BN_CTX *ctx = NULL; - const BIGNUM *order = NULL; + int ret = 0; EC_POINT *point = NULL; + const BIGNUM *order = NULL; if (eckey == NULL || eckey->group == NULL || eckey->pub_key == NULL) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER); + ECerr(0, ERR_R_PASSED_NULL_PARAMETER); return 0; } /* 5.6.2.3.3 (Step 1): Q != infinity */ if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_POINT_AT_INFINITY); - goto err; + ECerr(0, EC_R_POINT_AT_INFINITY); + return 0; } - if ((ctx = BN_CTX_new_ex(eckey->libctx)) == NULL) - goto err; - - if ((point = EC_POINT_new(eckey->group)) == NULL) - goto err; + point = EC_POINT_new(eckey->group); + if (point == NULL) + return 0; /* 5.6.2.3.3 (Step 2) Test if the public key is in range */ if (!ec_key_public_range_check(ctx, eckey)) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_COORDINATES_OUT_OF_RANGE); + ECerr(0, EC_R_COORDINATES_OUT_OF_RANGE); goto err; } /* 5.6.2.3.3 (Step 3) is the pub_key on the elliptic curve */ if (EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx) <= 0) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_POINT_IS_NOT_ON_CURVE); + ECerr(0, EC_R_POINT_IS_NOT_ON_CURVE); goto err; } order = eckey->group->order; if (BN_is_zero(order)) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_INVALID_GROUP_ORDER); + ECerr(0, EC_R_INVALID_GROUP_ORDER); goto err; } /* 5.6.2.3.3 (Step 4) : pub_key * order is the point at infinity. */ if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_EC_LIB); + ECerr(0, ERR_R_EC_LIB); goto err; } if (!EC_POINT_is_at_infinity(eckey->group, point)) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_WRONG_ORDER); + ECerr(0, EC_R_WRONG_ORDER); + goto err; + } + ret = 1; +err: + EC_POINT_free(point); + return ret; +} + +/* + * ECC Key validation as specified in SP800-56A R3. + * Section 5.6.2.1.2 Owner Assurance of Private-Key Validity + * The private key is in the range [1, order-1] + */ +int ec_key_private_check(const EC_KEY *eckey) +{ + if (eckey == NULL || eckey->group == NULL || eckey->priv_key == NULL) { + ECerr(0, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (BN_cmp(eckey->priv_key, BN_value_one()) < 0 + || BN_cmp(eckey->priv_key, eckey->group->order) >= 0) { + ECerr(0, EC_R_INVALID_PRIVATE_KEY); + return 0; + } + return 1; +} + +/* + * ECC Key validation as specified in SP800-56A R3. + * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency (b) + * Check if generator * priv_key = pub_key + */ +int ec_key_pairwise_check(const EC_KEY *eckey, BN_CTX *ctx) +{ + int ret = 0; + EC_POINT *point = NULL; + + if (eckey == NULL + || eckey->group == NULL + || eckey->pub_key == NULL + || eckey->priv_key == NULL) { + ECerr(0, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + point = EC_POINT_new(eckey->group); + if (point == NULL) + goto err; + + + if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) { + ECerr(0, ERR_R_EC_LIB); + goto err; + } + if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) { + ECerr(0, EC_R_INVALID_PRIVATE_KEY); goto err; } + ret = 1; +err: + EC_POINT_free(point); + return ret; +} + + +/* + * ECC Key validation as specified in SP800-56A R3. + * Section 5.6.2.3.3 ECC Full Public-Key Validation + * Section 5.6.2.1.2 Owner Assurance of Private-Key Validity + * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency + * NOTES: + * Before calling this method in fips mode, there should be an assurance that + * an approved elliptic-curve group is used. + * Returns 1 if the key is valid, otherwise it returns 0. + */ +int ec_key_simple_check_key(const EC_KEY *eckey) +{ + int ok = 0; + BN_CTX *ctx = NULL; + + if (eckey == NULL) { + ECerr(0, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if ((ctx = BN_CTX_new_ex(eckey->libctx)) == NULL) + return 0; + + if (!ec_key_public_check(eckey, ctx)) + goto err; if (eckey->priv_key != NULL) { - /* - * 5.6.2.1.2 Owner Assurance of Private-Key Validity - * The private key is in the range [1, order-1] - */ - if (BN_cmp(eckey->priv_key, BN_value_one()) < 0 - || BN_cmp(eckey->priv_key, order) >= 0) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_WRONG_ORDER); + if (!ec_key_private_check(eckey) + || !ec_key_pairwise_check(eckey, ctx)) goto err; - } - /* - * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency (b) - * Check if generator * priv_key = pub_key - */ - if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, - NULL, NULL, ctx)) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_EC_LIB); - goto err; - } - if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) { - ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_INVALID_PRIVATE_KEY); - goto err; - } } ok = 1; - err: +err: BN_CTX_free(ctx); - EC_POINT_free(point); return ok; } diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c index 078d8b35fa..e66a501a0e 100644 --- a/crypto/ec/ec_lib.c +++ b/crypto/ec/ec_lib.c @@ -1261,3 +1261,8 @@ int ec_point_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx) return group->meth->blind_coordinates(group, p, ctx); } + +OPENSSL_CTX *ec_key_get_libctx(const EC_KEY *eckey) +{ + return eckey->libctx; +} diff --git a/include/crypto/ec.h b/include/crypto/ec.h index c4f7d2e778..9ebf45d0f4 100644 --- a/include/crypto/ec.h +++ b/include/crypto/ec.h @@ -50,5 +50,9 @@ int ecdh_KDF_X9_63(unsigned char *out, size_t outlen, const EVP_MD *md); int ec_generate_key(OPENSSL_CTX *libctx, EC_KEY *eckey, int pairwise_test); +int ec_key_public_check(const EC_KEY *eckey, BN_CTX *ctx); +int ec_key_private_check(const EC_KEY *eckey); +int ec_key_pairwise_check(const EC_KEY *eckey, BN_CTX *ctx); +OPENSSL_CTX *ec_key_get_libctx(const EC_KEY *eckey); # endif /* OPENSSL_NO_EC */ #endif diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c index 107ab1b594..2db23cd489 100644 --- a/providers/implementations/keymgmt/ec_kmgmt.c +++ b/providers/implementations/keymgmt/ec_kmgmt.c @@ -16,10 +16,10 @@ #include #include #include -#include #include #include #include "crypto/bn.h" +#include "crypto/ec.h" #include "internal/param_build.h" #include "prov/implementations.h" #include "prov/providercommon.h" @@ -32,6 +32,7 @@ static OSSL_OP_keymgmt_set_params_fn ec_set_params; static OSSL_OP_keymgmt_settable_params_fn ec_settable_params; static OSSL_OP_keymgmt_has_fn ec_has; static OSSL_OP_keymgmt_match_fn ec_match; +static OSSL_OP_keymgmt_validate_fn ec_validate; static OSSL_OP_keymgmt_import_fn ec_import; static OSSL_OP_keymgmt_import_types_fn ec_import_types; static OSSL_OP_keymgmt_export_fn ec_export; @@ -730,6 +731,35 @@ int ec_set_params(void *key, const OSSL_PARAM params[]) return 1; } +static +int ec_validate(void *keydata, int selection) +{ + EC_KEY *eck = keydata; + int ok = 0; + BN_CTX *ctx = BN_CTX_new_ex(ec_key_get_libctx(eck)); + + if (ctx == NULL) + return 0; + + if ((selection & EC_POSSIBLE_SELECTIONS) != 0) + ok = 1; + + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) + ok = ok && EC_GROUP_check(EC_KEY_get0_group(eck), ctx); + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) + ok = ok && ec_key_public_check(eck, ctx); + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + ok = ok && ec_key_private_check(eck); + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR) + ok = ok && ec_key_pairwise_check(eck, ctx); + + BN_CTX_free(ctx); + return ok; +} + const OSSL_DISPATCH ec_keymgmt_functions[] = { { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata }, { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata }, @@ -739,6 +769,7 @@ const OSSL_DISPATCH ec_keymgmt_functions[] = { { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))ec_settable_params }, { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has }, { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match }, + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))ec_validate }, { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_import }, { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types }, { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export }, -- 2.25.1