[openssl] master update

shane.lontis at oracle.com shane.lontis at oracle.com
Wed Apr 15 11:03:45 UTC 2020


The branch master has been updated
       via  b03ec3b5d62ee26bf8437556b9040d4141d5bdd8 (commit)
      from  09b3654096ed344edd78cf156cb3ddcdbced6f9a (commit)


- Log -----------------------------------------------------------------
commit b03ec3b5d62ee26bf8437556b9040d4141d5bdd8
Author: Shane Lontis <shane.lontis at oracle.com>
Date:   Wed Apr 15 21:02:52 2020 +1000

    Add DSA keygen to provider
    
    Moved some shared FFC code into the FFC files.
    Added extra paramgen parameters for seed, gindex.
    Fixed bug in ossl_prov util to print bignums.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11303)

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

Summary of changes:
 crypto/dh/dh_ameth.c                               |   4 +-
 crypto/dh/dh_group_params.c                        |  28 +-
 crypto/dh/dh_key.c                                 |   9 +-
 crypto/dsa/build.info                              |   4 +-
 crypto/dsa/dsa_ameth.c                             |   4 +-
 crypto/dsa/dsa_backend.c                           |   2 +-
 crypto/dsa/dsa_gen.c                               |  23 +-
 crypto/dsa/dsa_key.c                               |   8 +-
 crypto/dsa/dsa_lib.c                               | 161 ++++++++++
 crypto/evp/p_lib.c                                 |  20 +-
 crypto/evp/pmeth_lib.c                             |  22 +-
 crypto/ffc/ffc_backend.c                           |  55 +++-
 crypto/ffc/ffc_key_generate.c                      |   1 +
 crypto/ffc/ffc_params.c                            |  85 +++++-
 crypto/ffc/ffc_params_generate.c                   |   2 +-
 doc/man1/openssl-genpkey.pod.in                    |  37 ++-
 doc/man3/EVP_PKEY_CTX_ctrl.pod                     |  56 +++-
 doc/man7/provider-keymgmt.pod                      |  50 +++
 include/crypto/dsa.h                               |   6 +-
 include/internal/ffc.h                             |  15 +-
 include/openssl/core_names.h                       |  13 +
 include/openssl/dsa.h                              |  20 +-
 providers/implementations/keymgmt/dh_kmgmt.c       |  14 +-
 providers/implementations/keymgmt/dsa_kmgmt.c      | 335 ++++++++++++++++++---
 providers/implementations/serializers/build.info   |   4 +
 .../serializers/serializer_common.c                | 104 +++----
 .../implementations/serializers/serializer_dsa.c   |  20 +-
 .../serializers/serializer_ffc_params.c            |  58 ++++
 .../implementations/serializers/serializer_local.h |   2 +
 test/dsatest.c                                     | 239 ++++++++++++---
 test/evp_pkey_provided_test.c                      | 239 ++++++++++++++-
 test/recipes/15-test_gendsa.t                      |  77 +++++
 .../recipes/30-test_evp_pkey_provided/DSA.priv.der | Bin 0 -> 617 bytes
 .../recipes/30-test_evp_pkey_provided/DSA.priv.pem |  15 +
 .../recipes/30-test_evp_pkey_provided/DSA.priv.txt |  72 +++++
 test/recipes/30-test_evp_pkey_provided/DSA.pub.der | Bin 0 -> 842 bytes
 test/recipes/30-test_evp_pkey_provided/DSA.pub.pem |  20 ++
 test/recipes/30-test_evp_pkey_provided/DSA.pub.txt |  72 +++++
 util/libcrypto.num                                 |   7 +
 39 files changed, 1678 insertions(+), 225 deletions(-)
 create mode 100644 providers/implementations/serializers/serializer_ffc_params.c
 create mode 100644 test/recipes/15-test_gendsa.t
 create mode 100644 test/recipes/30-test_evp_pkey_provided/DSA.priv.der
 create mode 100644 test/recipes/30-test_evp_pkey_provided/DSA.priv.pem
 create mode 100644 test/recipes/30-test_evp_pkey_provided/DSA.priv.txt
 create mode 100644 test/recipes/30-test_evp_pkey_provided/DSA.pub.der
 create mode 100644 test/recipes/30-test_evp_pkey_provided/DSA.pub.pem
 create mode 100644 test/recipes/30-test_evp_pkey_provided/DSA.pub.txt

diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index f5bcee2460..9c1fa0388d 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -24,7 +24,7 @@
 #include "crypto/evp.h"
 #include <openssl/cms.h>
 #include <openssl/core_names.h>
-#include "openssl/param_build.h"
+#include <openssl/param_build.h>
 #include "internal/ffc.h"
 
 /*
@@ -558,7 +558,7 @@ static int dh_pkey_import_from(const OSSL_PARAM params[], void *key)
         return 0;
     }
 
-    if (!ffc_fromdata(dh_get0_params(dh), params)
+    if (!ffc_params_fromdata(dh_get0_params(dh), params)
         || !dh_key_fromdata(dh, params)
         || !EVP_PKEY_assign_DH(pkey, dh)) {
         DH_free(dh);
diff --git a/crypto/dh/dh_group_params.c b/crypto/dh/dh_group_params.c
index d672ae3034..cc1c546655 100644
--- a/crypto/dh/dh_group_params.c
+++ b/crypto/dh/dh_group_params.c
@@ -23,12 +23,14 @@
 #include "crypto/bn_dh.h"
 #include "crypto/dh.h"
 #include "crypto/security_bits.h"
+#include "e_os.h" /* strcasecmp */
 
 
-#define FFDHE(sz) { NID_ffdhe##sz, sz, &_bignum_ffdhe##sz##_p }
-#define MODP(sz)  { NID_modp_##sz, sz, &_bignum_modp_##sz##_p }
+#define FFDHE(sz) { SN_ffdhe##sz, NID_ffdhe##sz, sz, &_bignum_ffdhe##sz##_p }
+#define MODP(sz)  { SN_modp_##sz, NID_modp_##sz, sz, &_bignum_modp_##sz##_p }
 
 typedef struct safe_prime_group_st {
+    const char *name;
     int nid;
     int32_t nbits;
     const BIGNUM *p;
@@ -50,6 +52,28 @@ static const SP_GROUP sp_groups[] = {
     MODP(8192),
 };
 
+int ffc_named_group_to_nid(const char *name)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(sp_groups); ++i) {
+        if (strcasecmp(sp_groups[i].name, name) == 0)
+            return sp_groups[i].nid;
+    }
+    return NID_undef;
+}
+
+const char *ffc_named_group_from_nid(int nid)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(sp_groups); ++i) {
+        if (sp_groups[i].nid == nid)
+            return sp_groups[i].name;
+    }
+    return NULL;
+}
+
 #ifndef FIPS_MODE
 static DH *dh_new_by_nid_with_ctx(OPENSSL_CTX *libctx, int nid);
 
diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c
index ab2e25ea87..e46946153b 100644
--- a/crypto/dh/dh_key.c
+++ b/crypto/dh/dh_key.c
@@ -19,6 +19,12 @@
 #include "crypto/bn.h"
 #include "crypto/dh.h"
 
+#ifdef FIPS_MODE
+# define MIN_STRENGTH 112
+#else
+# define MIN_STRENGTH 80
+#endif
+
 static int generate_key(DH *dh);
 static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
                          const BIGNUM *a, const BIGNUM *p,
@@ -287,7 +293,8 @@ static int generate_key(DH *dh)
                  * Max Private key size N = len(q)
                  */
                 if (!ffc_generate_private_key(ctx, &dh->params,
-                                              BN_num_bits(dh->params.q), 112,
+                                              BN_num_bits(dh->params.q),
+                                              MIN_STRENGTH,
                                               priv_key))
                     goto err;
             }
diff --git a/crypto/dsa/build.info b/crypto/dsa/build.info
index fb5a4fee2a..7f621cb56b 100644
--- a/crypto/dsa/build.info
+++ b/crypto/dsa/build.info
@@ -1,10 +1,10 @@
 LIBS=../../libcrypto
 
 $COMMON=dsa_sign.c dsa_vrf.c dsa_lib.c dsa_ossl.c dsa_check.c \
-        dsa_key.c dsa_backend.c
+        dsa_key.c dsa_backend.c dsa_gen.c
 
 SOURCE[../../libcrypto]=$COMMON\
-        dsa_gen.c dsa_asn1.c \
+        dsa_asn1.c \
         dsa_err.c dsa_depr.c dsa_ameth.c dsa_pmeth.c dsa_prn.c \
         dsa_meth.c
 SOURCE[../../providers/libfips.a]=$COMMON
diff --git a/crypto/dsa/dsa_ameth.c b/crypto/dsa/dsa_ameth.c
index d63c142fdd..81bb6d88f7 100644
--- a/crypto/dsa/dsa_ameth.c
+++ b/crypto/dsa/dsa_ameth.c
@@ -19,11 +19,11 @@
 #include <openssl/bn.h>
 #include <openssl/cms.h>
 #include <openssl/core_names.h>
+#include <openssl/param_build.h>
 #include "internal/cryptlib.h"
 #include "crypto/asn1.h"
 #include "crypto/dsa.h"
 #include "crypto/evp.h"
-#include "openssl/param_build.h"
 #include "internal/ffc.h"
 #include "dsa_local.h"
 
@@ -586,7 +586,7 @@ static int dsa_pkey_import_from(const OSSL_PARAM params[], void *key)
         return 0;
     }
 
-    if (!ffc_fromdata(dsa_get0_params(dsa), params)
+    if (!dsa_ffc_params_fromdata(dsa, params)
         || !dsa_key_fromdata(dsa, params)
         || !EVP_PKEY_assign_DSA(pkey, dsa)) {
         DSA_free(dsa);
diff --git a/crypto/dsa/dsa_backend.c b/crypto/dsa/dsa_backend.c
index b927465cfa..461cb187dd 100644
--- a/crypto/dsa/dsa_backend.c
+++ b/crypto/dsa/dsa_backend.c
@@ -34,7 +34,7 @@ int dsa_key_fromdata(DSA *dsa, const OSSL_PARAM params[])
         return 1;
 
     /*
-     * DH documentation says that a public key must be present if a
+     * DSA documentation says that a public key must be present if a
      * private key is present.
      */
     if (param_priv_key != NULL && param_pub_key == NULL)
diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c
index 2148a1a487..7b72867f71 100644
--- a/crypto/dsa/dsa_gen.c
+++ b/crypto/dsa/dsa_gen.c
@@ -24,32 +24,34 @@
 #include "dsa_local.h"
 
 int dsa_generate_ffc_parameters(DSA *dsa, int type,
-                                int pbits, int qbits, int gindex,
-                                BN_GENCB *cb)
+                                int pbits, int qbits,
+                                EVP_MD *md, BN_GENCB *cb)
 {
     int ret = 0, res;
 
     if (qbits <= 0) {
-        const EVP_MD *evpmd = pbits >= 2048 ? EVP_sha256() : EVP_sha1();
-
-        qbits = EVP_MD_size(evpmd) * 8;
+        if (md != NULL)
+            qbits = EVP_MD_size(md) * 8;
+        else
+            qbits = (pbits >= 2048 ? SHA256_DIGEST_LENGTH :
+                                     SHA_DIGEST_LENGTH) * 8;
     }
-    dsa->params.gindex = gindex;
 #ifndef FIPS_MODE
     if (type == DSA_PARAMGEN_TYPE_FIPS_186_2)
         ret = ffc_params_FIPS186_2_generate(dsa->libctx, &dsa->params,
                                             FFC_PARAM_TYPE_DSA,
-                                            pbits, qbits, NULL, &res, cb);
+                                            pbits, qbits, md, &res, cb);
     else
 #endif
         ret = ffc_params_FIPS186_4_generate(dsa->libctx, &dsa->params,
                                             FFC_PARAM_TYPE_DSA,
-                                            pbits, qbits, NULL, &res, cb);
+                                            pbits, qbits, md, &res, cb);
     if (ret > 0)
         dsa->dirty_cnt++;
     return ret;
 }
 
+#ifndef FIPS_MODE
 int DSA_generate_parameters_ex(DSA *dsa, int bits,
                                const unsigned char *seed_in, int seed_len,
                                int *counter_ret, unsigned long *h_ret,
@@ -68,13 +70,13 @@ int DSA_generate_parameters_ex(DSA *dsa, int bits,
     /* The old code used FIPS 186-2 DSA Parameter generation */
     if (bits <= 1024 && seed_len == 20) {
         if (!dsa_generate_ffc_parameters(dsa, DSA_PARAMGEN_TYPE_FIPS_186_2,
-                                         bits, 160, -1, cb))
+                                         bits, 160, NULL, cb))
             return 0;
     } else
 #endif
     {
         if (!dsa_generate_ffc_parameters(dsa, DSA_PARAMGEN_TYPE_FIPS_186_4,
-                                         bits, -1, -1, cb))
+                                         bits, -1, NULL, cb))
             return 0;
     }
 
@@ -84,3 +86,4 @@ int DSA_generate_parameters_ex(DSA *dsa, int bits,
         *h_ret = dsa->params.h;
     return 1;
 }
+#endif
diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c
index 2dec35f28f..1d625272e5 100644
--- a/crypto/dsa/dsa_key.c
+++ b/crypto/dsa/dsa_key.c
@@ -21,6 +21,12 @@
 #include "crypto/dsa.h"
 #include "dsa_local.h"
 
+#ifdef FIPS_MODE
+# define MIN_STRENGTH 112
+#else
+# define MIN_STRENGTH 80
+#endif
+
 static int dsa_keygen(DSA *dsa, int pairwise_test);
 static int dsa_keygen_pairwise_test(DSA *dsa, OSSL_CALLBACK *cb, void *cbarg);
 
@@ -69,7 +75,7 @@ static int dsa_keygen(DSA *dsa, int pairwise_test)
     }
 
     if (!ffc_generate_private_key(ctx, &dsa->params, BN_num_bits(dsa->params.q),
-                                  112, priv_key))
+                                  MIN_STRENGTH, priv_key))
         goto err;
 
     if (dsa->pub_key == NULL) {
diff --git a/crypto/dsa/dsa_lib.c b/crypto/dsa/dsa_lib.c
index e3205223e9..b773f2c526 100644
--- a/crypto/dsa/dsa_lib.c
+++ b/crypto/dsa/dsa_lib.c
@@ -19,7 +19,9 @@
 #include <openssl/bn.h>
 #include <openssl/asn1.h>
 #include <openssl/engine.h>
+#include <openssl/core_names.h>
 #include "dsa_local.h"
+#include "crypto/evp.h"
 #include "crypto/dsa.h"
 #include "crypto/dh.h" /* required by DSA_dup_DH() */
 
@@ -342,3 +344,162 @@ FFC_PARAMS *dsa_get0_params(DSA *dsa)
 {
     return &dsa->params;
 }
+
+int dsa_ffc_params_fromdata(DSA *dsa, const OSSL_PARAM params[])
+{
+    int ret;
+    FFC_PARAMS *ffc;
+
+    if (dsa == NULL)
+        return 0;
+    ffc = dsa_get0_params(dsa);
+    if (ffc == NULL)
+        return 0;
+
+    ret = ffc_params_fromdata(ffc, params);
+    if (ret)
+        dsa->dirty_cnt++;
+    return ret;
+}
+
+static int dsa_paramgen_check(EVP_PKEY_CTX *ctx)
+{
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+    /* If key type not DSA return error */
+    if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_DSA)
+        return -1;
+    return 1;
+}
+
+int EVP_PKEY_CTX_set_dsa_paramgen_type(EVP_PKEY_CTX *ctx, const char *name)
+{
+    int ret;
+    OSSL_PARAM params[2], *p = params;
+
+    if ((ret = dsa_paramgen_check(ctx)) <= 0)
+        return ret;
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE,
+                                            (char *)name, 0);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, params);
+}
+
+int EVP_PKEY_CTX_set_dsa_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex)
+{
+    int ret;
+    OSSL_PARAM params[2], *p = params;
+
+    if ((ret = dsa_paramgen_check(ctx)) <= 0)
+        return ret;
+
+    *p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_FFC_GINDEX, &gindex);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, params);
+}
+
+int EVP_PKEY_CTX_set_dsa_paramgen_seed(EVP_PKEY_CTX *ctx,
+                                       const unsigned char *seed,
+                                       size_t seedlen)
+{
+    int ret;
+    OSSL_PARAM params[2], *p = params;
+
+    if ((ret = dsa_paramgen_check(ctx)) <= 0)
+        return ret;
+
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_FFC_SEED,
+                                             (void *)seed, seedlen);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, params);
+}
+
+int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits)
+{
+    int ret;
+    OSSL_PARAM params[2], *p = params;
+    size_t bits = nbits;
+
+    if ((ret = dsa_paramgen_check(ctx)) <= 0)
+        return ret;
+
+#if !defined(FIPS_MODE)
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.keymgmt.genctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA,  EVP_PKEY_OP_PARAMGEN,
+                                 EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, nbits, NULL);
+#endif
+
+    *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_PBITS, &bits);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, params);
+}
+
+int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits)
+{
+    int ret;
+    OSSL_PARAM params[2], *p = params;
+    size_t bits2 = qbits;
+
+    if ((ret = dsa_paramgen_check(ctx)) <= 0)
+        return ret;
+
+#if !defined(FIPS_MODE)
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.keymgmt.genctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA,  EVP_PKEY_OP_PARAMGEN,
+                                 EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits, NULL);
+#endif
+
+    *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_QBITS, &bits2);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, params);
+}
+
+int EVP_PKEY_CTX_set_dsa_paramgen_md_props(EVP_PKEY_CTX *ctx,
+                                           const char *md_name,
+                                           const char *md_properties)
+{
+    int ret;
+    OSSL_PARAM params[3], *p = params;
+
+    if ((ret = dsa_paramgen_check(ctx)) <= 0)
+        return ret;
+
+#if !defined(FIPS_MODE)
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.keymgmt.genctx == NULL) {
+        const EVP_MD *md = EVP_get_digestbyname(md_name);
+
+         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
+                           EVP_PKEY_CTRL_DSA_PARAMGEN_MD, 0, (void *)(md));
+    }
+#endif
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST,
+                                            (char *)md_name, 0);
+    if (md_properties != NULL)
+        *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST_PROPS,
+                                                (char *)md_properties, 0);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, params);
+}
+
+#if !defined(FIPS_MODE)
+int EVP_PKEY_CTX_set_dsa_paramgen_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
+{
+    const char *md_name = (md == NULL) ? "" : EVP_MD_name(md);
+
+    return EVP_PKEY_CTX_set_dsa_paramgen_md_props(ctx, md_name, NULL);
+}
+#endif
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 9f04c72330..b0163f5792 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -627,14 +627,6 @@ RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey)
 # endif
 
 # ifndef OPENSSL_NO_DSA
