X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fec%2Fec_key.c;h=359e034ed9f5719cf9951b183c89dec7f6e3f377;hp=4c56777dfe2a14e37efa926205ff498f232e525a;hb=2da8d4eb2812e18cec5c8324a54a4c56b52563ed;hpb=0401d766afcd022748763f5614188301c9856c6e diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index 4c56777dfe..359e034ed9 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -20,26 +20,31 @@ #include "internal/refcount.h" #include #include +#include #include "crypto/bn.h" -#ifndef FIPS_MODE +static int ecdsa_keygen_pairwise_test(EC_KEY *eckey, OSSL_CALLBACK *cb, + void *cbarg); + +#ifndef FIPS_MODULE EC_KEY *EC_KEY_new(void) { - return ec_key_new_method_int(NULL, NULL); + return ec_key_new_method_int(NULL, NULL, NULL); } #endif -EC_KEY *EC_KEY_new_ex(OPENSSL_CTX *ctx) +EC_KEY *EC_KEY_new_with_libctx(OPENSSL_CTX *ctx, const char *propq) { - return ec_key_new_method_int(ctx, NULL); + return ec_key_new_method_int(ctx, propq, NULL); } -EC_KEY *EC_KEY_new_by_curve_name_ex(OPENSSL_CTX *ctx, int nid) +EC_KEY *EC_KEY_new_by_curve_name_with_libctx(OPENSSL_CTX *ctx, + const char *propq, int nid) { - EC_KEY *ret = EC_KEY_new_ex(ctx); + EC_KEY *ret = EC_KEY_new_with_libctx(ctx, propq); if (ret == NULL) return NULL; - ret->group = EC_GROUP_new_by_curve_name_ex(ctx, nid); + ret->group = EC_GROUP_new_by_curve_name_with_libctx(ctx, propq, nid); if (ret->group == NULL) { EC_KEY_free(ret); return NULL; @@ -52,10 +57,10 @@ EC_KEY *EC_KEY_new_by_curve_name_ex(OPENSSL_CTX *ctx, int nid) return ret; } -#ifndef FIPS_MODE +#ifndef FIPS_MODULE EC_KEY *EC_KEY_new_by_curve_name(int nid) { - return EC_KEY_new_by_curve_name_ex(NULL, nid); + return EC_KEY_new_by_curve_name_with_libctx(NULL, NULL, nid); } #endif @@ -75,20 +80,21 @@ void EC_KEY_free(EC_KEY *r) if (r->meth != NULL && r->meth->finish != NULL) r->meth->finish(r); -#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE) +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) ENGINE_finish(r->engine); #endif if (r->group && r->group->meth->keyfinish) r->group->meth->keyfinish(r); -#ifndef FIPS_MODE +#ifndef FIPS_MODULE CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, r, &r->ex_data); #endif CRYPTO_THREAD_lock_free(r->lock); EC_GROUP_free(r->group); EC_POINT_free(r->pub_key); BN_clear_free(r->priv_key); + OPENSSL_free(r->propq); OPENSSL_clear_free((void *)r, sizeof(EC_KEY)); } @@ -104,7 +110,7 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) dest->meth->finish(dest); if (dest->group && dest->group->meth->keyfinish) dest->group->meth->keyfinish(dest); -#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE) +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) if (ENGINE_finish(dest->engine) == 0) return 0; dest->engine = NULL; @@ -113,10 +119,10 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) dest->libctx = src->libctx; /* copy the parameters */ if (src->group != NULL) { - const EC_METHOD *meth = EC_GROUP_method_of(src->group); /* clear the old group */ EC_GROUP_free(dest->group); - dest->group = EC_GROUP_new_ex(src->libctx, meth); + dest->group = ec_group_new_with_libctx(src->libctx, src->propq, + src->group->meth); if (dest->group == NULL) return NULL; if (!EC_GROUP_copy(dest->group, src->group)) @@ -152,14 +158,14 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) dest->conv_form = src->conv_form; dest->version = src->version; dest->flags = src->flags; -#ifndef FIPS_MODE +#ifndef FIPS_MODULE if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EC_KEY, &dest->ex_data, &src->ex_data)) return NULL; #endif if (src->meth != dest->meth) { -#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE) +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) if (src->engine != NULL && ENGINE_init(src->engine) == 0) return NULL; dest->engine = src->engine; @@ -177,7 +183,8 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) EC_KEY *EC_KEY_dup(const EC_KEY *ec_key) { - EC_KEY *ret = ec_key_new_method_int(ec_key->libctx, ec_key->engine); + EC_KEY *ret = ec_key_new_method_int(ec_key->libctx, ec_key->propq, + ec_key->engine); if (ret == NULL) return NULL; @@ -241,11 +248,14 @@ int ossl_ec_key_gen(EC_KEY *eckey) * See SP800-56AR3 5.6.1.2.2 "Key Pair Generation by Testing Candidates" * * Params: + * libctx A context containing an optional self test callback. * eckey An EC key object that contains domain params. The generated keypair * is stored in this object. + * pairwise_test Set to non zero to perform a pairwise test. If the test + * fails then the keypair is not generated, * Returns 1 if the keypair was generated or 0 otherwise. */ -int ec_key_simple_generate_key(EC_KEY *eckey) +int ec_generate_key(OPENSSL_CTX *libctx, EC_KEY *eckey, int pairwise_test) { int ok = 0; BIGNUM *priv_key = NULL; @@ -305,8 +315,18 @@ int ec_key_simple_generate_key(EC_KEY *eckey) eckey->dirty_cnt++; +#ifdef FIPS_MODULE + pairwise_test = 1; +#endif /* FIPS_MODULE */ + ok = 1; + if (pairwise_test) { + OSSL_CALLBACK *cb = NULL; + void *cbarg = NULL; + OSSL_SELF_TEST_get_callback(libctx, &cb, &cbarg); + ok = ecdsa_keygen_pairwise_test(eckey, cb, cbarg); + } err: /* Step (9): If there is an error return an invalid keypair. */ if (!ok) { @@ -321,6 +341,11 @@ err: return ok; } +int ec_key_simple_generate_key(EC_KEY *eckey) +{ + return ec_generate_key(NULL, eckey, 0); +} + int ec_key_simple_generate_public_key(EC_KEY *eckey) { int ret; @@ -376,7 +401,7 @@ static int ec_key_public_range_check(BN_CTX *ctx, const EC_KEY *key) if (!EC_POINT_get_affine_coordinates(key->group, key->pub_key, x, y, ctx)) goto err; - if (EC_METHOD_get_field_type(key->group->meth) == NID_X9_62_prime_field) { + if (EC_GROUP_get_field_type(key->group) == NID_X9_62_prime_field) { if (BN_is_negative(x) || BN_cmp(x, key->group->field) >= 0 || BN_is_negative(y) @@ -397,93 +422,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); - 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); + if (!ec_key_private_check(eckey) + || !ec_key_pairwise_check(eckey, ctx)) 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; } @@ -547,6 +630,16 @@ int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, } +OPENSSL_CTX *ec_key_get_libctx(const EC_KEY *key) +{ + return key->libctx; +} + +const char *ec_key_get0_propq(const EC_KEY *key) +{ + return key->propq; +} + const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; @@ -603,7 +696,7 @@ int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) * This is important also because `BN_dup()` (and `BN_copy()`) do not * propagate the `BN_FLG_CONSTTIME` flag from the source `BIGNUM`, and * this brings an extra risk of inadvertently losing the flag, even when - * the called specifically set it. + * the caller specifically set it. * * The propagation has been turned on and off a few times in the past * years because in some conditions has shown unintended consequences in @@ -696,12 +789,14 @@ void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) EC_GROUP_set_asn1_flag(key->group, flag); } +#ifndef OPENSSL_NO_DEPRECATED_3_0 int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx) { if (key->group == NULL) return 0; return EC_GROUP_precompute_mult(key->group, ctx); } +#endif int EC_KEY_get_flags(const EC_KEY *key) { @@ -849,3 +944,45 @@ int EC_KEY_can_sign(const EC_KEY *eckey) return 0; return 1; } + +/* + * FIPS 140-2 IG 9.9 AS09.33 + * Perform a sign/verify operation. + * + * NOTE: When generating keys for key-agreement schemes - FIPS 140-2 IG 9.9 + * states that no additional pairwise tests are required (apart from the tests + * specified in SP800-56A) when generating keys. Hence pairwise ECDH tests are + * omitted here. + */ +static int ecdsa_keygen_pairwise_test(EC_KEY *eckey, OSSL_CALLBACK *cb, + void *cbarg) +{ + int ret = 0; + unsigned char dgst[16] = {0}; + int dgst_len = (int)sizeof(dgst); + ECDSA_SIG *sig = NULL; + OSSL_SELF_TEST *st = NULL; + + st = OSSL_SELF_TEST_new(cb, cbarg); + if (st == NULL) + return 0; + + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT, + OSSL_SELF_TEST_DESC_PCT_ECDSA); + + sig = ECDSA_do_sign(dgst, dgst_len, eckey); + if (sig == NULL) + goto err; + + OSSL_SELF_TEST_oncorrupt_byte(st, dgst); + + if (ECDSA_do_verify(dgst, dgst_len, sig, eckey) != 1) + goto err; + + ret = 1; +err: + OSSL_SELF_TEST_onend(st, ret); + OSSL_SELF_TEST_free(st); + ECDSA_SIG_free(sig); + return ret; +}