Add FFC param/key generation
authorShane Lontis <shane.lontis@oracle.com>
Thu, 6 Feb 2020 12:28:36 +0000 (22:28 +1000)
committerShane Lontis <shane.lontis@oracle.com>
Thu, 6 Feb 2020 12:28:36 +0000 (22:28 +1000)
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10909)

18 files changed:
crypto/dh/dh_asn1.c
crypto/dh/dh_gen.c
crypto/dh/dh_key.c
crypto/dh/dh_pmeth.c
crypto/dsa/dsa_gen.c
crypto/dsa/dsa_key.c
crypto/dsa/dsa_local.h
crypto/dsa/dsa_ossl.c
crypto/dsa/dsa_pmeth.c
crypto/ffc/build.info
crypto/ffc/ffc_key_generate.c [new file with mode: 0644]
crypto/ffc/ffc_params.c
crypto/ffc/ffc_params_generate.c [new file with mode: 0644]
doc/man3/EVP_PKEY_CTX_ctrl.pod
include/crypto/dh.h
include/crypto/dsa.h
include/internal/ffc.h
include/openssl/dh.h

index ec589757d0299cf1c699210e5ba23cc69e214aee..829cc87464c8ee1ac60f6e7375aedad0fb235f8a 100644 (file)
@@ -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;
index 75548592b88497dad7da68f4232d45a9008f6a80..3d3bcb22b2d9d681619b61a92f444ed3ed7e820b 100644 (file)
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/bn.h>
+#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 */
index 4c5d78a19ff169efc395f259b70eb59242bb22b9..0bee75c058c393b8c7f9227f68c19d126bd08a58 100644 (file)
@@ -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
 #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 */
index 4afedb95f6c04651cc61e07111743eedc7da9b5a..38935fd9e23555a448ea295c0335f89e19bed2d7 100644 (file)
@@ -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);
index 02c2bd8083fc0bfe01465f9666a34f5b9849da72..aa6b84c0912c537ce88ca5d024711c9099dde1da 100644 (file)
@@ -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 <openssl/opensslconf.h>
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/bn.h>
 #include <openssl/rand.h>
 #include <openssl/sha.h>
+#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);
 }
index efc125253ea4856ee99ac12ad2adaa18856d9bb4..e0a3c8257044646c1cbd17206b3d368e4ade23dd 100644 (file)
 #include <time.h>
 #include "internal/cryptlib.h"
 #include <openssl/bn.h>
+#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;
index 49b36c5f7767a0cef920caf9e372f7cd9c1a52bc..f01b0aae8c846d64c86d52c610e97563917b0e7b 100644 (file)
@@ -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);
index 8de5a364f5961360fce57805d9e0f4f51bdabb68..91cb83396d42e88af324b27ca8fb74c3bd83d18b 100644 (file)
@@ -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;
 }
 
index 24d5dbd3fd199844bb1c763e5aad59a0c1a1992e..0ab5372bacf5d7ad63d70330254b812aa60c0173 100644 (file)
@@ -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);
index 154d3c2510453518ca1cff96b2470d30c3f1de54..d3314c30d14beb58a5b8bf41aefc6b0f644f1872 100644 (file)
@@ -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 (file)
index 0000000..186245c
--- /dev/null
@@ -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 */
+}
index 838ace3827c51b0991b66ffc1edb84153aef2ba8..0c9d1a5d39bc667e703f3536ab37630f4cd62625 100644 (file)
@@ -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 (file)
index 0000000..c32c33e
--- /dev/null
@@ -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 <string.h> /* memset */
+#include <openssl/sha.h> /* SHA_DIGEST_LENGTH */
+#include <openssl/rand.h>
+#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;
+}
index 629c4190f67ed14b2ed0ebf56289e1be833b8db3..8334cfc110b7a3458a0fb6aafb3b7cd79279faf4 100644 (file)
@@ -390,19 +390,37 @@ SHA-256 is selected to match the bit length of B<q> above.
 
 The EVP_PKEY_CTX_set_dh_paramgen_prime_len() macro sets the length of the DH
 prime parameter B<p> 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<q> 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<DH_PARAMGEN_TYPE_FIPS_186_2> or
+B<DH_PARAMGEN_TYPE_FIPS_186_4>.
 
 The EVP_PKEY_CTX_set_dh_paramgen_generator() macro sets DH generator to B<gen>
 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<DH_PARAMGEN_TYPE_GENERATOR>
+
+Uses a generator g (PKCS#3 format).
+
+=item B<DH_PARAMGEN_TYPE_FIPS_186_2>
+
+FIPS186-2 FFC parameter generator (X9.42 DH).
+
+=item B<DH_PARAMGEN_TYPE_FIPS_186_4>
+
+FIPS186-4 FFC parameter generator.
+
+=back
+
+The default is B<DH_PARAMGEN_TYPE_GENERATOR>.
 
 The EVP_PKEY_CTX_set_dh_pad() function sets the DH padding mode.
 If B<pad> is 1 the shared secret is padded with zeros up to the size of the DH
index 1e856101f3dc44747b78fe02cd9b5836f27bfafb..2b48b5d9059b35bd06b571bd1494e5fc9765fb83 100644 (file)
@@ -10,6 +10,9 @@
 #include <openssl/dh.h>
 #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,
index 041ebd4f7f7fc13fd551b011b1c78b13bb8ec4b0..1865fe0f771d3418954c955ef8ae9874f4c7f279 100644 (file)
@@ -9,7 +9,19 @@
 
 #include <openssl/dsa.h>
 
+#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);
index 1ec980f9d041d50a25e043f7d5875d667a62a36c..75df3a1ffd38d4f7e20725f9899559b9a0fa4042 100644 (file)
 # define OSSL_INTERNAL_FFC_H
 
 # include <openssl/bn.h>
+# include <openssl/evp.h>
+# include <openssl/dh.h> /* 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 */
index ebcbc1550512724fdb78bbb0dd5b4f093c903d22..3040bc03a68c4d3791b611055bf3c8103934429a 100644 (file)
@@ -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, \