-int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key)
-{
-    int ret = EVP_PKEY_assign_DSA(pkey, key);
-    if (ret)
-        DSA_up_ref(key);
-    return ret;
-}
-
 DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey)
 {
     if (!evp_pkey_downgrade((EVP_PKEY *)pkey)) {
@@ -648,6 +640,13 @@ DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey)
     return pkey->pkey.dsa;
 }
 
+int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key)
+{
+    int ret = EVP_PKEY_assign_DSA(pkey, key);
+    if (ret)
+        DSA_up_ref(key);
+    return ret;
+}
 DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey)
 {
     DSA *ret = EVP_PKEY_get0_DSA(pkey);
@@ -655,10 +654,11 @@ DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey)
         DSA_up_ref(ret);
     return ret;
 }
-# endif
+# endif /*  OPENSSL_NO_DSA */
+#endif /* FIPS_MODE */
 
+#ifndef FIPS_MODE
 # ifndef OPENSSL_NO_EC
-
 int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key)
 {
     int ret = EVP_PKEY_assign_EC_KEY(pkey, key);
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index 6a86b26ded..6d34accc3c 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -8,7 +8,7 @@
  */
 
 /*
- * DH low level APIs are deprecated for public use, but still ok for
+ * Low level key APIs (DH etc) are deprecated for public use, but still ok for
  * internal use.
  */
 #include "internal/deprecated.h"
@@ -816,6 +816,18 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
         }
     }
 # endif
+# ifndef OPENSSL_NO_DSA
+    if (keytype == EVP_PKEY_DSA) {
+        switch (cmd) {
+        case EVP_PKEY_CTRL_DSA_PARAMGEN_BITS:
+            return EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, p1);
+        case EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS:
+            return EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, p1);
+        case EVP_PKEY_CTRL_DSA_PARAMGEN_MD:
+            return EVP_PKEY_CTX_set_dsa_paramgen_md(ctx, p2);
+        }
+    }
+# endif
 # ifndef OPENSSL_NO_EC
     if (keytype == EVP_PKEY_EC) {
         switch (cmd) {
@@ -1000,6 +1012,14 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
         name = OSSL_PKEY_PARAM_RSA_E;
     else if (strcmp(name, "rsa_keygen_primes") == 0)
         name = OSSL_PKEY_PARAM_RSA_PRIMES;
+# ifndef OPENSSL_NO_DSA
+    else if (strcmp(name, "dsa_paramgen_bits") == 0)
+        name = OSSL_PKEY_PARAM_FFC_PBITS;
+    else if (strcmp(name, "dsa_paramgen_q_bits") == 0)
+        name = OSSL_PKEY_PARAM_FFC_QBITS;
+    else if (strcmp(name, "dsa_paramgen_md") == 0)
+        name = OSSL_PKEY_PARAM_FFC_DIGEST;
+# endif
 # ifndef OPENSSL_NO_DH
     else if (strcmp(name, "dh_pad") == 0)
         name = OSSL_EXCHANGE_PARAM_PAD;
diff --git a/crypto/ffc/ffc_backend.c b/crypto/ffc/ffc_backend.c
index cde9e43da3..1d076184bc 100644
--- a/crypto/ffc/ffc_backend.c
+++ b/crypto/ffc/ffc_backend.c
@@ -9,6 +9,7 @@
 
 #include <openssl/core_names.h>
 #include "internal/ffc.h"
+#include "internal/sizes.h"
 
 /*
  * The intention with the "backend" source file is to offer backend support
@@ -16,27 +17,75 @@
  * implementations alike.
  */
 
-int ffc_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[])
+int ffc_params_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[])
 {
+    const OSSL_PARAM *prm;
     const OSSL_PARAM *param_p, *param_q, *param_g;
-    BIGNUM *p = NULL, *q = NULL, *g = NULL;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL, *j = NULL;
+#if 0
+    char group_name[OSSL_MAX_NAME_SIZE];
+    char *str = group_name;
+#endif
+    int i;
 
     if (ffc == NULL)
         return 0;
 
+/* TODO(3.0) Add for DH PR */
+#if 0
+    prm  = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GROUP);
+    if (prm != NULL) {
+        if (!OSSL_PARAM_get_utf8_string(prm, &str, sizeof(group_name)))
+            goto err;
+        if (!ffc_set_group_pqg(ffc, group_name))
+            goto err;
+    }
+#endif
     param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
-    param_q = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_Q);
     param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
+    param_q = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_Q);
 
     if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
         || (param_q != NULL && !OSSL_PARAM_get_BN(param_q, &q))
         || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g)))
         goto err;
 
+    prm = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX);
+    if (prm != NULL) {
+        if (!OSSL_PARAM_get_int(prm, &i))
+            goto err;
+        ffc->gindex =  i;
+    }
+    prm = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER);
+    if (prm != NULL) {
+        if (!OSSL_PARAM_get_int(prm, &i))
+            goto err;
+        ffc->pcounter = i;
+    }
+    prm = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_COFACTOR);
+    if (prm != NULL) {
+        if (!OSSL_PARAM_get_BN(prm, &j))
+            goto err;
+    }
+    prm = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H);
+    if (prm != NULL) {
+        if (!OSSL_PARAM_get_int(prm, &i))
+            goto err;
+        ffc->h =  i;
+    }
+    prm  = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED);
+    if (prm != NULL) {
+        if (prm->data_type != OSSL_PARAM_OCTET_STRING)
+            goto err;
+        if (!ffc_params_set_seed(ffc, prm->data, prm->data_size))
+            goto err;
+    }
     ffc_params_set0_pqg(ffc, p, q, g);
+    ffc_params_set0_j(ffc, j);
     return 1;
 
  err:
+    BN_free(j);
     BN_free(p);
     BN_free(q);
     BN_free(g);
diff --git a/crypto/ffc/ffc_key_generate.c b/crypto/ffc/ffc_key_generate.c
index 078e8d39a1..4e2f231d83 100644
--- a/crypto/ffc/ffc_key_generate.c
+++ b/crypto/ffc/ffc_key_generate.c
@@ -10,6 +10,7 @@
 #include "internal/ffc.h"
 
 /*
+ * For Fips mode:
  * 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)].
  *
diff --git a/crypto/ffc/ffc_params.c b/crypto/ffc/ffc_params.c
index cb8987b64d..5950847703 100644
--- a/crypto/ffc/ffc_params.c
+++ b/crypto/ffc/ffc_params.c
@@ -8,7 +8,10 @@
  */
 
 #include <string.h> /* memset */
+#include <openssl/core_names.h>
 #include "internal/ffc.h"
+#include "internal/param_build_set.h"
+
 #ifndef FIPS_MODE
 # include <openssl/asn1.h> /* ffc_params_print */
 #endif
@@ -67,15 +70,17 @@ void ffc_params_set0_j(FFC_PARAMS *d, BIGNUM *j)
         d->j = j;
 }
 
-int ffc_params_set_validate_params(FFC_PARAMS *params,
-                                   const unsigned char *seed, size_t seedlen,
-                                   int counter)
+int ffc_params_set_seed(FFC_PARAMS *params,
+                        const unsigned char *seed, size_t seedlen)
 {
     if (params == NULL)
         return 0;
 
-    if (params->seed != NULL)
+    if (params->seed != NULL) {
+        if (params->seed == seed)
+            return 1;
         OPENSSL_free(params->seed);
+    }
 
     if (seed != NULL && seedlen > 0) {
         params->seed = OPENSSL_memdup(seed, seedlen);
@@ -86,6 +91,30 @@ int ffc_params_set_validate_params(FFC_PARAMS *params,
         params->seed = NULL;
         params->seedlen = 0;
     }
+    return 1;
+}
+
+void ffc_params_set_gindex(FFC_PARAMS *params, int index)
+{
+    params->gindex = index;
+}
+
+void ffc_params_set_pcounter(FFC_PARAMS *params, int index)
+{
+    params->pcounter = index;
+}
+
+void ffc_params_set_h(FFC_PARAMS *params, int index)
+{
+    params->h = index;
+}
+
+int ffc_params_set_validate_params(FFC_PARAMS *params,
+                                   const unsigned char *seed, size_t seedlen,
+                                   int counter)
+{
+    if (!ffc_params_set_seed(params, seed, seedlen))
+        return 0;
     params->pcounter = counter;
     return 1;
 }
@@ -139,7 +168,10 @@ int ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src)
     } else {
         dst->seed = NULL;
     }
+    dst->nid = src->nid;
     dst->pcounter = src->pcounter;
+    dst->h = src->h;
+    dst->gindex = src->gindex;
     return 1;
 }
 
@@ -150,7 +182,52 @@ int ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q)
            && (ignore_q || BN_cmp(a->q, b->q) == 0); /* Note: q may be NULL */
 }
 
+int ffc_params_todata(const FFC_PARAMS *ffc, OSSL_PARAM_BLD *bld,
+                      OSSL_PARAM params[])
+{
+    if (ffc == NULL)
+        return 0;
+
+    if (ffc->p != NULL
+        && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_P, ffc->p))
+        return 0;
+    if (ffc->q != NULL
+        && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_Q, ffc->q))
+        return 0;
+    if (ffc->g != NULL
+        && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_G, ffc->g))
+        return 0;
+    if (ffc->j != NULL
+        && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_COFACTOR,
+                                    ffc->j))
+        return 0;
+    if (!ossl_param_build_set_int(bld, params, OSSL_PKEY_PARAM_FFC_GINDEX,
+                                  ffc->gindex))
+        return 0;
+    if (!ossl_param_build_set_int(bld, params, OSSL_PKEY_PARAM_FFC_PCOUNTER,
+                                  ffc->pcounter))
+        return 0;
+    if (!ossl_param_build_set_int(bld, params, OSSL_PKEY_PARAM_FFC_H, ffc->h))
+        return 0;
+    if (ffc->seed != NULL
+        && !ossl_param_build_set_octet_string(bld, params,
+                                              OSSL_PKEY_PARAM_FFC_SEED,
+                                              ffc->seed, ffc->seedlen))
+        return 0;
+    if (ffc->nid != NID_undef) {
+        const char *name = ffc_named_group_from_nid(ffc->nid);
+
+        if (name == NULL
+            || !ossl_param_build_set_utf8_string(bld, params,
+                                                 OSSL_PKEY_PARAM_FFC_GROUP,
+                                                 name))
+            return 0;
+    }
+    return 1;
+}
+
 #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))
diff --git a/crypto/ffc/ffc_params_generate.c b/crypto/ffc/ffc_params_generate.c
index cb51bf0e76..6d9b924387 100644
--- a/crypto/ffc/ffc_params_generate.c
+++ b/crypto/ffc/ffc_params_generate.c
@@ -487,7 +487,7 @@ int ffc_params_FIPS186_4_gen_verify(OPENSSL_CTX *libctx, FFC_PARAMS *params,
     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;
+    int canonical_g = 0, hret = 0;
     BN_CTX *ctx = NULL;
     EVP_MD_CTX *mctx = NULL;
     int generate = (validate_flags == 0);
diff --git a/doc/man1/openssl-genpkey.pod.in b/doc/man1/openssl-genpkey.pod.in
index 4f1128a049..8d7da6d7c7 100644
--- a/doc/man1/openssl-genpkey.pod.in
+++ b/doc/man1/openssl-genpkey.pod.in
@@ -194,11 +194,15 @@ The number of bits in the generated prime. If not specified 2048 is used.
 
 =item B<dsa_paramgen_q_bits>:I<numbits>
 
+=item B<qbits>:I<numbits>
+
 The number of bits in the q parameter. Must be one of 160, 224 or 256. If not
 specified 224 is used.
 
 =item B<dsa_paramgen_md>:I<digest>
 
+=item B<digest>:I<digest>
+
 The digest to use during parameter generation. Must be one of B<sha1>, B<sha224>
 or B<sha256>. If set, then the number of bits in B<q> will match the output size
 of the specified digest and the B<dsa_paramgen_q_bits> parameter will be
@@ -206,6 +210,31 @@ ignored. If not set, then a digest will be used that gives an output matching
 the number of bits in B<q>, i.e. B<sha1> if q length is 160, B<sha224> if it 224
 or B<sha256> if it is 256.
 
+
+=item B<properties>:I<query>
+
+The I<digest> property I<query> string to use when fetching a digest from a provider.
+
+=item B<type>:I<type>
+
+The type of generation to use. Set this to 1 to use legacy FIPS186-2 parameter
+generation. The default of 0 uses FIPS186-4 parameter generation.
+
+=item B<gindex>:I<index>
+
+The index to use for canonical generation and verification of the generator g.
+Set this to a positive value ranging from 0..255 to use this mode. Larger values
+will only use the bottom byte.
+This I<index> must then be reused during key validation to verify the value of g.
+If this value is not set then g is not verifiable. The default value is -1.
+
+=item B<hexseed>:I<seed>
+
+The seed I<seed> data to use instead of generating a random seed internally.
+This should be used for testing purposes only. This will either produced fixed
+values for the generated parameters OR it will fail if the seed did not
+generate valid primes.
+
 =back
 
 =head2 DH Parameter Generation Options
@@ -269,10 +298,12 @@ Generate a 2048 bit RSA key using 3 as the public exponent:
  openssl genpkey -algorithm RSA -out key.pem \
      -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:3
 
-Generate 2048 bit DSA parameters:
+Generate 2048 bit DSA parameters that can be validated: The output values for
+gindex and seed are required for key validation purposes and are not saved to
+the output pem file).
 
- openssl genpkey -genparam -algorithm DSA -out dsap.pem \
-     -pkeyopt dsa_paramgen_bits:2048
+ openssl genpkey -genparam -algorithm DSA -out dsap.pem -pkeyopt pbits:2048 \
+     -pkeyopt qbits:224 -pkeyopt digest:SHA256 -pkeyopt gindex:1 -text
 
 Generate DSA key from parameters:
 
diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod
index 829bdb9e3d..ded779feb0 100644
--- a/doc/man3/EVP_PKEY_CTX_ctrl.pod
+++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod
@@ -33,6 +33,10 @@ EVP_PKEY_CTX_get0_rsa_oaep_label,
 EVP_PKEY_CTX_set_dsa_paramgen_bits,
 EVP_PKEY_CTX_set_dsa_paramgen_q_bits,
 EVP_PKEY_CTX_set_dsa_paramgen_md,
+EVP_PKEY_CTX_set_dsa_paramgen_md_props,
+EVP_PKEY_CTX_set_dsa_paramgen_gindex,
+EVP_PKEY_CTX_set_dsa_paramgen_type,
+EVP_PKEY_CTX_set_dsa_paramgen_seed,
 EVP_PKEY_CTX_set_dh_paramgen_prime_len,
 EVP_PKEY_CTX_set_dh_paramgen_subprime_len,
 EVP_PKEY_CTX_set_dh_paramgen_generator,
@@ -121,6 +125,14 @@ EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len
  int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits);
  int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits);
  int EVP_PKEY_CTX_set_dsa_paramgen_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+ int EVP_PKEY_CTX_set_dsa_paramgen_md_props(EVP_PKEY_CTX *ctx,
+                                            const char *md_name,
+                                            const char *md_properties);
+ int EVP_PKEY_CTX_set_dsa_paramgen_type(EVP_PKEY_CTX *ctx, const char *name);
+ int EVP_PKEY_CTX_set_dsa_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex);
+ int EVP_PKEY_CTX_set_dsa_paramgen_seed(EVP_PKEY_CTX *ctx,
+                                        const unsigned char *seed,
+                                        size_t seedlen);
 
  #include <openssl/dh.h>
 
@@ -395,19 +407,42 @@ negotiated protocol version. Otherwise it should be left unset.
 
 =head2 DSA parameters
 
