diff options
author | Shane Lontis <shane.lontis@oracle.com> | 2020-02-16 13:03:46 +1000 |
---|---|---|
committer | Shane Lontis <shane.lontis@oracle.com> | 2020-02-16 13:03:46 +1000 |
commit | 8083fd3a183d4c881d6b15727cbc6cb7faeb3280 (patch) | |
tree | 82e998aa30cc9dc610b4f262df1f7ef73b23edad /crypto | |
parent | 98ad3fe82bd3e7e7f929dd1fa4ef3915426002c0 (diff) | |
download | openssl-8083fd3a183d4c881d6b15727cbc6cb7faeb3280.tar.gz |
Add FFC param/key validation
Embed libctx in dsa and dh objects and cleanup internal methods to not pass libctx (This makes it consistent with the rsa changes)
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10910)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/dh/dh_check.c | 123 | ||||
-rw-r--r-- | crypto/dh/dh_gen.c | 5 | ||||
-rw-r--r-- | crypto/dh/dh_group_params.c | 41 | ||||
-rw-r--r-- | crypto/dh/dh_key.c | 104 | ||||
-rw-r--r-- | crypto/dh/dh_lib.c | 27 | ||||
-rw-r--r-- | crypto/dh/dh_local.h | 1 | ||||
-rw-r--r-- | crypto/dsa/dsa_check.c | 85 | ||||
-rw-r--r-- | crypto/dsa/dsa_gen.c | 30 | ||||
-rw-r--r-- | crypto/dsa/dsa_key.c | 49 | ||||
-rw-r--r-- | crypto/dsa/dsa_lib.c | 26 | ||||
-rw-r--r-- | crypto/dsa/dsa_local.h | 4 | ||||
-rw-r--r-- | crypto/dsa/dsa_ossl.c | 7 | ||||
-rw-r--r-- | crypto/dsa/dsa_sign.c | 8 | ||||
-rw-r--r-- | crypto/ffc/build.info | 3 | ||||
-rw-r--r-- | crypto/ffc/ffc_key_generate.c | 20 | ||||
-rw-r--r-- | crypto/ffc/ffc_key_validate.c | 120 | ||||
-rw-r--r-- | crypto/ffc/ffc_params_generate.c | 32 | ||||
-rw-r--r-- | crypto/ffc/ffc_params_validate.c | 80 |
18 files changed, 573 insertions, 192 deletions
diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c index 8bb245207b..4832230f6c 100644 --- a/crypto/dh/dh_check.c +++ b/crypto/dh/dh_check.c @@ -11,6 +11,7 @@ #include "internal/cryptlib.h" #include <openssl/bn.h> #include "dh_local.h" +#include "crypto/dh.h" /*- * Check that p and g are suitable enough @@ -37,6 +38,28 @@ int DH_check_params_ex(const DH *dh) return errflags == 0; } +#ifdef FIPS_MODE +int DH_check_params(const DH *dh, int *ret) +{ + int nid; + + *ret = 0; + /* + * SP800-56A R3 Section 5.5.2 Assurances of Domain Parameter Validity + * (1a) The domain parameters correspond to any approved safe prime group. + */ + nid = DH_get_nid((DH *)dh); + if (nid != NID_undef) + return 1; + /* + * OR + * (2b) FFC domain params conform to FIPS-186-4 explicit domain param + * validity tests. + */ + return ffc_params_FIPS186_4_validate(&dh->params, FFC_PARAM_TYPE_DH, NULL, + FFC_PARAMS_VALIDATE_ALL, ret, NULL); +} +#else int DH_check_params(const DH *dh, int *ret) { int ok = 0; @@ -73,6 +96,7 @@ int DH_check_params(const DH *dh, int *ret) BN_CTX_free(ctx); return ok; } +#endif /* FIPS_MODE */ /*- * Check that p is a safe prime and @@ -107,11 +131,20 @@ int DH_check_ex(const DH *dh) return errflags == 0; } +/* Note: according to documentation - this only checks the params */ int DH_check(const DH *dh, int *ret) { +#ifdef FIPS_MODE + return DH_check_params(dh, ret); +#else int ok = 0, r; BN_CTX *ctx = NULL; BIGNUM *t1 = NULL, *t2 = NULL; + int nid = DH_get_nid((DH *)dh); + + *ret = 0; + if (nid != NID_undef) + return 1; if (!DH_check_params(dh, ret)) return 0; @@ -171,6 +204,7 @@ int DH_check(const DH *dh, int *ret) BN_CTX_end(ctx); BN_CTX_free(ctx); return ok; +#endif /* FIPS_MODE */ } int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) @@ -190,38 +224,83 @@ int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) return errflags == 0; } +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation. + */ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { + return ffc_validate_public_key(&dh->params, pub_key, ret); +} + +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation. + * To only be used with ephemeral FFC public keys generated using the approved + * safe-prime groups. + */ +int dh_check_pub_key_partial(const DH *dh, const BIGNUM *pub_key, int *ret) +{ + return ffc_validate_public_key_partial(&dh->params, pub_key, ret); +} + +int dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret) +{ int ok = 0; - BIGNUM *tmp = NULL; - BN_CTX *ctx = NULL; + BIGNUM *two_powN = NULL, *upper; *ret = 0; - ctx = BN_CTX_new(); - if (ctx == NULL) - goto err; - BN_CTX_start(ctx); - tmp = BN_CTX_get(ctx); - if (tmp == NULL || !BN_set_word(tmp, 1)) - goto err; - if (BN_cmp(pub_key, tmp) <= 0) - *ret |= DH_CHECK_PUBKEY_TOO_SMALL; - if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1)) + two_powN = BN_new(); + if (two_powN == NULL) + return 0; + if (dh->params.q == NULL) goto err; - if (BN_cmp(pub_key, tmp) >= 0) - *ret |= DH_CHECK_PUBKEY_TOO_LARGE; + upper = dh->params.q; - if (dh->params.q != NULL) { - /* Check pub_key^q == 1 mod p */ - if (!BN_mod_exp(tmp, pub_key, dh->params.q, dh->params.p, ctx)) + /* Is it from an approved Safe prime group ?*/ + if (DH_get_nid((DH *)dh) != NID_undef) { + if (!BN_lshift(two_powN, BN_value_one(), dh->length)) goto err; - if (!BN_is_one(tmp)) - *ret |= DH_CHECK_PUBKEY_INVALID; + if (BN_cmp(two_powN, dh->params.q) < 0) + upper = two_powN; } + if (!ffc_validate_private_key(upper, priv_key, ret)) + goto err; ok = 1; - err: - BN_CTX_end(ctx); - BN_CTX_free(ctx); +err: + BN_free(two_powN); return ok; } + +/* + * FFC pairwise check from SP800-56A R3. + * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency + */ +int dh_check_pairwise(DH *dh) +{ + int ret = 0; + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL; + + if (dh->params.p == NULL + || dh->params.g == NULL + || dh->priv_key == NULL + || dh->pub_key == NULL) + return 0; + + ctx = BN_CTX_new_ex(dh->libctx); + if (ctx == NULL) + goto err; + pub_key = BN_new(); + if (pub_key == NULL) + goto err; + + /* recalculate the public key = (g ^ priv) mod p */ + if (!dh_generate_public_key(ctx, dh, dh->priv_key, pub_key)) + goto err; + /* check it matches the existing pubic_key */ + ret = BN_cmp(pub_key, dh->pub_key) == 0; +err: + BN_free(pub_key); + BN_CTX_free(ctx); + return ret; +} diff --git a/crypto/dh/dh_gen.c b/crypto/dh/dh_gen.c index 3d3bcb22b2..89264e9fa8 100644 --- a/crypto/dh/dh_gen.c +++ b/crypto/dh/dh_gen.c @@ -27,7 +27,7 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator, * TODO(3.0): keygen should be able to use this method to do a FIPS186-4 style * paramgen. */ -int dh_generate_ffc_parameters(OPENSSL_CTX *libctx, DH *dh, int bits, +int dh_generate_ffc_parameters(DH *dh, int bits, int qbits, int gindex, BN_GENCB *cb) { int ret, res; @@ -38,7 +38,8 @@ int dh_generate_ffc_parameters(OPENSSL_CTX *libctx, DH *dh, int bits, qbits = EVP_MD_size(evpmd) * 8; } dh->params.gindex = gindex; - ret = ffc_params_FIPS186_4_generate(libctx, &dh->params, FFC_PARAM_TYPE_DH, + ret = ffc_params_FIPS186_4_generate(dh->libctx, &dh->params, + FFC_PARAM_TYPE_DH, bits, qbits, NULL, &res, cb); if (ret > 0) dh->dirty_cnt++; diff --git a/crypto/dh/dh_group_params.c b/crypto/dh/dh_group_params.c index 4996e854f5..6c057d1f1f 100644 --- a/crypto/dh/dh_group_params.c +++ b/crypto/dh/dh_group_params.c @@ -15,11 +15,16 @@ #include <openssl/bn.h> #include <openssl/objects.h> #include "crypto/bn_dh.h" +#include "crypto/dh.h" -static DH *dh_param_init(int nid, const BIGNUM *p, int32_t nbits) +#ifndef FIPS_MODE +static DH *dh_new_by_nid_with_ctx(OPENSSL_CTX *libctx, int nid); + +static DH *dh_param_init(OPENSSL_CTX *libctx, int nid, const BIGNUM *p, + int32_t nbits) { BIGNUM *q = NULL; - DH *dh = DH_new(); + DH *dh = dh_new_with_ctx(libctx); if (dh == NULL) return NULL; @@ -41,7 +46,7 @@ static DH *dh_param_init(int nid, const BIGNUM *p, int32_t nbits) return dh; } -DH *DH_new_by_nid(int nid) +static DH *dh_new_by_nid_with_ctx(OPENSSL_CTX *libctx, int nid) { /* * The last parameter specified in these fields is @@ -50,35 +55,41 @@ DH *DH_new_by_nid(int nid) */ switch (nid) { case NID_ffdhe2048: - return dh_param_init(nid, &_bignum_ffdhe2048_p, 225); + return dh_param_init(libctx, nid, &_bignum_ffdhe2048_p, 225); case NID_ffdhe3072: - return dh_param_init(nid, &_bignum_ffdhe3072_p, 275); + return dh_param_init(libctx, nid, &_bignum_ffdhe3072_p, 275); case NID_ffdhe4096: - return dh_param_init(nid, &_bignum_ffdhe4096_p, 325); + return dh_param_init(libctx, nid, &_bignum_ffdhe4096_p, 325); case NID_ffdhe6144: - return dh_param_init(nid, &_bignum_ffdhe6144_p, 375); + return dh_param_init(libctx, nid, &_bignum_ffdhe6144_p, 375); case NID_ffdhe8192: - return dh_param_init(nid, &_bignum_ffdhe8192_p, 400); + return dh_param_init(libctx, nid, &_bignum_ffdhe8192_p, 400); #ifndef FIPS_MODE case NID_modp_1536: - return dh_param_init(nid, &_bignum_modp_1536_p, 190); + return dh_param_init(libctx, nid, &_bignum_modp_1536_p, 190); #endif case NID_modp_2048: - return dh_param_init(nid, &_bignum_modp_2048_p, 225); + return dh_param_init(libctx, nid, &_bignum_modp_2048_p, 225); case NID_modp_3072: - return dh_param_init(nid, &_bignum_modp_3072_p, 275); + return dh_param_init(libctx, nid, &_bignum_modp_3072_p, 275); case NID_modp_4096: - return dh_param_init(nid, &_bignum_modp_4096_p, 325); + return dh_param_init(libctx, nid, &_bignum_modp_4096_p, 325); case NID_modp_6144: - return dh_param_init(nid, &_bignum_modp_6144_p, 375); + return dh_param_init(libctx, nid, &_bignum_modp_6144_p, 375); case NID_modp_8192: - return dh_param_init(nid, &_bignum_modp_8192_p, 400); + return dh_param_init(libctx, nid, &_bignum_modp_8192_p, 400); default: - DHerr(DH_F_DH_NEW_BY_NID, DH_R_INVALID_PARAMETER_NID); + DHerr(0, DH_R_INVALID_PARAMETER_NID); return NULL; } } +DH *DH_new_by_nid(int nid) +{ + return dh_new_by_nid_with_ctx(NULL, nid); +} +#endif + int DH_get_nid(DH *dh) { int nid = dh->params.nid; diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c index 0bee75c058..14d35466f1 100644 --- a/crypto/dh/dh_key.c +++ b/crypto/dh/dh_key.c @@ -20,8 +20,7 @@ static int dh_bn_mod_exp(const DH *dh, BIGNUM *r, static int dh_init(DH *dh); static int dh_finish(DH *dh); -int dh_compute_key(OPENSSL_CTX *libctx, unsigned char *key, - const BIGNUM *pub_key, DH *dh) +static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) { BN_CTX *ctx = NULL; BN_MONT_CTX *mont = NULL; @@ -41,7 +40,7 @@ int dh_compute_key(OPENSSL_CTX *libctx, unsigned char *key, return 0; } - ctx = BN_CTX_new_ex(libctx); + ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; BN_CTX_start(ctx); @@ -81,18 +80,21 @@ int dh_compute_key(OPENSSL_CTX *libctx, unsigned char *key, return ret; } -static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) +int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) { - return dh_compute_key(NULL, key, pub_key, dh); +#ifdef FIPS_MODE + return compute_key(key, pub_key, dh); +#else + return dh->meth->compute_key(key, pub_key, dh); +#endif } -int dh_compute_key_padded(OPENSSL_CTX *libctx, unsigned char *key, - const BIGNUM *pub_key, DH *dh) +int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) { int rv, pad; #ifdef FIPS_MODE - rv = dh_compute_key(libctx, key, pub_key, dh); + rv = compute_key(key, pub_key, dh); #else rv = dh->meth->compute_key(key, pub_key, dh); #endif @@ -106,18 +108,6 @@ int dh_compute_key_padded(OPENSSL_CTX *libctx, unsigned char *key, return rv + pad; } -#ifndef FIPS_MODE -int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) -{ - return dh->meth->compute_key(key, pub_key, dh); -} - -int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) -{ - return dh_compute_key_padded(NULL, key, pub_key, dh); -} -#endif - static DH_METHOD dh_ossl = { "OpenSSL DH Method", generate_key, @@ -168,14 +158,46 @@ void DH_set_default_method(const DH_METHOD *meth) { default_DH_method = meth; } +#endif /* FIPS_MODE */ int DH_generate_key(DH *dh) { +#ifdef FIPS_MODE + return generate_key(dh); +#else return dh->meth->generate_key(dh); +#endif } -#endif /* FIPS_MODE */ -static int dh_generate_key(OPENSSL_CTX *libctx, DH *dh) +int dh_generate_public_key(BN_CTX *ctx, DH *dh, const BIGNUM *priv_key, + BIGNUM *pub_key) +{ + int ret = 0; + BIGNUM *prk = BN_new(); + BN_MONT_CTX *mont = NULL; + + if (prk == NULL) + return 0; + + if (dh->flags & DH_FLAG_CACHE_MONT_P) { + mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, + dh->lock, dh->params.p, ctx); + if (mont == NULL) + goto err; + } + BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME); + + /* pub_key = g^priv_key mod p */ + if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p, + ctx, mont)) + goto err; + ret = 1; +err: + BN_clear_free(prk); + return ret; +} + +static int generate_key(DH *dh) { int ok = 0; int generate_new_key = 0; @@ -183,7 +205,6 @@ static int dh_generate_key(OPENSSL_CTX *libctx, DH *dh) unsigned l; #endif BN_CTX *ctx = NULL; - BN_MONT_CTX *mont = NULL; BIGNUM *pub_key = NULL, *priv_key = NULL; if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) { @@ -196,7 +217,7 @@ static int dh_generate_key(OPENSSL_CTX *libctx, DH *dh) return 0; } - ctx = BN_CTX_new_ex(libctx); + ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; @@ -205,23 +226,17 @@ static int dh_generate_key(OPENSSL_CTX *libctx, DH *dh) if (priv_key == NULL) goto err; generate_new_key = 1; - } else + } else { priv_key = dh->priv_key; + } if (dh->pub_key == NULL) { pub_key = BN_new(); if (pub_key == NULL) goto err; - } else + } else { pub_key = dh->pub_key; - - if (dh->flags & DH_FLAG_CACHE_MONT_P) { - mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, - dh->lock, dh->params.p, ctx); - if (!mont) - goto err; } - if (generate_new_key) { /* Is it an approved safe prime ?*/ if (DH_get_nid(dh) != NID_undef) { @@ -274,22 +289,8 @@ static int dh_generate_key(OPENSSL_CTX *libctx, DH *dh) } } - { - BIGNUM *prk = BN_new(); - - if (prk == NULL) - goto err; - BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME); - - /* pub_key = g^priv_key mod p */ - if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p, - ctx, mont)) { - BN_clear_free(prk); - goto err; - } - /* We MUST free prk before any further use of priv_key */ - BN_clear_free(prk); - } + if (!dh_generate_public_key(ctx, dh, priv_key, pub_key)) + goto err; dh->pub_key = pub_key; dh->priv_key = priv_key; @@ -307,11 +308,6 @@ static int dh_generate_key(OPENSSL_CTX *libctx, DH *dh) return ok; } -static int generate_key(DH *dh) -{ - return dh_generate_key(NULL, dh); -} - int dh_buf2key(DH *dh, const unsigned char *buf, size_t len) { int err_reason = DH_R_BN_ERROR; diff --git a/crypto/dh/dh_lib.c b/crypto/dh/dh_lib.c index 0c1cccb5db..e6fc3ef2c5 100644 --- a/crypto/dh/dh_lib.c +++ b/crypto/dh/dh_lib.c @@ -16,6 +16,8 @@ #include "crypto/dh.h" #include "dh_local.h" +static DH *dh_new_intern(ENGINE *engine, OPENSSL_CTX *libctx); + #ifndef FIPS_MODE int DH_set_method(DH *dh, const DH_METHOD *meth) { @@ -36,36 +38,47 @@ int DH_set_method(DH *dh, const DH_METHOD *meth) meth->init(dh); return 1; } -#endif /* !FIPS_MODE */ DH *DH_new(void) { - return DH_new_method(NULL); + return dh_new_intern(NULL, NULL); } DH *DH_new_method(ENGINE *engine) { + return dh_new_intern(engine, NULL); +} +#endif /* !FIPS_MODE */ + +DH *dh_new_with_ctx(OPENSSL_CTX *libctx) +{ + return dh_new_intern(NULL, libctx); +} + +static DH *dh_new_intern(ENGINE *engine, OPENSSL_CTX *libctx) +{ DH *ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE); + DHerr(0, ERR_R_MALLOC_FAILURE); return NULL; } ret->references = 1; ret->lock = CRYPTO_THREAD_lock_new(); if (ret->lock == NULL) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE); + DHerr(0, ERR_R_MALLOC_FAILURE); OPENSSL_free(ret); return NULL; } + ret->libctx = libctx; ret->meth = DH_get_default_method(); #if !defined(FIPS_MODE) && !defined(OPENSSL_NO_ENGINE) ret->flags = ret->meth->flags; /* early default init */ if (engine) { if (!ENGINE_init(engine)) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB); + DHerr(0, ERR_R_ENGINE_LIB); goto err; } ret->engine = engine; @@ -74,7 +87,7 @@ DH *DH_new_method(ENGINE *engine) if (ret->engine) { ret->meth = ENGINE_get_DH(ret->engine); if (ret->meth == NULL) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB); + DHerr(0, ERR_R_ENGINE_LIB); goto err; } } @@ -88,7 +101,7 @@ DH *DH_new_method(ENGINE *engine) #endif /* FIPS_MODE */ if ((ret->meth->init != NULL) && !ret->meth->init(ret)) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_INIT_FAIL); + DHerr(0, ERR_R_INIT_FAIL); goto err; } diff --git a/crypto/dh/dh_local.h b/crypto/dh/dh_local.h index 57d9d3489f..7fefcf76f3 100644 --- a/crypto/dh/dh_local.h +++ b/crypto/dh/dh_local.h @@ -31,6 +31,7 @@ struct dh_st { CRYPTO_EX_DATA ex_data; ENGINE *engine; #endif + OPENSSL_CTX *libctx; const DH_METHOD *meth; CRYPTO_RWLOCK *lock; diff --git a/crypto/dsa/dsa_check.c b/crypto/dsa/dsa_check.c new file mode 100644 index 0000000000..3b86d2dc7a --- /dev/null +++ b/crypto/dsa/dsa_check.c @@ -0,0 +1,85 @@ +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include "internal/cryptlib.h" +#include <openssl/bn.h> +#include "dsa_local.h" +#include "crypto/dsa.h" + +int dsa_check_params(const DSA *dsa, int *ret) +{ + int nid; + /* + * (2b) FFC domain params conform to FIPS-186-4 explicit domain param + * validity tests. + */ + return ffc_params_FIPS186_4_validate(&dsa->params, FFC_PARAM_TYPE_DSA, NULL, + FFC_PARAMS_VALIDATE_ALL, ret, NULL); +} + +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation. + */ +int dsa_check_pub_key(const DSA *dsa, const BIGNUM *pub_key, int *ret) +{ + return ffc_validate_public_key(&dsa->params, pub_key, ret); +} + +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation. + * To only be used with ephemeral FFC public keys generated using the approved + * safe-prime groups. + */ +int dsa_check_pub_key_partial(const DSA *dsa, const BIGNUM *pub_key, int *ret) +{ + return ffc_validate_public_key_partial(&dsa->params, pub_key, ret); +} + +int dsa_check_priv_key(const DSA *dsa, const BIGNUM *priv_key, int *ret) +{ + *ret = 0; + + return (dsa->params.q != NULL + && ffc_validate_private_key(dsa->params.q, priv_key, ret)); +} + +/* + * FFC pairwise check from SP800-56A R3. + * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency + */ +int dsa_check_pairwise(const DSA *dsa) +{ + int ret = 0; + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL; + + if (dsa->params.p == NULL + || dsa->params.g == NULL + || dsa->priv_key == NULL + || dsa->pub_key == NULL) + return 0; + + ctx = BN_CTX_new_ex(dsa->libctx); + if (ctx == NULL) + goto err; + pub_key = BN_new(); + if (pub_key == NULL) + goto err; + + /* recalculate the public key = (g ^ priv) mod p */ + if (!dsa_generate_public_key(ctx, dsa, dsa->priv_key, pub_key)) + goto err; + /* check it matches the existing pubic_key */ + ret = BN_cmp(pub_key, dsa->pub_key) == 0; +err: + BN_free(pub_key); + BN_CTX_free(ctx); + return ret; +} diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c index ac5907c4f8..2148a1a487 100644 --- a/crypto/dsa/dsa_gen.c +++ b/crypto/dsa/dsa_gen.c @@ -23,7 +23,7 @@ #include "crypto/dsa.h" #include "dsa_local.h" -int dsa_generate_ffc_parameters(OPENSSL_CTX *libctx, DSA *dsa, int type, +int dsa_generate_ffc_parameters(DSA *dsa, int type, int pbits, int qbits, int gindex, BN_GENCB *cb) { @@ -37,12 +37,12 @@ int dsa_generate_ffc_parameters(OPENSSL_CTX *libctx, DSA *dsa, int type, dsa->params.gindex = gindex; #ifndef FIPS_MODE if (type == DSA_PARAMGEN_TYPE_FIPS_186_2) - ret = ffc_params_FIPS186_2_generate(libctx, &dsa->params, + ret = ffc_params_FIPS186_2_generate(dsa->libctx, &dsa->params, FFC_PARAM_TYPE_DSA, pbits, qbits, NULL, &res, cb); else #endif - ret = ffc_params_FIPS186_4_generate(libctx, &dsa->params, + ret = ffc_params_FIPS186_4_generate(dsa->libctx, &dsa->params, FFC_PARAM_TYPE_DSA, pbits, qbits, NULL, &res, cb); if (ret > 0) @@ -50,10 +50,10 @@ int dsa_generate_ffc_parameters(OPENSSL_CTX *libctx, DSA *dsa, int type, return ret; } -int dsa_generate_parameters_ctx(OPENSSL_CTX *libctx, DSA *dsa, int bits, - const unsigned char *seed_in, int seed_len, - int *counter_ret, unsigned long *h_ret, - BN_GENCB *cb) +int DSA_generate_parameters_ex(DSA *dsa, int bits, + const unsigned char *seed_in, int seed_len, + int *counter_ret, unsigned long *h_ret, + BN_GENCB *cb) { #ifndef FIPS_MODE if (dsa->meth->dsa_paramgen) @@ -67,15 +67,13 @@ int dsa_generate_parameters_ctx(OPENSSL_CTX *libctx, DSA *dsa, int bits, #ifndef FIPS_MODE /* The old code used FIPS 186-2 DSA Parameter generation */ if (bits <= 1024 && seed_len == 20) { - if (!dsa_generate_ffc_parameters(libctx, dsa, - DSA_PARAMGEN_TYPE_FIPS_186_2, + if (!dsa_generate_ffc_parameters(dsa, DSA_PARAMGEN_TYPE_FIPS_186_2, bits, 160, -1, cb)) return 0; } else #endif { - if (!dsa_generate_ffc_parameters(libctx, dsa, - DSA_PARAMGEN_TYPE_FIPS_186_4, + if (!dsa_generate_ffc_parameters(dsa, DSA_PARAMGEN_TYPE_FIPS_186_4, bits, -1, -1, cb)) return 0; } @@ -86,13 +84,3 @@ int dsa_generate_parameters_ctx(OPENSSL_CTX *libctx, DSA *dsa, int bits, *h_ret = dsa->params.h; return 1; } - -int DSA_generate_parameters_ex(DSA *dsa, int bits, - const unsigned char *seed_in, int seed_len, - int *counter_ret, unsigned long *h_ret, - BN_GENCB *cb) -{ - return dsa_generate_parameters_ctx(NULL, dsa, bits, - seed_in, seed_len, - counter_ret, h_ret, cb); -} diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c index 00e7213b97..c93ea15b76 100644 --- a/crypto/dsa/dsa_key.c +++ b/crypto/dsa/dsa_key.c @@ -20,31 +20,43 @@ #include "crypto/dsa.h" #include "dsa_local.h" -static int dsa_builtin_keygen(OPENSSL_CTX *libctx, DSA *dsa); +static int dsa_builtin_keygen(DSA *dsa); int DSA_generate_key(DSA *dsa) { +#ifndef FIPS_MODE if (dsa->meth->dsa_keygen != NULL) return dsa->meth->dsa_keygen(dsa); - return dsa_builtin_keygen(NULL, dsa); +#endif + return dsa_builtin_keygen(dsa); } -int dsa_generate_key_ctx(OPENSSL_CTX *libctx, DSA *dsa) +int dsa_generate_public_key(BN_CTX *ctx, const DSA *dsa, const BIGNUM *priv_key, + BIGNUM *pub_key) { -#ifndef FIPS_MODE - if (dsa->meth->dsa_keygen != NULL) - return dsa->meth->dsa_keygen(dsa); -#endif - return dsa_builtin_keygen(libctx, dsa); + int ret = 0; + BIGNUM *prk = BN_new(); + + if (prk == NULL) + return 0; + BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME); + + /* pub_key = g ^ priv_key mod p */ + if (!BN_mod_exp(pub_key, dsa->params.g, prk, dsa->params.p, ctx)) + goto err; + ret = 1; +err: + BN_clear_free(prk); + return ret; } -static int dsa_builtin_keygen(OPENSSL_CTX *libctx, DSA *dsa) +static int dsa_builtin_keygen(DSA *dsa) { int ok = 0; BN_CTX *ctx = NULL; BIGNUM *pub_key = NULL, *priv_key = NULL; - if ((ctx = BN_CTX_new_ex(libctx)) == NULL) + if ((ctx = BN_CTX_new_ex(dsa->libctx)) == NULL) goto err; if (dsa->priv_key == NULL) { @@ -65,21 +77,8 @@ static int dsa_builtin_keygen(OPENSSL_CTX *libctx, DSA *dsa) pub_key = dsa->pub_key; } - { - BIGNUM *prk = BN_new(); - - if (prk == NULL) - goto err; - BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME); - - /* pub_key = g ^ priv_key mod p */ - if (!BN_mod_exp(pub_key, dsa->params.g, prk, dsa->params.p, ctx)) { - BN_free(prk); - goto err; - } - /* We MUST free prk before any further use of priv_key */ - BN_free(prk); - } + if (!dsa_generate_public_key(ctx, dsa, priv_key, pub_key)) + goto err; dsa->priv_key = priv_key; dsa->pub_key = pub_key; diff --git a/crypto/dsa/dsa_lib.c b/crypto/dsa/dsa_lib.c index 11f09891b2..4b048d48c5 100644 --- a/crypto/dsa/dsa_lib.c +++ b/crypto/dsa/dsa_lib.c @@ -23,6 +23,8 @@ #include "crypto/dsa.h" #include "crypto/dh.h" /* required by DSA_dup_DH() */ +static DSA *dsa_new_intern(ENGINE *engine, OPENSSL_CTX *libctx); + #ifndef FIPS_MODE int DSA_set_ex_data(DSA *d, int idx, void *arg) @@ -128,29 +130,30 @@ const DSA_METHOD *DSA_get_method(DSA *d) return d->meth; } -static DSA *dsa_new_method(OPENSSL_CTX *libctx, ENGINE *engine) +static DSA *dsa_new_intern(ENGINE *engine, OPENSSL_CTX *libctx) { DSA *ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { - DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_MALLOC_FAILURE); + DSAerr(0, ERR_R_MALLOC_FAILURE); return NULL; } ret->references = 1; ret->lock = CRYPTO_THREAD_lock_new(); if (ret->lock == NULL) { - DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_MALLOC_FAILURE); + DSAerr(0, ERR_R_MALLOC_FAILURE); OPENSSL_free(ret); return NULL; } + ret->libctx = libctx; ret->meth = DSA_get_default_method(); #if !defined(FIPS_MODE) && !defined(OPENSSL_NO_ENGINE) ret->flags = ret->meth->flags & ~DSA_FLAG_NON_FIPS_ALLOW; /* early default init */ if (engine) { if (!ENGINE_init(engine)) { - DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_ENGINE_LIB); + DSAerr(0, ERR_R_ENGINE_LIB); goto err; } ret->engine = engine; @@ -159,7 +162,7 @@ static DSA *dsa_new_method(OPENSSL_CTX *libctx, ENGINE *engine) if (ret->engine) { ret->meth = ENGINE_get_DSA(ret->engine); if (ret->meth == NULL) { - DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_ENGINE_LIB); + DSAerr(0, ERR_R_ENGINE_LIB); goto err; } } @@ -173,7 +176,7 @@ static DSA *dsa_new_method(OPENSSL_CTX *libctx, ENGINE *engine) #endif if ((ret->meth->init != NULL) && !ret->meth->init(ret)) { - DSAerr(DSA_F_DSA_NEW_METHOD, ERR_R_INIT_FAIL); + DSAerr(0, ERR_R_INIT_FAIL); goto err; } @@ -186,13 +189,20 @@ static DSA *dsa_new_method(OPENSSL_CTX *libctx, ENGINE *engine) DSA *DSA_new_method(ENGINE *engine) { - return dsa_new_method(NULL, engine); + return dsa_new_intern(engine, NULL); +} + +DSA *dsa_new_with_ctx(OPENSSL_CTX *libctx) +{ + return dsa_new_intern(NULL, libctx); } +#ifndef FIPS_MODE DSA *DSA_new(void) { - return DSA_new_method(NULL); + return dsa_new_intern(NULL, NULL); } +#endif void DSA_free(DSA *r) { diff --git a/crypto/dsa/dsa_local.h b/crypto/dsa/dsa_local.h index f01b0aae8c..f68ae2d05b 100644 --- a/crypto/dsa/dsa_local.h +++ b/crypto/dsa/dsa_local.h @@ -32,6 +32,7 @@ struct dsa_st { /* functional reference if 'meth' is ENGINE-provided */ ENGINE *engine; CRYPTO_RWLOCK *lock; + OPENSSL_CTX *libctx; /* Provider data */ size_t dirty_cnt; /* If any key material changes, increment this */ @@ -68,5 +69,4 @@ struct dsa_method { int (*dsa_keygen) (DSA *dsa); }; -DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst, - int dlen, DSA *dsa); +DSA_SIG *dsa_do_sign_int(const unsigned char *dgst, int dlen, DSA *dsa); diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c index 6ff22e8c87..a87493a061 100644 --- a/crypto/dsa/dsa_ossl.c +++ b/crypto/dsa/dsa_ossl.c @@ -67,8 +67,7 @@ const DSA_METHOD *DSA_OpenSSL(void) return &openssl_dsa_meth; } -DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst, - int dlen, DSA *dsa) +DSA_SIG *dsa_do_sign_int(const unsigned char *dgst, int dlen, DSA *dsa) { BIGNUM *kinv = NULL; BIGNUM *m, *blind, *blindm, *tmp; @@ -96,7 +95,7 @@ DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst, if (ret->r == NULL || ret->s == NULL) goto err; - ctx = BN_CTX_new_ex(libctx); + ctx = BN_CTX_new_ex(dsa->libctx); if (ctx == NULL) goto err; m = BN_CTX_get(ctx); @@ -186,7 +185,7 @@ DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst, static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) { - return dsa_do_sign_int(NULL, dgst, dlen, dsa); + return dsa_do_sign_int(dgst, dlen, dsa); } static int dsa_sign_setup_no_digest(DSA *dsa, BN_CTX *ctx_in, diff --git a/crypto/dsa/dsa_sign.c b/crypto/dsa/dsa_sign.c index 1ee9272ced..9ef8f30f1e 100644 --- a/crypto/dsa/dsa_sign.c +++ b/crypto/dsa/dsa_sign.c @@ -148,16 +148,16 @@ int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) return 1; } -int dsa_sign_int(OPENSSL_CTX *libctx, int type, const unsigned char *dgst, +int dsa_sign_int(int type, const unsigned char *dgst, int dlen, unsigned char *sig, unsigned int *siglen, DSA *dsa) { DSA_SIG *s; /* legacy case uses the method table */ - if (libctx == NULL || dsa->meth != DSA_get_default_method()) + if (dsa->libctx == NULL || dsa->meth != DSA_get_default_method()) s = DSA_do_sign(dgst, dlen, dsa); else - s = dsa_do_sign_int(libctx, dgst, dlen, dsa); + s = dsa_do_sign_int(dgst, dlen, dsa); if (s == NULL) { *siglen = 0; return 0; @@ -170,7 +170,7 @@ int dsa_sign_int(OPENSSL_CTX *libctx, int type, const unsigned char *dgst, int DSA_sign(int type, const unsigned char *dgst, int dlen, unsigned char *sig, unsigned int *siglen, DSA *dsa) { - return dsa_sign_int(NULL, type, dgst, dlen, sig, siglen, dsa); + return dsa_sign_int(type, dgst, dlen, sig, siglen, dsa); } /* data has already been hashed (probably with SHA or SHA-1). */ diff --git a/crypto/ffc/build.info b/crypto/ffc/build.info index d3314c30d1..c8bc7e9018 100644 --- a/crypto/ffc/build.info +++ b/crypto/ffc/build.info @@ -1,6 +1,7 @@ LIBS=../../libcrypto -$COMMON=ffc_params.c ffc_params_generate.c ffc_key_generate.c +$COMMON=ffc_params.c ffc_params_generate.c ffc_key_generate.c\ + ffc_params_validate.c ffc_key_validate.c SOURCE[../../libcrypto]=$COMMON SOURCE[../../providers/libfips.a]=$COMMON diff --git a/crypto/ffc/ffc_key_generate.c b/crypto/ffc/ffc_key_generate.c index 186245cc87..b8c85480c1 100644 --- a/crypto/ffc/ffc_key_generate.c +++ b/crypto/ffc/ffc_key_generate.c @@ -23,6 +23,19 @@ int ffc_generate_private_key(BN_CTX *ctx, const FFC_PARAMS *params, int N, int s, BIGNUM *priv) { #ifdef FIPS_MODE + return ffc_generate_private_key_fips(ctx, params, N, s, priv); +#else + do { + if (!BN_priv_rand_range_ex(priv, params->q, ctx)) + return 0; + } while (BN_is_zero(priv) || BN_is_one(priv)); + return 1; +#endif /* FIPS_MODE */ +} + +int ffc_generate_private_key_fips(BN_CTX *ctx, const FFC_PARAMS *params, + int N, int s, BIGNUM *priv) +{ int ret = 0; BIGNUM *m, *two_powN = NULL; @@ -51,11 +64,4 @@ int ffc_generate_private_key(BN_CTX *ctx, const FFC_PARAMS *params, err: BN_free(two_powN); return ret; -#else - do { - if (!BN_priv_rand_range_ex(priv, params->q, ctx)) - return 0; - } while (BN_is_zero(priv) || BN_is_one(priv)); - return 1; -#endif /* FIPS_MODE */ } diff --git a/crypto/ffc/ffc_key_validate.c b/crypto/ffc/ffc_key_validate.c new file mode 100644 index 0000000000..a35f52e1b9 --- /dev/null +++ b/crypto/ffc/ffc_key_validate.c @@ -0,0 +1,120 @@ +/* + * Copyright 2019-2020 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/ffc.h" + +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation. + * To only be used with ephemeral FFC public keys generated using the approved + * safe-prime groups. (Checks that the public key is in the range [2, p - 1] + * + * ret contains 0 on success, or error flags (see FFC_ERROR_PUBKEY_TOO_SMALL) + */ +int ffc_validate_public_key_partial(const FFC_PARAMS *params, + const BIGNUM *pub_key, int *ret) +{ + int ok = 0; + BIGNUM *tmp = NULL; + BN_CTX *ctx = NULL; + + *ret = 0; + ctx = BN_CTX_new_ex(NULL); + if (ctx == NULL) + goto err; + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + /* Step(1): Verify pub_key >= 2 */ + if (tmp == NULL + || !BN_set_word(tmp, 1)) + goto err; + if (BN_cmp(pub_key, tmp) <= 0) { + *ret |= FFC_ERROR_PUBKEY_TOO_SMALL; + goto err; + } + /* Step(1): Verify pub_key <= p-2 */ + if (BN_copy(tmp, params->p) == NULL + || !BN_sub_word(tmp, 1)) + goto err; + if (BN_cmp(pub_key, tmp) >= 0) { + *ret |= FFC_ERROR_PUBKEY_TOO_LARGE; + goto err; + } + ok = 1; + err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} + +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation. + */ +int ffc_validate_public_key(const FFC_PARAMS *params, const BIGNUM *pub_key, + int *ret) +{ + int ok = 0; + BIGNUM *tmp = NULL; + BN_CTX *ctx = NULL; + + if (!ffc_validate_public_key_partial(params, pub_key, ret)) + return 0; + + if (params->q != NULL) { + ctx = BN_CTX_new_ex(NULL); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + + /* Check pub_key^q == 1 mod p */ + if (tmp == NULL + || !BN_mod_exp(tmp, pub_key, params->q, params->p, ctx)) + goto err; + if (!BN_is_one(tmp)) { + *ret |= FFC_ERROR_PUBKEY_INVALID; + goto err; + } + } + + ok = 1; + err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} + +/* + * See SP800-56Ar3 Section 5.6.2.1.2: Owner assurance of Private key validity. + * Verifies priv_key is in the range [1..upper-1]. The passed in value of upper + * is normally params->q but can be 2^N for approved safe prime groups. + * Note: This assumes that the domain parameters are valid. + */ +int ffc_validate_private_key(const BIGNUM *upper, const BIGNUM *priv, int *ret) +{ + int ok = 0; + + *ret = 0; + + if (BN_cmp(priv, BN_value_one()) < 0) { + *ret |= FFC_ERROR_PRIVKEY_TOO_SMALL; + goto err; + } + if (BN_cmp(priv, upper) >= 0) { + *ret |= FFC_ERROR_PRIVKEY_TOO_LARGE; + goto err; + } + ok = 1; +err: + return ok; +} diff --git a/crypto/ffc/ffc_params_generate.c b/crypto/ffc/ffc_params_generate.c index 54d5c58e09..cb51bf0e76 100644 --- a/crypto/ffc/ffc_params_generate.c +++ b/crypto/ffc/ffc_params_generate.c @@ -474,10 +474,10 @@ static EVP_MD *fetch_default_md(OPENSSL_CTX *libctx, size_t N) * - FFC_PARAMS_RET_STATUS_UNVERIFIABLE_G if the validation of G succeeded, * but G is unverifiable. */ -int ffc_param_FIPS186_4_gen_verify(OPENSSL_CTX *libctx, FFC_PARAMS *params, - int type, size_t L, size_t N, - const EVP_MD *evpmd, int validate_flags, - int *res, BN_GENCB *cb) +int ffc_params_FIPS186_4_gen_verify(OPENSSL_CTX *libctx, FFC_PARAMS *params, + int type, size_t L, size_t N, + const EVP_MD *evpmd, int validate_flags, + int *res, BN_GENCB *cb) { int ok = FFC_PARAMS_RET_STATUS_FAILED; unsigned char *seed = NULL, *seed_tmp = NULL; @@ -750,10 +750,10 @@ err: return ok; } -int ffc_param_FIPS186_2_gen_verify(OPENSSL_CTX *libctx, FFC_PARAMS *params, - int type, size_t L, size_t N, - const EVP_MD *evpmd, int validate_flags, - int *res, BN_GENCB *cb) +int ffc_params_FIPS186_2_gen_verify(OPENSSL_CTX *libctx, FFC_PARAMS *params, + int type, size_t L, size_t N, + const EVP_MD *evpmd, int validate_flags, + int *res, BN_GENCB *cb) { int ok = FFC_PARAMS_RET_STATUS_FAILED; unsigned char seed[SHA256_DIGEST_LENGTH]; @@ -977,8 +977,8 @@ int ffc_params_FIPS186_4_generate(OPENSSL_CTX *libctx, FFC_PARAMS *params, int type, size_t L, size_t N, const EVP_MD *evpmd, int *res, BN_GENCB *cb) { - return ffc_param_FIPS186_4_gen_verify(libctx, params, type, L, N, evpmd, 0, - res, cb); + return ffc_params_FIPS186_4_gen_verify(libctx, params, type, L, N, evpmd, 0, + res, cb); } /* This should no longer be used in FIPS mode */ @@ -986,14 +986,6 @@ int ffc_params_FIPS186_2_generate(OPENSSL_CTX *libctx, FFC_PARAMS *params, int type, size_t L, size_t N, const EVP_MD *evpmd, int *res, BN_GENCB *cb) { - return ffc_param_FIPS186_2_gen_verify(libctx, params, type, L, N, evpmd, - 0, res, cb); -} - -/* TODO(3.0) - Add this in another PR - just add a stub for now */ -int ffc_params_validate_unverifiable_g(BN_CTX *ctx, BN_MONT_CTX *mont, - const BIGNUM *p, const BIGNUM *q, - const BIGNUM *g, BIGNUM *tmp, int *ret) -{ - return 1; + return ffc_params_FIPS186_2_gen_verify(libctx, params, type, L, N, evpmd, + 0, res, cb); } diff --git a/crypto/ffc/ffc_params_validate.c b/crypto/ffc/ffc_params_validate.c new file mode 100644 index 0000000000..4d0a4d837f --- /dev/null +++ b/crypto/ffc/ffc_params_validate.c @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2020 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Finite Field cryptography (FFC) is used for DSA and DH. + * This file contains methods for validation of FFC parameters. + * It calls the same functions as the generation as the code is very similar. + */ + +#include "internal/ffc.h" + +/* FIPS186-4 A.2.2 Unverifiable partial validation of Generator g */ +int ffc_params_validate_unverifiable_g(BN_CTX *ctx, BN_MONT_CTX *mont, + const BIGNUM *p, const BIGNUM *q, + const BIGNUM *g, BIGNUM *tmp, int *ret) +{ + /* + * A.2.2 Step (1) AND + * A.2.4 Step (2) + * Verify that 2 <= g <= (p - 1) + */ + if (BN_cmp(g, BN_value_one()) <= 0 || BN_cmp(g, p) >= 0) { + *ret |= FFC_ERROR_NOT_SUITABLE_GENERATOR; + return 0; + } + + /* + * A.2.2 Step (2) AND + * A.2.4 Step (3) + * Check g^q mod p = 1 + */ + if (!BN_mod_exp_mont(tmp, g, q, p, ctx, mont)) + return 0; + if (BN_cmp(tmp, BN_value_one()) != 0) { + *ret |= FFC_ERROR_NOT_SUITABLE_GENERATOR; + return 0; + } + return 1; +} + +int ffc_params_FIPS186_4_validate(const FFC_PARAMS *params, int type, + const EVP_MD *evpmd, int validate_flags, + int *res, BN_GENCB *cb) +{ + size_t L, N; + + if (params == NULL || params->p == NULL || params->q == NULL) + return FFC_PARAMS_RET_STATUS_FAILED; + + /* A.1.1.3 Step (1..2) : L = len(p), N = len(q) */ + L = BN_num_bits(params->p); + N = BN_num_bits(params->q); + return ffc_params_FIPS186_4_gen_verify(NULL, (FFC_PARAMS *)params, type, L, N, + evpmd, validate_flags, res, cb); +} + +/* This may be used in FIPS mode to validate deprecated FIPS-186-2 Params */ +int ffc_params_FIPS186_2_validate(const FFC_PARAMS *params, int type, + const EVP_MD *evpmd, int validate_flags, + int *res, BN_GENCB *cb) +{ + size_t L, N; + + if (params->p == NULL || params->q == NULL) { + *res = FFC_CHECK_INVALID_PQ; + return FFC_PARAMS_RET_STATUS_FAILED; + } + + /* A.1.1.3 Step (1..2) : L = len(p), N = len(q) */ + L = BN_num_bits(params->p); + N = BN_num_bits(params->q); + return ffc_params_FIPS186_2_gen_verify(NULL, (FFC_PARAMS *)params, type, L, N, + evpmd, validate_flags, res, cb); +} |