[openssl] master update

shane.lontis at oracle.com shane.lontis at oracle.com
Fri Jan 24 04:11:18 UTC 2020


The branch master has been updated
       via  dc8de3e6f1eed18617dc42d41dec6c6566c2ac0c (commit)
      from  21d08b9ee9c0f7fabcad27b5d0b0c8c16f7dd1e9 (commit)


- Log -----------------------------------------------------------------
commit dc8de3e6f1eed18617dc42d41dec6c6566c2ac0c
Author: Shane Lontis <shane.lontis at oracle.com>
Date:   Fri Jan 24 14:09:33 2020 +1000

    Modify DSA and DH keys to use a shared FFC_PARAMS struct
    
    This is required in order to share code for FIPS related parameter generation and validation routinues.
    Note the 'counter' field is now stored as a integer (as that is the form required for generation/validation functions).
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10860)

-----------------------------------------------------------------------

Summary of changes:
 crypto/build.info               |   3 +-
 crypto/dh/dh_ameth.c            |  93 +++----------------
 crypto/dh/dh_asn1.c             |  67 ++++++++------
 crypto/dh/dh_check.c            |  41 +++++----
 crypto/dh/dh_gen.c              |   8 +-
 crypto/dh/dh_key.c              |  30 ++++---
 crypto/dh/dh_lib.c              |  56 +++++-------
 crypto/dh/dh_local.h            |  14 +--
 crypto/dh/dh_rfc5114.c          |   8 +-
 crypto/dh/dh_rfc7919.c          |  22 ++---
 crypto/dsa/dsa_ameth.c          |  62 +++++--------
 crypto/dsa/dsa_asn1.c           |  18 ++--
 crypto/dsa/dsa_gen.c            |  44 ++++-----
 crypto/dsa/dsa_key.c            |   4 +-
 crypto/dsa/dsa_lib.c            |  79 ++++++-----------
 crypto/dsa/dsa_local.h          |   5 +-
 crypto/dsa/dsa_ossl.c           |  86 ++++++++++--------
 crypto/dsa/dsa_sign.c           |   2 +-
 crypto/{hmac => ffc}/build.info |   4 +-
 crypto/ffc/ffc_params.c         | 191 ++++++++++++++++++++++++++++++++++++++++
 include/crypto/dh.h             |   2 +
 include/internal/ffc.h          |  57 ++++++++++++
 22 files changed, 519 insertions(+), 377 deletions(-)
 copy crypto/{hmac => ffc}/build.info (52%)
 create mode 100644 crypto/ffc/ffc_params.c
 create mode 100644 include/internal/ffc.h

diff --git a/crypto/build.info b/crypto/build.info
index daa26b8ed4..6906c54db2 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -5,7 +5,8 @@ SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 conf \
         md2 md4 md5 sha mdc2 hmac ripemd whrlpool poly1305 \
         siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \
         seed sm4 chacha modes bn ec rsa dsa dh sm2 dso engine \
-        err comp ocsp cms ts srp cmac ct async ess crmf cmp serializer
+        err comp ocsp cms ts srp cmac ct async ess crmf cmp serializer \
+        ffc
 
 LIBS=../libcrypto
 
diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index 174bd04cef..fd241831dc 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -282,7 +282,7 @@ static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype)
     else
         pub_key = NULL;
 
-    if (x->p == NULL || (ptype == 2 && priv_key == NULL)
+    if (x->params.p == NULL || (ptype == 2 && priv_key == NULL)
             || (ptype > 0 && pub_key == NULL)) {
         reason = ERR_R_PASSED_NULL_PARAMETER;
         goto err;
@@ -296,7 +296,7 @@ static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype)
         ktype = "DH Parameters";
 
     if (!BIO_indent(bp, indent, 128)
-            || BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0)
+            || BIO_printf(bp, "%s: (%d bit)\n", ktype, DH_bits(x)) <= 0)
         goto err;
     indent += 4;
 
@@ -305,35 +305,9 @@ static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype)
     if (!ASN1_bn_print(bp, "public-key:", pub_key, NULL, indent))
         goto err;
 
-    if (!ASN1_bn_print(bp, "prime:", x->p, NULL, indent))
+    if (!ffc_params_print(bp, &x->params, indent))
         goto err;