-The EVP_PKEY_CTX_set_dsa_paramgen_bits() macro sets the number of bits used
+The EVP_PKEY_CTX_set_dsa_paramgen_bits() method sets the number of bits used
 for DSA parameter generation to I<nbits>. If not specified, 2048 is used.
 
-The EVP_PKEY_CTX_set_dsa_paramgen_q_bits() macro sets the number of bits in the
+The EVP_PKEY_CTX_set_dsa_paramgen_q_bits() method sets the number of bits in the
 subprime parameter I<q> for DSA parameter generation to I<qbits>. If not
 specified, 224 is used. If a digest function is specified below, this parameter
 is ignored and instead, the number of bits in I<q> matches the size of the
 digest.
 
-The EVP_PKEY_CTX_set_dsa_paramgen_md() macro sets the digest function used for
+The EVP_PKEY_CTX_set_dsa_paramgen_md() method sets the digest function used for
 DSA parameter generation to I<md>. If not specified, one of SHA-1, SHA-224, or
 SHA-256 is selected to match the bit length of I<q> above.
 
+The EVP_PKEY_CTX_set_dsa_paramgen_md_props() method sets the digest function
+used for DSA parameter generation using I<md_name> and I<md_properties> to
+retrieve the digest from a provider.
+If not specified, I<md_name> will be set to one of SHA-1, SHA-224, or
+SHA-256 depending on the bit length of I<q> above. I<md_properties> is a
+property query string that has a default value of '' if not specified.
+
+The EVP_PKEY_CTX_set_dsa_paramgen_gindex() method sets the I<gindex> used by
+the generator G. The default value is -1 which uses unverifiable g, otherwise
+a positive value uses verifiable g. This value must be saved if key validation
+of g is required, since it is not part of a persisted key.
+
+The EVP_PKEY_CTX_set_dsa_paramgen_seed() method sets the I<seed> to use for
+generation rather than using a randomly generated value for the seed. This is
+useful for testing purposes only and can fail if the seed does not produce
+primes for both p & q on its first iteration. This value must be saved if
+key validation of p, q, and verifiable g are required, since it is not part of
+a persisted key.
+
+The EVP_PKEY_CTX_set_dsa_paramgen_type() method sets the generation type to
+use FIPS186-4 generation if I<name> is "fips186_4", or FIPS186-2 generation if
+I<name> is "fips186_2". The default value is "fips186_4".
+
 =head2 DH parameters
 
 The EVP_PKEY_CTX_set_dh_paramgen_prime_len() macro sets the length of the DH
@@ -417,8 +452,7 @@ 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 I<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 B<DH_PARAMGEN_TYPE_FIPS_186_2> or
-B<DH_PARAMGEN_TYPE_FIPS_186_4>.
+paramgen type must have been set to "fips186_4".
 
 The EVP_PKEY_CTX_set_dh_paramgen_generator() macro sets DH generator to I<gen>
 for DH parameter generation. If not specified 2 is used.
@@ -633,12 +667,16 @@ EVP_PKEY_CTX_get_rsa_padding(), EVP_PKEY_CTX_get_rsa_mgf1_md(),
 EVP_PKEY_CTX_set_rsa_mgf1_md(), EVP_PKEY_CTX_set_rsa_oaep_md(),
 EVP_PKEY_CTX_get_rsa_oaep_md(), EVP_PKEY_CTX_set0_rsa_oaep_label(),
 EVP_PKEY_CTX_get0_rsa_oaep_label(), EVP_PKEY_CTX_set_rsa_pss_saltlen(),
-EVP_PKEY_CTX_get_rsa_pss_saltlen(), were macros in OpenSSL 1.1.1 and below.
+EVP_PKEY_CTX_get_rsa_pss_saltlen(), EVP_PKEY_CTX_set_dsa_paramgen_bits(),
+EVP_PKEY_CTX_set_dsa_paramgen_q_bits() and EVP_PKEY_CTX_set_dsa_paramgen_md()
+were macros in OpenSSL 1.1.1 and below.
 From OpenSSL 3.0 they are functions.
 
 EVP_PKEY_CTX_get_rsa_oaep_md_name(), EVP_PKEY_CTX_get_rsa_mgf1_md_name(),
-EVP_PKEY_CTX_set_rsa_mgf1_md_name() and EVP_PKEY_CTX_set_rsa_oaep_md_name() were
-added in OpenSSL 3.0.
+EVP_PKEY_CTX_set_rsa_mgf1_md_name(), EVP_PKEY_CTX_set_rsa_oaep_md_name(),
+EVP_PKEY_CTX_set_dsa_paramgen_md_props(), EVP_PKEY_CTX_set_dsa_paramgen_gindex(),
+EVP_PKEY_CTX_set_dsa_paramgen_type() and EVP_PKEY_CTX_set_dsa_paramgen_seed()
+were added in OpenSSL 3.0.
 
 The EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and
 EVP_PKEY_CTX_get1_id_len() macros were added in 1.1.1, other functions were
@@ -646,7 +684,7 @@ added in OpenSSL 1.0.0.
 
 =head1 COPYRIGHT
 
-Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2006-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
diff --git a/doc/man7/provider-keymgmt.pod b/doc/man7/provider-keymgmt.pod
index 52cb977cb4..c93abba8eb 100644
--- a/doc/man7/provider-keymgmt.pod
+++ b/doc/man7/provider-keymgmt.pod
@@ -328,6 +328,56 @@ from I<keydata_from> to I<keydata_to>.  It is assumed that the caller
 has ensured that I<keydata_to> and I<keydata_from> are both owned by
 the implementation of this function.
 
+=head2 Built-in DSA Key Generation Types
+
+The following Key Generation types are available for the built-in DSA algorithm:
+
+=over 4
+
+=item "pbits" (B<OSSL_PKEY_PARAM_FFC_PBITS>) <unsigned integer>
+
+Sets the DSA size (in bits) of the prime 'p'.
+The value should be 2048 or 3072.
+
+=item "qbits" (B<OSSL_PKEY_PARAM_FFC_QBITS>) <unsigned integer>
+
+Sets the DSA size (in bits) of the prime 'q'.
+The value should be 224 or 256.
+
+=item "type" (B<OSSL_PKEY_PARAM_FFC_TYPE>) <integer>
+
+Sets the type of parameter generation.
+Use 0 for FIPS186-4,  or 1 for legacy FIPS186-2.
+The default is 0.
+
+=item "digest" (B<OSSL_PKEY_PARAM_FFC_DIGEST>)  <utf8_string>
+
+Sets the Digest algorithm to be used as part of the Key Generation Function
+associated with the given Key Generation I<ctx>.
+
+=item "properties" (B<OSSL_PKEY_PARAM_FFC_DIGEST_PROPS>) <utf8_string>
+
+Sets properties to be used upon look up of the implementation for the selected
+Digest algorithm for the Key Generation Function associated with the given key
+Generation I<ctx>.
+
+=item "gindex" (B<OSSL_PKEY_PARAM_FFC_GINDEX>) <integer>
+
+Sets the index to use for canonical generation and verification of the generator g.
+Set this to a positive value to use this mode. This I<index> can then be reused
+during key validation to verify the value of g. If this value is not set then
+g is not verifiable. The default value is -1.
+
+=item "seed" (B<OSSL_PKEY_PARAM_FFC_SEED>) <octet_string>
+
+Sets the I<seed> data to use instead of generating a random seed internally.
+This should be used for testing purposes only. This will either produced fixed
+values for the generated parameters OR it will fail if the seed did not
+generate valid primes.
+
+=back
+
+
 =head2 Built-in RSA Import/Export Types
 
 The following Import/Export types are available for the built-in RSA algorithm:
diff --git a/include/crypto/dsa.h b/include/crypto/dsa.h
index 0afec99ae6..1a278fecf2 100644
--- a/include/crypto/dsa.h
+++ b/include/crypto/dsa.h
@@ -11,20 +11,20 @@
 #include <openssl/dsa.h>
 #include "internal/ffc.h"
 
+#define DSA_PARAMGEN_TYPE_FIPS_186_4   0   /* Use FIPS186-4 standard */
 #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 */
 
 DSA *dsa_new_with_ctx(OPENSSL_CTX *libctx);
 
 int dsa_generate_ffc_parameters(DSA *dsa, int type,
-                                int pbits, int qbits, int gindex,
-                                BN_GENCB *cb);
+                                int pbits, int qbits, EVP_MD *md, BN_GENCB *cb);
 
 int dsa_sign_int(int type, const unsigned char *dgst,
                  int dlen, unsigned char *sig, unsigned int *siglen, DSA *dsa);
 const unsigned char *dsa_algorithmidentifier_encoding(int md_nid, size_t *len);
 
 FFC_PARAMS *dsa_get0_params(DSA *dsa);
+int dsa_ffc_params_fromdata(DSA *dsa, const OSSL_PARAM params[]);
 int dsa_key_fromdata(DSA *dsa, const OSSL_PARAM params[]);
 
 int dsa_generate_public_key(BN_CTX *ctx, const DSA *dsa, const BIGNUM *priv_key,
diff --git a/include/internal/ffc.h b/include/internal/ffc.h
index fd1007631e..c8b2cb8c3c 100644
--- a/include/internal/ffc.h
+++ b/include/internal/ffc.h
@@ -14,6 +14,8 @@
 # include <openssl/bn.h>
 # include <openssl/evp.h>
 # include <openssl/dh.h> /* Uses Error codes from DH */
+# include <openssl/params.h>
+# include <openssl/param_build.h>
 
 /* Default value for gindex when canonical generation of g is not used */
 # define FFC_UNVERIFIABLE_GINDEX -1
@@ -100,6 +102,12 @@ 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_seed(FFC_PARAMS *params,
+                        const unsigned char *seed, size_t seedlen);
+void ffc_params_set_gindex(FFC_PARAMS *params, int index);
+void ffc_params_set_pcounter(FFC_PARAMS *params, int index);
+void ffc_params_set_h(FFC_PARAMS *params, int index);
+
 int ffc_params_set_validate_params(FFC_PARAMS *params,
                                    const unsigned char *seed, size_t seedlen,
                                    int counter);
@@ -155,6 +163,11 @@ int ffc_validate_public_key_partial(const FFC_PARAMS *params,
 int ffc_validate_private_key(const BIGNUM *upper, const BIGNUM *priv_key,
                              int *ret);
 
-int ffc_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[]);
+int ffc_params_todata(const FFC_PARAMS *ffc, OSSL_PARAM_BLD *tmpl,
+                              OSSL_PARAM params[]);
+int ffc_params_fromdata(FFC_PARAMS *ffc, const OSSL_PARAM params[]);
+int ffc_named_group_to_nid(const char *name);
+const char *ffc_named_group_from_nid(int nid);
+int ffc_set_group_pqg(FFC_PARAMS *ffc, const char *group_name);
 
 #endif /* OSSL_INTERNAL_FFC_H */
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index c8a88285d8..18f835231c 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -191,6 +191,12 @@ extern "C" {
 #define OSSL_PKEY_PARAM_FFC_P        "p"
 #define OSSL_PKEY_PARAM_FFC_G        "g"
 #define OSSL_PKEY_PARAM_FFC_Q        "q"
+#define OSSL_PKEY_PARAM_FFC_GINDEX   "gindex"
+#define OSSL_PKEY_PARAM_FFC_PCOUNTER "pcounter"
+#define OSSL_PKEY_PARAM_FFC_SEED     "seed"
+#define OSSL_PKEY_PARAM_FFC_COFACTOR "j"
+#define OSSL_PKEY_PARAM_FFC_H        "hindex"
+#define OSSL_PKEY_PARAM_FFC_GROUP    "group"
 
 /* Elliptic Curve Domain Parameters */
 #define OSSL_PKEY_PARAM_EC_NAME      "curve-name"
@@ -255,6 +261,13 @@ extern "C" {
 #define OSSL_PKEY_PARAM_RSA_BITS        OSSL_PKEY_PARAM_BITS
 #define OSSL_PKEY_PARAM_RSA_PRIMES      "primes"
 
+/* Key generation parameters */
+#define OSSL_PKEY_PARAM_FFC_TYPE         "type"
+#define OSSL_PKEY_PARAM_FFC_PBITS        "pbits"
+#define OSSL_PKEY_PARAM_FFC_QBITS        "qbits"
+#define OSSL_PKEY_PARAM_FFC_DIGEST       OSSL_PKEY_PARAM_DIGEST
+#define OSSL_PKEY_PARAM_FFC_DIGEST_PROPS OSSL_PKEY_PARAM_PROPERTIES
+
 /* Key Exchange parameters */
 
 #define OSSL_EXCHANGE_PARAM_PAD                   "pad" /* uint */
diff --git a/include/openssl/dsa.h b/include/openssl/dsa.h
index c704d5d5c9..fce6e94d66 100644
--- a/include/openssl/dsa.h
+++ b/include/openssl/dsa.h
@@ -182,15 +182,17 @@ DEPRECATEDIN_3_0(int DSA_print_fp(FILE *bp, const DSA *x, int off))
 DEPRECATEDIN_3_0(DH *DSA_dup_DH(const DSA *r))
 #  endif
 
-#  define EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, nbits) \
-         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \
-                           EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, nbits, NULL)
-#  define EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, qbits) \
-         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \
-                           EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits, NULL)
-#  define EVP_PKEY_CTX_set_dsa_paramgen_md(ctx, md) \
-         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \
-                           EVP_PKEY_CTRL_DSA_PARAMGEN_MD, 0, (void *)(md))
+int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits);
+int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits);
+int EVP_PKEY_CTX_set_dsa_paramgen_md_props(EVP_PKEY_CTX *ctx,
+                                           const char *md_name,
+                                           const char *md_properties);
+int EVP_PKEY_CTX_set_dsa_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex);
+int EVP_PKEY_CTX_set_dsa_paramgen_type(EVP_PKEY_CTX *ctx, const char *name);
+int EVP_PKEY_CTX_set_dsa_paramgen_seed(EVP_PKEY_CTX *ctx,
+                                       const unsigned char *seed,
+                                       size_t seedlen);
+int EVP_PKEY_CTX_set_dsa_paramgen_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
 
 #  define EVP_PKEY_CTRL_DSA_PARAMGEN_BITS         (EVP_PKEY_ALG_CTRL + 1)
 #  define EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS       (EVP_PKEY_ALG_CTRL + 2)
diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c
index 6514d8f066..250e7aac95 100644
--- a/providers/implementations/keymgmt/dh_kmgmt.c
+++ b/providers/implementations/keymgmt/dh_kmgmt.c
@@ -18,11 +18,11 @@
 #include <openssl/bn.h>
 #include <openssl/dh.h>
 #include <openssl/params.h>
+#include <openssl/param_build.h>
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
 #include "prov/provider_ctx.h"
 #include "crypto/dh.h"
-#include "openssl/param_build.h"
 
 static OSSL_OP_keymgmt_new_fn dh_newdata;
 static OSSL_OP_keymgmt_free_fn dh_freedata;
@@ -137,7 +137,7 @@ static int dh_import(void *keydata, int selection, const OSSL_PARAM params[])
         ok = 1;
 
     if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
-        ok = ok && ffc_fromdata(dh_get0_params(dh), params);
+        ok = ok && ffc_params_fromdata(dh_get0_params(dh), params);
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
         ok = ok && dh_key_fromdata(dh, params);
 
@@ -148,7 +148,7 @@ static int dh_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
                      void *cbarg)
 {
     DH *dh = keydata;
-    OSSL_PARAM_BLD *tmpl;
+    OSSL_PARAM_BLD *tmpl = NULL;
     OSSL_PARAM *params = NULL;
     int ok = 1;
 
@@ -166,13 +166,13 @@ static int dh_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
 
     if (!ok
         || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) {
-        OSSL_PARAM_BLD_free(tmpl);
-        return 0;
+        ok = 0;
+        goto err;
     }
-    OSSL_PARAM_BLD_free(tmpl);
-
     ok = param_cb(params, cbarg);
     OSSL_PARAM_BLD_free_params(params);
+err:
+    OSSL_PARAM_BLD_free(tmpl);
     return ok;
 }
 
diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c
index 78edcaa9d4..1261035296 100644
--- a/providers/implementations/keymgmt/dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/dsa_kmgmt.c
@@ -13,18 +13,27 @@
  */
 #include "internal/deprecated.h"
 
+#include "e_os.h" /* strcasecmp */
 #include <openssl/core_numbers.h>
 #include <openssl/core_names.h>
 #include <openssl/bn.h>
-#include <openssl/params.h>
-#include "prov/implementations.h"
+#include <openssl/err.h>
 #include "prov/providercommon.h"
+#include "prov/implementations.h"
 #include "prov/provider_ctx.h"
 #include "crypto/dsa.h"
-#include "openssl/param_build.h"
+#include "internal/sizes.h"
+#include "internal/nelem.h"
+#include "internal/param_build_set.h"
 
 static OSSL_OP_keymgmt_new_fn dsa_newdata;
 static OSSL_OP_keymgmt_free_fn dsa_freedata;
+static OSSL_OP_keymgmt_gen_init_fn dsa_gen_init;
+static OSSL_OP_keymgmt_gen_set_template_fn dsa_gen_set_template;
+static OSSL_OP_keymgmt_gen_set_params_fn dsa_gen_set_params;
+static OSSL_OP_keymgmt_gen_settable_params_fn dsa_gen_settable_params;
+static OSSL_OP_keymgmt_gen_fn dsa_gen;
+static OSSL_OP_keymgmt_gen_cleanup_fn dsa_gen_cleanup;
 static OSSL_OP_keymgmt_get_params_fn dsa_get_params;
 static OSSL_OP_keymgmt_gettable_params_fn dsa_gettable_params;
 static OSSL_OP_keymgmt_has_fn dsa_has;
