From f11f86f6ec7fb31bde1da2810ac975c032205321 Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Thu, 6 Feb 2020 22:28:36 +1000 Subject: Add FFC param/key generation Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10909) --- crypto/dh/dh_asn1.c | 1 + crypto/dh/dh_gen.c | 70 ++++++++++++++++++++++++++++++++++++++++ crypto/dh/dh_key.c | 91 ++++++++++++++++++++++++++++++++++------------------ crypto/dh/dh_pmeth.c | 84 ++++++++++++++++++++++-------------------------- 4 files changed, 168 insertions(+), 78 deletions(-) (limited to 'crypto/dh') diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c index ec58975..829cc87 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 7554859..3d3bcb2 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 4c5d78a..0bee75c 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 4afedb9..38935fd 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); -- cgit v1.1