-    if (!ASN1_bn_print(bp, "generator:", x->g, NULL, indent))
-        goto err;
-    if (x->q && !ASN1_bn_print(bp, "subgroup order:", x->q, NULL, indent))
-        goto err;
-    if (x->j && !ASN1_bn_print(bp, "subgroup factor:", x->j, NULL, indent))
-        goto err;
-    if (x->seed) {
-        int i;
 
-        if (!BIO_indent(bp, indent, 128)
-                || BIO_puts(bp, "seed:") <= 0)
-            goto err;
-        for (i = 0; i < x->seedlen; i++) {
-            if ((i % 15) == 0) {
-                if (BIO_puts(bp, "\n") <= 0
-                    || !BIO_indent(bp, indent + 4, 128))
-                    goto err;
-            }
-            if (BIO_printf(bp, "%02x%s", x->seed[i],
-                           ((i + 1) == x->seedlen) ? "" : ":") <= 0)
-                goto err;
-        }
-        if (BIO_write(bp, "\n", 1) <= 0)
-            return 0;
-    }
-    if (x->counter && !ASN1_bn_print(bp, "counter:", x->counter, NULL, indent))
-        goto err;
     if (x->length != 0) {
         if (!BIO_indent(bp, indent, 128)
                 || BIO_printf(bp, "recommended-private-length: %d bits\n",
@@ -355,7 +329,7 @@ static int int_dh_size(const EVP_PKEY *pkey)
 
 static int dh_bits(const EVP_PKEY *pkey)
 {
-    return BN_num_bits(pkey->pkey.dh->p);
+    return DH_bits(pkey->pkey.dh);
 }
 
 static int dh_security_bits(const EVP_PKEY *pkey)
@@ -365,59 +339,17 @@ static int dh_security_bits(const EVP_PKEY *pkey)
 
 static int dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
 {
-    if (BN_cmp(a->pkey.dh->p, b->pkey.dh->p) ||
-        BN_cmp(a->pkey.dh->g, b->pkey.dh->g))
-        return 0;
-    else if (a->ameth == &dhx_asn1_meth) {
-        if (BN_cmp(a->pkey.dh->q, b->pkey.dh->q))
-            return 0;
-    }
-    return 1;
-}
-
-static int int_dh_bn_cpy(BIGNUM **dst, const BIGNUM *src)
-{
-    BIGNUM *a;
-
-    /*
-     * If source is read only just copy the pointer, so
-     * we don't have to reallocate it.
-     */
-    if (src == NULL)
-        a = NULL;
-    else if (BN_get_flags(src, BN_FLG_STATIC_DATA)
-                && !BN_get_flags(src, BN_FLG_MALLOCED))
-        a = (BIGNUM *)src;
-    else if ((a = BN_dup(src)) == NULL)
-        return 0;
-    BN_clear_free(*dst);
-    *dst = a;
-    return 1;
+    return ffc_params_cmp(&a->pkey.dh->params, &a->pkey.dh->params,
+                          a->ameth != &dhx_asn1_meth);
 }
 
 static int int_dh_param_copy(DH *to, const DH *from, int is_x942)
 {
     if (is_x942 == -1)
-        is_x942 = ! !from->q;
-    if (!int_dh_bn_cpy(&to->p, from->p))
+        is_x942 = (from->params.q != NULL);
+    if (!ffc_params_copy(&to->params, &from->params))
         return 0;
-    if (!int_dh_bn_cpy(&to->g, from->g))
-        return 0;
-    if (is_x942) {
-        if (!int_dh_bn_cpy(&to->q, from->q))
-            return 0;
-        if (!int_dh_bn_cpy(&to->j, from->j))
-            return 0;
-        OPENSSL_free(to->seed);
-        to->seed = NULL;
-        to->seedlen = 0;
-        if (from->seed) {
-            to->seed = OPENSSL_memdup(from->seed, from->seedlen);
-            if (!to->seed)
-                return 0;
-            to->seedlen = from->seedlen;
-        }
-    } else
+    if (!is_x942)
         to->length = from->length;
     to->dirty_cnt++;
     return 1;
@@ -449,9 +381,9 @@ static int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
 
 static int dh_missing_parameters(const EVP_PKEY *a)
 {
-    if (a->pkey.dh == NULL || a->pkey.dh->p == NULL || a->pkey.dh->g == NULL)
-        return 1;
-    return 0;
+    return a->pkey.dh == NULL
+        || a->pkey.dh->params.p == NULL
+        || a->pkey.dh->params.g == NULL;
 }
 
 static int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
@@ -820,6 +752,7 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
 static int dh_cms_decrypt(CMS_RecipientInfo *ri)
 {
     EVP_PKEY_CTX *pctx;
+
     pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
 
     if (pctx == NULL)
diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c
index 2708a81cd0..75f2dd5bde 100644
--- a/crypto/dh/dh_asn1.c
+++ b/crypto/dh/dh_asn1.c
@@ -34,8 +34,8 @@ static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
 }
 
 ASN1_SEQUENCE_cb(DHparams, dh_cb) = {
-        ASN1_SIMPLE(DH, p, BIGNUM),
-        ASN1_SIMPLE(DH, g, BIGNUM),
+        ASN1_SIMPLE(DH, params.p, BIGNUM),
+        ASN1_SIMPLE(DH, params.g, BIGNUM),
         ASN1_OPT_EMBED(DH, length, ZINT32),
 } ASN1_SEQUENCE_END_cb(DH, DHparams)
 
@@ -82,6 +82,7 @@ IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(int_dhx942_dh, DHxparams, int_dhx)
 
 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();
@@ -93,22 +94,22 @@ DH *d2i_DHxparams(DH **a, const unsigned char **pp, long length)
         return NULL;
     }
 
-    if (a) {
+    if (a != NULL) {
         DH_free(*a);
         *a = dh;
     }
 
-    dh->p = dhx->p;
-    dh->q = dhx->q;
-    dh->g = dhx->g;
-    dh->j = dhx->j;
+    params = &dh->params;
+    ffc_params_set0_pqg(params, dhx->p, dhx->q, dhx->g);
+    ffc_params_set0_j(params, dhx->j);
 
-    if (dhx->vparams) {
-        dh->seed = dhx->vparams->seed->data;
-        dh->seedlen = dhx->vparams->seed->length;
-        dh->counter = dhx->vparams->counter;
-        dhx->vparams->seed->data = NULL;
+    if (dhx->vparams != NULL) {
+        /* The counter has a maximum value of 4 * numbits(p) - 1 */
+        size_t counter = (size_t)BN_get_word(dhx->vparams->counter);
+        ffc_params_set_validate_params(params, dhx->vparams->seed->data,
+                                       dhx->vparams->seed->length, counter);
         ASN1_BIT_STRING_free(dhx->vparams->seed);
+        BN_free(dhx->vparams->counter);
         OPENSSL_free(dhx->vparams);
         dhx->vparams = NULL;
     }
@@ -119,22 +120,34 @@ DH *d2i_DHxparams(DH **a, const unsigned char **pp, long length)
 
 int i2d_DHxparams(const DH *dh, unsigned char **pp)
 {
+    int ret = 0;
     int_dhx942_dh dhx;
-    int_dhvparams dhv;
-    ASN1_BIT_STRING bs;
-    dhx.p = dh->p;
-    dhx.g = dh->g;
-    dhx.q = dh->q;
-    dhx.j = dh->j;
-    if (dh->counter && dh->seed && dh->seedlen > 0) {
-        bs.flags = ASN1_STRING_FLAG_BITS_LEFT;
-        bs.data = dh->seed;
-        bs.length = dh->seedlen;
-        dhv.seed = &bs;
-        dhv.counter = dh->counter;
+    int_dhvparams dhv = { NULL, NULL };
+    ASN1_BIT_STRING seed;
+    size_t seedlen = 0;
+    const FFC_PARAMS *params = &dh->params;
+    int counter;
+
+    ffc_params_get0_pqg(params, (const BIGNUM **)&dhx.p,
+                        (const BIGNUM **)&dhx.q, (const BIGNUM **)&dhx.g);
+    dhx.j = params->j;
+    ffc_params_get_validate_params(params, &seed.data, &seedlen, &counter);
+    seed.length = (int)seedlen;
+
+    if (counter != -1 && seed.data != NULL && seed.length > 0) {
+        seed.flags = ASN1_STRING_FLAG_BITS_LEFT;
+        dhv.seed = &seed;
+        dhv.counter = BN_new();
+        if (dhv.counter == NULL)
+            return 0;
+        if (!BN_set_word(dhv.counter, (BN_ULONG)counter))
+            goto err;
         dhx.vparams = &dhv;
-    } else
+    } else {
         dhx.vparams = NULL;
-
-    return i2d_int_dhx(&dhx, pp);
+    }
+    ret = i2d_int_dhx(&dhx, pp);
+err:
+    BN_free(dhv.counter);
+    return ret;
 }
diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c
index 70f083603f..8bb245207b 100644
--- a/crypto/dh/dh_check.c
+++ b/crypto/dh/dh_check.c
@@ -52,17 +52,19 @@ int DH_check_params(const DH *dh, int *ret)
     if (tmp == NULL)
         goto err;
 
-    if (!BN_is_odd(dh->p))
+    if (!BN_is_odd(dh->params.p))
         *ret |= DH_CHECK_P_NOT_PRIME;
-    if (BN_is_negative(dh->g) || BN_is_zero(dh->g) || BN_is_one(dh->g))
+    if (BN_is_negative(dh->params.g)
+        || BN_is_zero(dh->params.g)
+        || BN_is_one(dh->params.g))
         *ret |= DH_NOT_SUITABLE_GENERATOR;
-    if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1))
+    if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1))
         goto err;
-    if (BN_cmp(dh->g, tmp) >= 0)
+    if (BN_cmp(dh->params.g, tmp) >= 0)
         *ret |= DH_NOT_SUITABLE_GENERATOR;
-    if (BN_num_bits(dh->p) < DH_MIN_MODULUS_BITS)
+    if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS)
         *ret |= DH_MODULUS_TOO_SMALL;
-    if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS)
+    if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS)
         *ret |= DH_MODULUS_TOO_LARGE;
 
     ok = 1;
@@ -123,39 +125,40 @@ int DH_check(const DH *dh, int *ret)
     if (t2 == NULL)
         goto err;
 
-    if (dh->q) {
-        if (BN_cmp(dh->g, BN_value_one()) <= 0)
+    if (dh->params.q != NULL) {
+        if (BN_cmp(dh->params.g, BN_value_one()) <= 0)
             *ret |= DH_NOT_SUITABLE_GENERATOR;
-        else if (BN_cmp(dh->g, dh->p) >= 0)
+        else if (BN_cmp(dh->params.g, dh->params.p) >= 0)
             *ret |= DH_NOT_SUITABLE_GENERATOR;
         else {
             /* Check g^q == 1 mod p */
-            if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx))
+            if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx))
                 goto err;
             if (!BN_is_one(t1))
                 *ret |= DH_NOT_SUITABLE_GENERATOR;
         }
-        r = BN_check_prime(dh->q, ctx, NULL);
+        r = BN_check_prime(dh->params.q, ctx, NULL);
         if (r < 0)
             goto err;
         if (!r)
             *ret |= DH_CHECK_Q_NOT_PRIME;
         /* Check p == 1 mod q  i.e. q divides p - 1 */
-        if (!BN_div(t1, t2, dh->p, dh->q, ctx))
+        if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx))
             goto err;
         if (!BN_is_one(t2))
             *ret |= DH_CHECK_INVALID_Q_VALUE;
-        if (dh->j && BN_cmp(dh->j, t1))
+        if (dh->params.j != NULL
+            && BN_cmp(dh->params.j, t1))
             *ret |= DH_CHECK_INVALID_J_VALUE;
     }
 
-    r = BN_check_prime(dh->p, ctx, NULL);
+    r = BN_check_prime(dh->params.p, ctx, NULL);
     if (r < 0)
         goto err;
     if (!r)
         *ret |= DH_CHECK_P_NOT_PRIME;
-    else if (!dh->q) {
-        if (!BN_rshift1(t1, dh->p))
+    else if (dh->params.q == NULL) {
+        if (!BN_rshift1(t1, dh->params.p))
             goto err;
         r = BN_check_prime(t1, ctx, NULL);
         if (r < 0)
@@ -203,14 +206,14 @@ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret)
         goto err;
     if (BN_cmp(pub_key, tmp) <= 0)
         *ret |= DH_CHECK_PUBKEY_TOO_SMALL;
-    if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1))
+    if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1))
         goto err;
     if (BN_cmp(pub_key, tmp) >= 0)
         *ret |= DH_CHECK_PUBKEY_TOO_LARGE;
 