@@ -36,45 +45,63 @@ static OSSL_OP_keymgmt_export_fn dsa_export;
 static OSSL_OP_keymgmt_export_types_fn dsa_export_types;
 
 #define DSA_DEFAULT_MD "SHA256"
-#define DSA_POSSIBLE_SELECTIONS                 \
+#define DSA_POSSIBLE_SELECTIONS                                                \
     (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS)
 
-static int domparams_to_params(DSA *dsa, OSSL_PARAM_BLD *tmpl)
-{
-    const BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
+struct dsa_gen_ctx {
+    OPENSSL_CTX *libctx;
+
+    FFC_PARAMS *ffc_params;
+    int selection;
+    /* All these parameters are used for parameter generation only */
+    size_t pbits;
+    size_t qbits;
+    EVP_MD *md;
+    unsigned char *seed; /* optional FIPS186-4 param for testing */
+    size_t seedlen;
+    int gindex; /* optional  FIPS186-4 generator index (ignored if -1) */
+    int gen_type; /* DSA_PARAMGEN_TYPE_FIPS_186_2 or DSA_PARAMGEN_TYPE_FIPS_186_4 */
+    int pcounter;
+    int hindex;
+    OSSL_CALLBACK *cb;
+    void *cbarg;
+};
+typedef struct dh_name2id_st{
+    const char *name;
+    int id;
+} DSA_GENTYPE_NAME2ID;
 
-    if (dsa == NULL)
-        return 0;
+static const DSA_GENTYPE_NAME2ID dsatype2id[]=
+{
+    { "default", DSA_PARAMGEN_TYPE_FIPS_186_4 },
+    { "fips186_4", DSA_PARAMGEN_TYPE_FIPS_186_4 },
+    { "fips186_2", DSA_PARAMGEN_TYPE_FIPS_186_2 },
+};
 
-    DSA_get0_pqg(dsa, &dsa_p, &dsa_q, &dsa_g);
-    if (dsa_p != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, dsa_p))
-        return 0;
-    if (dsa_q != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_Q, dsa_q))
-        return 0;
-    if (dsa_g != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, dsa_g))
-        return 0;
+static int dsa_gen_type_name2id(const char *name)
+{
+    size_t i;
 
-    return 1;
+    for (i = 0; i < OSSL_NELEM(dsatype2id); ++i) {
+        if (strcasecmp(dsatype2id[i].name, name) == 0)
+            return dsatype2id[i].id;
+    }
+    return -1;
 }
 
-static int key_to_params(DSA *dsa, OSSL_PARAM_BLD *tmpl)
+static int dsa_key_todata(DSA *dsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[])
 {
-    const BIGNUM *priv_key = NULL, *pub_key = NULL;
+    const BIGNUM *priv = NULL, *pub = NULL;
 
     if (dsa == NULL)
         return 0;
-    if (!domparams_to_params(dsa, tmpl))
-        return 0;
 
-    DSA_get0_key(dsa, &pub_key, &priv_key);
-    if (priv_key != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, priv_key))
+    DSA_get0_key(dsa, &pub, &priv);
+    if (priv != NULL
+        && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PRIV_KEY, priv))
         return 0;
-    if (pub_key != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key))
+    if (pub != NULL
+        && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PUB_KEY, pub))
         return 0;
 
     return 1;
@@ -133,16 +160,16 @@ static int dsa_match(const void *keydata1, const void *keydata2, int selection)
 static int dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
 {
     DSA *dsa = keydata;
-    int ok = 0;
+    int ok = 1;
 
     if (dsa == NULL)
         return 0;
 
-    if ((selection & DSA_POSSIBLE_SELECTIONS) != 0)
-        ok = 1;
+    if ((selection & DSA_POSSIBLE_SELECTIONS) == 0)
+        return 0;
 
     if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
-        ok = ok && ffc_fromdata(dsa_get0_params(dsa), params);
+        ok = ok && dsa_ffc_params_fromdata(dsa, params);
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
         ok = ok && dsa_key_fromdata(dsa, params);
 
@@ -158,12 +185,12 @@ static int dsa_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
     int ok = 1;
 
     if (dsa == NULL)
-        goto err;;
+        goto err;
 
     if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
-        ok = ok && domparams_to_params(dsa, tmpl);
+        ok = ok && ffc_params_todata(dsa_get0_params(dsa), tmpl, NULL);
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
-        ok = ok && key_to_params(dsa, tmpl);
+        ok = ok && dsa_key_todata(dsa, tmpl, NULL);
 
     if (!ok
         || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL)
@@ -178,10 +205,16 @@ err:
 
 /* IMEXPORT = IMPORT + EXPORT */
 
-# define DSA_IMEXPORTABLE_PARAMETERS                    \
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_P, NULL, 0),      \
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_Q, NULL, 0),      \
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0)
+# define DSA_IMEXPORTABLE_PARAMETERS                                           \
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_P, NULL, 0),                             \
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_Q, NULL, 0),                             \
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0),                             \
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_COFACTOR, NULL, 0),                      \
+    OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL),                          \
+    OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL),                        \
+    OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL),                               \
+    OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_GROUP, NULL, 0),                \
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0)
 # define DSA_IMEXPORTABLE_PUBLIC_KEY                    \
     OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0)
 # define DSA_IMEXPORTABLE_PRIVATE_KEY                   \
@@ -246,7 +279,8 @@ static ossl_inline int dsa_get_params(void *key, OSSL_PARAM params[])
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL
         && !OSSL_PARAM_set_utf8_string(p, DSA_DEFAULT_MD))
         return 0;
-    return 1;
+    return ffc_params_todata(dsa_get0_params(dsa), NULL, params)
+           && dsa_key_todata(dsa, NULL, params);
 }
 
 static const OSSL_PARAM dsa_params[] = {
@@ -254,6 +288,9 @@ static const OSSL_PARAM dsa_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
     OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0),
+    DSA_IMEXPORTABLE_PARAMETERS,
+    DSA_IMEXPORTABLE_PUBLIC_KEY,
+    DSA_IMEXPORTABLE_PRIVATE_KEY,
     OSSL_PARAM_END
 };
 
@@ -311,8 +348,224 @@ static int dsa_validate(void *keydata, int selection)
     return ok;
 }
 
+static void *dsa_gen_init(void *provctx, int selection)
+{
+    OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+    struct dsa_gen_ctx *gctx = NULL;
+
+    if ((selection & DSA_POSSIBLE_SELECTIONS) == 0)
+        return NULL;
+
+    if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
+        gctx->selection = selection;
+        gctx->libctx = libctx;
+        gctx->pbits = 2048;
+        gctx->qbits = 224;
+        gctx->md = NULL;
+        gctx->gen_type = DSA_PARAMGEN_TYPE_FIPS_186_4;
+        gctx->gindex = -1;
+        gctx->pcounter = -1;
+        gctx->hindex = 0;
+    }
+    return gctx;
+}
+
+static int dsa_gen_set_template(void *genctx, void *templ)
+{
+    struct dsa_gen_ctx *gctx = genctx;
+    DSA *dsa = templ;
+
+    if (gctx == NULL || dsa == NULL)
+        return 0;
+    gctx->ffc_params = dsa_get0_params(dsa);
+    return 1;
+}
+
+static int dsa_set_gen_seed(struct dsa_gen_ctx *gctx, unsigned char *seed,
+                            size_t seedlen)
+{
+    OPENSSL_clear_free(gctx->seed, gctx->seedlen);
+    gctx->seed = NULL;
+    gctx->seedlen = 0;
+    if (seed != NULL && seedlen > 0) {
+        gctx->seed = OPENSSL_memdup(seed, seedlen);
+        if (gctx->seed == NULL)
+            return 0;
+        gctx->seedlen = seedlen;
+    }
+    return 1;
+}
+
+static int dsa_gen_set_params(void *genctx, const OSSL_PARAM params[])
+{
+    struct dsa_gen_ctx *gctx = genctx;
+    const OSSL_PARAM *p;
+
+    if (gctx == NULL)
+        return 0;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_TYPE);
+    if (p != NULL) {
+        if (p->data_type != OSSL_PARAM_UTF8_STRING
+            || ((gctx->gen_type = dsa_gen_type_name2id(p->data)) == -1)) {
+            ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
+            return 0;
+        }
+    }
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_GINDEX);
+    if (p != NULL
+        && !OSSL_PARAM_get_int(p, &gctx->gindex))
+        return 0;
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PCOUNTER);
+    if (p != NULL
+        && !OSSL_PARAM_get_int(p, &gctx->pcounter))
+        return 0;
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_H);
+    if (p != NULL
+        && !OSSL_PARAM_get_int(p, &gctx->hindex))
+        return 0;
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_SEED);
+    if (p != NULL
+        && (p->data_type != OSSL_PARAM_OCTET_STRING
+            || !dsa_set_gen_seed(gctx, p->data, p->data_size)))
+            return 0;
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_PBITS)) != NULL
+        && !OSSL_PARAM_get_size_t(p, &gctx->pbits))
+        return 0;
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_QBITS)) != NULL
+        && !OSSL_PARAM_get_size_t(p, &gctx->qbits))
+        return 0;
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST);
+    if (p != NULL) {
+        const OSSL_PARAM *p1;
+        char mdprops[OSSL_MAX_PROPQUERY_SIZE] = { '\0' };
+        char *str = mdprops;
+
+        if (p->data_type != OSSL_PARAM_UTF8_STRING)
+            return 0;
+        p1 = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_DIGEST_PROPS);
+        if (p1 != NULL) {
+            if (!OSSL_PARAM_get_utf8_string(p1, &str, sizeof(mdprops)))
+                return 0;
+        }
+        EVP_MD_free(gctx->md);
+        gctx->md = EVP_MD_fetch(gctx->libctx, p->data, mdprops);
+        if (gctx->md == NULL)
+            return 0;
+    }
+    return 1;
+}
+
+static const OSSL_PARAM *dsa_gen_settable_params(void *provctx)
+{
+    static OSSL_PARAM settable[] = {
+        OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, NULL, 0),
+        OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_PBITS, NULL),
+        OSSL_PARAM_size_t(OSSL_PKEY_PARAM_FFC_QBITS, NULL),
+        OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST, NULL, 0),
+        OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST_PROPS, NULL, 0),
+        OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_GINDEX, NULL),
+        OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_FFC_SEED, NULL, 0),
+        OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_PCOUNTER, NULL),
+        OSSL_PARAM_int(OSSL_PKEY_PARAM_FFC_H, NULL),
+        OSSL_PARAM_END
+    };
+    return settable;
+}
+
+static int dsa_gencb(int p, int n, BN_GENCB *cb)
+{
+    struct dsa_gen_ctx *gctx = BN_GENCB_get_arg(cb);
+    OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
+
+    params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p);
+    params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n);
+
+    return gctx->cb(params, gctx->cbarg);
+}
+
+static void *dsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+    struct dsa_gen_ctx *gctx = genctx;
+    DSA *dsa = NULL;
+    BN_GENCB *gencb = NULL;
+    int ret = 0;
+    FFC_PARAMS *ffc;
+
+    if (gctx == NULL)
+        return NULL;
+    dsa = dsa_new_with_ctx(gctx->libctx);
+    if (dsa == NULL)
+        return NULL;
+
+    gctx->cb = osslcb;
+    gctx->cbarg = cbarg;
+    gencb = BN_GENCB_new();
+    if (gencb != NULL)
+        BN_GENCB_set(gencb, dsa_gencb, genctx);
+
+    ffc = dsa_get0_params(dsa);
+    /* Copy the template value if one was passed */
+    if (gctx->ffc_params != NULL
+        && !ffc_params_copy(ffc, gctx->ffc_params))
+        goto end;
+
+    if (gctx->seed != NULL
+        && !ffc_params_set_seed(ffc, gctx->seed, gctx->seedlen))
+        goto end;
+    if (gctx->gindex != -1) {
+        ffc_params_set_gindex(ffc, gctx->gindex);
+        if (gctx->pcounter != -1)
+            ffc_params_set_pcounter(ffc, gctx->pcounter);
+    } else if (gctx->hindex != 0) {
+        ffc_params_set_h(ffc, gctx->hindex);
+    }
+    if ((gctx->selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
+
+         if (dsa_generate_ffc_parameters(dsa, gctx->gen_type,
+                                         gctx->pbits, gctx->qbits, gctx->md,
+                                         gencb) <= 0)
+             goto end;
+    }
+    if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
+        if (ffc->p == NULL
+            || ffc->q == NULL
+            || ffc->g == NULL)
+            goto end;
+        if (DSA_generate_key(dsa) <= 0)
+            goto end;
+    }
+    ret = 1;
+end:
+    if (ret <= 0) {
+        DSA_free(dsa);
+        dsa = NULL;
+    }
+    BN_GENCB_free(gencb);
+    return dsa;
+}
+
+static void dsa_gen_cleanup(void *genctx)
+{
+    struct dsa_gen_ctx *gctx = genctx;
+
+    if (gctx == NULL)
+        return;
+
+    OPENSSL_clear_free(gctx->seed, gctx->seedlen);
+    EVP_MD_free(gctx->md);
+    OPENSSL_free(gctx);
+}
+
 const OSSL_DISPATCH dsa_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))dsa_newdata },
+    { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))dsa_gen_init },
+    { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))dsa_gen_set_template },
+    { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))dsa_gen_set_params },
+    { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
+      (void (*)(void))dsa_gen_settable_params },
+    { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))dsa_gen },
+    { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))dsa_gen_cleanup },
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dsa_freedata },
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dsa_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dsa_gettable_params },
diff --git a/providers/implementations/serializers/build.info b/providers/implementations/serializers/build.info
index 66502c76aa..097bdcac1c 100644
--- a/providers/implementations/serializers/build.info
+++ b/providers/implementations/serializers/build.info
@@ -3,6 +3,7 @@
 
 $SERIALIZER_GOAL=../../libimplementations.a
 $RSA_GOAL=../../libimplementations.a
+$FFC_GOAL=../../libimplementations.a
 $DH_GOAL=../../libimplementations.a
 $DSA_GOAL=../../libimplementations.a
 $ECX_GOAL=../../libimplementations.a
@@ -10,6 +11,9 @@ $EC_GOAL=../../libimplementations.a
 
 SOURCE[$SERIALIZER_GOAL]=serializer_common.c
 SOURCE[$RSA_GOAL]=serializer_rsa.c serializer_rsa_priv.c serializer_rsa_pub.c
+IF[{- !$disabled{"dh"} || !$disabled{"dsa"} -}]
+  SOURCE[$FFC_GOAL]=serializer_ffc_params.c
+ENDIF
 IF[{- !$disabled{dh} -}]
   SOURCE[$DH_GOAL]=serializer_dh.c serializer_dh_priv.c serializer_dh_pub.c serializer_dh_param.c
 ENDIF
diff --git a/providers/implementations/serializers/serializer_common.c b/providers/implementations/serializers/serializer_common.c
index 7c6b5afe18..2dbbe6b37c 100644
--- a/providers/implementations/serializers/serializer_common.c
+++ b/providers/implementations/serializers/serializer_common.c
@@ -14,6 +14,7 @@
 #include <openssl/types.h>
 #include <openssl/x509.h>        /* i2d_X509_PUBKEY_bio() */
 #include "crypto/bn.h"           /* bn_get_words() */
+#include "crypto/ctype.h"
 #include "crypto/ecx.h"
 #include "prov/bio.h"            /* ossl_prov_bio_printf() */
 #include "prov/implementations.h"
