From: Shane Lontis Date: Thu, 6 Feb 2020 12:28:36 +0000 (+1000) Subject: Add FFC param/key generation X-Git-Tag: openssl-3.0.0-alpha1~539 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f11f86f6ec7fb31bde1da2810ac975c032205321;hp=104a733df65dfd8c3dd110de9bd56f6ebfc8f2f6;p=thirdparty%2Fopenssl.git Add FFC param/key generation Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10909) --- diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c index ec589757d0..829cc87464 100644 --- a/crypto/dh/dh_asn1.c +++ b/crypto/dh/dh_asn1.c @@ -85,6 +85,7 @@ DH *d2i_DHxparams(DH **a, const unsigned char **pp, long length) FFC_PARAMS *params; int_dhx942_dh *dhx = NULL; DH *dh = NULL; + dh = DH_new(); if (dh == NULL) return NULL; diff --git a/crypto/dh/dh_gen.c b/crypto/dh/dh_gen.c index 75548592b8..3d3bcb22b2 100644 --- a/crypto/dh/dh_gen.c +++ b/crypto/dh/dh_gen.c @@ -15,19 +15,88 @@ #include #include "internal/cryptlib.h" #include +#include "crypto/dh.h" #include "dh_local.h" +#ifndef FIPS_MODE static int dh_builtin_genparams(DH *ret, int prime_len, int generator, BN_GENCB *cb); +#endif /* FIPS_MODE */ + +/* + * 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 qbits, int gindex, BN_GENCB *cb) +{ + int ret, res; + + if (qbits <= 0) { + const EVP_MD *evpmd = bits >= 2048 ? EVP_sha256() : EVP_sha1(); + + qbits = EVP_MD_size(evpmd) * 8; + } + dh->params.gindex = gindex; + ret = ffc_params_FIPS186_4_generate(libctx, &dh->params, FFC_PARAM_TYPE_DH, + bits, qbits, NULL, &res, cb); + if (ret > 0) + dh->dirty_cnt++; + return ret; +} int DH_generate_parameters_ex(DH *ret, int prime_len, int generator, BN_GENCB *cb) { +#ifdef FIPS_MODE + /* + * Just choose an approved safe prime group. + * The alternative to this is to generate FIPS186-4 domain parameters i.e. + * return dh_generate_ffc_parameters(ret, prime_len, -1, -1, cb); + * As the FIPS186-4 generated params are for backwards compatability, + * the safe prime group should be used as the default. + */ + DH *dh = NULL; + int ok = 0, nid; + + if (generator != 2) + return 0; + + switch (prime_len) { + case 2048: + nid = NID_ffdhe2048; + break; + case 3072: + nid = NID_ffdhe3072; + break; + case 4096: + nid = NID_ffdhe4096; + break; + case 6144: + nid = NID_ffdhe6144; + break; + case 8192: + nid = NID_ffdhe8192; + break; + /* unsupported prime_len */ + default: + return 0; + } + dh = DH_new_by_nid(nid); + if (dh != NULL && ffc_params_copy(&ret->params, &dh->params)) { + ok = 1; + ret->dirty_cnt++; + } + DH_free(dh); + return ok; +#else if (ret->meth->generate_params) return ret->meth->generate_params(ret, prime_len, generator, cb); return dh_builtin_genparams(ret, prime_len, generator, cb); +#endif /* FIPS_MODE */ } +#ifndef FIPS_MODE /*- * We generate DH parameters as follows * find a prime p which is prime_len bits long, @@ -133,3 +202,4 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator, BN_CTX_free(ctx); return ok; } +#endif /* FIPS_MODE */ diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c index 4c5d78a19f..0bee75c058 100644 --- a/crypto/dh/dh_key.c +++ b/crypto/dh/dh_key.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-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 @@ -13,10 +13,7 @@ #include "crypto/bn.h" #include "crypto/dh.h" -#ifndef FIPS_MODE static int generate_key(DH *dh); -#endif /* FIPS_MODE */ - static int dh_bn_mod_exp(const DH *dh, BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); @@ -123,11 +120,7 @@ int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) static DH_METHOD dh_ossl = { "OpenSSL DH Method", -#ifndef FIPS_MODE generate_key, -#else - NULL, /* TODO(3.0) : solve this in a keygen related PR */ -#endif compute_key, dh_bn_mod_exp, dh_init, @@ -160,6 +153,7 @@ static int dh_init(DH *dh) { dh->flags |= DH_FLAG_CACHE_MONT_P; ffc_params_init(&dh->params); + dh->dirty_cnt++; return 1; } @@ -170,7 +164,6 @@ static int dh_finish(DH *dh) } #ifndef FIPS_MODE - void DH_set_default_method(const DH_METHOD *meth) { default_DH_method = meth; @@ -180,27 +173,30 @@ int DH_generate_key(DH *dh) { return dh->meth->generate_key(dh); } +#endif /* FIPS_MODE */ -static int generate_key(DH *dh) +static int dh_generate_key(OPENSSL_CTX *libctx, DH *dh) { int ok = 0; int generate_new_key = 0; +#ifndef FIPS_MODE 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) { - DHerr(DH_F_GENERATE_KEY, DH_R_MODULUS_TOO_LARGE); + DHerr(0, DH_R_MODULUS_TOO_LARGE); return 0; } if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) { - DHerr(DH_F_GENERATE_KEY, DH_R_MODULUS_TOO_SMALL); + DHerr(0, DH_R_MODULUS_TOO_SMALL); return 0; } - ctx = BN_CTX_new(); + ctx = BN_CTX_new_ex(libctx); if (ctx == NULL) goto err; @@ -227,25 +223,52 @@ static int generate_key(DH *dh) } if (generate_new_key) { - if (dh->params.q != NULL) { - do { - if (!BN_priv_rand_range(priv_key, dh->params.q)) - goto err; - } - while (BN_is_zero(priv_key) || BN_is_one(priv_key)); - } else { - /* secret exponent length */ - l = dh->length ? dh->length : BN_num_bits(dh->params.p) - 1; - if (!BN_priv_rand(priv_key, l, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY)) - goto err; + /* Is it an approved safe prime ?*/ + if (DH_get_nid(dh) != NID_undef) { /* - * We handle just one known case where g is a quadratic non-residue: - * for g = 2: p % 8 == 3 + * The safe prime group code sets N = 2*s + * (where s = max security strength supported). + * N = dh->length (N = maximum bit length of private key) */ - if (BN_is_word(dh->params.g, DH_GENERATOR_2) - && !BN_is_bit_set(dh->params.p, 2)) { - /* clear bit 0, since it won't be a secret anyway */ - if (!BN_clear_bit(priv_key, 0)) + if (dh->length == 0 + || dh->params.q == NULL + || dh->length > BN_num_bits(dh->params.q)) + goto err; + if (!ffc_generate_private_key(ctx, &dh->params, dh->length, + dh->length / 2, priv_key)) + goto err; + } else { +#ifdef FIPS_MODE + if (dh->params.q == NULL) + goto err; +#else + if (dh->params.q == NULL) { + /* secret exponent length */ + l = dh->length ? dh->length : BN_num_bits(dh->params.p) - 1; + if (!BN_priv_rand_ex(priv_key, l, BN_RAND_TOP_ONE, + BN_RAND_BOTTOM_ANY, ctx)) + goto err; + /* + * We handle just one known case where g is a quadratic non-residue: + * for g = 2: p % 8 == 3 + */ + if (BN_is_word(dh->params.g, DH_GENERATOR_2) + && !BN_is_bit_set(dh->params.p, 2)) { + /* clear bit 0, since it won't be a secret anyway */ + if (!BN_clear_bit(priv_key, 0)) + goto err; + } + } else +#endif + { + /* + * For FFC FIPS 186-4 keygen + * security strength s = 112, + * Max Private key size N = len(q) + */ + if (!ffc_generate_private_key(ctx, &dh->params, + BN_num_bits(dh->params.q), 112, + priv_key)) goto err; } } @@ -258,6 +281,7 @@ static int generate_key(DH *dh) 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); @@ -273,7 +297,7 @@ static int generate_key(DH *dh) ok = 1; err: if (ok != 1) - DHerr(DH_F_GENERATE_KEY, ERR_R_BN_LIB); + DHerr(0, ERR_R_BN_LIB); if (pub_key != dh->pub_key) BN_free(pub_key); @@ -283,6 +307,10 @@ static int generate_key(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) { @@ -346,4 +374,3 @@ size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out) *pbuf_out = pbuf; return p_size; } -#endif /* FIPS_MODE */ diff --git a/crypto/dh/dh_pmeth.c b/crypto/dh/dh_pmeth.c index 4afedb95f6..38935fd9e2 100644 --- a/crypto/dh/dh_pmeth.c +++ b/crypto/dh/dh_pmeth.c @@ -24,7 +24,7 @@ typedef struct { /* Parameter gen parameters */ int prime_len; int generator; - int use_dsa; + int paramgen_type; int subprime_len; int pad; /* message digest used for parameter generation */ @@ -69,6 +69,7 @@ static int pkey_dh_init(EVP_PKEY_CTX *ctx) static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx) { DH_PKEY_CTX *dctx = ctx->data; + if (dctx != NULL) { OPENSSL_free(dctx->kdf_ukm); ASN1_OBJECT_free(dctx->kdf_oid); @@ -88,7 +89,7 @@ static int pkey_dh_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src) dctx->prime_len = sctx->prime_len; dctx->subprime_len = sctx->subprime_len; dctx->generator = sctx->generator; - dctx->use_dsa = sctx->use_dsa; + dctx->paramgen_type = sctx->paramgen_type; dctx->pad = sctx->pad; dctx->md = sctx->md; dctx->rfc5114_param = sctx->rfc5114_param; @@ -120,7 +121,7 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return 1; case EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN: - if (dctx->use_dsa == 0) + if (dctx->paramgen_type == DH_PARAMGEN_TYPE_GENERATOR) return -2; dctx->subprime_len = p1; return 1; @@ -130,20 +131,20 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return 1; case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR: - if (dctx->use_dsa) + if (dctx->paramgen_type != DH_PARAMGEN_TYPE_GENERATOR) return -2; dctx->generator = p1; return 1; case EVP_PKEY_CTRL_DH_PARAMGEN_TYPE: #ifdef OPENSSL_NO_DSA - if (p1 != 0) + if (p1 != DH_PARAMGEN_TYPE_GENERATOR) return -2; #else if (p1 < 0 || p1 > 2) return -2; #endif - dctx->use_dsa = p1; + dctx->paramgen_type = p1; return 1; case EVP_PKEY_CTRL_DH_RFC5114: @@ -271,33 +272,22 @@ static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, return -2; } -#ifndef OPENSSL_NO_DSA - -extern int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, - const EVP_MD *evpmd, - const unsigned char *seed_in, size_t seed_len, - unsigned char *seed_out, int *counter_ret, - unsigned long *h_ret, BN_GENCB *cb); - -extern int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, - const EVP_MD *evpmd, - const unsigned char *seed_in, - size_t seed_len, int idx, - unsigned char *seed_out, int *counter_ret, - unsigned long *h_ret, BN_GENCB *cb); - -static DSA *dsa_dh_generate(DH_PKEY_CTX *dctx, BN_GENCB *pcb) +static DH *ffc_params_generate(OPENSSL_CTX *libctx, DH_PKEY_CTX *dctx, + BN_GENCB *pcb) { - DSA *ret; + DH *ret; int rv = 0; + int res; int prime_len = dctx->prime_len; int subprime_len = dctx->subprime_len; const EVP_MD *md = dctx->md; - if (dctx->use_dsa > 2) + + if (dctx->paramgen_type > DH_PARAMGEN_TYPE_FIPS_186_4) return NULL; - ret = DSA_new(); + ret = DH_new(); if (ret == NULL) return NULL; + if (subprime_len == -1) { if (prime_len >= 2048) subprime_len = 256; @@ -310,22 +300,29 @@ static DSA *dsa_dh_generate(DH_PKEY_CTX *dctx, BN_GENCB *pcb) else md = EVP_sha1(); } - if (dctx->use_dsa == 1) - rv = dsa_builtin_paramgen(ret, prime_len, subprime_len, md, - NULL, 0, NULL, NULL, NULL, pcb); - else if (dctx->use_dsa == 2) - rv = dsa_builtin_paramgen2(ret, prime_len, subprime_len, md, - NULL, 0, -1, NULL, NULL, NULL, pcb); +# ifndef FIPS_MODE + if (dctx->paramgen_type == DH_PARAMGEN_TYPE_FIPS_186_2) + rv = ffc_params_FIPS186_2_generate(libctx, &ret->params, + FFC_PARAM_TYPE_DH, + prime_len, subprime_len, md, &res, + pcb); + else +# endif + /* For FIPS we always use the DH_PARAMGEN_TYPE_FIPS_186_4 generator */ + if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2) + rv = ffc_params_FIPS186_4_generate(libctx, &ret->params, + FFC_PARAM_TYPE_DH, + prime_len, subprime_len, md, &res, + pcb); if (rv <= 0) { - DSA_free(ret); + DH_free(ret); return NULL; } return ret; } -#endif - -static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) +static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, + EVP_PKEY *pkey) { DH *dh = NULL; DH_PKEY_CTX *dctx = ctx->data; @@ -372,22 +369,17 @@ static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) return 0; evp_pkey_set_cb_translate(pcb, ctx); } -#ifndef OPENSSL_NO_DSA - if (dctx->use_dsa) { - DSA *dsa_dh; - - dsa_dh = dsa_dh_generate(dctx, pcb); +# ifdef FIPS_MODE + dctx->paramgen_type = DH_PARAMGEN_TYPE_FIPS_186_4; +# endif /* FIPS_MODE */ + if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2) { + dh = ffc_params_generate(NULL, dctx, pcb); BN_GENCB_free(pcb); - if (dsa_dh == NULL) - return 0; - dh = DSA_dup_DH(dsa_dh); - DSA_free(dsa_dh); - if (!dh) + if (dh == NULL) return 0; EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh); return 1; } -#endif dh = DH_new(); if (dh == NULL) { BN_GENCB_free(pcb); diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c index 02c2bd8083..aa6b84c091 100644 --- a/crypto/dsa/dsa_gen.c +++ b/crypto/dsa/dsa_gen.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-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 @@ -7,13 +7,6 @@ * https://www.openssl.org/source/license.html */ -/* - * Parameter generation follows the updated Appendix 2.2 for FIPS PUB 186, - * also Appendix 2.2 of FIPS PUB 186-1 (i.e. use SHA as defined in FIPS PUB - * 180-1) - */ -#define xxxHASH EVP_sha1() - #include #include #include "internal/cryptlib.h" @@ -21,598 +14,79 @@ #include #include #include +#include "crypto/dsa.h" #include "dsa_local.h" -int DSA_generate_parameters_ex(DSA *ret, int bits, - const unsigned char *seed_in, int seed_len, - int *counter_ret, unsigned long *h_ret, - BN_GENCB *cb) +int dsa_generate_ffc_parameters(OPENSSL_CTX *libctx, DSA *dsa, int type, + int pbits, int qbits, int gindex, + BN_GENCB *cb) { - if (ret->meth->dsa_paramgen) - return ret->meth->dsa_paramgen(ret, bits, seed_in, seed_len, - counter_ret, h_ret, cb); - else { - const EVP_MD *evpmd = bits >= 2048 ? EVP_sha256() : EVP_sha1(); - size_t qbits = EVP_MD_size(evpmd) * 8; + int ret = 0, res; - return dsa_builtin_paramgen(ret, bits, qbits, evpmd, - seed_in, seed_len, NULL, counter_ret, - h_ret, cb); + if (qbits <= 0) { + const EVP_MD *evpmd = pbits >= 2048 ? EVP_sha256() : EVP_sha1(); + + qbits = EVP_MD_size(evpmd) * 8; } + dsa->params.gindex = gindex; +#ifndef FIPS_MODE + if (type == DSA_PARAMGEN_TYPE_FIPS_186_2) + ret = ffc_params_FIPS186_2_generate(libctx, &dsa->params, + FFC_PARAM_TYPE_DSA, + pbits, qbits, NULL, &res, cb); + else +#endif + ret = ffc_params_FIPS186_4_generate(libctx, &dsa->params, + FFC_PARAM_TYPE_DSA, + pbits, qbits, NULL, &res, cb); + if (ret > 0) + dsa->dirty_cnt++; + return ret; } -int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, - const EVP_MD *evpmd, const unsigned char *seed_in, - size_t seed_len, unsigned char *seed_out, - int *counter_ret, unsigned long *h_ret, BN_GENCB *cb) +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 ok = 0; - unsigned char seed[SHA256_DIGEST_LENGTH]; - unsigned char md[SHA256_DIGEST_LENGTH]; - unsigned char buf[SHA256_DIGEST_LENGTH], buf2[SHA256_DIGEST_LENGTH]; - BIGNUM *r0, *W, *X, *c, *test; - BIGNUM *g = NULL, *q = NULL, *p = NULL; - BN_MONT_CTX *mont = NULL; - int i, k, n = 0, m = 0, qsize = qbits >> 3; - int counter = 0; - int r = 0; - BN_CTX *ctx = NULL; - unsigned int h = 2; - - if (qsize != SHA_DIGEST_LENGTH && qsize != SHA224_DIGEST_LENGTH && - qsize != SHA256_DIGEST_LENGTH) - /* invalid q size */ +#ifndef FIPS_MODE + if (dsa->meth->dsa_paramgen) + return dsa->meth->dsa_paramgen(dsa, bits, seed_in, seed_len, + counter_ret, h_ret, cb); +#endif + if (seed_in != NULL + && !ffc_params_set_validate_params(&dsa->params, seed_in, seed_len, -1)) return 0; - if (evpmd == NULL) { - if (qsize == SHA_DIGEST_LENGTH) - evpmd = EVP_sha1(); - else if (qsize == SHA224_DIGEST_LENGTH) - evpmd = EVP_sha224(); - else - evpmd = EVP_sha256(); - } else { - qsize = EVP_MD_size(evpmd); - } - - if (bits < 512) - bits = 512; - - bits = (bits + 63) / 64 * 64; - - if (seed_in != NULL) { - if (seed_len < (size_t)qsize) { - DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN, DSA_R_SEED_LEN_SMALL); +#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, + bits, 160, -1, cb)) + return 0; + } else +#endif + { + if (!dsa_generate_ffc_parameters(libctx, dsa, + DSA_PARAMGEN_TYPE_FIPS_186_4, + bits, -1, -1, cb)) return 0; - } - if (seed_len > (size_t)qsize) { - /* Only consume as much seed as is expected. */ - seed_len = qsize; - } - memcpy(seed, seed_in, seed_len); - } - - if ((mont = BN_MONT_CTX_new()) == NULL) - goto err; - - if ((ctx = BN_CTX_new()) == NULL) - goto err; - - BN_CTX_start(ctx); - - r0 = BN_CTX_get(ctx); - g = BN_CTX_get(ctx); - W = BN_CTX_get(ctx); - q = BN_CTX_get(ctx); - X = BN_CTX_get(ctx); - c = BN_CTX_get(ctx); - p = BN_CTX_get(ctx); - test = BN_CTX_get(ctx); - - if (test == NULL) - goto err; - - if (!BN_lshift(test, BN_value_one(), bits - 1)) - goto err; - - for (;;) { - for (;;) { /* find q */ - int use_random_seed = (seed_in == NULL); - - /* step 1 */ - if (!BN_GENCB_call(cb, 0, m++)) - goto err; - - if (use_random_seed) { - if (RAND_bytes(seed, qsize) <= 0) - goto err; - } else { - /* If we come back through, use random seed next time. */ - seed_in = NULL; - } - memcpy(buf, seed, qsize); - memcpy(buf2, seed, qsize); - /* precompute "SEED + 1" for step 7: */ - for (i = qsize - 1; i >= 0; i--) { - buf[i]++; - if (buf[i] != 0) - break; - } - - /* step 2 */ - if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL)) - goto err; - if (!EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL)) - goto err; - for (i = 0; i < qsize; i++) - md[i] ^= buf2[i]; - - /* step 3 */ - md[0] |= 0x80; - md[qsize - 1] |= 0x01; - if (!BN_bin2bn(md, qsize, q)) - goto err; - - /* step 4 */ - r = BN_check_prime(q, ctx, cb); - if (r > 0) - break; - if (r != 0) - goto err; - - /* do a callback call */ - /* step 5 */ - } - - if (!BN_GENCB_call(cb, 2, 0)) - goto err; - if (!BN_GENCB_call(cb, 3, 0)) - goto err; - - /* step 6 */ - counter = 0; - /* "offset = 2" */ - - n = (bits - 1) / 160; - - for (;;) { - if ((counter != 0) && !BN_GENCB_call(cb, 0, counter)) - goto err; - - /* step 7 */ - BN_zero(W); - /* now 'buf' contains "SEED + offset - 1" */ - for (k = 0; k <= n; k++) { - /* - * obtain "SEED + offset + k" by incrementing: - */ - for (i = qsize - 1; i >= 0; i--) { - buf[i]++; - if (buf[i] != 0) - break; - } - - if (!EVP_Digest(buf, qsize, md, NULL, evpmd, NULL)) - goto err; - - /* step 8 */ - if (!BN_bin2bn(md, qsize, r0)) - goto err; - if (!BN_lshift(r0, r0, (qsize << 3) * k)) - goto err; - if (!BN_add(W, W, r0)) - goto err; - } - - /* more of step 8 */ - if (!BN_mask_bits(W, bits - 1)) - goto err; - if (!BN_copy(X, W)) - goto err; - if (!BN_add(X, X, test)) - goto err; - - /* step 9 */ - if (!BN_lshift1(r0, q)) - goto err; - if (!BN_mod(c, X, r0, ctx)) - goto err; - if (!BN_sub(r0, c, BN_value_one())) - goto err; - if (!BN_sub(p, X, r0)) - goto err; - - /* step 10 */ - if (BN_cmp(p, test) >= 0) { - /* step 11 */ - r = BN_check_prime(p, ctx, cb); - if (r > 0) - goto end; /* found it */ - if (r != 0) - goto err; - } - - /* step 13 */ - counter++; - /* "offset = offset + n + 1" */ - - /* step 14 */ - if (counter >= 4096) - break; - } - } - end: - if (!BN_GENCB_call(cb, 2, 1)) - goto err; - - /* We now need to generate g */ - /* Set r0=(p-1)/q */ - if (!BN_sub(test, p, BN_value_one())) - goto err; - if (!BN_div(r0, NULL, test, q, ctx)) - goto err; - - if (!BN_set_word(test, h)) - goto err; - if (!BN_MONT_CTX_set(mont, p, ctx)) - goto err; - - for (;;) { - /* g=test^r0%p */ - if (!BN_mod_exp_mont(g, test, r0, p, ctx, mont)) - goto err; - if (!BN_is_one(g)) - break; - if (!BN_add(test, test, BN_value_one())) - goto err; - h++; } - if (!BN_GENCB_call(cb, 3, 1)) - goto err; - - ok = 1; - err: - if (ok) { - BN_free(ret->params.p); - BN_free(ret->params.q); - BN_free(ret->params.g); - ret->params.p = BN_dup(p); - ret->params.q = BN_dup(q); - ret->params.g = BN_dup(g); - ret->dirty_cnt++; - if (ret->params.p == NULL - || ret->params.q == NULL - || ret->params.g == NULL) { - ok = 0; - goto err; - } - if (counter_ret != NULL) - *counter_ret = counter; - if (h_ret != NULL) - *h_ret = h; - if (seed_out) - memcpy(seed_out, seed, qsize); - } - BN_CTX_end(ctx); - BN_CTX_free(ctx); - BN_MONT_CTX_free(mont); - return ok; + if (counter_ret != NULL) + *counter_ret = dsa->params.pcounter; + if (h_ret != NULL) + *h_ret = dsa->params.h; + return 1; } -/* - * This is a parameter generation algorithm for the DSA2 algorithm as - * described in FIPS 186-3. - */ - -int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, - const EVP_MD *evpmd, const unsigned char *seed_in, - size_t seed_len, int idx, unsigned char *seed_out, - 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) { - int ok = -1; - unsigned char *seed = NULL, *seed_tmp = NULL; - unsigned char md[EVP_MAX_MD_SIZE]; - int mdsize; - BIGNUM *r0, *W, *X, *c, *test; - BIGNUM *g = NULL, *q = NULL, *p = NULL; - BN_MONT_CTX *mont = NULL; - int i, k, n = 0, m = 0, qsize = N >> 3; - int counter = 0; - int r = 0; - BN_CTX *ctx = NULL; - EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - unsigned int h = 2; - - if (mctx == NULL) - goto err; - - /* make sure L > N, otherwise we'll get trapped in an infinite loop */ - if (L <= N) { - DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN2, DSA_R_INVALID_PARAMETERS); - goto err; - } - - if (evpmd == NULL) { - if (N == 160) - evpmd = EVP_sha1(); - else if (N == 224) - evpmd = EVP_sha224(); - else - evpmd = EVP_sha256(); - } - - mdsize = EVP_MD_size(evpmd); - /* If unverifiable g generation only don't need seed */ - if (!ret->params.p || !ret->params.q || idx >= 0) { - if (seed_len == 0) - seed_len = mdsize; - - seed = OPENSSL_malloc(seed_len); - - if (seed_out) - seed_tmp = seed_out; - else - seed_tmp = OPENSSL_malloc(seed_len); - - if (seed == NULL || seed_tmp == NULL) - goto err; - - if (seed_in) - memcpy(seed, seed_in, seed_len); - - } - - if ((ctx = BN_CTX_new()) == NULL) - goto err; - - if ((mont = BN_MONT_CTX_new()) == NULL) - goto err; - - BN_CTX_start(ctx); - r0 = BN_CTX_get(ctx); - g = BN_CTX_get(ctx); - W = BN_CTX_get(ctx); - X = BN_CTX_get(ctx); - c = BN_CTX_get(ctx); - test = BN_CTX_get(ctx); - if (test == NULL) - goto err; - - /* if p, q already supplied generate g only */ - if (ret->params.p && ret->params.q) { - p = ret->params.p; - q = ret->params.q; - if (idx >= 0) - memcpy(seed_tmp, seed, seed_len); - goto g_only; - } else { - p = BN_CTX_get(ctx); - q = BN_CTX_get(ctx); - if (q == NULL) - goto err; - } - - if (!BN_lshift(test, BN_value_one(), L - 1)) - goto err; - for (;;) { - for (;;) { /* find q */ - unsigned char *pmd; - /* step 1 */ - if (!BN_GENCB_call(cb, 0, m++)) - goto err; - - if (!seed_in) { - if (RAND_bytes(seed, seed_len) <= 0) - goto err; - } - /* step 2 */ - if (!EVP_Digest(seed, seed_len, md, NULL, evpmd, NULL)) - goto err; - /* Take least significant bits of md */ - if (mdsize > qsize) - pmd = md + mdsize - qsize; - else - pmd = md; - - if (mdsize < qsize) - memset(md + mdsize, 0, qsize - mdsize); - - /* step 3 */ - pmd[0] |= 0x80; - pmd[qsize - 1] |= 0x01; - if (!BN_bin2bn(pmd, qsize, q)) - goto err; - - /* step 4 */ - r = BN_check_prime(q, ctx, cb); - if (r > 0) - break; - if (r != 0) - goto err; - /* Provided seed didn't produce a prime: error */ - if (seed_in) { - ok = 0; - DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN2, DSA_R_Q_NOT_PRIME); - goto err; - } - - /* do a callback call */ - /* step 5 */ - } - /* Copy seed to seed_out before we mess with it */ - if (seed_out) - memcpy(seed_out, seed, seed_len); - - if (!BN_GENCB_call(cb, 2, 0)) - goto err; - if (!BN_GENCB_call(cb, 3, 0)) - goto err; - - /* step 6 */ - counter = 0; - /* "offset = 1" */ - - n = (L - 1) / (mdsize << 3); - - for (;;) { - if ((counter != 0) && !BN_GENCB_call(cb, 0, counter)) - goto err; - - /* step 7 */ - BN_zero(W); - /* now 'buf' contains "SEED + offset - 1" */ - for (k = 0; k <= n; k++) { - /* - * obtain "SEED + offset + k" by incrementing: - */ - for (i = seed_len - 1; i >= 0; i--) { - seed[i]++; - if (seed[i] != 0) - break; - } - - if (!EVP_Digest(seed, seed_len, md, NULL, evpmd, NULL)) - goto err; - - /* step 8 */ - if (!BN_bin2bn(md, mdsize, r0)) - goto err; - if (!BN_lshift(r0, r0, (mdsize << 3) * k)) - goto err; - if (!BN_add(W, W, r0)) - goto err; - } - - /* more of step 8 */ - if (!BN_mask_bits(W, L - 1)) - goto err; - if (!BN_copy(X, W)) - goto err; - if (!BN_add(X, X, test)) - goto err; - - /* step 9 */ - if (!BN_lshift1(r0, q)) - goto err; - if (!BN_mod(c, X, r0, ctx)) - goto err; - if (!BN_sub(r0, c, BN_value_one())) - goto err; - if (!BN_sub(p, X, r0)) - goto err; - - /* step 10 */ - if (BN_cmp(p, test) >= 0) { - /* step 11 */ - r = BN_check_prime(p, ctx, cb); - if (r > 0) - goto end; /* found it */ - if (r != 0) - goto err; - } - - /* step 13 */ - counter++; - /* "offset = offset + n + 1" */ - - /* step 14 */ - if (counter >= (int)(4 * L)) - break; - } - if (seed_in) { - ok = 0; - DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN2, DSA_R_INVALID_PARAMETERS); - goto err; - } - } - end: - if (!BN_GENCB_call(cb, 2, 1)) - goto err; - - g_only: - - /* We now need to generate g */ - /* Set r0=(p-1)/q */ - if (!BN_sub(test, p, BN_value_one())) - goto err; - if (!BN_div(r0, NULL, test, q, ctx)) - goto err; - - if (idx < 0) { - if (!BN_set_word(test, h)) - goto err; - } else - h = 1; - if (!BN_MONT_CTX_set(mont, p, ctx)) - goto err; - - for (;;) { - static const unsigned char ggen[4] = { 0x67, 0x67, 0x65, 0x6e }; - if (idx >= 0) { - md[0] = idx & 0xff; - md[1] = (h >> 8) & 0xff; - md[2] = h & 0xff; - if (!EVP_DigestInit_ex(mctx, evpmd, NULL)) - goto err; - if (!EVP_DigestUpdate(mctx, seed_tmp, seed_len)) - goto err; - if (!EVP_DigestUpdate(mctx, ggen, sizeof(ggen))) - goto err; - if (!EVP_DigestUpdate(mctx, md, 3)) - goto err; - if (!EVP_DigestFinal_ex(mctx, md, NULL)) - goto err; - if (!BN_bin2bn(md, mdsize, test)) - goto err; - } - /* g=test^r0%p */ - if (!BN_mod_exp_mont(g, test, r0, p, ctx, mont)) - goto err; - if (!BN_is_one(g)) - break; - if (idx < 0 && !BN_add(test, test, BN_value_one())) - goto err; - h++; - if (idx >= 0 && h > 0xffff) - goto err; - } - - if (!BN_GENCB_call(cb, 3, 1)) - goto err; - - ok = 1; - err: - if (ok == 1) { - if (p != ret->params.p) { - BN_free(ret->params.p); - ret->params.p = BN_dup(p); - } - if (q != ret->params.q) { - BN_free(ret->params.q); - ret->params.q = BN_dup(q); - } - BN_free(ret->params.g); - ret->params.g = BN_dup(g); - if (ret->params.p == NULL - || ret->params.q == NULL - || ret->params.g == NULL) { - ok = -1; - goto err; - } - ret->dirty_cnt++; - if (counter_ret != NULL) - *counter_ret = counter; - if (h_ret != NULL) - *h_ret = h; - } - OPENSSL_free(seed); - if (seed_out != seed_tmp) - OPENSSL_free(seed_tmp); - BN_CTX_end(ctx); - BN_CTX_free(ctx); - BN_MONT_CTX_free(mont); - EVP_MD_CTX_free(mctx); - return ok; + 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 efc125253e..e0a3c82570 100644 --- a/crypto/dsa/dsa_key.c +++ b/crypto/dsa/dsa_key.c @@ -11,42 +11,53 @@ #include #include "internal/cryptlib.h" #include +#include "crypto/dsa.h" #include "dsa_local.h" -static int dsa_builtin_keygen(DSA *dsa); +static int dsa_builtin_keygen(OPENSSL_CTX *libctx, DSA *dsa); int DSA_generate_key(DSA *dsa) { - if (dsa->meth->dsa_keygen) + if (dsa->meth->dsa_keygen != NULL) return dsa->meth->dsa_keygen(dsa); - return dsa_builtin_keygen(dsa); + return dsa_builtin_keygen(NULL, dsa); } -static int dsa_builtin_keygen(DSA *dsa) +int dsa_generate_key_ctx(OPENSSL_CTX *libctx, DSA *dsa) +{ +#ifndef FIPS_MODE + if (dsa->meth->dsa_keygen != NULL) + return dsa->meth->dsa_keygen(dsa); +#endif + return dsa_builtin_keygen(libctx, dsa); +} + +static int dsa_builtin_keygen(OPENSSL_CTX *libctx, DSA *dsa) { int ok = 0; BN_CTX *ctx = NULL; BIGNUM *pub_key = NULL, *priv_key = NULL; - if ((ctx = BN_CTX_new()) == NULL) + if ((ctx = BN_CTX_new_ex(libctx)) == NULL) goto err; if (dsa->priv_key == NULL) { if ((priv_key = BN_secure_new()) == NULL) goto err; - } else + } else { priv_key = dsa->priv_key; + } - do - if (!BN_priv_rand_range(priv_key, dsa->params.q)) - goto err; - while (BN_is_zero(priv_key)) ; + if (!ffc_generate_private_key(ctx, &dsa->params, BN_num_bits(dsa->params.q), + 112, priv_key)) + goto err; if (dsa->pub_key == NULL) { if ((pub_key = BN_new()) == NULL) goto err; - } else + } else { pub_key = dsa->pub_key; + } { BIGNUM *prk = BN_new(); @@ -55,6 +66,7 @@ static int dsa_builtin_keygen(DSA *dsa) 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; diff --git a/crypto/dsa/dsa_local.h b/crypto/dsa/dsa_local.h index 49b36c5f77..f01b0aae8c 100644 --- a/crypto/dsa/dsa_local.h +++ b/crypto/dsa/dsa_local.h @@ -68,17 +68,5 @@ struct dsa_method { int (*dsa_keygen) (DSA *dsa); }; -int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, - const EVP_MD *evpmd, const unsigned char *seed_in, - size_t seed_len, unsigned char *seed_out, - int *counter_ret, unsigned long *h_ret, - BN_GENCB *cb); - -int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, - const EVP_MD *evpmd, const unsigned char *seed_in, - size_t seed_len, int idx, unsigned char *seed_out, - int *counter_ret, unsigned long *h_ret, - BN_GENCB *cb); - DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst, int dlen, DSA *dsa); diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c index 8de5a364f5..91cb83396d 100644 --- a/crypto/dsa/dsa_ossl.c +++ b/crypto/dsa/dsa_ossl.c @@ -318,6 +318,7 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len, BN_MONT_CTX *mont = NULL; const BIGNUM *r, *s; int ret = -1, i; + if (dsa->params.p == NULL || dsa->params.q == NULL || dsa->params.g == NULL) { @@ -421,6 +422,7 @@ static int dsa_init(DSA *dsa) { dsa->flags |= DSA_FLAG_CACHE_MONT_P; ffc_params_init(&dsa->params); + dsa->dirty_cnt++; return 1; } diff --git a/crypto/dsa/dsa_pmeth.c b/crypto/dsa/dsa_pmeth.c index 24d5dbd3fd..0ab5372bac 100644 --- a/crypto/dsa/dsa_pmeth.c +++ b/crypto/dsa/dsa_pmeth.c @@ -197,7 +197,7 @@ static int pkey_dsa_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) DSA *dsa = NULL; DSA_PKEY_CTX *dctx = ctx->data; BN_GENCB *pcb; - int ret; + int ret, res; if (ctx->pkey_gencb) { pcb = BN_GENCB_new(); @@ -211,8 +211,9 @@ static int pkey_dsa_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) BN_GENCB_free(pcb); return 0; } - ret = dsa_builtin_paramgen(dsa, dctx->nbits, dctx->qbits, dctx->pmd, - NULL, 0, NULL, NULL, NULL, pcb); + ret = ffc_params_FIPS186_4_generate(NULL, &dsa->params, FFC_PARAM_TYPE_DSA, + dctx->nbits, dctx->qbits, dctx->pmd, + &res, pcb); BN_GENCB_free(pcb); if (ret) EVP_PKEY_assign_DSA(pkey, dsa); diff --git a/crypto/ffc/build.info b/crypto/ffc/build.info index 154d3c2510..d3314c30d1 100644 --- a/crypto/ffc/build.info +++ b/crypto/ffc/build.info @@ -1,6 +1,6 @@ LIBS=../../libcrypto -$COMMON=ffc_params.c +$COMMON=ffc_params.c ffc_params_generate.c ffc_key_generate.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 new file mode 100644 index 0000000000..186245cc87 --- /dev/null +++ b/crypto/ffc/ffc_key_generate.c @@ -0,0 +1,61 @@ +/* + * 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" + +/* + * SP800-56Ar3 5.6.1.1.4 Key pair generation by testing candidates. + * Generates a private key in the interval [1, min(2 ^ N - 1, q - 1)]. + * + * ctx must be set up with a libctx (for fips mode). + * params contains the FFC domain parameters p, q and g (for DH or DSA). + * N is the maximum bit length of the generated private key, + * s is the security strength. + * priv_key is the returned private key, + */ +int ffc_generate_private_key(BN_CTX *ctx, const FFC_PARAMS *params, + int N, int s, BIGNUM *priv) +{ +#ifdef FIPS_MODE + int ret = 0; + BIGNUM *m, *two_powN = NULL; + + /* Step (2) : check range of N */ + if (N < 2 * s || N > BN_num_bits(params->q)) + return 0; + + two_powN = BN_new(); + /* 2^N */ + if (two_powN == NULL || !BN_lshift(two_powN, BN_value_one(), N)) + goto err; + + /* Step (5) : M = min(2 ^ N, q) */ + m = (BN_cmp(two_powN, params->q) > 0) ? params->q : two_powN; + do { + /* Steps (3, 4 & 7) : c + 1 = 1 + random[0..2^N - 1] */ + if (!BN_priv_rand_range_ex(priv, two_powN, ctx) + || !BN_add_word(priv, 1)) + goto err; + /* Step (6) : loop if c > M - 2 (i.e. c + 1 >= M) */ + if (BN_cmp(priv, m) < 0) + break; + } while (1); + + ret = 1; +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_params.c b/crypto/ffc/ffc_params.c index 838ace3827..0c9d1a5d39 100644 --- a/crypto/ffc/ffc_params.c +++ b/crypto/ffc/ffc_params.c @@ -17,6 +17,7 @@ void ffc_params_init(FFC_PARAMS *params) { memset(params, 0, sizeof(FFC_PARAMS)); params->pcounter = -1; + params->gindex = FFC_UNVERIFIABLE_GINDEX; } void ffc_params_cleanup(FFC_PARAMS *params) diff --git a/crypto/ffc/ffc_params_generate.c b/crypto/ffc/ffc_params_generate.c new file mode 100644 index 0000000000..c32c33e8b8 --- /dev/null +++ b/crypto/ffc/ffc_params_generate.c @@ -0,0 +1,1001 @@ +/* + * 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 + */ + +/* + * For the prime check.. + * FIPS 186-4 Section C.3 Table C.1 + * Returns the minimum number of Miller Rabin iterations for a L,N pair + * (where L = len(p), N = len(q)) + * L N Min + * 1024 160 40 + * 2048 224 56 + * 2048 256 56 + * 3072 256 64 + * + * BN_check_prime() uses: + * 64 iterations for L <= 2048 OR + * 128 iterations for L > 2048 + * So this satisfies the requirement. + */ + +#include /* memset */ +#include /* SHA_DIGEST_LENGTH */ +#include +#include "crypto/bn.h" +#include "internal/ffc.h" + +/* + * Verify that the passed in L, N pair for DH or DSA is valid. + * Returns 0 if invalid, otherwise it returns the security strength. + */ +static int ffc_validate_LN(size_t L, size_t N, int type) +{ + if (type == FFC_PARAM_TYPE_DH) { + /* Valid DH L,N parameters from SP800-56Ar3 5.5.1 Table 1 */ + if (L == 2048 && (N == 224 || N == 256)) + return 112; + } else if (type == FFC_PARAM_TYPE_DSA) { + /* Valid DSA L,N parameters from FIPS 186-4 Section 4.2 */ + if (L == 1024 && N == 160) + return 80; + if (L == 2048 && (N == 224 || N == 256)) + return 112; + if (L == 2048 && N == 256) + return 112; + if (L == 3072 && N == 256) + return 128; + } + return 0; +} + +/* FIPS186-4 A.2.1 Unverifiable Generation of Generator g */ +static int generate_unverifiable_g(BN_CTX *ctx, BN_MONT_CTX *mont, BIGNUM *g, + BIGNUM *hbn, const BIGNUM *p, + const BIGNUM *e,const BIGNUM *pm1, + int *hret) +{ + int h = 2; + + /* Step (2): choose h (where 1 < h)*/ + if (!BN_set_word(hbn, h)) + return 0; + + for (;;) { + /* Step (3): g = h^e % p */ + if (!BN_mod_exp_mont(g, hbn, e, p, ctx, mont)) + return 0; + /* Step (4): Finish if g > 1 */ + if (BN_cmp(g, BN_value_one()) > 0) + break; + + /* Step (2) Choose any h in the range 1 < h < (p-1) */ + if (!BN_add_word(hbn, 1) || BN_cmp(hbn, pm1) >= 0) + return 0; + ++h; + } + *hret = h; + return 1; +} + +/* + * FIPS186-4 A.2 Generation of canonical generator g. + * + * It requires the following values as input: + * 'evpmd' digest, 'p' prime, 'e' cofactor, gindex and seed. + * tmp is a passed in temporary BIGNUM. + * mont is used in a BN_mod_exp_mont() with a modulus of p. + * Returns a value in g. + */ +static int generate_canonical_g(BN_CTX *ctx, BN_MONT_CTX *mont, + const EVP_MD *evpmd, BIGNUM *g, BIGNUM *tmp, + const BIGNUM *p, const BIGNUM *e, + int gindex, unsigned char *seed, size_t seedlen) +{ + int ret = 0; + int counter = 1; + unsigned char md[EVP_MAX_MD_SIZE]; + EVP_MD_CTX *mctx = NULL; + int mdsize; + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto err; + + mdsize = EVP_MD_size(evpmd); + if (mdsize <= 0) + goto err; + /* + * A.2.3 Step (4) & (5) + * A.2.4 Step (6) & (7) + * counter = 0; counter += 1 + */ + for (counter = 1; counter <= 0xFFFF; ++counter) { + /* + * A.2.3 Step (7) & (8) & (9) + * A.2.4 Step (9) & (10) & (11) + * W = Hash(seed || "ggen" || index || counter) + * g = W^e % p + */ + static const unsigned char ggen[4] = { 0x67, 0x67, 0x65, 0x6e }; + + md[0] = (unsigned char)(gindex & 0xff); + md[1] = (unsigned char)((counter >> 8) & 0xff); + md[2] = (unsigned char)(counter & 0xff); + if (!EVP_DigestInit_ex(mctx, evpmd, NULL) + || !EVP_DigestUpdate(mctx, seed, seedlen) + || !EVP_DigestUpdate(mctx, ggen, sizeof(ggen)) + || !EVP_DigestUpdate(mctx, md, 3) + || !EVP_DigestFinal_ex(mctx, md, NULL) + || (BN_bin2bn(md, mdsize, tmp) == NULL) + || !BN_mod_exp_mont(g, tmp, e, p, ctx, mont)) + return 0; + /* + * A.2.3 Step (10) + * A.2.4 Step (12) + * Found a value for g if (g >= 2) + */ + if (BN_cmp(g, BN_value_one()) > 0) { + ret = 1; + break; /* found g */ + } + } +err: + EVP_MD_CTX_free(mctx); + return ret; +} + +/* Generation of p is the same for FIPS 186-4 & FIPS 186-2 */ +static int generate_p(BN_CTX *ctx, const EVP_MD *evpmd, int max_counter, int n, + unsigned char *buf, size_t buf_len, const BIGNUM *q, + BIGNUM *p, int L, BN_GENCB *cb, int *counter, + int *res) +{ + int ret = -1; + int i, j, k, r; + unsigned char md[EVP_MAX_MD_SIZE]; + int mdsize; + BIGNUM *W, *X, *tmp, *c, *test; + + BN_CTX_start(ctx); + W = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + c = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + if (tmp == NULL) + goto err; + + if (!BN_lshift(test, BN_value_one(), L - 1)) + goto err; + + mdsize = EVP_MD_size(evpmd); + if (mdsize <= 0) + goto err; + + /* A.1.1.2 Step (10) AND + * A.1.1.2 Step (12) + * offset = 1 (this is handled below) + */ + /* + * A.1.1.2 Step (11) AND + * A.1.1.3 Step (13) + */ + for (i = 0; i <= max_counter; i++) { + if ((i != 0) && !BN_GENCB_call(cb, 0, i)) + goto err; + + BN_zero(W); + /* seed_tmp buffer contains "seed + offset - 1" */ + for (j = 0; j <= n; j++) { + /* obtain "seed + offset + j" by incrementing by 1: */ + for (k = (int)buf_len - 1; k >= 0; k--) { + buf[k]++; + if (buf[k] != 0) + break; + } + /* + * A.1.1.2 Step (11.1) AND + * A.1.1.3 Step (13.1) + * tmp = V(j) = Hash((seed + offset + j) % 2^seedlen) + */ + if (!EVP_Digest(buf, buf_len, md, NULL, evpmd, NULL) + || (BN_bin2bn(md, mdsize, tmp) == NULL) + /* + * A.1.1.2 Step (11.2) + * A.1.1.3 Step (13.2) + * W += V(j) * 2^(outlen * j) + */ + || !BN_lshift(tmp, tmp, (mdsize << 3) * j) + || !BN_add(W, W, tmp)) + goto err; + } + + /* + * A.1.1.2 Step (11.3) AND + * A.1.1.3 Step (13.3) + * X = W + 2^(L-1) where W < 2^(L-1) + */ + if (!BN_mask_bits(W, L - 1) + || !BN_copy(X, W) + || !BN_add(X, X, test) + /* + * A.1.1.2 Step (11.4) AND + * A.1.1.3 Step (13.4) + * c = X mod 2q + */ + || !BN_lshift1(tmp, q) + || !BN_mod(c, X, tmp, ctx) + /* + * A.1.1.2 Step (11.5) AND + * A.1.1.3 Step (13.5) + * p = X - (c - 1) + */ + || !BN_sub(tmp, c, BN_value_one()) + || !BN_sub(p, X, tmp)) + goto err; + + /* + * A.1.1.2 Step (11.6) AND + * A.1.1.3 Step (13.6) + * if (p < 2 ^ (L-1)) continue + * This makes sure the top bit is set. + */ + if (BN_cmp(p, test) >= 0) { + /* + * A.1.1.2 Step (11.7) AND + * A.1.1.3 Step (13.7) + * Test if p is prime + * (This also makes sure the bottom bit is set) + */ + r = BN_check_prime(p, ctx, cb); + /* A.1.1.2 Step (11.8) : Return if p is prime */ + if (r > 0) { + *counter = i; + ret = 1; /* return success */ + goto err; + } + if (r != 0) + goto err; + } + /* Step (11.9) : offset = offset + n + 1 is done auto-magically */ + } + /* No prime P found */ + ret = 0; + *res |= FFC_CHECK_P_NOT_PRIME; +err: + BN_CTX_end(ctx); + return ret; +} + +static int generate_q_fips186_4(BN_CTX *ctx, BIGNUM *q, const EVP_MD *evpmd, + int qsize, unsigned char *seed, size_t seedlen, + int generate_seed, int *retm, int *res, + BN_GENCB *cb) +{ + int ret = 0, r; + int m = *retm; + unsigned char md[EVP_MAX_MD_SIZE]; + int mdsize = EVP_MD_size(evpmd); + unsigned char *pmd; + OPENSSL_CTX *libctx = bn_get_lib_ctx(ctx); + + /* find q */ + for (;;) { + if(!BN_GENCB_call(cb, 0, m++)) + goto err; + + /* A.1.1.2 Step (5) : generate seed with size seed_len */ + if (generate_seed + && RAND_bytes_ex(libctx, seed, (int)seedlen) < 0) + goto err; + /* + * A.1.1.2 Step (6) AND + * A.1.1.3 Step (7) + * U = Hash(seed) % (2^(N-1)) + */ + if (!EVP_Digest(seed, seedlen, md, NULL, evpmd, NULL)) + goto err; + /* Take least significant bits of md */ + if (mdsize > qsize) + pmd = md + mdsize - qsize; + else + pmd = md; + if (mdsize < qsize) + memset(md + mdsize, 0, qsize - mdsize); + + /* + * A.1.1.2 Step (7) AND + * A.1.1.3 Step (8) + * q = U + 2^(N-1) + (1 - U %2) (This sets top and bottom bits) + */ + pmd[0] |= 0x80; + pmd[qsize-1] |= 0x01; + if (!BN_bin2bn(pmd, qsize, q)) + goto err; + + /* + * A.1.1.2 Step (8) AND + * A.1.1.3 Step (9) + * Test if q is prime + */ + r = BN_check_prime(q, ctx, cb); + if (r > 0) { + ret = 1; + goto err; + } + /* + * A.1.1.3 Step (9) : If the provided seed didn't produce a prime q + * return an error. + */ + if (!generate_seed) { + *res |= FFC_CHECK_Q_NOT_PRIME; + goto err; + } + if (r != 0) + goto err; + /* A.1.1.2 Step (9) : if q is not prime, try another q */ + } +err: + *retm = m; + return ret; +} + +static int generate_q_fips186_2(BN_CTX *ctx, BIGNUM *q, const EVP_MD *evpmd, + unsigned char *buf, unsigned char *seed, + size_t qsize, int generate_seed, int *retm, + int *res, BN_GENCB *cb) +{ + unsigned char buf2[EVP_MAX_MD_SIZE]; + unsigned char md[EVP_MAX_MD_SIZE]; + int i, r, ret = 0, m = *retm; + OPENSSL_CTX *libctx = bn_get_lib_ctx(ctx); + + /* find q */ + for (;;) { + /* step 1 */ + if (!BN_GENCB_call(cb, 0, m++)) + goto err; + + if (generate_seed && RAND_bytes_ex(libctx, seed, (int)qsize) <= 0) + goto err; + + memcpy(buf, seed, qsize); + memcpy(buf2, seed, qsize); + + /* precompute "SEED + 1" for step 7: */ + for (i = (int)qsize - 1; i >= 0; i--) { + buf[i]++; + if (buf[i] != 0) + break; + } + + /* step 2 */ + if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL)) + goto err; + if (!EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL)) + goto err; + for (i = 0; i < (int)qsize; i++) + md[i] ^= buf2[i]; + + /* step 3 */ + md[0] |= 0x80; + md[qsize - 1] |= 0x01; + if (!BN_bin2bn(md, (int)qsize, q)) + goto err; + + /* step 4 */ + r = BN_check_prime(q, ctx, cb); + if (r > 0) { + /* Found a prime */ + ret = 1; + goto err; + } + if (r != 0) + goto err; /* Exit if error */ + /* Try another iteration if it wasnt prime - was in old code.. */ + generate_seed = 1; + } +err: + *retm = m; + return ret; +} + +static EVP_MD *fetch_default_md(OPENSSL_CTX *libctx, size_t N) +{ + char *name = NULL; + + if (N == 160) + name = "SHA1"; + else if (N == 224) + name = "SHA-224"; + else if (N == 256) + name = "SHA-256"; + + return name != NULL ? EVP_MD_fetch(libctx, name, "") : NULL; +} + +/* + * FIPS 186-4 FFC parameter generation (as defined in Appendix A). + * The same code is used for validation (when validate_flags != 0) + * + * The primes p & q are generated/validated using: + * A.1.1.2 Generation of probable primes p & q using approved hash. + * A.1.1.3 Validation of generated probable primes + * + * Generator 'g' has 2 types in FIPS 186-4: + * (1) A.2.1 unverifiable generation of generator g. + * A.2.2 Assurance of the validity of unverifiable generator g. + * (2) A.2.3 Verifiable Canonical Generation of the generator g. + * A.2.4 Validation for Canonical Generation of the generator g. + * + * Notes: + * (1) is only a partial validation of g, The validation of (2) requires + * the seed and index used during generation as input. + * + * params: used to pass in values for generation and validation. + * For generation of p & q: + * - This is skipped if p & q are passed in. + * - If the seed is passed in then generation of p & q uses this seed (and if + * this fails an error will occur). + * - Otherwise the seed is generated, and values of p & q are generated and + * the value of seed and counter are optionally returned. + * For the generation of g (after the generation of p, q): + * - If the seed has been generated or passed in and a valid gindex is passed + * in then canonical generation of g is used otherwise unverifiable + * generation of g is chosen. + * For validation of p & q: + * - p, q, and the seed and counter used for generation must be passed in. + * For validation of g: + * - For a partial validation : p, q and g are required. + * - For a canonical validation : the gindex and seed used for generation are + * also required. + * type: The key type - FFC_PARAM_TYPE_DSA or FFC_PARAM_TYPE_DH. + * L: is the size of the prime p in bits (e.g 2048) + * N: is the size of the prime q in bits (e.g 256) + * evpmd: is the digest to use, If this value is NULL, then the digest is chosen + * using the value of N. + * validate_flags: + * or generation: FFC_PARAMS_GENERATE. + * For validation one of: + * -FFC_PARAMS_VALIDATE_PQ + * -FFC_PARAMS_VALIDATE_G + * -FFC_PARAMS_VALIDATE_ALL + * res: A returned failure reason (One of FFC_CHECK_XXXX), + * or 0 for general failures. + * cb: A callback (can be NULL) that is called during different phases + * + * Returns: + * - FFC_PARAMS_RET_STATUS_FAILED: if there was an error, or validation failed. + * - FFC_PARAMS_RET_STATUS_SUCCESS if the generation or validation succeeded. + * - 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 ok = FFC_PARAMS_RET_STATUS_FAILED; + unsigned char *seed = NULL, *seed_tmp = NULL; + int mdsize, counter = 0, pcounter = 0, r = 0; + size_t seedlen = 0; + BIGNUM *tmp, *pm1, *e, *test; + BIGNUM *g = NULL, *q = NULL, *p = NULL; + BN_MONT_CTX *mont = NULL; + int n = 0, m = 0, qsize = N >> 3; + int canonical_g = 0, hret = -1; + BN_CTX *ctx = NULL; + EVP_MD_CTX *mctx = NULL; + int generate = (validate_flags == 0); + EVP_MD *evpmd_fetch = NULL; + + *res = 0; + + /* + * A.1.1.2 Step (1) AND + * A.1.1.3 Step (3) + * Check that the L,N pair is an acceptable pair. + */ + if (L <= N || !ffc_validate_LN(L, N, type)) { + *res = FFC_CHECK_BAD_LN_PAIR; + goto err; + } + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto err; + + if (evpmd == NULL) { + evpmd_fetch = fetch_default_md(libctx, N); + evpmd = evpmd_fetch; + } + + mdsize = EVP_MD_size(evpmd); + if (mdsize <= 0) + goto err; + + if ((ctx = BN_CTX_new_ex(libctx)) == NULL) + goto err; + + BN_CTX_start(ctx); + g = BN_CTX_get(ctx); + pm1 = BN_CTX_get(ctx); + e = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + if (tmp == NULL) + goto err; + + seedlen = params->seedlen; + if (seedlen == 0) + seedlen = (size_t)mdsize; + /* If the seed was passed in - use this value as the seed */ + if (params->seed != NULL) + seed = params->seed; + + if (generate) { + /* For generation: p & q must both be NULL or NON-NULL */ + if ((params->p == NULL) != (params->q == NULL)) { + *res = FFC_CHECK_INVALID_PQ; + goto err; + } + } else { + /* Validation of p,q requires seed and counter to be valid */ + if ((validate_flags & FFC_PARAMS_VALIDATE_PQ) != 0) { + if (seed == NULL || params->pcounter < 0) { + *res = FFC_CHECK_MISSING_SEED_OR_COUNTER; + goto err; + } + } + if ((validate_flags & FFC_PARAMS_VALIDATE_G) != 0) { + /* validation of g also requires g to be set */ + if (params->g == NULL) { + *res = FFC_CHECK_INVALID_G; + goto err; + } + } + } + + /* + * If p & q are passed in and + * validate_flags = 0 then skip the generation of PQ. + * validate_flags = VALIDATE_G then also skip the validation of PQ. + */ + if (params->p != NULL && ((validate_flags & FFC_PARAMS_VALIDATE_PQ) == 0)) { + /* p and q already exists so only generate g */ + p = params->p; + q = params->q; + goto g_only; + /* otherwise fall thru to validate p & q */ + } + + /* p & q will be used for generation and validation */ + p = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + if (q == NULL) + goto err; + + /* + * A.1.1.2 Step (2) AND + * A.1.1.3 Step (6) + * Return invalid if seedlen < N + */ + if ((seedlen * 8) < N) { + *res = FFC_CHECK_INVALID_SEED_SIZE; + goto err; + } + + seed_tmp = OPENSSL_malloc(seedlen); + if (seed_tmp == NULL) + goto err; + + if (seed == NULL) { + /* Validation requires the seed to be supplied */ + if (validate_flags) { + *res = FFC_CHECK_MISSING_SEED_OR_COUNTER; + goto err; + } + /* if the seed is not supplied then alloc a seed buffer */ + seed = OPENSSL_malloc(seedlen); + if (seed == NULL) + goto err; + } + + /* A.1.1.2 Step (11): max loop count = 4L - 1 */ + counter = 4 * L - 1; + /* Validation requires the counter to be supplied */ + if (validate_flags) { + /* A.1.1.3 Step (4) : if (counter > (4L -1)) return INVALID */ + if (params->pcounter > counter) { + *res = FFC_CHECK_INVALID_COUNTER; + goto err; + } + counter = params->pcounter; + } + + /* + * A.1.1.2 Step (3) AND + * A.1.1.3 Step (10) + * n = floor(L / hash_outlen) - 1 + */ + n = (L - 1 ) / (mdsize << 3); + + /* Calculate 2^(L-1): Used in step A.1.1.2 Step (11.3) */ + if (!BN_lshift(test, BN_value_one(), L - 1)) + goto err; + + for (;;) { + if (!generate_q_fips186_4(ctx, q, evpmd, qsize, seed, seedlen, + seed != params->seed, &m, res, cb)) + goto err; + /* A.1.1.3 Step (9): Verify that q matches the expected value */ + if (validate_flags && (BN_cmp(q, params->q) != 0)) { + *res = FFC_CHECK_Q_MISMATCH; + goto err; + } + if(!BN_GENCB_call(cb, 2, 0)) + goto err; + if(!BN_GENCB_call(cb, 3, 0)) + goto err; + + memcpy(seed_tmp, seed, seedlen); + r = generate_p(ctx, evpmd, counter, n, seed_tmp, seedlen, q, p, L, cb, + &pcounter, res); + if (r > 0) + break; /* found p */ + if (r < 0) + goto err; + /* + * A.1.1.3 Step (14): + * If we get here we failed to get a p for the given seed. If the + * seed is not random then it needs to fail (as it will always fail). + */ + if (seed == params->seed) { + *res = FFC_CHECK_P_NOT_PRIME; + goto err; + } + } + if(!BN_GENCB_call(cb, 2, 1)) + goto err; + /* + * Gets here if we found p. + * A.1.1.3 Step (14): return error if i != counter OR computed_p != known_p. + */ + if (validate_flags && (pcounter != counter || (BN_cmp(p, params->p) != 0))) + goto err; + + /* If validating p & q only then skip the g validation test */ + if ((validate_flags & FFC_PARAMS_VALIDATE_ALL) == FFC_PARAMS_VALIDATE_PQ) + goto pass; +g_only: + if ((mont = BN_MONT_CTX_new()) == NULL) + goto err; + if (!BN_MONT_CTX_set(mont, p, ctx)) + goto err; + + if (((validate_flags & FFC_PARAMS_VALIDATE_G) != 0) + && !ffc_params_validate_unverifiable_g(ctx, mont, p, q, params->g, + tmp, res)) + goto err; + + /* + * A.2.1 Step (1) AND + * A.2.3 Step (3) AND + * A.2.4 Step (5) + * e = (p - 1) / q (i.e- Cofactor 'e' is given by p = q * e + 1) + */ + if (!(BN_sub(pm1, p, BN_value_one()) && BN_div(e, NULL, pm1, q, ctx))) + goto err; + + /* Canonical g requires a seed and index to be set */ + if ((seed != NULL) && (params->gindex != FFC_UNVERIFIABLE_GINDEX)) { + canonical_g = 1; + if (!generate_canonical_g(ctx, mont, evpmd, g, tmp, p, e, + params->gindex, seed, seedlen)) { + *res = FFC_CHECK_INVALID_G; + goto err; + } + /* A.2.4 Step (13): Return valid if computed_g == g */ + if (validate_flags && BN_cmp(g, params->g) != 0) { + *res = FFC_CHECK_G_MISMATCH; + goto err; + } + } else if (generate) { + if (!generate_unverifiable_g(ctx, mont, g, tmp, p, e, pm1, &hret)) + goto err; + } + + if (!BN_GENCB_call(cb, 3, 1)) + goto err; + + if (generate) { + if (p != params->p) { + BN_free(params->p); + params->p = BN_dup(p); + } + if (q != params->q) { + BN_free(params->q); + params->q = BN_dup(q); + } + if (g != params->g) { + BN_free(params->g); + params->g = BN_dup(g); + } + if (params->p == NULL || params->q == NULL || params->g == NULL) + goto err; + if (!ffc_params_set_validate_params(params, seed, seedlen, pcounter)) + goto err; + params->h = hret; + } +pass: + if ((validate_flags & FFC_PARAMS_VALIDATE_G) != 0 && (canonical_g == 0)) + /* Return for the case where g is partially valid */ + ok = FFC_PARAMS_RET_STATUS_UNVERIFIABLE_G; + else + ok = FFC_PARAMS_RET_STATUS_SUCCESS; +err: + if (seed != params->seed) + OPENSSL_free(seed); + OPENSSL_free(seed_tmp); + if (ctx) + BN_CTX_end(ctx); + BN_CTX_free(ctx); + BN_MONT_CTX_free(mont); + EVP_MD_free(evpmd_fetch); + EVP_MD_CTX_free(mctx); + 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 ok = FFC_PARAMS_RET_STATUS_FAILED; + unsigned char seed[SHA256_DIGEST_LENGTH]; + unsigned char buf[SHA256_DIGEST_LENGTH]; + BIGNUM *r0, *test, *tmp, *g = NULL, *q = NULL, *p = NULL; + BN_MONT_CTX *mont = NULL; + size_t qsize = N >> 3; + int n = 0, m = 0; + int counter = 0, pcounter = 0, use_random_seed; + int rv; + BN_CTX *ctx = NULL; + int hret = -1; + int generate = (validate_flags == 0); + unsigned char *seed_in = params->seed; + size_t seed_len = params->seedlen; + EVP_MD *evpmd_fetch = NULL; + + *res = 0; +#ifdef FIPS_MODE + /* + * FIPS 186-4 states that validation can only be done for this pair. + * (Even though the original spec allowed L = 512 + 64*j (j = 0.. 8)) + */ + if (L != 1024 || N != 160) { + *res = FFC_CHECK_BAD_LN_PAIR; + return FFC_PARAMS_RET_STATUS_FAILED; + } +#endif + if (qsize != SHA_DIGEST_LENGTH + && qsize != SHA224_DIGEST_LENGTH + && qsize != SHA256_DIGEST_LENGTH) { + /* invalid q size */ + *res = FFC_CHECK_INVALID_Q_VALUE; + return FFC_PARAMS_RET_STATUS_FAILED; + } + + if (evpmd == NULL) { + evpmd_fetch = fetch_default_md(libctx, qsize * 8); + evpmd = evpmd_fetch; + } else { + rv = EVP_MD_size(evpmd); + if (rv <= 0) + return 0; + qsize = (size_t)rv; + } + + if (L < 512) + L = 512; + + L = (L + 63) / 64 * 64; + + if (seed_in != NULL) { + if (seed_len < qsize) { + *res = FFC_CHECK_INVALID_SEED_SIZE; + return 0; + } + if (seed_len > qsize) { + /* Only consume as much seed as is expected. */ + seed_len = qsize; + } + memcpy(seed, seed_in, seed_len); + } + + ctx = BN_CTX_new_ex(libctx); + if (ctx == NULL) + goto err; + + BN_CTX_start(ctx); + + r0 = BN_CTX_get(ctx); + g = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + p = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + if (test == NULL) + goto err; + + if (!BN_lshift(test, BN_value_one(), L - 1)) + goto err; + + if (generate) { + /* For generation: p & q must both be NULL or NON-NULL */ + if ((params->p != NULL) != (params->q != NULL)) { + *res = FFC_CHECK_INVALID_PQ; + goto err; + } + } else { + if ((validate_flags & FFC_PARAMS_VALIDATE_PQ) != 0) { + /* Validation of p,q requires seed and counter to be valid */ + if (seed_in == NULL || params->pcounter < 0) { + *res = FFC_CHECK_MISSING_SEED_OR_COUNTER; + goto err; + } + } + if ((validate_flags & FFC_PARAMS_VALIDATE_G) != 0) { + /* validation of g also requires g to be set */ + if (params->g == NULL) { + *res = FFC_CHECK_INVALID_G; + goto err; + } + } + } + + if (params->p != NULL && ((validate_flags & FFC_PARAMS_VALIDATE_PQ) == 0)) { + /* p and q already exists so only generate g */ + p = params->p; + q = params->q; + goto g_only; + /* otherwise fall thru to validate p and q */ + } + + use_random_seed = (seed_in == NULL); + for (;;) { + if (!generate_q_fips186_2(ctx, q, evpmd, buf, seed, qsize, + use_random_seed, &m, res, cb)) + goto err; + + if (!BN_GENCB_call(cb, 2, 0)) + goto err; + if (!BN_GENCB_call(cb, 3, 0)) + goto err; + + /* step 6 */ + n = (L - 1) / 160; + counter = 4 * L - 1; /* Was 4096 */ + /* Validation requires the counter to be supplied */ + if (validate_flags) { + if (params->pcounter > counter) { + *res = FFC_CHECK_INVALID_COUNTER; + goto err; + } + counter = params->pcounter; + } + + rv = generate_p(ctx, evpmd, counter, n, buf, qsize, q, p, L, cb, + &pcounter, res); + if (rv > 0) + break; /* found it */ + if (rv == -1) + goto err; + /* This is what the old code did - probably not a good idea! */ + use_random_seed = 1; + } + + if (!BN_GENCB_call(cb, 2, 1)) + goto err; + + if (validate_flags) { + if (pcounter != counter) { + *res = FFC_CHECK_COUNTER_MISMATCH; + goto err; + } + if (BN_cmp(p, params->p) != 0) { + *res = FFC_CHECK_P_MISMATCH; + goto err; + } + } + /* If validating p & q only then skip the g validation test */ + if ((validate_flags & FFC_PARAMS_VALIDATE_ALL) == FFC_PARAMS_VALIDATE_PQ) + goto pass; +g_only: + if ((mont = BN_MONT_CTX_new()) == NULL) + goto err; + if (!BN_MONT_CTX_set(mont, p, ctx)) + goto err; + + if (generate) { + /* We now need to generate g */ + /* set test = p - 1 */ + if (!BN_sub(test, p, BN_value_one())) + goto err; + /* Set r0 = (p - 1) / q */ + if (!BN_div(r0, NULL, test, q, ctx)) + goto err; + if (!generate_unverifiable_g(ctx, mont, g, tmp, p, r0, test, &hret)) + goto err; + } else if (((validate_flags & FFC_PARAMS_VALIDATE_G) != 0) + && !ffc_params_validate_unverifiable_g(ctx, mont, p, q, + params->g, tmp, res)) { + goto err; + } + + if (!BN_GENCB_call(cb, 3, 1)) + goto err; + + if (generate) { + if (p != params->p) { + BN_free(params->p); + params->p = BN_dup(p); + } + if (q != params->q) { + BN_free(params->q); + params->q = BN_dup(q); + } + if (g != params->g) { + BN_free(params->g); + params->g = BN_dup(g); + } + if (params->p == NULL || params->q == NULL || params->g == NULL) + goto err; + if (!ffc_params_set_validate_params(params, seed, qsize, pcounter)) + goto err; + params->h = hret; + } +pass: + if ((validate_flags & FFC_PARAMS_VALIDATE_G) != 0) + ok = FFC_PARAMS_RET_STATUS_UNVERIFIABLE_G; + else + ok = FFC_PARAMS_RET_STATUS_SUCCESS; +err: + if (ctx != NULL) + BN_CTX_end(ctx); + BN_CTX_free(ctx); + EVP_MD_free(evpmd_fetch); + BN_MONT_CTX_free(mont); + return ok; +} + +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); +} + +/* This should no longer be used in FIPS mode */ +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; +} diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod index 629c4190f6..8334cfc110 100644 --- a/doc/man3/EVP_PKEY_CTX_ctrl.pod +++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod @@ -390,19 +390,37 @@ SHA-256 is selected to match the bit length of B above. The EVP_PKEY_CTX_set_dh_paramgen_prime_len() macro sets the length of the DH prime parameter B