-    if (dh->q != NULL) {
+    if (dh->params.q != NULL) {
         /* Check pub_key^q == 1 mod p */
-        if (!BN_mod_exp(tmp, pub_key, dh->q, dh->p, ctx))
+        if (!BN_mod_exp(tmp, pub_key, dh->params.q, dh->params.p, ctx))
             goto err;
         if (!BN_is_one(tmp))
             *ret |= DH_CHECK_PUBKEY_INVALID;
diff --git a/crypto/dh/dh_gen.c b/crypto/dh/dh_gen.c
index 0506bbe2e5..75548592b8 100644
--- a/crypto/dh/dh_gen.c
+++ b/crypto/dh/dh_gen.c
@@ -81,9 +81,9 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator,
         goto err;
 
     /* Make sure 'ret' has the necessary elements */
-    if (!ret->p && ((ret->p = BN_new()) == NULL))
+    if (ret->params.p == NULL && ((ret->params.p = BN_new()) == NULL))
         goto err;
-    if (!ret->g && ((ret->g = BN_new()) == NULL))
+    if (ret->params.g == NULL && ((ret->params.g = BN_new()) == NULL))
         goto err;
 
     if (generator <= 1) {
@@ -115,11 +115,11 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator,
         g = generator;
     }
 
-    if (!BN_generate_prime_ex(ret->p, prime_len, 1, t1, t2, cb))
+    if (!BN_generate_prime_ex(ret->params.p, prime_len, 1, t1, t2, cb))
         goto err;
     if (!BN_GENCB_call(cb, 3, 0))
         goto err;
-    if (!BN_set_word(ret->g, g))
+    if (!BN_set_word(ret->params.g, g))
         goto err;
     ret->dirty_cnt++;
     ok = 1;
diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c
index bd9b5c824b..4c5d78a19f 100644
--- a/crypto/dh/dh_key.c
+++ b/crypto/dh/dh_key.c
@@ -34,12 +34,12 @@ int dh_compute_key(OPENSSL_CTX *libctx, unsigned char *key,
     int check_result;
 #endif
 
-    if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) {
+    if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
         DHerr(0, DH_R_MODULUS_TOO_LARGE);
         goto err;
     }
 
-    if (BN_num_bits(dh->p) < DH_MIN_MODULUS_BITS) {
+    if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) {
         DHerr(0, DH_R_MODULUS_TOO_SMALL);
         return 0;
     }
@@ -59,7 +59,7 @@ int dh_compute_key(OPENSSL_CTX *libctx, unsigned char *key,
 
     if (dh->flags & DH_FLAG_CACHE_MONT_P) {
         mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
-                                      dh->lock, dh->p, ctx);
+                                      dh->lock, dh->params.p, ctx);
         BN_set_flags(dh->priv_key, BN_FLG_CONSTTIME);
         if (!mont)
             goto err;
@@ -71,7 +71,7 @@ int dh_compute_key(OPENSSL_CTX *libctx, unsigned char *key,
         goto err;
     }
 #endif
-    if (!dh->meth->bn_mod_exp(dh, tmp, pub_key, dh->priv_key, dh->p, ctx,
+    if (!dh->meth->bn_mod_exp(dh, tmp, pub_key, dh->priv_key, dh->params.p, ctx,
                               mont)) {
         DHerr(0, ERR_R_BN_LIB);
         goto err;
@@ -101,7 +101,7 @@ int dh_compute_key_padded(OPENSSL_CTX *libctx, unsigned char *key,
 #endif
     if (rv <= 0)
         return rv;
-    pad = BN_num_bytes(dh->p) - rv;
+    pad = BN_num_bytes(dh->params.p) - rv;
     if (pad > 0) {
         memmove(key + pad, key, rv);
         memset(key, 0, pad);
@@ -159,6 +159,7 @@ static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
 static int dh_init(DH *dh)
 {
     dh->flags |= DH_FLAG_CACHE_MONT_P;
+    ffc_params_init(&dh->params);
     return 1;
 }
 
@@ -189,12 +190,12 @@ static int generate_key(DH *dh)
     BN_MONT_CTX *mont = NULL;
     BIGNUM *pub_key = NULL, *priv_key = NULL;
 
-    if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) {
+    if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
         DHerr(DH_F_GENERATE_KEY, DH_R_MODULUS_TOO_LARGE);
         return 0;
     }
 
-    if (BN_num_bits(dh->p) < DH_MIN_MODULUS_BITS) {
+    if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) {
         DHerr(DH_F_GENERATE_KEY, DH_R_MODULUS_TOO_SMALL);
         return 0;
     }
@@ -220,28 +221,29 @@ static int generate_key(DH *dh)
 
     if (dh->flags & DH_FLAG_CACHE_MONT_P) {
         mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
-                                      dh->lock, dh->p, ctx);
+                                      dh->lock, dh->params.p, ctx);
         if (!mont)
             goto err;
     }
 
     if (generate_new_key) {
-        if (dh->q) {
+        if (dh->params.q != NULL) {
             do {
-                if (!BN_priv_rand_range(priv_key, dh->q))
+                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->p) - 1;
+            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;
             /*
              * We handle just one known case where g is a quadratic non-residue:
              * for g = 2: p % 8 == 3
              */
-            if (BN_is_word(dh->g, DH_GENERATOR_2) && !BN_is_bit_set(dh->p, 2)) {
+            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;
@@ -256,7 +258,8 @@ static int generate_key(DH *dh)
             goto err;
         BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME);
 
-        if (!dh->meth->bn_mod_exp(dh, pub_key, dh->g, prk, dh->p, ctx, mont)) {
+        if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p,
+                                  ctx, mont)) {
             BN_clear_free(prk);
             goto err;
         }
@@ -280,6 +283,7 @@ static int generate_key(DH *dh)
     return ok;
 }
 
+
 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 c9679d7e52..2f5aa10401 100644
--- a/crypto/dh/dh_lib.c
+++ b/crypto/dh/dh_lib.c
@@ -14,6 +14,7 @@
 #include "dh_local.h"
 #include "crypto/dh.h"
 #include <openssl/engine.h>
+#include "crypto/dh.h"
 
 #ifndef FIPS_MODE
 int DH_set_method(DH *dh, const DH_METHOD *meth)
@@ -122,12 +123,7 @@ void DH_free(DH *r)
 
     CRYPTO_THREAD_lock_free(r->lock);
 
-    BN_clear_free(r->p);
-    BN_clear_free(r->g);
-    BN_clear_free(r->q);
-    BN_clear_free(r->j);
-    OPENSSL_free(r->seed);
-    BN_clear_free(r->counter);
+    ffc_params_cleanup(&r->params);
     BN_clear_free(r->pub_key);
     BN_clear_free(r->priv_key);
     OPENSSL_free(r);
@@ -159,35 +155,30 @@ void *DH_get_ex_data(DH *d, int idx)
 
 int DH_bits(const DH *dh)
 {
-    return BN_num_bits(dh->p);
+    return BN_num_bits(dh->params.p);
 }
 
 int DH_size(const DH *dh)
 {
-    return BN_num_bytes(dh->p);
+    return BN_num_bytes(dh->params.p);
 }
 
 int DH_security_bits(const DH *dh)
 {
     int N;
-    if (dh->q)
-        N = BN_num_bits(dh->q);
+    if (dh->params.q != NULL)
+        N = BN_num_bits(dh->params.q);
     else if (dh->length)
         N = dh->length;
     else
         N = -1;
-    return BN_security_bits(BN_num_bits(dh->p), N);
+    return BN_security_bits(BN_num_bits(dh->params.p), N);
 }
 
 void DH_get0_pqg(const DH *dh,
                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
 {
-    if (p != NULL)
-        *p = dh->p;
-    if (q != NULL)
-        *q = dh->q;
-    if (g != NULL)
-        *g = dh->g;
+    ffc_params_get0_pqg(&dh->params, p, q, g);
 }
 
 int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
@@ -195,26 +186,14 @@ int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
     /* If the fields p and g in d are NULL, the corresponding input
      * parameters MUST be non-NULL.  q may remain NULL.
      */
-    if ((dh->p == NULL && p == NULL)
-        || (dh->g == NULL && g == NULL))
+    if ((dh->params.p == NULL && p == NULL)
+        || (dh->params.g == NULL && g == NULL))
         return 0;
 
-    if (p != NULL) {
-        BN_free(dh->p);
-        dh->p = p;
-    }
-    if (q != NULL) {
-        BN_free(dh->q);
-        dh->q = q;
-    }
-    if (g != NULL) {
-        BN_free(dh->g);
-        dh->g = g;
-    }
+    ffc_params_set0_pqg(&dh->params, p, q, g);
 
-    if (q != NULL) {
+    if (q != NULL)
         dh->length = BN_num_bits(q);
-    }
 
     dh->dirty_cnt++;
     return 1;
@@ -256,17 +235,17 @@ int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
 
 const BIGNUM *DH_get0_p(const DH *dh)
 {
-    return dh->p;
+    return dh->params.p;
 }
 
 const BIGNUM *DH_get0_q(const DH *dh)
 {
-    return dh->q;
+    return dh->params.q;
 }
 
 const BIGNUM *DH_get0_g(const DH *dh)
 {
-    return dh->g;
+    return dh->params.g;
 }
 
 const BIGNUM *DH_get0_priv_key(const DH *dh)
@@ -300,3 +279,8 @@ ENGINE *DH_get0_engine(DH *dh)
     return dh->engine;
 }
 #endif /*FIPS_MODE */
+
+FFC_PARAMS *dh_get0_params(DH *dh)
+{
+    return &dh->params;
+}
diff --git a/crypto/dh/dh_local.h b/crypto/dh/dh_local.h
index 2a200c748e..57d9d3489f 100644
--- a/crypto/dh/dh_local.h
+++ b/crypto/dh/dh_local.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-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
@@ -9,6 +9,7 @@
 
 #include <openssl/dh.h>
 #include "internal/refcount.h"
+#include "internal/ffc.h"
 
 #define DH_MIN_MODULUS_BITS     512
 
@@ -19,19 +20,12 @@ struct dh_st {
      */
     int pad;
     int version;
-    BIGNUM *p;
-    BIGNUM *g;
-    int32_t length;             /* optional */
+    FFC_PARAMS params;
+    int32_t length;             /* optional value of N (if there is no q) */
     BIGNUM *pub_key;            /* g^x % p */
     BIGNUM *priv_key;           /* x */
     int flags;
     BN_MONT_CTX *method_mont_p;
-    /* Place holders if we want to do X9.42 DH */
-    BIGNUM *q;
-    BIGNUM *j;
-    unsigned char *seed;
-    int seedlen;
-    BIGNUM *counter;
     CRYPTO_REF_COUNT references;
 #ifndef FIPS_MODE
     CRYPTO_EX_DATA ex_data;
diff --git a/crypto/dh/dh_rfc5114.c b/crypto/dh/dh_rfc5114.c
index 823f6d92e3..3bbfea12d3 100644
--- a/crypto/dh/dh_rfc5114.c
+++ b/crypto/dh/dh_rfc5114.c
@@ -26,10 +26,10 @@ DH *DH_get_##x(void) \
 \
     if (dh == NULL) \
         return NULL; \
-    dh->p = BN_dup(&_bignum_dh##x##_p); \
-    dh->g = BN_dup(&_bignum_dh##x##_g); \
-    dh->q = BN_dup(&_bignum_dh##x##_q); \
-    if (dh->p == NULL || dh->q == NULL || dh->g == NULL) {\
+    dh->params.p = BN_dup(&_bignum_dh##x##_p); \
+    dh->params.g = BN_dup(&_bignum_dh##x##_g); \
+    dh->params.q = BN_dup(&_bignum_dh##x##_q); \
+    if (dh->params.p == NULL || dh->params.q == NULL || dh->params.g == NULL) {\
         DH_free(dh); \
         return NULL; \
     } \
diff --git a/crypto/dh/dh_rfc7919.c b/crypto/dh/dh_rfc7919.c
index e36712facf..92e5000e28 100644
--- a/crypto/dh/dh_rfc7919.c
+++ b/crypto/dh/dh_rfc7919.c
@@ -19,8 +19,8 @@ static DH *dh_param_init(const BIGNUM *p, int32_t nbits)
     DH *dh = DH_new();
     if (dh == NULL)
         return NULL;
-    dh->p = (BIGNUM *)p;
-    dh->g = (BIGNUM *)&_bignum_const_2;
+    dh->params.p = (BIGNUM *)p;
+    dh->params.g = (BIGNUM *)&_bignum_const_2;
     dh->length = nbits;
     dh->dirty_cnt++;
     return dh;
@@ -49,25 +49,25 @@ int DH_get_nid(const DH *dh)
 {
     int nid;
 
-    if (BN_get_word(dh->g) != 2)
+    if (BN_get_word(dh->params.g) != 2)
         return NID_undef;
-    if (!BN_cmp(dh->p, &_bignum_ffdhe2048_p))
+    if (!BN_cmp(dh->params.p, &_bignum_ffdhe2048_p))
         nid = NID_ffdhe2048;
-    else if (!BN_cmp(dh->p, &_bignum_ffdhe3072_p))
+    else if (!BN_cmp(dh->params.p, &_bignum_ffdhe3072_p))
         nid = NID_ffdhe3072;
-    else if (!BN_cmp(dh->p, &_bignum_ffdhe4096_p))
+    else if (!BN_cmp(dh->params.p, &_bignum_ffdhe4096_p))
         nid = NID_ffdhe4096;
-    else if (!BN_cmp(dh->p, &_bignum_ffdhe6144_p))
+    else if (!BN_cmp(dh->params.p, &_bignum_ffdhe6144_p))
         nid = NID_ffdhe6144;
-    else if (!BN_cmp(dh->p, &_bignum_ffdhe8192_p))
+    else if (!BN_cmp(dh->params.p, &_bignum_ffdhe8192_p))
         nid = NID_ffdhe8192;
     else
         return NID_undef;
-    if (dh->q != NULL) {
-        BIGNUM *q = BN_dup(dh->p);
+    if (dh->params.q != NULL) {
+        BIGNUM *q = BN_dup(dh->params.p);
 
         /* Check q = p * 2 + 1 we already know q is odd, so just shift right */
-        if (q == NULL || !BN_rshift1(q, q) || !BN_cmp(dh->q, q))
+        if (q == NULL || !BN_rshift1(q, q) || !BN_cmp(dh->params.q, q))
             nid = NID_undef;
         BN_free(q);
     }
diff --git a/crypto/dsa/dsa_ameth.c b/crypto/dsa/dsa_ameth.c
index ddd262bdde..510b204b2d 100644
--- a/crypto/dsa/dsa_ameth.c
+++ b/crypto/dsa/dsa_ameth.c
@@ -88,7 +88,10 @@ static int dsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
     ASN1_OBJECT *aobj;
 
     dsa = pkey->pkey.dsa;
-    if (pkey->save_parameters && dsa->p && dsa->q && dsa->g) {
+    if (pkey->save_parameters
+        && dsa->params.p != NULL
+        && dsa->params.q != NULL
+        && dsa->params.g != NULL) {
         str = ASN1_STRING_new();
         if (str == NULL) {
             DSAerr(DSA_F_DSA_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
@@ -183,7 +186,8 @@ static int dsa_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
     }
 
     BN_set_flags(dsa->priv_key, BN_FLG_CONSTTIME);
-    if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) {
+    if (!BN_mod_exp(dsa->pub_key, dsa->params.g, dsa->priv_key, dsa->params.p,
+                    ctx)) {
         DSAerr(DSA_F_DSA_PRIV_DECODE, DSA_R_BN_ERROR);
         goto dsaerr;
     }
@@ -275,55 +279,34 @@ static int dsa_missing_parameters(const EVP_PKEY *pkey)
 {
     DSA *dsa;
     dsa = pkey->pkey.dsa;
-    if (dsa == NULL || dsa->p == NULL || dsa->q == NULL || dsa->g == NULL)
-        return 1;
-    return 0;
+    return dsa == NULL
+        || dsa->params.p == NULL
+        || dsa->params.q == NULL
+        || dsa->params.g == NULL;
 }
 
 static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
 {
-    BIGNUM *a;
-
     if (to->pkey.dsa == NULL) {
         to->pkey.dsa = DSA_new();
         if (to->pkey.dsa == NULL)
             return 0;
     }
-
-    if ((a = BN_dup(from->pkey.dsa->p)) == NULL)
+    if (!ffc_params_copy(&to->pkey.dsa->params, &from->pkey.dsa->params))
         return 0;
-    BN_free(to->pkey.dsa->p);
-    to->pkey.dsa->p = a;
 
-    if ((a = BN_dup(from->pkey.dsa->q)) == NULL)
-        return 0;
-    BN_free(to->pkey.dsa->q);
-    to->pkey.dsa->q = a;
-
-    if ((a = BN_dup(from->pkey.dsa->g)) == NULL)
-        return 0;
-    BN_free(to->pkey.dsa->g);
-    to->pkey.dsa->g = a;
     to->pkey.dsa->dirty_cnt++;
     return 1;
 }
 
 static int dsa_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
 {
-    if (BN_cmp(a->pkey.dsa->p, b->pkey.dsa->p) ||
-        BN_cmp(a->pkey.dsa->q, b->pkey.dsa->q) ||
-        BN_cmp(a->pkey.dsa->g, b->pkey.dsa->g))
-        return 0;
-    else
-        return 1;
+    return ffc_params_cmp(&a->pkey.dsa->params, &b->pkey.dsa->params, 1);
 }
 
 static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
 {
-    if (BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) != 0)
-        return 0;
-    else
-        return 1;
+    return BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) == 0;
 }
 
 static void int_dsa_free(EVP_PKEY *pkey)
@@ -338,8 +321,8 @@ static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype)
     const BIGNUM *priv_key, *pub_key;
     int mod_len = 0;
 
-    if (x->p != NULL)
-        mod_len = BN_num_bits(x->p);
+    if (x->params.p != NULL)
+        mod_len = DSA_bits(x);
 
     if (ptype == 2)
         priv_key = x->priv_key;
@@ -358,11 +341,10 @@ static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype)
     else
         ktype = "DSA-Parameters";
 
-    if (priv_key) {
+    if (priv_key != NULL) {
         if (!BIO_indent(bp, off, 128))
             goto err;
-        if (BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p))
-            <= 0)
+        if (BIO_printf(bp, "%s: (%d bit)\n", ktype, mod_len) <= 0)
             goto err;
     } else {
         if (BIO_printf(bp, "Public-Key: (%d bit)\n", mod_len) <= 0)
@@ -373,11 +355,7 @@ static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype)
         goto err;
     if (!ASN1_bn_print(bp, "pub: ", pub_key, NULL, off))
         goto err;
-    if (!ASN1_bn_print(bp, "P:   ", x->p, NULL, off))
-        goto err;
-    if (!ASN1_bn_print(bp, "Q:   ", x->q, NULL, off))
-        goto err;
-    if (!ASN1_bn_print(bp, "G:   ", x->g, NULL, off))
+    if (!ffc_params_print(bp, &x->params, off))
         goto err;
     ret = 1;
  err:
@@ -446,7 +424,7 @@ static int dsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
     DSA_SIG *dsa_sig;
     const unsigned char *p;
 
-    if (!sig) {
+    if (sig == NULL) {
         if (BIO_puts(bp, "\n") <= 0)
             return 0;
         else
@@ -454,7 +432,7 @@ static int dsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
     }
     p = sig->data;
     dsa_sig = d2i_DSA_SIG(NULL, &p, sig->length);
-    if (dsa_sig) {
+    if (dsa_sig != NULL) {
         int rv = 0;
         const BIGNUM *r, *s;
 
diff --git a/crypto/dsa/dsa_asn1.c b/crypto/dsa/dsa_asn1.c
index 20bf2518c8..ba1cbad2ae 100644
--- a/crypto/dsa/dsa_asn1.c
+++ b/crypto/dsa/dsa_asn1.c
@@ -34,9 +34,9 @@ static int dsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
 
 ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = {
         ASN1_EMBED(DSA, version, INT32),
-        ASN1_SIMPLE(DSA, p, BIGNUM),
-        ASN1_SIMPLE(DSA, q, BIGNUM),
-        ASN1_SIMPLE(DSA, g, BIGNUM),
+        ASN1_SIMPLE(DSA, params.p, BIGNUM),
+        ASN1_SIMPLE(DSA, params.q, BIGNUM),
+        ASN1_SIMPLE(DSA, params.g, BIGNUM),
         ASN1_SIMPLE(DSA, pub_key, BIGNUM),
         ASN1_SIMPLE(DSA, priv_key, CBIGNUM)
 } static_ASN1_SEQUENCE_END_cb(DSA, DSAPrivateKey)
@@ -44,18 +44,18 @@ ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = {
 IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(DSA, DSAPrivateKey, DSAPrivateKey)
 
 ASN1_SEQUENCE_cb(DSAparams, dsa_cb) = {
-        ASN1_SIMPLE(DSA, p, BIGNUM),
-        ASN1_SIMPLE(DSA, q, BIGNUM),
-        ASN1_SIMPLE(DSA, g, BIGNUM),
+        ASN1_SIMPLE(DSA, params.p, BIGNUM),
+        ASN1_SIMPLE(DSA, params.q, BIGNUM),
+        ASN1_SIMPLE(DSA, params.g, BIGNUM),
 } static_ASN1_SEQUENCE_END_cb(DSA, DSAparams)
 
 IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(DSA, DSAparams, DSAparams)
 
 ASN1_SEQUENCE_cb(DSAPublicKey, dsa_cb) = {
         ASN1_SIMPLE(DSA, pub_key, BIGNUM),
-        ASN1_SIMPLE(DSA, p, BIGNUM),
-        ASN1_SIMPLE(DSA, q, BIGNUM),
-        ASN1_SIMPLE(DSA, g, BIGNUM)
+        ASN1_SIMPLE(DSA, params.p, BIGNUM),
+        ASN1_SIMPLE(DSA, params.q, BIGNUM),
+        ASN1_SIMPLE(DSA, params.g, BIGNUM)
 } static_ASN1_SEQUENCE_END_cb(DSA, DSAPublicKey)
 
 IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(DSA, DSAPublicKey, DSAPublicKey)
diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c
index 67551e545b..02c2bd8083 100644
--- a/crypto/dsa/dsa_gen.c
+++ b/crypto/dsa/dsa_gen.c
@@ -274,14 +274,16 @@ int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits,
     ok = 1;
  err:
     if (ok) {
-        BN_free(ret->p);
-        BN_free(ret->q);
-        BN_free(ret->g);
-        ret->p = BN_dup(p);
-        ret->q = BN_dup(q);
-        ret->g = BN_dup(g);
+        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->p == NULL || ret->q == NULL || ret->g == NULL) {
+        if (ret->params.p == NULL
+            || ret->params.q == NULL
+            || ret->params.g == NULL) {
             ok = 0;
             goto err;
         }
@@ -343,7 +345,7 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N,
 
     mdsize = EVP_MD_size(evpmd);
     /* If unverifiable g generation only don't need seed */
-    if (!ret->p || !ret->q || idx >= 0) {
+    if (!ret->params.p || !ret->params.q || idx >= 0) {
         if (seed_len == 0)
             seed_len = mdsize;
 
@@ -379,9 +381,9 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N,
         goto err;
 
     /* if p, q already supplied generate g only */
-    if (ret->p && ret->q) {
-        p = ret->p;
-        q = ret->q;
+    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;
@@ -583,17 +585,19 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N,
     ok = 1;
  err:
     if (ok == 1) {
-        if (p != ret->p) {
-            BN_free(ret->p);
-            ret->p = BN_dup(p);
+        if (p != ret->params.p) {
+            BN_free(ret->params.p);
+            ret->params.p = BN_dup(p);
         }
-        if (q != ret->q) {
-            BN_free(ret->q);
-            ret->q = BN_dup(q);
+        if (q != ret->params.q) {
+            BN_free(ret->params.q);
+            ret->params.q = BN_dup(q);
         }
-        BN_free(ret->g);
-        ret->g = BN_dup(g);
-        if (ret->p == NULL || ret->q == NULL || ret->g == NULL) {
+        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;
         }
diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c
index 6e5039a696..efc125253e 100644
--- a/crypto/dsa/dsa_key.c
+++ b/crypto/dsa/dsa_key.c
@@ -38,7 +38,7 @@ static int dsa_builtin_keygen(DSA *dsa)
         priv_key = dsa->priv_key;
 
     do
-        if (!BN_priv_rand_range(priv_key, dsa->q))
+        if (!BN_priv_rand_range(priv_key, dsa->params.q))
             goto err;
     while (BN_is_zero(priv_key)) ;
 
@@ -55,7 +55,7 @@ static int dsa_builtin_keygen(DSA *dsa)
             goto err;
         BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME);
 
-        if (!BN_mod_exp(pub_key, dsa->g, prk, dsa->p, ctx)) {
+        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_lib.c b/crypto/dsa/dsa_lib.c
index 976eb622aa..469746e65d 100644
--- a/crypto/dsa/dsa_lib.c
+++ b/crypto/dsa/dsa_lib.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
@@ -11,11 +11,11 @@
 #include "internal/cryptlib.h"
 #include "internal/refcount.h"
 #include <openssl/bn.h>
-#include "dsa_local.h"
 #include <openssl/asn1.h>
 #include <openssl/engine.h>
-#include <openssl/dh.h>
+#include "dsa_local.h"
 #include "crypto/dsa.h"
+#include "crypto/dh.h" /* required by DSA_dup_DH() */
 
 #ifndef FIPS_MODE
 
@@ -29,34 +29,25 @@ void *DSA_get_ex_data(DSA *d, int idx)
     return CRYPTO_get_ex_data(&d->ex_data, idx);
 }
 
-#ifndef OPENSSL_NO_DH
+# ifndef OPENSSL_NO_DH
 DH *DSA_dup_DH(const DSA *r)
 {
     /*
-     * DSA has p, q, g, optional pub_key, optional priv_key. DH has p,
-     * optional length, g, optional pub_key, optional priv_key, optional q.
+     * DSA has p, q, g, optional pub_key, optional priv_key.
+     * DH has p, optional length, g, optional pub_key,
+     * optional priv_key, optional q.
      */
-
     DH *ret = NULL;
-    BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL, *priv_key = NULL;
+    BIGNUM *pub_key = NULL, *priv_key = NULL;
 
     if (r == NULL)
         goto err;
     ret = DH_new();
     if (ret == NULL)
         goto err;
-    if (r->p != NULL || r->g != NULL || r->q != NULL) {
-        if (r->p == NULL || r->g == NULL || r->q == NULL) {
-            /* Shouldn't happen */
-            goto err;
-        }
-        p = BN_dup(r->p);
-        g = BN_dup(r->g);
-        q = BN_dup(r->q);
-        if (p == NULL || g == NULL || q == NULL || !DH_set0_pqg(ret, p, q, g))
-            goto err;
-        p = g = q = NULL;
-    }
+
+    if (!ffc_params_copy(dh_get0_params(ret), &r->params))
+        goto err;
 
     if (r->pub_key != NULL) {
         pub_key = BN_dup(r->pub_key);
@@ -77,29 +68,26 @@ DH *DSA_dup_DH(const DSA *r)
     return ret;
 
  err:
-    BN_free(p);
-    BN_free(g);
-    BN_free(q);
     BN_free(pub_key);
     BN_free(priv_key);
     DH_free(ret);
     return NULL;
 }
-#endif
+# endif /*  OPENSSL_NO_DH */
 
 const BIGNUM *DSA_get0_p(const DSA *d)
 {
-    return d->p;
+    return d->params.p;
 }
 
 const BIGNUM *DSA_get0_q(const DSA *d)
 {
-    return d->q;
+    return d->params.q;
 }
 
 const BIGNUM *DSA_get0_g(const DSA *d)
 {
-    return d->g;
+    return d->params.g;
 }
 
 const BIGNUM *DSA_get0_pub_key(const DSA *d)
@@ -250,9 +238,7 @@ void DSA_free(DSA *r)
 
     CRYPTO_THREAD_lock_free(r->lock);
 
-    BN_clear_free(r->p);
-    BN_clear_free(r->q);
-    BN_clear_free(r->g);
+    ffc_params_cleanup(&r->params);
     BN_clear_free(r->pub_key);
     BN_clear_free(r->priv_key);
     OPENSSL_free(r);
@@ -273,12 +259,7 @@ int DSA_up_ref(DSA *r)
 void DSA_get0_pqg(const DSA *d,
                   const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
 {
-    if (p != NULL)
-        *p = d->p;
-    if (q != NULL)
-        *q = d->q;
-    if (g != NULL)
-        *g = d->g;
+    ffc_params_get0_pqg(&d->params, p, q, g);
 }
 
 int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
@@ -286,23 +267,12 @@ int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
     /* If the fields p, q and g in d are NULL, the corresponding input
      * parameters MUST be non-NULL.
      */
-    if ((d->p == NULL && p == NULL)
-        || (d->q == NULL && q == NULL)
-        || (d->g == NULL && g == NULL))
+    if ((d->params.p == NULL && p == NULL)
+        || (d->params.q == NULL && q == NULL)
+        || (d->params.g == NULL && g == NULL))
         return 0;
 
-    if (p != NULL) {
-        BN_free(d->p);
-        d->p = p;
-    }
-    if (q != NULL) {
-        BN_free(d->q);
-        d->q = q;
-    }
-    if (g != NULL) {
-        BN_free(d->g);
-        d->g = g;
-    }
+    ffc_params_set0_pqg(&d->params, p, q, g);
     d->dirty_cnt++;
 
     return 1;
@@ -341,12 +311,13 @@ int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
 
 int DSA_security_bits(const DSA *d)
 {
-    if (d->p && d->q)
-        return BN_security_bits(BN_num_bits(d->p), BN_num_bits(d->q));
+    if (d->params.p != NULL && d->params.q != NULL)
+        return BN_security_bits(BN_num_bits(d->params.p),
+                                BN_num_bits(d->params.q));
     return -1;
 }
 
 int DSA_bits(const DSA *dsa)
 {
-    return BN_num_bits(dsa->p);
+    return BN_num_bits(dsa->params.p);
 }
diff --git a/crypto/dsa/dsa_local.h b/crypto/dsa/dsa_local.h
index f0ec73410b..49b36c5f77 100644
--- a/crypto/dsa/dsa_local.h
+++ b/crypto/dsa/dsa_local.h
@@ -9,6 +9,7 @@
 
 #include <openssl/dsa.h>
 #include "internal/refcount.h"
+#include "internal/ffc.h"
 
 struct dsa_st {
     /*
@@ -17,9 +18,7 @@ struct dsa_st {
      */
     int pad;
     int32_t version;
-    BIGNUM *p;
-    BIGNUM *q;                  /* == 20 */
-    BIGNUM *g;
+    FFC_PARAMS params;
     BIGNUM *pub_key;            /* y public key */
     BIGNUM *priv_key;           /* x private key */
     int flags;
diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c
index af0fa6b566..8de5a364f5 100644
--- a/crypto/dsa/dsa_ossl.c
+++ b/crypto/dsa/dsa_ossl.c
@@ -71,7 +71,9 @@ DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst,
     DSA_SIG *ret = NULL;
     int rv = 0;
 
-    if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
+    if (dsa->params.p == NULL
+        || dsa->params.q == NULL
+        || dsa->params.g == NULL) {
         reason = DSA_R_MISSING_PARAMETERS;
         goto err;
     }
@@ -102,13 +104,13 @@ DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst,
     if (!dsa_sign_setup(dsa, ctx, &kinv, &ret->r, dgst, dlen))
         goto err;
 
-    if (dlen > BN_num_bytes(dsa->q))
+    if (dlen > BN_num_bytes(dsa->params.q))
         /*
          * if the digest length is greater than the size of q use the
          * BN_num_bits(dsa->q) leftmost bits of the digest, see fips 186-3,
          * 4.2
          */
-        dlen = BN_num_bytes(dsa->q);
+        dlen = BN_num_bytes(dsa->params.q);
     if (BN_bin2bn(dgst, dlen, m) == NULL)
         goto err;
 
@@ -124,7 +126,7 @@ DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst,
 
     /* Generate a blinding value */
     do {
-        if (!BN_priv_rand_ex(blind, BN_num_bits(dsa->q) - 1,
+        if (!BN_priv_rand_ex(blind, BN_num_bits(dsa->params.q) - 1,
                              BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, ctx))
             goto err;
     } while (BN_is_zero(blind));
@@ -133,27 +135,27 @@ DSA_SIG *dsa_do_sign_int(OPENSSL_CTX *libctx, const unsigned char *dgst,
     BN_set_flags(tmp, BN_FLG_CONSTTIME);
 
     /* tmp := blind * priv_key * r mod q */
-    if (!BN_mod_mul(tmp, blind, dsa->priv_key, dsa->q, ctx))
+    if (!BN_mod_mul(tmp, blind, dsa->priv_key, dsa->params.q, ctx))
         goto err;
-    if (!BN_mod_mul(tmp, tmp, ret->r, dsa->q, ctx))
+    if (!BN_mod_mul(tmp, tmp, ret->r, dsa->params.q, ctx))
         goto err;
 
     /* blindm := blind * m mod q */
-    if (!BN_mod_mul(blindm, blind, m, dsa->q, ctx))
+    if (!BN_mod_mul(blindm, blind, m, dsa->params.q, ctx))
         goto err;
 
     /* s : = (blind * priv_key * r) + (blind * m) mod q */
-    if (!BN_mod_add_quick(ret->s, tmp, blindm, dsa->q))
+    if (!BN_mod_add_quick(ret->s, tmp, blindm, dsa->params.q))
         goto err;
 
     /* s := s * k^-1 mod q */
-    if (!BN_mod_mul(ret->s, ret->s, kinv, dsa->q, ctx))
+    if (!BN_mod_mul(ret->s, ret->s, kinv, dsa->params.q, ctx))
         goto err;
 
     /* s:= s * blind^-1 mod q */
-    if (BN_mod_inverse(blind, blind, dsa->q, ctx) == NULL)
+    if (BN_mod_inverse(blind, blind, dsa->params.q, ctx) == NULL)
         goto err;
-    if (!BN_mod_mul(ret->s, ret->s, blind, dsa->q, ctx))
+    if (!BN_mod_mul(ret->s, ret->s, blind, dsa->params.q, ctx))
         goto err;
 
     /*
@@ -197,13 +199,15 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
     int ret = 0;
     int q_bits, q_words;
 
-    if (!dsa->p || !dsa->q || !dsa->g) {
+    if (!dsa->params.p || !dsa->params.q || !dsa->params.g) {
         DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_MISSING_PARAMETERS);
         return 0;
     }
 
     /* Reject obviously invalid parameters */
-    if (BN_is_zero(dsa->p) || BN_is_zero(dsa->q) || BN_is_zero(dsa->g)) {
+    if (BN_is_zero(dsa->params.p)
+        || BN_is_zero(dsa->params.q)
+        || BN_is_zero(dsa->params.g)) {
         DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_INVALID_PARAMETERS);
         return 0;
     }
@@ -225,8 +229,8 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
         ctx = ctx_in;
 
     /* Preallocate space */
-    q_bits = BN_num_bits(dsa->q);
-    q_words = bn_get_top(dsa->q);
+    q_bits = BN_num_bits(dsa->params.q);
+    q_words = bn_get_top(dsa->params.q);
     if (!bn_wexpand(k, q_words + 2)
         || !bn_wexpand(l, q_words + 2))
         goto err;
@@ -238,10 +242,10 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
              * We calculate k from SHA512(private_key + H(message) + random).
              * This protects the private key from a weak PRNG.
              */
-            if (!BN_generate_dsa_nonce(k, dsa->q, dsa->priv_key, dgst,
+            if (!BN_generate_dsa_nonce(k, dsa->params.q, dsa->priv_key, dgst,
                                        dlen, ctx))
                 goto err;
-        } else if (!BN_priv_rand_range_ex(k, dsa->q, ctx))
+        } else if (!BN_priv_rand_range_ex(k, dsa->params.q, ctx))
             goto err;
     } while (BN_is_zero(k));
 
@@ -250,7 +254,7 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
 
     if (dsa->flags & DSA_FLAG_CACHE_MONT_P) {
         if (!BN_MONT_CTX_set_locked(&dsa->method_mont_p,
-                                    dsa->lock, dsa->p, ctx))
+                                    dsa->lock, dsa->params.p, ctx))
             goto err;
     }
 
@@ -269,26 +273,27 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
      *     https://github.com/openssl/openssl/pull/7486#discussion_r228323705
      * The fix is to rework BN so these gymnastics aren't required.
      */
-    if (!BN_add(l, k, dsa->q)
-        || !BN_add(k, l, dsa->q))
+    if (!BN_add(l, k, dsa->params.q)
+        || !BN_add(k, l, dsa->params.q))
         goto err;
 
     BN_consttime_swap(BN_is_bit_set(l, q_bits), k, l, q_words + 2);
 
     if ((dsa)->meth->bn_mod_exp != NULL) {
-            if (!dsa->meth->bn_mod_exp(dsa, r, dsa->g, k, dsa->p, ctx,
-                                       dsa->method_mont_p))
+            if (!dsa->meth->bn_mod_exp(dsa, r, dsa->params.g, k, dsa->params.p,
+                                       ctx, dsa->method_mont_p))
                 goto err;
     } else {
-            if (!BN_mod_exp_mont(r, dsa->g, k, dsa->p, ctx, dsa->method_mont_p))
+            if (!BN_mod_exp_mont(r, dsa->params.g, k, dsa->params.p, ctx,
+                                 dsa->method_mont_p))
                 goto err;
     }
 
-    if (!BN_mod(r, r, dsa->q, ctx))
+    if (!BN_mod(r, r, dsa->params.q, ctx))
         goto err;
 
     /* Compute part of 's = inv(k) (m + xr) mod q' */
-    if ((kinv = dsa_mod_inverse_fermat(k, dsa->q, ctx)) == NULL)
+    if ((kinv = dsa_mod_inverse_fermat(k, dsa->params.q, ctx)) == NULL)
         goto err;
 
     BN_clear_free(*kinvp);
@@ -313,19 +318,21 @@ 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->p || !dsa->q || !dsa->g) {
+    if (dsa->params.p == NULL
+        || dsa->params.q == NULL
+        || dsa->params.g == NULL) {
         DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_MISSING_PARAMETERS);
         return -1;
     }
 
-    i = BN_num_bits(dsa->q);
+    i = BN_num_bits(dsa->params.q);
     /* fips 186-3 allows only different sizes for q */
     if (i != 160 && i != 224 && i != 256) {
         DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_BAD_Q_VALUE);
         return -1;
     }
 
-    if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) {
+    if (BN_num_bits(dsa->params.p) > OPENSSL_DSA_MAX_MODULUS_BITS) {
         DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_MODULUS_TOO_LARGE);
         return -1;
     }
@@ -339,12 +346,12 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
     DSA_SIG_get0(sig, &r, &s);
 
     if (BN_is_zero(r) || BN_is_negative(r) ||
-        BN_ucmp(r, dsa->q) >= 0) {
+        BN_ucmp(r, dsa->params.q) >= 0) {
         ret = 0;
         goto err;
     }
     if (BN_is_zero(s) || BN_is_negative(s) ||
-        BN_ucmp(s, dsa->q) >= 0) {
+        BN_ucmp(s, dsa->params.q) >= 0) {
         ret = 0;
         goto err;
     }
@@ -352,7 +359,7 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
     /*
      * Calculate W = inv(S) mod Q save W in u2
      */
-    if ((BN_mod_inverse(u2, s, dsa->q, ctx)) == NULL)
+    if ((BN_mod_inverse(u2, s, dsa->params.q, ctx)) == NULL)
         goto err;
 
     /* save M in u1 */
@@ -367,32 +374,32 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
         goto err;
 
     /* u1 = M * w mod q */
-    if (!BN_mod_mul(u1, u1, u2, dsa->q, ctx))
+    if (!BN_mod_mul(u1, u1, u2, dsa->params.q, ctx))
         goto err;
 
     /* u2 = r * w mod q */
-    if (!BN_mod_mul(u2, r, u2, dsa->q, ctx))
+    if (!BN_mod_mul(u2, r, u2, dsa->params.q, ctx))
         goto err;
 
     if (dsa->flags & DSA_FLAG_CACHE_MONT_P) {
         mont = BN_MONT_CTX_set_locked(&dsa->method_mont_p,
-                                      dsa->lock, dsa->p, ctx);
+                                      dsa->lock, dsa->params.p, ctx);
         if (!mont)
             goto err;
     }
 
     if (dsa->meth->dsa_mod_exp != NULL) {
-        if (!dsa->meth->dsa_mod_exp(dsa, t1, dsa->g, u1, dsa->pub_key, u2,
-                                    dsa->p, ctx, mont))
+        if (!dsa->meth->dsa_mod_exp(dsa, t1, dsa->params.g, u1, dsa->pub_key, u2,
+                                    dsa->params.p, ctx, mont))
             goto err;
     } else {
-        if (!BN_mod_exp2_mont(t1, dsa->g, u1, dsa->pub_key, u2, dsa->p, ctx,
-                              mont))
+        if (!BN_mod_exp2_mont(t1, dsa->params.g, u1, dsa->pub_key, u2,
+                              dsa->params.p, ctx, mont))
             goto err;
     }
 
     /* let u1 = u1 mod q */
-    if (!BN_mod(u1, t1, dsa->q, ctx))
+    if (!BN_mod(u1, t1, dsa->params.q, ctx))
         goto err;
 
     /*
@@ -413,6 +420,7 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
 static int dsa_init(DSA *dsa)
 {
     dsa->flags |= DSA_FLAG_CACHE_MONT_P;
+    ffc_params_init(&dsa->params);
     return 1;
 }
 
diff --git a/crypto/dsa/dsa_sign.c b/crypto/dsa/dsa_sign.c
index d09aaea6db..d3e8cfa1ff 100644
--- a/crypto/dsa/dsa_sign.c
+++ b/crypto/dsa/dsa_sign.c
@@ -115,7 +115,7 @@ int DSA_size(const DSA *dsa)
     int ret;
     DSA_SIG sig;
 
-    sig.r = sig.s = dsa->q;
+    sig.r = sig.s = dsa->params.q;
     ret = i2d_DSA_SIG(&sig, NULL);
 
     if (ret < 0)
diff --git a/crypto/hmac/build.info b/crypto/ffc/build.info
similarity index 52%
copy from crypto/hmac/build.info
copy to crypto/ffc/build.info
index 4ed90c09f4..154d3c2510 100644
--- a/crypto/hmac/build.info
+++ b/crypto/ffc/build.info
@@ -1,6 +1,6 @@
 LIBS=../../libcrypto
 
-$COMMON=hmac.c
+$COMMON=ffc_params.c
 
-SOURCE[../../libcrypto]=$COMMON hm_ameth.c
+SOURCE[../../libcrypto]=$COMMON
 SOURCE[../../providers/libfips.a]=$COMMON
diff --git a/crypto/ffc/ffc_params.c b/crypto/ffc/ffc_params.c
new file mode 100644
index 0000000000..838ace3827
--- /dev/null
+++ b/crypto/ffc/ffc_params.c
@@ -0,0 +1,191 @@
+/*
+ * 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 <string.h> /* memset */
+#include "internal/ffc.h"
+#ifndef FIPS_MODE
+# include <openssl/asn1.h> /* ffc_params_print */
+#endif
+
+void ffc_params_init(FFC_PARAMS *params)
+{
+    memset(params, 0, sizeof(FFC_PARAMS));
+    params->pcounter = -1;
+}
+
+void ffc_params_cleanup(FFC_PARAMS *params)
+{
+    BN_free(params->p);
+    BN_free(params->q);
+    BN_free(params->g);
+    BN_free(params->j);
+    OPENSSL_free(params->seed);
+    ffc_params_init(params);
+}
+
+void ffc_params_set0_pqg(FFC_PARAMS *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+    if (p != NULL && p != d->p) {
+        BN_free(d->p);
+        d->p = p;
+    }
+    if (q != NULL && q != d->q) {
+        BN_free(d->q);
+        d->q = q;
+    }
+    if (g != NULL && g != d->g) {
+        BN_free(d->g);
+        d->g = g;
+    }
+}
+
+void ffc_params_get0_pqg(const FFC_PARAMS *d, const BIGNUM **p,
+                         const BIGNUM **q, const BIGNUM **g)
+{
+    if (p != NULL)
+        *p = d->p;
+    if (q != NULL)
+        *q = d->q;
+    if (g != NULL)
+        *g = d->g;
+}
+
+
+/* j is the 'cofactor' that is optionally output for ASN1. */
+void ffc_params_set0_j(FFC_PARAMS *d, BIGNUM *j)
+{
+    BN_free(d->j);
+    d->j = NULL;
+    if (j != NULL)
+        d->j = j;
+}
+
+int ffc_params_set_validate_params(FFC_PARAMS *params,
+                                   const unsigned char *seed, size_t seedlen,
+                                   int counter)
+{
+    if (params == NULL)
+        return 0;
+
+    if (params->seed != NULL)
+        OPENSSL_free(params->seed);
+
+    if (seed != NULL && seedlen > 0) {
+        params->seed = OPENSSL_memdup(seed, seedlen);
+        if (params->seed == NULL)
+            return 0;
+        params->seedlen = seedlen;
+    } else {
+        params->seed = NULL;
+        params->seedlen = 0;
+    }
+    params->pcounter = counter;
+    return 1;
+}
+
+void ffc_params_get_validate_params(const FFC_PARAMS *params,
+                                    unsigned char **seed, size_t *seedlen,
+                                    int *pcounter)
+{
+    if (seed != NULL)
+        *seed = params->seed;
+    if (seedlen != NULL)
+        *seedlen = params->seedlen;
+    if (pcounter != NULL)
+        *pcounter = params->pcounter;
+}
+
+static int ffc_bn_cpy(BIGNUM **dst, const BIGNUM *src)
+{
+    BIGNUM *a;
+
+    /*
+     * If source is read only just copy the pointer, so
+     * we don't have to reallocate it.
+     */
+    if (src == NULL)
+        a = NULL;
+    else if (BN_get_flags(src, BN_FLG_STATIC_DATA)
+             && !BN_get_flags(src, BN_FLG_MALLOCED))
+        a = (BIGNUM *)src;
+    else if ((a = BN_dup(src)) == NULL)
+        return 0;
+    BN_clear_free(*dst);
+    *dst = a;
+    return 1;
+}
+
+int ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src)
+{
+    if (!ffc_bn_cpy(&dst->p, src->p)
+        || !ffc_bn_cpy(&dst->g, src->g)
+        || !ffc_bn_cpy(&dst->q, src->q)
+        || !ffc_bn_cpy(&dst->j, src->j))
+        return 0;
+
+    OPENSSL_free(dst->seed);
+    dst->seedlen = src->seedlen;
+    if (src->seed != NULL) {
+        dst->seed = OPENSSL_memdup(src->seed, src->seedlen);
+        if  (dst->seed == NULL)
+            return 0;
+    } else {
+        dst->seed = NULL;
+    }
+    dst->pcounter = src->pcounter;
+    return 1;
+}
+
+int ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q)
+{
+    return BN_cmp(a->p, b->p) == 0
+           && BN_cmp(a->g, b->g) == 0
+           && (ignore_q || BN_cmp(a->q, b->q) == 0); /* Note: q may be NULL */
+}
+
+#ifndef FIPS_MODE
+int ffc_params_print(BIO *bp, const FFC_PARAMS *ffc, int indent)
+{
+    if (!ASN1_bn_print(bp, "prime P:", ffc->p, NULL, indent))
+        goto err;
+    if (!ASN1_bn_print(bp, "generator G:", ffc->g, NULL, indent))
+        goto err;
+    if (ffc->q != NULL
+        && !ASN1_bn_print(bp, "subgroup order Q:", ffc->q, NULL, indent))
+        goto err;
+    if (ffc->j != NULL
+        && !ASN1_bn_print(bp, "subgroup factor:", ffc->j, NULL, indent))
+        goto err;
+    if (ffc->seed != NULL) {
+        size_t i;
+        BIO_indent(bp, indent, 128);
+        BIO_puts(bp, "seed:");
+        for (i = 0; i < ffc->seedlen; i++) {
+            if ((i % 15) == 0) {
+                if (BIO_puts(bp, "\n") <= 0
+                    || !BIO_indent(bp, indent + 4, 128))
+                    goto err;
+            }
+            if (BIO_printf(bp, "%02x%s", ffc->seed[i],
+                           ((i + 1) == ffc->seedlen) ? "" : ":") <= 0)
+                goto err;
+        }
+        if (BIO_write(bp, "\n", 1) <= 0)
+            return 0;
+    }
+    if (ffc->pcounter != -1) {
+        BIO_indent(bp, indent, 128);
+        if (BIO_printf(bp, "counter: %d\n", ffc->pcounter) <= 0)
+            goto err;
+    }
+    return 1;
+err:
+    return 0;
+}
+#endif /* FIPS_MODE */
diff --git a/include/crypto/dh.h b/include/crypto/dh.h
index 4032bdc10e..b1f37c6018 100644
--- a/include/crypto/dh.h
+++ b/include/crypto/dh.h
@@ -8,8 +8,10 @@
  */
 
 #include <openssl/dh.h>
+#include "internal/ffc.h"
 
 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,
                           const BIGNUM *pub_key, DH *dh);
+FFC_PARAMS *dh_get0_params(DH *dh);
diff --git a/include/internal/ffc.h b/include/internal/ffc.h
new file mode 100644
index 0000000000..56703fb2e8
--- /dev/null
+++ b/include/internal/ffc.h
@@ -0,0 +1,57 @@
+/*
+ * 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
+ */
+
+#ifndef OSSL_INTERNAL_FFC_H
+# define OSSL_INTERNAL_FFC_H
+
+# include <openssl/bn.h>
+
+/*
+ * Finite field cryptography (FFC) domain parameters are used by DH and DSA.
+ * Refer to FIPS186_4 Appendix A & B.
+ */
+typedef struct ffc_params_st {
+    /* Primes */
+    BIGNUM *p;
+    BIGNUM *q;
+    /* Generator */
+    BIGNUM *g;
+    /* DH X9.42 Optional Subgroup factor j >= 2 where p = j * q + 1 */
+    BIGNUM *j;
+
+    /* Required for FIPS186_4 validation of p, q and optionally canonical g */
+    unsigned char *seed;
+    /* If this value is zero the hash size is used as the seed length */
+    size_t seedlen;
+    /* Required for FIPS186_4 validation of p and q */
+    int pcounter;
+
+} FFC_PARAMS;
+
+void ffc_params_init(FFC_PARAMS *params);
+void ffc_params_cleanup(FFC_PARAMS *params);
+void ffc_params_set0_pqg(FFC_PARAMS *params, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+void ffc_params_get0_pqg(const FFC_PARAMS *params, const BIGNUM **p,
+                         const BIGNUM **q, const BIGNUM **g);
+void ffc_params_set0_j(FFC_PARAMS *d, BIGNUM *j);
+int ffc_params_set_validate_params(FFC_PARAMS *params,
+                                   const unsigned char *seed, size_t seedlen,
+                                   int counter);
+void ffc_params_get_validate_params(const FFC_PARAMS *params,
+                                    unsigned char **seed, size_t *seedlen,
+                                    int *pcounter);
+
+int ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src);
+int ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q);
+
+#ifndef FIPS_MODE
+int ffc_params_print(BIO *bp, const FFC_PARAMS *ffc, int indent);
+#endif /* FIPS_MODE */
+
+#endif /* OSSL_INTERNAL_FFC_H */


More information about the openssl-commits mailing list