@@ -161,11 +162,13 @@ OSSL_OP_keymgmt_import_fn *ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns
 int ossl_prov_print_labeled_bignum(BIO *out, const char *label,
                                    const BIGNUM *bn)
 {
-    const char *neg;
+    int ret = 0, use_sep = 0;
+    char *hex_str = NULL, *p;
+    const char spaces[] = "    ";
     const char *post_label_spc = " ";
+
+    const char *neg = "";
     int bytes;
-    BN_ULONG *words;
-    int n, i;
 
     if (bn == NULL)
         return 0;
@@ -174,74 +177,63 @@ int ossl_prov_print_labeled_bignum(BIO *out, const char *label,
         post_label_spc = "";
     }
 
-    bytes = BN_num_bytes(bn);
-    words = bn_get_words(bn);
-    neg = BN_is_negative(bn) ? "-" : "";
-
     if (BN_is_zero(bn))
         return ossl_prov_bio_printf(out, "%s%s0\n", label, post_label_spc);
 
-    if (BN_num_bytes(bn) <= BN_BYTES)
+    if (BN_num_bytes(bn) <= BN_BYTES) {
+        BN_ULONG *words = bn_get_words(bn);
+
+        if (BN_is_negative(bn))
+            neg = "-";
+
         return ossl_prov_bio_printf(out,
                                     "%s%s%s" BN_FMTu " (%s0x" BN_FMTx ")\n",
                                     label, post_label_spc, neg, words[0],
                                     neg, words[0]);
+    }
 
-    if (neg[0] == '-')
+    hex_str = BN_bn2hex(bn);
+    p = hex_str;
+    if (*p == '-') {
+        ++p;
         neg = " (Negative)";
-
+    }
     if (ossl_prov_bio_printf(out, "%s%s\n", label, neg) <= 0)
-        return 0;
+        goto err;
 
     /* Keep track of how many bytes we have printed out so far */
-    n = 0;
-
-    /*
-     * OpenSSL BIGNUMs are little endian limbs, so we print them last to
-     * first limb.
-     * i is used as limb index, j is used as the "byte index" in the limb
-     */
-    for (i = bytes / BN_BYTES - 1; i >= 0; i--) {
-        BN_ULONG l = words[i];
-        int  j;
-
-        for (j = BN_BYTES - 1; j >= 0; j--) {
-            int o = 8 * j;
-            int b = ((l & (0xffLU << o)) >> o) & 0xff;
-
-            /* Indent every new line with 4 spaces */
-            if ((n % 15) == 0) {
-                if (n > 0)
-                    if (ossl_prov_bio_printf(out, "\n") <= 0)
-                        return 0;
-                if (ossl_prov_bio_printf(out, "    ") <= 0)
-                    return 0;
-            }
-
-            /*
-             * Upper bit set, then we print an extra zero and pretend the
-             * BIGNUM was one byte longer
-             */
-            if (n == 0 && b > 127) {
-                if (ossl_prov_bio_printf(out, "%02x:", 0) <= 0)
-                    return 0;
-                n++;
-                bytes++;
-            }
-
-            if (++n < bytes) {
-                if (ossl_prov_bio_printf(out, "%02x:", b) <= 0)
-                    return 0;
-            } else {
-                if (ossl_prov_bio_printf(out, "%02x", b) <= 0)
-                    return 0;
-            }
+    bytes = 0;
+
+    if (ossl_prov_bio_printf(out, "%s", spaces) <= 0)
+        goto err;
+
+    /* Add a leading 00 if the top bit is set */
+    if (*p >= '8') {
+        if (ossl_prov_bio_printf(out, "%02x", 0) <= 0)
+            goto err;
+        ++bytes;
+        use_sep = 1;
+    }
+    while (*p != '\0') {
+        /* Do a newline after every 15 hex bytes + add the space indent */
+        if ((bytes % 15) == 0 && bytes > 0) {
+            if (ossl_prov_bio_printf(out, ":\n%s", spaces) <= 0)
+                goto err;
+            use_sep = 0; /* The first byte on the next line doesnt have a : */
         }
+        if (ossl_prov_bio_printf(out, "%s%c%c", use_sep ? ":" : "",
+                                 ossl_tolower(p[0]), ossl_tolower(p[1])) <= 0)
+            goto err;
+        ++bytes;
+        p += 2;
+        use_sep = 1;
     }
     if (ossl_prov_bio_printf(out, "\n") <= 0)
-        return 0;
-
-    return 1;
+        goto err;
+    ret = 1;
+err:
+    OPENSSL_free(hex_str);
+    return ret;
 }
 
 /* Number of octets per line */
diff --git a/providers/implementations/serializers/serializer_dsa.c b/providers/implementations/serializers/serializer_dsa.c
index c26be47e66..f5189d05fb 100644
--- a/providers/implementations/serializers/serializer_dsa.c
+++ b/providers/implementations/serializers/serializer_dsa.c
@@ -19,6 +19,8 @@
 #include "prov/implementations.h" /* rsa_keymgmt_functions */
 #include "prov/providercommonerr.h" /* PROV_R_BN_ERROR */
 #include "serializer_local.h"
+#include "internal/ffc.h"
+#include "crypto/dsa.h"
 
 OSSL_OP_keymgmt_new_fn *ossl_prov_get_keymgmt_dsa_new(void)
 {
@@ -39,7 +41,7 @@ int ossl_prov_print_dsa(BIO *out, DSA *dsa, enum dsa_print_type type)
 {
     const char *type_label = NULL;
     const BIGNUM *priv_key = NULL, *pub_key = NULL;
-    const BIGNUM *p = NULL, *q = NULL, *g = NULL;
+    const BIGNUM *p = NULL;
 
 
     switch (type) {
@@ -66,15 +68,13 @@ int ossl_prov_print_dsa(BIO *out, DSA *dsa, enum dsa_print_type type)
             goto null_err;
     }
 
-    p = DSA_get0_p(dsa);
-    q = DSA_get0_q(dsa);
-    g = DSA_get0_p(dsa);
 
-    if (p == NULL || q == NULL || g == NULL)
+    p = DSA_get0_p(dsa);
+    if (p == NULL)
         goto null_err;
 
-    if (ossl_prov_bio_printf(out, "%s: (%d bit)\n", type_label, BN_num_bits(p))
-        <= 0)
+    if (ossl_prov_bio_printf(out, "%s: (%d bit)\n", type_label,
+                             BN_num_bits(p)) <= 0)
         goto err;
     if (priv_key != NULL
         && !ossl_prov_print_labeled_bignum(out, "priv:", priv_key))
@@ -82,11 +82,7 @@ int ossl_prov_print_dsa(BIO *out, DSA *dsa, enum dsa_print_type type)
     if (pub_key != NULL
         && !ossl_prov_print_labeled_bignum(out, "pub: ", pub_key))
         goto err;
-    if (!ossl_prov_print_labeled_bignum(out, "P:   ", p))
-        goto err;
-    if (!ossl_prov_print_labeled_bignum(out, "Q:   ", q))
-        goto err;
-    if (!ossl_prov_print_labeled_bignum(out, "G:   ", g))
+    if (!ffc_params_prov_print(out, dsa_get0_params(dsa)))
         goto err;
 
     return 1;
diff --git a/providers/implementations/serializers/serializer_ffc_params.c b/providers/implementations/serializers/serializer_ffc_params.c
new file mode 100644
index 0000000000..da38763cfe
--- /dev/null
+++ b/providers/implementations/serializers/serializer_ffc_params.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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
+ */
+
+/* Utility function for printing DSA/DH params. */
+
+#include "prov/bio.h"
+#include "serializer_local.h"
+
+int ffc_params_prov_print(BIO *out, const FFC_PARAMS *ffc)
+{
+    if (ffc->nid != NID_undef) {
+        const char *name = ffc_named_group_from_nid(ffc->nid);
+
+        if (name == NULL)
+            goto err;
+        if (ossl_prov_bio_printf(out, "GROUP: %s\n", name) <= 0)
+            goto err;
+        return 1;
+    }
+
+    if (!ossl_prov_print_labeled_bignum(out, "P:   ", ffc->p))
+        goto err;
+    if (ffc->q != NULL) {
+        if (!ossl_prov_print_labeled_bignum(out, "Q:   ", ffc->q))
+            goto err;
+    }
+    if (!ossl_prov_print_labeled_bignum(out, "G:   ", ffc->g))
+        goto err;
+    if (ffc->j != NULL) {
+        if (!ossl_prov_print_labeled_bignum(out, "J:   ", ffc->j))
+            goto err;
+    }
+    if (ffc->seed != NULL) {
+        if (!ossl_prov_print_labeled_buf(out, "SEED:", ffc->seed, ffc->seedlen))
+            goto err;
+    }
+    if (ffc->gindex != -1) {
+        if (ossl_prov_bio_printf(out, "gindex: %d\n", ffc->gindex) <= 0)
+            goto err;
+    }
+    if (ffc->pcounter != -1) {
+        if (ossl_prov_bio_printf(out, "pcounter: %d\n", ffc->pcounter) <= 0)
+            goto err;
+    }
+    if (ffc->h != 0) {
+        if (ossl_prov_bio_printf(out, "h: %d\n", ffc->h) <= 0)
+            goto err;
+    }
+    return 1;
+err:
+    return 0;
+}
diff --git a/providers/implementations/serializers/serializer_local.h b/providers/implementations/serializers/serializer_local.h
index b1c36a2221..2ee610565e 100644
--- a/providers/implementations/serializers/serializer_local.h
+++ b/providers/implementations/serializers/serializer_local.h
@@ -14,6 +14,7 @@
 #include <openssl/x509.h>        /* X509_SIG */
 #include <openssl/types.h>
 #include <crypto/ecx.h>
+#include "internal/ffc.h"
 
 struct pkcs8_encrypt_ctx_st {
     /* Set to 1 if intending to encrypt/decrypt, otherwise 0 */
@@ -54,6 +55,7 @@ int ossl_prov_prepare_ec_params(const void *eckey, int nid,
 int ossl_prov_ec_pub_to_der(const void *eckey, unsigned char **pder);
 int ossl_prov_ec_priv_to_der(const void *eckey, unsigned char **pder);
 
+int ffc_params_prov_print(BIO *out, const FFC_PARAMS *ffc);
 int ossl_prov_prepare_dh_params(const void *dh, int nid,
                                 void **pstr, int *pstrtype);
 int ossl_prov_dh_pub_to_der(const void *dh, unsigned char **pder);
diff --git a/test/dsatest.c b/test/dsatest.c
index 288efb71d0..39a271307b 100644
--- a/test/dsatest.c
+++ b/test/dsatest.c
@@ -23,6 +23,8 @@
 #include <openssl/rand.h>
 #include <openssl/bn.h>
 #include <openssl/dsa.h>
+#include <openssl/evp.h>
+#include <openssl/core_names.h>
 
 #include "testutil.h"
 #include "internal/nelem.h"
@@ -30,45 +32,6 @@
 #ifndef OPENSSL_NO_DSA
 static int dsa_cb(int p, int n, BN_GENCB *arg);
 
-/*
- * seed, out_p, out_q, out_g are taken from the updated Appendix 5 to FIPS
- * PUB 186 and also appear in Appendix 5 to FIPS PIB 186-1
- */
-static unsigned char seed[20] = {
-    0xd5, 0x01, 0x4e, 0x4b, 0x60, 0xef, 0x2b, 0xa8, 0xb6, 0x21, 0x1b, 0x40,
-    0x62, 0xba, 0x32, 0x24, 0xe0, 0x42, 0x7d, 0xd3,
-};
-
-static unsigned char out_p[] = {
-    0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76, 0xaa,
-    0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69, 0xcb,
-    0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c, 0xf7,
-    0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82, 0xe5,
-    0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e, 0xaf,
-    0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a, 0xac,
-    0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24, 0xc2,
-    0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02, 0x91,
-};
-
-static unsigned char out_q[] = {
-    0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8, 0xee,
-    0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4, 0x8e,
-    0xda, 0xce, 0x91, 0x5f,
-};
-
-static unsigned char out_g[] = {
-    0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a, 0x13,
-    0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5, 0x00,
-    0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef, 0xcb,
-    0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c, 0x2e,
-    0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba, 0xbf,
-    0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c, 0x9c,
-    0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08, 0x8c,
-    0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88, 0x02,
-};
-
-static const unsigned char str1[] = "12345678901234567890";
-
 static int dsa_test(void)
 {
     BN_GENCB *cb;
@@ -79,6 +42,41 @@ static int dsa_test(void)
     unsigned char sig[256];
     unsigned int siglen;
     const BIGNUM *p = NULL, *q = NULL, *g = NULL;
+    /*
+     * seed, out_p, out_q, out_g are taken from the updated Appendix 5 to FIPS
+     * PUB 186 and also appear in Appendix 5 to FIPS PIB 186-1
+     */
+    static unsigned char seed[20] = {
+        0xd5, 0x01, 0x4e, 0x4b, 0x60, 0xef, 0x2b, 0xa8,
+        0xb6, 0x21, 0x1b, 0x40, 0x62, 0xba, 0x32, 0x24,
+        0xe0, 0x42, 0x7d, 0xd3,
+    };
+    static unsigned char out_p[] = {
+        0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76, 0xaa,
+        0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69, 0xcb,
+        0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c, 0xf7,
+        0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82, 0xe5,
+        0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e, 0xaf,
+        0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a, 0xac,
+        0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24, 0xc2,
+        0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02, 0x91,
+    };
+    static unsigned char out_q[] = {
+        0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8, 0xee,
+        0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4, 0x8e,
+        0xda, 0xce, 0x91, 0x5f,
+    };
+    static unsigned char out_g[] = {
+        0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a, 0x13,
+        0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5, 0x00,
+        0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef, 0xcb,
+        0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c, 0x2e,
+        0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba, 0xbf,
+        0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c, 0x9c,
+        0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08, 0x8c,
+        0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88, 0x02,
+    };
+    static const unsigned char str1[] = "12345678901234567890";
 
     if (!TEST_ptr(cb = BN_GENCB_new()))
         goto end;
@@ -136,12 +134,175 @@ static int dsa_cb(int p, int n, BN_GENCB *arg)
     }
     return 1;
 }
+
+# define P      0
+# define Q      1
+# define G      2
+# define SEED   3
+# define PCOUNT 4
+# define GINDEX 5
+# define HCOUNT 6
+# define GROUP  7
+
+static int dsa_keygen_test(void)
+{
+    int ret = 0;
+    EVP_PKEY *param_key = NULL, *key = NULL;
+    EVP_PKEY_CTX *pg_ctx = NULL, *kg_ctx = NULL;
+    BIGNUM *p_in = NULL, *q_in = NULL, *g_in = NULL;
+    BIGNUM *p_out = NULL, *q_out = NULL, *g_out = NULL;
+    int gindex_out = 0, pcount_out = 0, hcount_out = 0;
+    unsigned char seed_out[32];
+    char group_out[32];
+    size_t len = 0;
+    static const unsigned char seed_data[] = {
+        0xa6, 0xf5, 0x28, 0x8c, 0x50, 0x77, 0xa5, 0x68,
+        0x6d, 0x3a, 0xf5, 0xf1, 0xc6, 0x4c, 0xdc, 0x35,
+        0x95, 0x26, 0x3f, 0x03, 0xdc, 0x00, 0x3f, 0x44,
+        0x7b, 0x2a, 0xc7, 0x29
+    };
+    static const unsigned char expected_p[]= {
+        0xdb, 0x47, 0x07, 0xaf, 0xf0, 0x06, 0x49, 0x55,
+        0xc9, 0xbb, 0x09, 0x41, 0xb8, 0xdb, 0x1f, 0xbc,
+        0xa8, 0xed, 0x12, 0x06, 0x7f, 0x88, 0x49, 0xb8,
+        0xc9, 0x12, 0x87, 0x21, 0xbb, 0x08, 0x6c, 0xbd,
+        0xf1, 0x89, 0xef, 0x84, 0xd9, 0x7a, 0x93, 0xe8,
+        0x45, 0x40, 0x81, 0xec, 0x37, 0x27, 0x1a, 0xa4,
+        0x22, 0x51, 0x99, 0xf0, 0xde, 0x04, 0xdb, 0xea,
+        0xa1, 0xf9, 0x37, 0x83, 0x80, 0x96, 0x36, 0x53,
+        0xf6, 0xae, 0x14, 0x73, 0x33, 0x0f, 0xdf, 0x0b,
+        0xf9, 0x2f, 0x08, 0x46, 0x31, 0xf9, 0x66, 0xcd,
+        0x5a, 0xeb, 0x6c, 0xf3, 0xbb, 0x74, 0xf3, 0x88,
+        0xf0, 0x31, 0x5c, 0xa4, 0xc8, 0x0f, 0x86, 0xf3,
+        0x0f, 0x9f, 0xc0, 0x8c, 0x57, 0xe4, 0x7f, 0x95,
+        0xb3, 0x62, 0xc8, 0x4e, 0xae, 0xf3, 0xd8, 0x14,
+        0xcc, 0x47, 0xc2, 0x4b, 0x4f, 0xef, 0xaf, 0xcd,
+        0xcf, 0xb2, 0xbb, 0xe8, 0xbe, 0x08, 0xca, 0x15,
+        0x90, 0x59, 0x35, 0xef, 0x35, 0x1c, 0xfe, 0xeb,
+        0x33, 0x2e, 0x25, 0x22, 0x57, 0x9c, 0x55, 0x23,
+        0x0c, 0x6f, 0xed, 0x7c, 0xb6, 0xc7, 0x36, 0x0b,
+        0xcb, 0x2b, 0x6a, 0x21, 0xa1, 0x1d, 0x55, 0x77,
+        0xd9, 0x91, 0xcd, 0xc1, 0xcd, 0x3d, 0x82, 0x16,
+        0x9c, 0xa0, 0x13, 0xa5, 0x83, 0x55, 0x3a, 0x73,
+        0x7e, 0x2c, 0x44, 0x3e, 0x70, 0x2e, 0x50, 0x91,
+        0x6e, 0xca, 0x3b, 0xef, 0xff, 0x85, 0x35, 0x70,
+        0xff, 0x61, 0x0c, 0xb1, 0xb2, 0xb7, 0x94, 0x6f,
+        0x65, 0xa4, 0x57, 0x62, 0xef, 0x21, 0x83, 0x0f,
+        0x3e, 0x71, 0xae, 0x7d, 0xe4, 0xad, 0xfb, 0xe3,
+        0xdd, 0xd6, 0x03, 0xda, 0x9a, 0xd8, 0x8f, 0x2d,
+        0xbb, 0x90, 0x87, 0xf8, 0xdb, 0xdc, 0xec, 0x71,
+        0xf2, 0xdb, 0x0b, 0x8e, 0xfc, 0x1a, 0x7e, 0x79,
+        0xb1, 0x1b, 0x0d, 0xfc, 0x70, 0xec, 0x85, 0xc2,
+        0xc5, 0xba, 0xb9, 0x69, 0x3f, 0x88, 0xbc, 0xcb
+    };
+    static const unsigned char expected_q[]= {
+        0x99, 0xb6, 0xa0, 0xee, 0xb3, 0xa6, 0x99, 0x1a,
+        0xb6, 0x67, 0x8d, 0xc1, 0x2b, 0x9b, 0xce, 0x2b,
+        0x01, 0x72, 0x5a, 0x65, 0x76, 0x3d, 0x93, 0x69,
+        0xe2, 0x56, 0xae, 0xd7
+    };
+    static const unsigned char expected_g[]= {
+        0x63, 0xf8, 0xb6, 0xee, 0x2a, 0x27, 0xaf, 0x4f,
+        0x4c, 0xf6, 0x08, 0x28, 0x87, 0x4a, 0xe7, 0x1f,
+        0x45, 0x46, 0x27, 0x52, 0x3b, 0x7f, 0x6f, 0xd2,
+        0x29, 0xcb, 0xe8, 0x11, 0x19, 0x25, 0x35, 0x76,
+        0x99, 0xcb, 0x4f, 0x1b, 0xe0, 0xed, 0x32, 0x9e,
+        0x05, 0xb5, 0xbe, 0xd7, 0xf6, 0x5a, 0xb2, 0xf6,
+        0x0e, 0x0c, 0x7e, 0xf5, 0xe1, 0x05, 0xfe, 0xda,
+        0xaf, 0x0f, 0x27, 0x1e, 0x40, 0x2a, 0xf7, 0xa7,
+        0x23, 0x49, 0x2c, 0xd9, 0x1b, 0x0a, 0xbe, 0xff,
+        0xc7, 0x7c, 0x7d, 0x60, 0xca, 0xa3, 0x19, 0xc3,
+        0xb7, 0xe4, 0x43, 0xb0, 0xf5, 0x75, 0x44, 0x90,
+        0x46, 0x47, 0xb1, 0xa6, 0x48, 0x0b, 0x21, 0x8e,
+        0xee, 0x75, 0xe6, 0x3d, 0xa7, 0xd3, 0x7b, 0x31,
+        0xd1, 0xd2, 0x9d, 0xe2, 0x8a, 0xfc, 0x57, 0xfd,
+        0x8a, 0x10, 0x31, 0xeb, 0x87, 0x36, 0x3f, 0x65,
+        0x72, 0x23, 0x2c, 0xd3, 0xd6, 0x17, 0xa5, 0x62,
+        0x58, 0x65, 0x57, 0x6a, 0xd4, 0xa8, 0xfe, 0xec,
+        0x57, 0x76, 0x0c, 0xb1, 0x4c, 0x93, 0xed, 0xb0,
+        0xb4, 0xf9, 0x45, 0xb3, 0x3e, 0xdd, 0x47, 0xf1,
+        0xfb, 0x7d, 0x25, 0x79, 0x3d, 0xfc, 0xa7, 0x39,
+        0x90, 0x68, 0x6a, 0x6b, 0xae, 0xf2, 0x6e, 0x64,
+        0x8c, 0xfb, 0xb8, 0xdd, 0x76, 0x4e, 0x4a, 0x69,
+        0x8c, 0x97, 0x15, 0x77, 0xb2, 0x67, 0xdc, 0xeb,
+        0x4a, 0x40, 0x6b, 0xb9, 0x47, 0x8f, 0xa6, 0xab,
+        0x6e, 0x98, 0xc0, 0x97, 0x9a, 0x0c, 0xea, 0x00,
+        0xfd, 0x56, 0x1a, 0x74, 0x9a, 0x32, 0x6b, 0xfe,
+        0xbd, 0xdf, 0x6c, 0x82, 0x54, 0x53, 0x4d, 0x70,
+        0x65, 0xe3, 0x8b, 0x37, 0xb8, 0xe4, 0x70, 0x08,
+        0xb7, 0x3b, 0x30, 0x27, 0xaf, 0x1c, 0x77, 0xf3,
+        0x62, 0xd4, 0x9a, 0x59, 0xba, 0xd1, 0x6e, 0x89,
+        0x5c, 0x34, 0x9a, 0xa1, 0xb7, 0x4f, 0x7d, 0x8c,
+        0xdc, 0xbc, 0x74, 0x25, 0x5e, 0xbf, 0x77, 0x46
+    };
+    int expected_c = 1316;
+    int expected_h = 2;
+
+    if (!TEST_ptr(p_in = BN_bin2bn(expected_p, sizeof(expected_p), NULL))
+        || !TEST_ptr(q_in = BN_bin2bn(expected_q, sizeof(expected_q), NULL))
+        || !TEST_ptr(g_in = BN_bin2bn(expected_g, sizeof(expected_g), NULL)))
+        goto end;
+    if (!TEST_ptr(pg_ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL))
+        || !TEST_int_gt(EVP_PKEY_paramgen_init(pg_ctx), 0)
+        || !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_bits(pg_ctx, 2048))
+        || !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_q_bits(pg_ctx, 224))
+        || !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_seed(pg_ctx, seed_data,
+                                                         sizeof(seed_data)))
+        || !TEST_true(EVP_PKEY_CTX_set_dsa_paramgen_md_props(pg_ctx, "SHA256",
+                                                             ""))
+        || !TEST_int_gt(EVP_PKEY_gen(pg_ctx, &param_key), 0)
+        || !TEST_ptr(kg_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, param_key, NULL))
+        || !TEST_int_gt(EVP_PKEY_keygen_init(kg_ctx), 0)
+        || !TEST_int_gt(EVP_PKEY_gen(kg_ctx, &key), 0))
+        goto end;
+
+    if (!TEST_true(EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_FFC_P, &p_out))
+        || !TEST_BN_eq(p_in, p_out)
+        || !TEST_true(EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_FFC_Q, &q_out))
+        || !TEST_BN_eq(q_in, q_out)
+        || !TEST_true(EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_FFC_G, &g_out))
+        || !TEST_BN_eq(g_in, g_out)
+        || !TEST_true(EVP_PKEY_get_octet_string_param(
+                          key, OSSL_PKEY_PARAM_FFC_SEED, seed_out,
+                          sizeof(seed_out), &len))
+        || !TEST_mem_eq(seed_out, len, seed_data, sizeof(seed_data))
+        || !TEST_true(EVP_PKEY_get_int_param(key, OSSL_PKEY_PARAM_FFC_GINDEX,
+                                             &gindex_out))
+        || !TEST_int_eq(gindex_out, -1)
+        || !TEST_true(EVP_PKEY_get_int_param(key, OSSL_PKEY_PARAM_FFC_H,
+                                             &hcount_out))
+        || !TEST_int_eq(hcount_out, expected_h)
+        || !TEST_true(EVP_PKEY_get_int_param(key,
+                                             OSSL_PKEY_PARAM_FFC_PCOUNTER,
+                                             &pcount_out))
+        || !TEST_int_eq(pcount_out, expected_c)
+        || !TEST_false(EVP_PKEY_get_utf8_string_param(key,
+                                                      OSSL_PKEY_PARAM_FFC_GROUP,
+                                                      group_out,
+                                                      sizeof(group_out), &len)))
+        goto end;
+    ret = 1;
+end:
+    BN_free(p_in);
+    BN_free(q_in);
+    BN_free(g_in);
+    BN_free(p_out);
+    BN_free(q_out);
+    BN_free(g_out);
+    EVP_PKEY_free(param_key);
+    EVP_PKEY_free(key);
+    EVP_PKEY_CTX_free(kg_ctx);
+    EVP_PKEY_CTX_free(pg_ctx);
+    return ret;
+}
+
 #endif /* OPENSSL_NO_DSA */
 
 int setup_tests(void)
 {
 #ifndef OPENSSL_NO_DSA
     ADD_TEST(dsa_test);
+    ADD_TEST(dsa_keygen_test);
 #endif
     return 1;
 }
diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c
index 9f8d0086f7..5a66162cae 100644
--- a/test/evp_pkey_provided_test.c
+++ b/test/evp_pkey_provided_test.c
@@ -49,7 +49,7 @@ static int compare_with_file(const char *alg, int type, BIO *membio)
 {
     char filename[80];
     BIO *file = NULL;
-    char buf[1024];
+    char buf[4096];
     char *memdata, *fullfile = NULL;
     const char *suffix;
     size_t readbytes;
@@ -437,18 +437,17 @@ static int test_fromdata_dh(void)
         || !TEST_true(EVP_PKEY_copy_parameters(copy_pk, pk)))
         goto err;
 
-    ret = test_print_key_using_pem("DH", pk)
-          && test_print_key_using_serializer("DH", pk);
-
     if (!TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, "")))
         goto err;
 
     if (!TEST_false(EVP_PKEY_check(key_ctx))
         || !TEST_true(EVP_PKEY_public_check(key_ctx))
         || !TEST_false(EVP_PKEY_private_check(key_ctx)) /* Need a q */
-        || !TEST_true(EVP_PKEY_pairwise_check(key_ctx)))
+        || !TEST_false(EVP_PKEY_pairwise_check(key_ctx)))
         goto err;
 
+    ret = test_print_key_using_pem("DH", pk)
+          && test_print_key_using_serializer("DH", pk);
  err:
     EVP_PKEY_free(pk);
     EVP_PKEY_free(copy_pk);
@@ -776,6 +775,233 @@ err:
 
 #endif /* OPENSSL_NO_EC */
 