for DH parameter generation. If this macro is not called -then 1024 is used. Only accepts lengths greater than or equal to 256. +then 2048 is used. Only accepts lengths greater than or equal to 256. The EVP_PKEY_CTX_set_dh_paramgen_subprime_len() macro sets the length of the DH optional subprime parameter B for DH parameter generation. The default is 256 if the prime is at least 2048 bits long or 160 otherwise. The DH -paramgen type must have been set to x9.42. +paramgen type must have been set to B or +B. The EVP_PKEY_CTX_set_dh_paramgen_generator() macro sets DH generator to B for DH parameter generation. If not specified 2 is used. The EVP_PKEY_CTX_set_dh_paramgen_type() macro sets the key type for DH -parameter generation. Use 0 for PKCS#3 DH and 1 for X9.42 DH. -The default is 0. +parameter generation. The supported parameters are: + +=over 4 + +=item B + +Uses a generator g (PKCS#3 format). + +=item B + +FIPS186-2 FFC parameter generator (X9.42 DH). + +=item B + +FIPS186-4 FFC parameter generator. + +=back + +The default is B. The EVP_PKEY_CTX_set_dh_pad() function sets the DH padding mode. If B is 1 the shared secret is padded with zeros up to the size of the DH diff --git a/include/crypto/dh.h b/include/crypto/dh.h index 1e856101f3..2b48b5d905 100644 --- a/include/crypto/dh.h +++ b/include/crypto/dh.h @@ -10,6 +10,9 @@ #include #include "internal/ffc.h" +int dh_generate_ffc_parameters(OPENSSL_CTX *libctx, DH *dh, int bits, + int qbits, int gindex, BN_GENCB *cb); + int dh_compute_key(OPENSSL_CTX *ctx, unsigned char *key, const BIGNUM *pub_key, DH *dh); int dh_compute_key_padded(OPENSSL_CTX *ctx, unsigned char *key, diff --git a/include/crypto/dsa.h b/include/crypto/dsa.h index 041ebd4f7f..1865fe0f77 100644 --- a/include/crypto/dsa.h +++ b/include/crypto/dsa.h @@ -9,7 +9,19 @@ #include +#define DSA_PARAMGEN_TYPE_FIPS_186_2 1 /* Use legacy FIPS186-2 standard */ +#define DSA_PARAMGEN_TYPE_FIPS_186_4 2 /* Use FIPS186-4 standard */ + +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_ffc_parameters(OPENSSL_CTX *libctx, DSA *dsa, int type, + int pbits, int qbits, int gindex, + BN_GENCB *cb); + int dsa_sign_int(OPENSSL_CTX *libctx, int type, const unsigned char *dgst, int dlen, unsigned char *sig, unsigned int *siglen, DSA *dsa); - +int dsa_generate_key_ctx(OPENSSL_CTX *libctx, DSA *dsa); const unsigned char *dsa_algorithmidentifier_encoding(int md_nid, size_t *len); diff --git a/include/internal/ffc.h b/include/internal/ffc.h index 1ec980f9d0..75df3a1ffd 100644 --- a/include/internal/ffc.h +++ b/include/internal/ffc.h @@ -11,6 +11,45 @@ # define OSSL_INTERNAL_FFC_H # include +# include +# include /* Uses Error codes from DH */ + +/* Default value for gindex when canonical generation of g is not used */ +# define FFC_UNVERIFIABLE_GINDEX -1 + +/* The different types of FFC keys */ +# define FFC_PARAM_TYPE_DSA 0 +# define FFC_PARAM_TYPE_DH 1 + +/* Return codes for generation and validation of FFC parameters */ +#define FFC_PARAMS_RET_STATUS_FAILED 0 +#define FFC_PARAMS_RET_STATUS_SUCCESS 1 +/* Returned if validating and g is only partially verifiable */ +#define FFC_PARAMS_RET_STATUS_UNVERIFIABLE_G 2 + +/* Validation flags */ +# define FFC_PARAMS_GENERATE 0x00 +# define FFC_PARAMS_VALIDATE_PQ 0x01 +# define FFC_PARAMS_VALIDATE_G 0x02 +# define FFC_PARAMS_VALIDATE_ALL (FFC_PARAMS_VALIDATE_PQ | FFC_PARAMS_VALIDATE_G) + +# define FFC_CHECK_P_NOT_PRIME DH_CHECK_P_NOT_PRIME +# define FFC_CHECK_P_NOT_SAFE_PRIME DH_CHECK_P_NOT_SAFE_PRIME +# define FFC_CHECK_UNKNOWN_GENERATOR DH_UNABLE_TO_CHECK_GENERATOR +# define FFC_CHECK_NOT_SUITABLE_GENERATOR DH_NOT_SUITABLE_GENERATOR +# define FFC_CHECK_Q_NOT_PRIME DH_CHECK_Q_NOT_PRIME +# define FFC_CHECK_INVALID_Q_VALUE DH_CHECK_INVALID_Q_VALUE +# define FFC_CHECK_INVALID_J_VALUE DH_CHECK_INVALID_J_VALUE +# define FFC_CHECK_BAD_LN_PAIR 0x00080 +# define FFC_CHECK_INVALID_SEED_SIZE 0x00100 +# define FFC_CHECK_MISSING_SEED_OR_COUNTER 0x00200 +# define FFC_CHECK_INVALID_G 0x00400 +# define FFC_CHECK_INVALID_PQ 0x00800 +# define FFC_CHECK_INVALID_COUNTER 0x01000 +# define FFC_CHECK_P_MISMATCH 0x02000 +# define FFC_CHECK_Q_MISMATCH 0x04000 +# define FFC_CHECK_G_MISMATCH 0x08000 +# define FFC_CHECK_COUNTER_MISMATCH 0x10000 /* * Finite field cryptography (FFC) domain parameters are used by DH and DSA. @@ -33,6 +72,12 @@ typedef struct ffc_params_st { int pcounter; int nid; /* The identity of a named group */ + /* + * Required for FIPS186_4 generation & validation of canonical g. + * It uses unverifiable g if this value is -1. + */ + int gindex; + int h; /* loop counter for unverifiable g */ } FFC_PARAMS; void ffc_params_init(FFC_PARAMS *params); @@ -55,4 +100,28 @@ int ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q); int ffc_params_print(BIO *bp, const FFC_PARAMS *ffc, int indent); #endif /* FIPS_MODE */ + +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); +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); + +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_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_generate_private_key(BN_CTX *ctx, const FFC_PARAMS *params, + int N, int s, BIGNUM *priv); + +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); + #endif /* OSSL_INTERNAL_FFC_H */ diff --git a/include/openssl/dh.h b/include/openssl/dh.h index ebcbc15505..3040bc03a6 100644 --- a/include/openssl/dh.h +++ b/include/openssl/dh.h @@ -96,6 +96,11 @@ DECLARE_ASN1_ITEM(DHparams) */ # define DH_CHECK_P_NOT_STRONG_PRIME DH_CHECK_P_NOT_SAFE_PRIME +/* DH parameter generation types used by EVP_PKEY_CTX_set_dh_paramgen_type() */ +# define DH_PARAMGEN_TYPE_GENERATOR 0 /* Use a generator g */ +# define DH_PARAMGEN_TYPE_FIPS_186_2 1 /* Use legacy FIPS186-2 standard */ +# define DH_PARAMGEN_TYPE_FIPS_186_4 2 /* Use FIPS186-4 standard */ + # define d2i_DHparams_fp(fp,x) \ (DH *)ASN1_d2i_fp((char *(*)())DH_new, \ (char *(*)())d2i_DHparams, \