+#ifndef OPENSSL_NO_DSA
+static int test_fromdata_dsa_fips186_4(void)
+{
+    int ret = 0;
+    EVP_PKEY_CTX *ctx = NULL, *key_ctx = NULL;
+    EVP_PKEY *pk = NULL, *copy_pk = NULL;
+    BIGNUM *pub = NULL, *priv = NULL;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL;
+    BIGNUM *pub_out = NULL, *priv_out = NULL;
+    BIGNUM *p_out = NULL, *q_out = NULL, *g_out = NULL, *j_out = NULL;
+    int gindex_out = 0, pcounter_out = 0, hindex_out = 0;
+    char name_out[80];
+    unsigned char seed_out[32];
+    size_t len;
+    OSSL_PARAM_BLD *bld = NULL;
+    OSSL_PARAM *fromdata_params = NULL;
+
+    /*
+     * DSA parameter data was generated using the following:
+     * openssl genpkey -genparam -algorithm DSA -pkeyopt pbits:2048 \
+     *                 -pkeyopt qbits:256 -pkeyopt type:0 \
+     *                 -pkeyopt gindex:1 -out dsa_params.pem -text
+     */
+    static const unsigned char p_data[] = {
+        0x00, 0xa0, 0xb7, 0x02, 0xc4, 0xac, 0xa6, 0x42, 0xab, 0xf2, 0x34, 0x0b,
+        0x22, 0x47, 0x1f, 0x33, 0xcf, 0xd5, 0x04, 0xe4, 0x3e, 0xec, 0xa1, 0x21,
+        0xc8, 0x41, 0x2b, 0xef, 0xb8, 0x1f, 0x0b, 0x5b, 0x88, 0x8b, 0x67, 0xf8,
+        0x68, 0x6d, 0x7c, 0x4d, 0x96, 0x5f, 0x3c, 0x66, 0xef, 0x58, 0x34, 0xd7,
+        0xf6, 0xa2, 0x1b, 0xad, 0xc8, 0x12, 0x52, 0xb8, 0xe8, 0x2a, 0x63, 0xcc,
+        0xea, 0xe7, 0x4e, 0xc8, 0x34, 0x4c, 0x58, 0x59, 0x0a, 0xc2, 0x4a, 0xe4,
+        0xb4, 0x64, 0x20, 0xf4, 0xf6, 0x0a, 0xcf, 0x86, 0x01, 0x6c, 0x7f, 0x23,
+        0x4a, 0x51, 0x07, 0x99, 0x42, 0x28, 0x7a, 0xff, 0x18, 0x67, 0x52, 0x64,
+        0xf2, 0x9a, 0x62, 0x30, 0xc3, 0x00, 0xde, 0x23, 0xe9, 0x11, 0x95, 0x7e,
+        0xd1, 0x3d, 0x8d, 0xb4, 0x0e, 0x9f, 0x9e, 0xb1, 0x30, 0x03, 0xf0, 0x73,
+        0xa8, 0x40, 0x48, 0x42, 0x7b, 0x60, 0xa0, 0xc4, 0xf2, 0x3b, 0x2d, 0x0a,
+        0x0c, 0xb8, 0x19, 0xfb, 0xb4, 0xf8, 0xe0, 0x2a, 0xc7, 0xf1, 0xc0, 0xc6,
+        0x86, 0x14, 0x60, 0x12, 0x0f, 0xc0, 0xde, 0x4a, 0x67, 0xec, 0xc7, 0xde,
+        0x76, 0x21, 0x1a, 0x55, 0x7f, 0x86, 0xc3, 0x97, 0x98, 0xce, 0xf5, 0xcd,
+        0xf0, 0xe7, 0x12, 0xd6, 0x93, 0xee, 0x1b, 0x9b, 0x61, 0xef, 0x05, 0x8c,
+        0x45, 0x46, 0xd9, 0x64, 0x6f, 0xbe, 0x27, 0xaa, 0x67, 0x01, 0xcc, 0x71,
+        0xb1, 0x60, 0xce, 0x21, 0xd8, 0x51, 0x17, 0x27, 0x0d, 0x90, 0x3d, 0x18,
+        0x7c, 0x87, 0x15, 0x8e, 0x48, 0x4c, 0x6c, 0xc5, 0x72, 0xeb, 0xb7, 0x56,
+        0xf5, 0x6b, 0x60, 0x8f, 0xc2, 0xfd, 0x3f, 0x46, 0x5c, 0x00, 0x91, 0x85,
+        0x79, 0x45, 0x5b, 0x1c, 0x82, 0xc4, 0x87, 0x50, 0x79, 0xba, 0xcc, 0x1c,
+        0x32, 0x7e, 0x2e, 0xb8, 0x2e, 0xc5, 0x4e, 0xd1, 0x9b, 0xdb, 0x66, 0x79,
+        0x7c, 0xfe, 0xaf, 0x6a, 0x05
+    };
+    static const unsigned char q_data[] = {
+        0xa8, 0xcd, 0xf4, 0x33, 0x7b, 0x13, 0x0a, 0x24, 0xc1, 0xde, 0x4a, 0x04,
+        0x7b, 0x4b, 0x71, 0x51, 0x32, 0xe9, 0x47, 0x74, 0xbd, 0x0c, 0x21, 0x40,
+        0x84, 0x12, 0x0a, 0x17, 0x73, 0xdb, 0x29, 0xc7
+    };
+    static const unsigned char g_data[] = {
+        0x6c, 0xc6, 0xa4, 0x3e, 0x61, 0x84, 0xc1, 0xff, 0x6f, 0x4a, 0x1a, 0x6b,
+        0xb0, 0x24, 0x4b, 0xd2, 0x92, 0x5b, 0x29, 0x5c, 0x61, 0xb8, 0xc9, 0x2b,
+        0xd6, 0xf7, 0x59, 0xfd, 0xd8, 0x70, 0x66, 0x77, 0xfc, 0xc1, 0xa4, 0xd4,
+        0xb0, 0x1e, 0xd5, 0xbf, 0x59, 0x98, 0xb3, 0x66, 0x8b, 0xf4, 0x2e, 0xe6,
+        0x12, 0x3e, 0xcc, 0xf8, 0x02, 0xb8, 0xc6, 0xc3, 0x47, 0xd2, 0xf5, 0xaa,
+        0x0c, 0x5f, 0x51, 0xf5, 0xd0, 0x4c, 0x55, 0x3d, 0x07, 0x73, 0xa6, 0x57,
+        0xce, 0x5a, 0xad, 0x42, 0x0c, 0x13, 0x0f, 0xe2, 0x31, 0x25, 0x8e, 0x72,
+        0x12, 0x73, 0x10, 0xdb, 0x7f, 0x79, 0xeb, 0x59, 0xfc, 0xfe, 0xf7, 0x0c,
+        0x1a, 0x81, 0x53, 0x96, 0x22, 0xb8, 0xe7, 0x58, 0xd8, 0x67, 0x80, 0x60,
+        0xad, 0x8b, 0x55, 0x1c, 0x91, 0xf0, 0x72, 0x9a, 0x7e, 0xad, 0x37, 0xf1,
+        0x77, 0x18, 0x96, 0x8a, 0x68, 0x70, 0xfc, 0x71, 0xa9, 0xa2, 0xe8, 0x35,
+        0x27, 0x78, 0xf2, 0xef, 0x59, 0x36, 0x6d, 0x7c, 0xb6, 0x98, 0xd8, 0x1e,
+        0xfa, 0x25, 0x73, 0x97, 0x45, 0x58, 0xe3, 0xae, 0xbd, 0x52, 0x54, 0x05,
+        0xd8, 0x26, 0x26, 0xba, 0xba, 0x05, 0xb5, 0xe9, 0xe5, 0x76, 0xae, 0x25,
+        0xdd, 0xfc, 0x10, 0x89, 0x5a, 0xa9, 0xee, 0x59, 0xc5, 0x79, 0x8b, 0xeb,
+        0x1e, 0x2c, 0x61, 0xab, 0x0d, 0xd1, 0x10, 0x04, 0x91, 0x32, 0x77, 0x4a,
+        0xa6, 0x64, 0x53, 0xda, 0x4c, 0xd7, 0x3a, 0x29, 0xd4, 0xf3, 0x82, 0x25,
+        0x1d, 0x6f, 0x4a, 0x7f, 0xd3, 0x08, 0x3b, 0x42, 0x30, 0x10, 0xd8, 0xd0,
+        0x97, 0x3a, 0xeb, 0x92, 0x63, 0xec, 0x93, 0x2b, 0x6f, 0x32, 0xd8, 0xcd,
+        0x80, 0xd3, 0xc0, 0x4c, 0x03, 0xd5, 0xca, 0xbc, 0x8f, 0xc7, 0x43, 0x53,
+        0x64, 0x66, 0x1c, 0x82, 0x2d, 0xfb, 0xff, 0x39, 0xba, 0xd6, 0x42, 0x62,
+        0x02, 0x6f, 0x96, 0x36
+    };
+    static const unsigned char seed_data[] = {
+        0x64, 0x46, 0x07, 0x32, 0x8d, 0x70, 0x9c, 0xb3, 0x8a, 0x35, 0xde, 0x62,
+        0x00, 0xf2, 0x6d, 0x52, 0x37, 0x4d, 0xb3, 0x84, 0xe1, 0x9d, 0x41, 0x04,
+        0xda, 0x7b, 0xdc, 0x0d, 0x8b, 0x5e, 0xe0, 0x84
+    };
+    const int gindex = 1;
+    const int pcounter = 53;
+    /*
+     * The keypair was generated using
+     * openssl genpkey -paramfile dsa_params.pem --pkeyopt pcounter:53 \
+     *                 -pkeyopt gindex:1 \
+     *                 -pkeyopt hexseed:644607328d709cb38a35de6200f26d -text
+     */
+    static const unsigned char priv_data[] = {
+        0x00, 0x8f, 0xc5, 0x9e, 0xd0, 0xf7, 0x2a, 0x0b, 0x66, 0xf1, 0x32, 0x73,
+        0xae, 0xf6, 0xd9, 0xd4, 0xdb, 0x2d, 0x96, 0x55, 0x89, 0xff, 0xef, 0xa8,
+        0x5f, 0x47, 0x8f, 0xca, 0x02, 0x8a, 0xe1, 0x35, 0x90
+    };
+    static const unsigned char pub_data[] = {
+        0x44, 0x19, 0xc9, 0x46, 0x45, 0x57, 0xc1, 0xa9, 0xd8, 0x30, 0x99, 0x29,
+        0x6a, 0x4b, 0x63, 0x71, 0x69, 0x96, 0x35, 0x17, 0xb2, 0x62, 0x9b, 0x80,
+        0x0a, 0x95, 0x9d, 0x6a, 0xc0, 0x32, 0x0d, 0x07, 0x5f, 0x19, 0x44, 0x02,
+        0xf1, 0xbd, 0xce, 0xdf, 0x10, 0xf8, 0x02, 0x5d, 0x7d, 0x98, 0x8a, 0x73,
+        0x89, 0x00, 0xb6, 0x24, 0xd6, 0x33, 0xe7, 0xcf, 0x8b, 0x49, 0x2a, 0xaf,
+        0x13, 0x1c, 0xb2, 0x52, 0x15, 0xfd, 0x9b, 0xd5, 0x40, 0x4a, 0x1a, 0xda,
+        0x29, 0x4c, 0x92, 0x7e, 0x66, 0x06, 0xdb, 0x61, 0x86, 0xac, 0xb5, 0xda,
+        0x3c, 0x7d, 0x73, 0x7e, 0x54, 0x32, 0x68, 0xa5, 0x02, 0xbc, 0x59, 0x47,
+        0x84, 0xd3, 0x87, 0x71, 0x5f, 0xeb, 0x43, 0x45, 0x24, 0xd3, 0xec, 0x08,
+        0x52, 0xc2, 0x89, 0x2d, 0x9c, 0x1a, 0xcc, 0x91, 0x65, 0x5d, 0xa3, 0xa1,
+        0x35, 0x31, 0x10, 0x1c, 0x3a, 0xa8, 0x4d, 0x18, 0xd5, 0x06, 0xaf, 0xb2,
+        0xec, 0x5c, 0x89, 0x9e, 0x90, 0x86, 0x10, 0x01, 0xeb, 0x51, 0xd5, 0x1b,
+        0x9c, 0xcb, 0x66, 0x07, 0x3f, 0xc4, 0x6e, 0x0a, 0x1b, 0x73, 0xa0, 0x4b,
+        0x5f, 0x4d, 0xab, 0x35, 0x28, 0xfa, 0xda, 0x3a, 0x0c, 0x08, 0xe8, 0xf3,
+        0xef, 0x42, 0x67, 0xbc, 0x21, 0xf2, 0xc2, 0xb8, 0xff, 0x1a, 0x81, 0x05,
+        0x68, 0x73, 0x62, 0xdf, 0xd7, 0xab, 0x0f, 0x22, 0x89, 0x57, 0x96, 0xd4,
+        0x93, 0xaf, 0xa1, 0x21, 0xa3, 0x48, 0xe9, 0xf0, 0x97, 0x47, 0xa0, 0x27,
+        0xba, 0x87, 0xb8, 0x15, 0x5f, 0xff, 0x2c, 0x50, 0x41, 0xf1, 0x7e, 0xc6,
+        0x81, 0xc4, 0x51, 0xf1, 0xfd, 0xd6, 0x86, 0xf7, 0x69, 0x97, 0xf1, 0x49,
+        0xc9, 0xf9, 0xf4, 0x9b, 0xf4, 0xe8, 0x85, 0xa7, 0xbd, 0x36, 0x55, 0x4a,
+        0x3d, 0xe8, 0x65, 0x09, 0x7b, 0xb7, 0x12, 0x64, 0xd2, 0x0a, 0x53, 0x60,
+        0x48, 0xd1, 0x8a, 0xbd
+    };
+
+    if (!TEST_ptr(bld = OSSL_PARAM_BLD_new())
+        || !TEST_ptr(pub = BN_bin2bn(pub_data, sizeof(pub_data), NULL))
+        || !TEST_ptr(priv = BN_bin2bn(priv_data, sizeof(priv_data), NULL))
+        || !TEST_ptr(p = BN_bin2bn(p_data, sizeof(p_data), NULL))
+        || !TEST_ptr(q = BN_bin2bn(q_data, sizeof(q_data), NULL))
+        || !TEST_ptr(g = BN_bin2bn(g_data, sizeof(g_data), NULL))
+
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p))
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q))
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g))
+        || !TEST_true(OSSL_PARAM_BLD_push_octet_string(bld,
+                                                       OSSL_PKEY_PARAM_FFC_SEED,
+                                                       seed_data,
+                                                       sizeof(seed_data)))
+        || !TEST_true(OSSL_PARAM_BLD_push_int(bld, OSSL_PKEY_PARAM_FFC_GINDEX,
+                                              gindex))
+        || !TEST_true(OSSL_PARAM_BLD_push_int(bld,
+                                              OSSL_PKEY_PARAM_FFC_PCOUNTER,
+                                              pcounter))
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY,
+                                             pub))
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY,
+                                             priv))
+        || !TEST_ptr(fromdata_params = OSSL_PARAM_BLD_to_param(bld)))
+        goto err;
+
+    if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL)))
+        goto err;
+
+    if (!TEST_true(EVP_PKEY_key_fromdata_init(ctx))
+        || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params))
+        || !TEST_int_eq(EVP_PKEY_bits(pk), 2048)
+        || !TEST_int_eq(EVP_PKEY_security_bits(pk), 112)
+        || !TEST_int_eq(EVP_PKEY_size(pk), 2 + 2 * (3 + sizeof(q_data))))
+        goto err;
+
+    if (!TEST_false(EVP_PKEY_get_utf8_string_param(pk, OSSL_PKEY_PARAM_FFC_GROUP,
+                                                   name_out, sizeof(name_out),
+                                                   &len))
+        || !TEST_true(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_PUB_KEY,
+                                            &pub_out))
+        || !TEST_BN_eq(pub, pub_out)
+        || !TEST_true(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_PRIV_KEY,
+                                            &priv_out))
+        || !TEST_BN_eq(priv, priv_out)
+        || !TEST_true(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_FFC_P, &p_out))
+        || !TEST_BN_eq(p, p_out)
+        || !TEST_true(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_FFC_Q, &q_out))
+        || !TEST_BN_eq(q, q_out)
+        || !TEST_true(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_FFC_G, &g_out))
+        || !TEST_BN_eq(g, g_out)
+        || !TEST_false(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_FFC_COFACTOR,
+                                             &j_out))
+        || !TEST_ptr_null(j_out)
+        || !TEST_true(EVP_PKEY_get_octet_string_param(pk,
+                                                      OSSL_PKEY_PARAM_FFC_SEED,
+                                                      seed_out, sizeof(seed_out),
+                                                      &len))
+        || !TEST_true(EVP_PKEY_get_int_param(pk, OSSL_PKEY_PARAM_FFC_GINDEX,
+                                             &gindex_out))
+        || !TEST_int_eq(gindex, gindex_out)
+        || !TEST_true(EVP_PKEY_get_int_param(pk, OSSL_PKEY_PARAM_FFC_H,
+                                             &hindex_out))
+        || !TEST_int_eq(hindex_out, 0)
+        || !TEST_true(EVP_PKEY_get_int_param(pk, OSSL_PKEY_PARAM_FFC_PCOUNTER,
+                                             &pcounter_out))
+        || !TEST_int_eq(pcounter, pcounter_out))
+        goto err;
+
+    if (!TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, "")))
+        goto err;
+
+    if (!TEST_true(EVP_PKEY_check(key_ctx))
+        || !TEST_true(EVP_PKEY_public_check(key_ctx))
+        || !TEST_true(EVP_PKEY_private_check(key_ctx))
+        || !TEST_true(EVP_PKEY_pairwise_check(key_ctx)))
+        goto err;
+
+    if (!TEST_ptr(copy_pk = EVP_PKEY_new())
+        || !TEST_true(EVP_PKEY_copy_parameters(copy_pk, pk)))
+        goto err;
+
+    ret = test_print_key_using_pem("DSA", pk)
+          && test_print_key_using_serializer("DSA", pk);
+ err:
+    OSSL_PARAM_BLD_free_params(fromdata_params);
+    OSSL_PARAM_BLD_free(bld);
+    BN_free(p);
+    BN_free(q);
+    BN_free(g);
+    BN_free(pub);
+    BN_free(priv);
+    BN_free(p_out);
+    BN_free(q_out);
+    BN_free(g_out);
+    BN_free(pub_out);
+    BN_free(priv_out);
+    BN_free(j_out);
+    EVP_PKEY_free(pk);
+    EVP_PKEY_free(copy_pk);
+    EVP_PKEY_CTX_free(ctx);
+    EVP_PKEY_CTX_free(key_ctx);
+
+    return ret;
+}
+#endif /* OPENSSL_NO_DSA */
+
+
 int setup_tests(void)
 {
     if (!test_skip_common_options()) {
@@ -791,6 +1017,9 @@ int setup_tests(void)
 #ifndef OPENSSL_NO_DH
     ADD_TEST(test_fromdata_dh);
 #endif
+#ifndef OPENSSL_NO_DSA
+    ADD_TEST(test_fromdata_dsa_fips186_4);
+#endif
 #ifndef OPENSSL_NO_EC
     ADD_ALL_TESTS(test_fromdata_ecx, 4);
     ADD_TEST(test_fromdata_ec);
diff --git a/test/recipes/15-test_gendsa.t b/test/recipes/15-test_gendsa.t
new file mode 100644
index 0000000000..71d47254de
--- /dev/null
+++ b/test/recipes/15-test_gendsa.t
@@ -0,0 +1,77 @@
+#! /usr/bin/env perl
+# Copyright 2017-2018 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
+
+
+use strict;
+use warnings;
+
+use File::Spec;
+use OpenSSL::Test qw/:DEFAULT srctop_file/;
+use OpenSSL::Test::Utils;
+
+setup("test_gendsa");
+
+plan skip_all => "This test is unsupported in a no-dsa build"
+    if disabled("dsa");
+
+plan tests => 8;
+
+ok(run(app([ 'openssl', 'genpkey', '-genparam',
+             '-algorithm', 'DSA',
+             '-pkeyopt', 'gindex:1',
+             '-pkeyopt', 'type:fips186_4',
+             '-text'])),
+   "genpkey DSA params fips186_4 with verifiable g");
+
+ok(run(app([ 'openssl', 'genpkey', '-genparam',
+             '-algorithm', 'DSA',
+             '-pkeyopt', 'type:fips186_4',
+             '-text'])),
+   "genpkey DSA params fips186_4 with unverifiable g");
+
+ok(run(app([ 'openssl', 'genpkey', '-genparam',
+             '-algorithm', 'DSA',
+             '-pkeyopt', 'type:fips186_2',
+             '-text'])),
+   "genpkey DSA params fips186_2");
+
+ok(!run(app([ 'openssl', 'genpkey', '-algorithm', 'DSA',
+             '-pkeyopt', 'type:group',
+             '-text'])),
+   "genpkey DSA does not support groups");
+
+ok(run(app([ 'openssl', 'genpkey', '-genparam',
+             '-algorithm', 'DSA',
+             '-pkeyopt', 'gindex:1',
+             '-pkeyopt', 'type:fips186_4',
+             '-out', 'dsagen.pem'])),
+   "genpkey DSA params fips186_4 PEM");
+
+ok(run(app([ 'openssl', 'genpkey', '-genparam',
+             '-algorithm', 'DSA',
+             '-pkeyopt', 'gindex:1',
+             '-pkeyopt', 'pbits:2048',
+             '-pkeyopt', 'qbits:256',
+             '-pkeyopt', 'type:fips186_4',
+             '-outform', 'DER',
+             '-out', 'dsagen.der'])),
+   "genpkey DSA params fips186_4 DER");
+
+# The seed and counter should be the ones generated from the param generation
+# Just put some dummy ones in to show it works.
+ok(run(app([ 'openssl', 'genpkey',
+             '-paramfile', 'dsagen.der',
+             '-pkeyopt', 'gindex:1',
+             '-pkeyopt', 'hexseed:0102030405060708090A0B0C0D0E0F1011121314',
+             '-pkeyopt', 'pcounter:25',
+             '-text'])),
+   "genpkey DSA fips186_4 with DER params");
+
+ok(!run(app([ 'openssl', 'genpkey',
+              '-algorithm', 'DSA'])),
+   "genpkey DSA with no params should fail");
diff --git a/test/recipes/30-test_evp_pkey_provided/DSA.priv.der b/test/recipes/30-test_evp_pkey_provided/DSA.priv.der
new file mode 100644
index 0000000000..d10a69db0d
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/DSA.priv.der differ
diff --git a/test/recipes/30-test_evp_pkey_provided/DSA.priv.pem b/test/recipes/30-test_evp_pkey_provided/DSA.priv.pem
new file mode 100644
index 0000000000..8836ac1f23
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/DSA.priv.pem
@@ -0,0 +1,15 @@
+-----BEGIN PRIVATE KEY-----
+MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQCgtwLErKZCq/I0CyJHHzPP1QTk
+PuyhIchBK++4HwtbiItn+GhtfE2WXzxm71g01/aiG63IElK46CpjzOrnTsg0TFhZ
+CsJK5LRkIPT2Cs+GAWx/I0pRB5lCKHr/GGdSZPKaYjDDAN4j6RGVftE9jbQOn56x
+MAPwc6hASEJ7YKDE8jstCgy4Gfu0+OAqx/HAxoYUYBIPwN5KZ+zH3nYhGlV/hsOX
+mM71zfDnEtaT7hubYe8FjEVG2WRvvieqZwHMcbFgziHYURcnDZA9GHyHFY5ITGzF
+cuu3VvVrYI/C/T9GXACRhXlFWxyCxIdQebrMHDJ+LrguxU7Rm9tmeXz+r2oFAiEA
+qM30M3sTCiTB3koEe0txUTLpR3S9DCFAhBIKF3PbKccCggEAbMakPmGEwf9vShpr
+sCRL0pJbKVxhuMkr1vdZ/dhwZnf8waTUsB7Vv1mYs2aL9C7mEj7M+AK4xsNH0vWq
+DF9R9dBMVT0Hc6ZXzlqtQgwTD+IxJY5yEnMQ239561n8/vcMGoFTliK451jYZ4Bg
+rYtVHJHwcpp+rTfxdxiWimhw/HGpoug1J3jy71k2bXy2mNge+iVzl0VY4669UlQF
+2CYmuroFtenldq4l3fwQiVqp7lnFeYvrHixhqw3REASRMndKpmRT2kzXOinU84Il
+HW9Kf9MIO0IwENjQlzrrkmPskytvMtjNgNPATAPVyryPx0NTZGYcgi37/zm61kJi
+Am+WNgQjAiEAj8We0PcqC2bxMnOu9tnU2y2WVYn/76hfR4/KAorhNZA=
+-----END PRIVATE KEY-----
diff --git a/test/recipes/30-test_evp_pkey_provided/DSA.priv.txt b/test/recipes/30-test_evp_pkey_provided/DSA.priv.txt
new file mode 100644
index 0000000000..1b1b758b03
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/DSA.priv.txt
@@ -0,0 +1,72 @@
+Private-Key: (2048 bit)
+priv:
+    00:8f:c5:9e:d0:f7:2a:0b:66:f1:32:73:ae:f6:d9:
+    d4:db:2d:96:55:89:ff:ef:a8:5f:47:8f:ca:02:8a:
+    e1:35:90
+pub: 
+    44:19:c9:46:45:57:c1:a9:d8:30:99:29:6a:4b:63:
+    71:69:96:35:17:b2:62:9b:80:0a:95:9d:6a:c0:32:
+    0d:07:5f:19:44:02:f1:bd:ce:df:10:f8:02:5d:7d:
+    98:8a:73:89:00:b6:24:d6:33:e7:cf:8b:49:2a:af:
+    13:1c:b2:52:15:fd:9b:d5:40:4a:1a:da:29:4c:92:
+    7e:66:06:db:61:86:ac:b5:da:3c:7d:73:7e:54:32:
+    68:a5:02:bc:59:47:84:d3:87:71:5f:eb:43:45:24:
+    d3:ec:08:52:c2:89:2d:9c:1a:cc:91:65:5d:a3:a1:
+    35:31:10:1c:3a:a8:4d:18:d5:06:af:b2:ec:5c:89:
+    9e:90:86:10:01:eb:51:d5:1b:9c:cb:66:07:3f:c4:
+    6e:0a:1b:73:a0:4b:5f:4d:ab:35:28:fa:da:3a:0c:
+    08:e8:f3:ef:42:67:bc:21:f2:c2:b8:ff:1a:81:05:
+    68:73:62:df:d7:ab:0f:22:89:57:96:d4:93:af:a1:
+    21:a3:48:e9:f0:97:47:a0:27:ba:87:b8:15:5f:ff:
+    2c:50:41:f1:7e:c6:81:c4:51:f1:fd:d6:86:f7:69:
+    97:f1:49:c9:f9:f4:9b:f4:e8:85:a7:bd:36:55:4a:
+    3d:e8:65:09:7b:b7:12:64:d2:0a:53:60:48:d1:8a:
+    bd
+P:   
+    00:a0:b7:02:c4:ac:a6:42:ab:f2:34:0b:22:47:1f:
+    33:cf:d5:04:e4:3e:ec:a1:21:c8:41:2b:ef:b8:1f:
+    0b:5b:88:8b:67:f8:68:6d:7c:4d:96:5f:3c:66:ef:
+    58:34:d7:f6:a2:1b:ad:c8:12:52:b8:e8:2a:63:cc:
+    ea:e7:4e:c8:34:4c:58:59:0a:c2:4a:e4:b4:64:20:
+    f4:f6:0a:cf:86:01:6c:7f:23:4a:51:07:99:42:28:
+    7a:ff:18:67:52:64:f2:9a:62:30:c3:00:de:23:e9:
+    11:95:7e:d1:3d:8d:b4:0e:9f:9e:b1:30:03:f0:73:
+    a8:40:48:42:7b:60:a0:c4:f2:3b:2d:0a:0c:b8:19:
+    fb:b4:f8:e0:2a:c7:f1:c0:c6:86:14:60:12:0f:c0:
+    de:4a:67:ec:c7:de:76:21:1a:55:7f:86:c3:97:98:
+    ce:f5:cd:f0:e7:12:d6:93:ee:1b:9b:61:ef:05:8c:
+    45:46:d9:64:6f:be:27:aa:67:01:cc:71:b1:60:ce:
+    21:d8:51:17:27:0d:90:3d:18:7c:87:15:8e:48:4c:
+    6c:c5:72:eb:b7:56:f5:6b:60:8f:c2:fd:3f:46:5c:
+    00:91:85:79:45:5b:1c:82:c4:87:50:79:ba:cc:1c:
+    32:7e:2e:b8:2e:c5:4e:d1:9b:db:66:79:7c:fe:af:
+    6a:05
+Q:   
+    00:a8:cd:f4:33:7b:13:0a:24:c1:de:4a:04:7b:4b:
+    71:51:32:e9:47:74:bd:0c:21:40:84:12:0a:17:73:
+    db:29:c7
+G:   
+    6c:c6:a4:3e:61:84:c1:ff:6f:4a:1a:6b:b0:24:4b:
+    d2:92:5b:29:5c:61:b8:c9:2b:d6:f7:59:fd:d8:70:
+    66:77:fc:c1:a4:d4:b0:1e:d5:bf:59:98:b3:66:8b:
+    f4:2e:e6:12:3e:cc:f8:02:b8:c6:c3:47:d2:f5:aa:
+    0c:5f:51:f5:d0:4c:55:3d:07:73:a6:57:ce:5a:ad:
+    42:0c:13:0f:e2:31:25:8e:72:12:73:10:db:7f:79:
+    eb:59:fc:fe:f7:0c:1a:81:53:96:22:b8:e7:58:d8:
+    67:80:60:ad:8b:55:1c:91:f0:72:9a:7e:ad:37:f1:
+    77:18:96:8a:68:70:fc:71:a9:a2:e8:35:27:78:f2:
+    ef:59:36:6d:7c:b6:98:d8:1e:fa:25:73:97:45:58:
+    e3:ae:bd:52:54:05:d8:26:26:ba:ba:05:b5:e9:e5:
+    76:ae:25:dd:fc:10:89:5a:a9:ee:59:c5:79:8b:eb:
+    1e:2c:61:ab:0d:d1:10:04:91:32:77:4a:a6:64:53:
+    da:4c:d7:3a:29:d4:f3:82:25:1d:6f:4a:7f:d3:08:
+    3b:42:30:10:d8:d0:97:3a:eb:92:63:ec:93:2b:6f:
+    32:d8:cd:80:d3:c0:4c:03:d5:ca:bc:8f:c7:43:53:
+    64:66:1c:82:2d:fb:ff:39:ba:d6:42:62:02:6f:96:
+    36
+SEED:
+    64:46:07:32:8d:70:9c:b3:8a:35:de:62:00:f2:6d:
+    52:37:4d:b3:84:e1:9d:41:04:da:7b:dc:0d:8b:5e:
+    e0:84
+gindex: 1
+pcounter: 53
diff --git a/test/recipes/30-test_evp_pkey_provided/DSA.pub.der b/test/recipes/30-test_evp_pkey_provided/DSA.pub.der
new file mode 100644
index 0000000000..7432479d5b
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/DSA.pub.der differ
diff --git a/test/recipes/30-test_evp_pkey_provided/DSA.pub.pem b/test/recipes/30-test_evp_pkey_provided/DSA.pub.pem
new file mode 100644
index 0000000000..98242b49bb
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/DSA.pub.pem
@@ -0,0 +1,20 @@
+-----BEGIN PUBLIC KEY-----
+MIIDRjCCAjkGByqGSM44BAEwggIsAoIBAQCgtwLErKZCq/I0CyJHHzPP1QTkPuyh
+IchBK++4HwtbiItn+GhtfE2WXzxm71g01/aiG63IElK46CpjzOrnTsg0TFhZCsJK
+5LRkIPT2Cs+GAWx/I0pRB5lCKHr/GGdSZPKaYjDDAN4j6RGVftE9jbQOn56xMAPw
+c6hASEJ7YKDE8jstCgy4Gfu0+OAqx/HAxoYUYBIPwN5KZ+zH3nYhGlV/hsOXmM71
+zfDnEtaT7hubYe8FjEVG2WRvvieqZwHMcbFgziHYURcnDZA9GHyHFY5ITGzFcuu3
+VvVrYI/C/T9GXACRhXlFWxyCxIdQebrMHDJ+LrguxU7Rm9tmeXz+r2oFAiEAqM30
+M3sTCiTB3koEe0txUTLpR3S9DCFAhBIKF3PbKccCggEAbMakPmGEwf9vShprsCRL
+0pJbKVxhuMkr1vdZ/dhwZnf8waTUsB7Vv1mYs2aL9C7mEj7M+AK4xsNH0vWqDF9R
+9dBMVT0Hc6ZXzlqtQgwTD+IxJY5yEnMQ239561n8/vcMGoFTliK451jYZ4BgrYtV
+HJHwcpp+rTfxdxiWimhw/HGpoug1J3jy71k2bXy2mNge+iVzl0VY4669UlQF2CYm
+uroFtenldq4l3fwQiVqp7lnFeYvrHixhqw3REASRMndKpmRT2kzXOinU84IlHW9K
+f9MIO0IwENjQlzrrkmPskytvMtjNgNPATAPVyryPx0NTZGYcgi37/zm61kJiAm+W
+NgOCAQUAAoIBAEQZyUZFV8Gp2DCZKWpLY3FpljUXsmKbgAqVnWrAMg0HXxlEAvG9
+zt8Q+AJdfZiKc4kAtiTWM+fPi0kqrxMcslIV/ZvVQEoa2ilMkn5mBtthhqy12jx9
+c35UMmilArxZR4TTh3Ff60NFJNPsCFLCiS2cGsyRZV2joTUxEBw6qE0Y1Qavsuxc
+iZ6QhhAB61HVG5zLZgc/xG4KG3OgS19NqzUo+to6DAjo8+9CZ7wh8sK4/xqBBWhz
+Yt/Xqw8iiVeW1JOvoSGjSOnwl0egJ7qHuBVf/yxQQfF+xoHEUfH91ob3aZfxScn5
+9Jv06IWnvTZVSj3oZQl7txJk0gpTYEjRir0=
+-----END PUBLIC KEY-----
diff --git a/test/recipes/30-test_evp_pkey_provided/DSA.pub.txt b/test/recipes/30-test_evp_pkey_provided/DSA.pub.txt
new file mode 100644
index 0000000000..1b1b758b03
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/DSA.pub.txt
@@ -0,0 +1,72 @@
+Private-Key: (2048 bit)
+priv:
+    00:8f:c5:9e:d0:f7:2a:0b:66:f1:32:73:ae:f6:d9:
+    d4:db:2d:96:55:89:ff:ef:a8:5f:47:8f:ca:02:8a:
+    e1:35:90
+pub: 
+    44:19:c9:46:45:57:c1:a9:d8:30:99:29:6a:4b:63:
+    71:69:96:35:17:b2:62:9b:80:0a:95:9d:6a:c0:32:
+    0d:07:5f:19:44:02:f1:bd:ce:df:10:f8:02:5d:7d:
+    98:8a:73:89:00:b6:24:d6:33:e7:cf:8b:49:2a:af:
+    13:1c:b2:52:15:fd:9b:d5:40:4a:1a:da:29:4c:92:
+    7e:66:06:db:61:86:ac:b5:da:3c:7d:73:7e:54:32:
+    68:a5:02:bc:59:47:84:d3:87:71:5f:eb:43:45:24:
+    d3:ec:08:52:c2:89:2d:9c:1a:cc:91:65:5d:a3:a1:
+    35:31:10:1c:3a:a8:4d:18:d5:06:af:b2:ec:5c:89:
+    9e:90:86:10:01:eb:51:d5:1b:9c:cb:66:07:3f:c4:
+    6e:0a:1b:73:a0:4b:5f:4d:ab:35:28:fa:da:3a:0c:
+    08:e8:f3:ef:42:67:bc:21:f2:c2:b8:ff:1a:81:05:
+    68:73:62:df:d7:ab:0f:22:89:57:96:d4:93:af:a1:
+    21:a3:48:e9:f0:97:47:a0:27:ba:87:b8:15:5f:ff:
+    2c:50:41:f1:7e:c6:81:c4:51:f1:fd:d6:86:f7:69:
+    97:f1:49:c9:f9:f4:9b:f4:e8:85:a7:bd:36:55:4a:
+    3d:e8:65:09:7b:b7:12:64:d2:0a:53:60:48:d1:8a:
+    bd
+P:   
+    00:a0:b7:02:c4:ac:a6:42:ab:f2:34:0b:22:47:1f:
+    33:cf:d5:04:e4:3e:ec:a1:21:c8:41:2b:ef:b8:1f:
+    0b:5b:88:8b:67:f8:68:6d:7c:4d:96:5f:3c:66:ef:
+    58:34:d7:f6:a2:1b:ad:c8:12:52:b8:e8:2a:63:cc:
+    ea:e7:4e:c8:34:4c:58:59:0a:c2:4a:e4:b4:64:20:
+    f4:f6:0a:cf:86:01:6c:7f:23:4a:51:07:99:42:28:
+    7a:ff:18:67:52:64:f2:9a:62:30:c3:00:de:23:e9:
+    11:95:7e:d1:3d:8d:b4:0e:9f:9e:b1:30:03:f0:73:
+    a8:40:48:42:7b:60:a0:c4:f2:3b:2d:0a:0c:b8:19:
+    fb:b4:f8:e0:2a:c7:f1:c0:c6:86:14:60:12:0f:c0:
+    de:4a:67:ec:c7:de:76:21:1a:55:7f:86:c3:97:98:
+    ce:f5:cd:f0:e7:12:d6:93:ee:1b:9b:61:ef:05:8c:
+    45:46:d9:64:6f:be:27:aa:67:01:cc:71:b1:60:ce:
+    21:d8:51:17:27:0d:90:3d:18:7c:87:15:8e:48:4c:
+    6c:c5:72:eb:b7:56:f5:6b:60:8f:c2:fd:3f:46:5c:
+    00:91:85:79:45:5b:1c:82:c4:87:50:79:ba:cc:1c:
+    32:7e:2e:b8:2e:c5:4e:d1:9b:db:66:79:7c:fe:af:
+    6a:05
+Q:   
+    00:a8:cd:f4:33:7b:13:0a:24:c1:de:4a:04:7b:4b:
+    71:51:32:e9:47:74:bd:0c:21:40:84:12:0a:17:73:
+    db:29:c7
+G:   
+    6c:c6:a4:3e:61:84:c1:ff:6f:4a:1a:6b:b0:24:4b:
+    d2:92:5b:29:5c:61:b8:c9:2b:d6:f7:59:fd:d8:70:
+    66:77:fc:c1:a4:d4:b0:1e:d5:bf:59:98:b3:66:8b:
+    f4:2e:e6:12:3e:cc:f8:02:b8:c6:c3:47:d2:f5:aa:
+    0c:5f:51:f5:d0:4c:55:3d:07:73:a6:57:ce:5a:ad:
+    42:0c:13:0f:e2:31:25:8e:72:12:73:10:db:7f:79:
+    eb:59:fc:fe:f7:0c:1a:81:53:96:22:b8:e7:58:d8:
+    67:80:60:ad:8b:55:1c:91:f0:72:9a:7e:ad:37:f1:
+    77:18:96:8a:68:70:fc:71:a9:a2:e8:35:27:78:f2:
+    ef:59:36:6d:7c:b6:98:d8:1e:fa:25:73:97:45:58:
+    e3:ae:bd:52:54:05:d8:26:26:ba:ba:05:b5:e9:e5:
+    76:ae:25:dd:fc:10:89:5a:a9:ee:59:c5:79:8b:eb:
+    1e:2c:61:ab:0d:d1:10:04:91:32:77:4a:a6:64:53:
+    da:4c:d7:3a:29:d4:f3:82:25:1d:6f:4a:7f:d3:08:
+    3b:42:30:10:d8:d0:97:3a:eb:92:63:ec:93:2b:6f:
+    32:d8:cd:80:d3:c0:4c:03:d5:ca:bc:8f:c7:43:53:
+    64:66:1c:82:2d:fb:ff:39:ba:d6:42:62:02:6f:96:
+    36
+SEED:
+    64:46:07:32:8d:70:9c:b3:8a:35:de:62:00:f2:6d:
+    52:37:4d:b3:84:e1:9d:41:04:da:7b:dc:0d:8b:5e:
+    e0:84
+gindex: 1
+pcounter: 53
diff --git a/util/libcrypto.num b/util/libcrypto.num
index dd3ddef833..032548097e 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5056,3 +5056,10 @@ d2i_PrivateKey_ex_fp                    ?	3_0_0	EXIST::FUNCTION:STDIO
 d2i_PrivateKey_ex_bio                   ?	3_0_0	EXIST::FUNCTION:
 PEM_read_bio_PrivateKey_ex              ?	3_0_0	EXIST::FUNCTION:
 PEM_read_PrivateKey_ex                  ?	3_0_0	EXIST::FUNCTION:STDIO
+EVP_PKEY_CTX_set_dsa_paramgen_bits      ?	3_0_0	EXIST::FUNCTION:DSA
+EVP_PKEY_CTX_set_dsa_paramgen_q_bits    ?	3_0_0	EXIST::FUNCTION:DSA
+EVP_PKEY_CTX_set_dsa_paramgen_md_props  ?	3_0_0	EXIST::FUNCTION:DSA
+EVP_PKEY_CTX_set_dsa_paramgen_gindex    ?	3_0_0	EXIST::FUNCTION:DSA
+EVP_PKEY_CTX_set_dsa_paramgen_type      ?	3_0_0	EXIST::FUNCTION:DSA
+EVP_PKEY_CTX_set_dsa_paramgen_seed      ?	3_0_0	EXIST::FUNCTION:DSA
+EVP_PKEY_CTX_set_dsa_paramgen_md        ?	3_0_0	EXIST::FUNCTION:DSA


More information about the openssl-commits mailing list