Allow speicification of domain parameters for DSA key generation.
authorWerner Koch <wk@gnupg.org>
Wed, 10 Dec 2008 12:23:30 +0000 (12:23 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 10 Dec 2008 12:23:30 +0000 (12:23 +0000)
Doc updates.
Allows the use of the strings AES-128, AES-192, AES-256 to specify AES
algorithms.

NEWS
cipher/ChangeLog
cipher/dsa.c
cipher/rijndael.c
doc/ChangeLog
doc/gcrypt.texi
src/hmac256.c
tests/ChangeLog
tests/fipsdrv.c
tests/pubkey.c

diff --git a/NEWS b/NEWS
index 37ea62b..4fee4fc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ Noteworthy changes in version 1.4.4
  * In fips mode, RSA keys are now generated using the X9.31 algorithm
    and DSA keys using the FIPS 186-2 algorithm.
 
+ * The transient-key flag is now also supported for DSA key
+   generation.  DSA domain parameters may given as well.
+
 
 Noteworthy changes in version 1.4.3 (2008-09-18)
 ------------------------------------------------
index c6371f4..9952551 100644 (file)
@@ -1,3 +1,14 @@
+2008-12-10  Werner Koch  <wk@g10code.com>
+
+       * dsa.c (generate): Add arg DOMAIN and use it if specified.
+       (generate_fips186): Ditto.
+       (dsa_generate_ext): Parse and check the optional "domain"
+       parameter and pass them to the generate functions.
+
+       * rijndael.c (rijndael_names): Add "AES128" and "AES-128".
+       (rijndael192_names): Add "AES-192".
+       (rijndael256_names): Add "AES-256".
+
 2008-12-05  Werner Koch  <wk@g10code.com>
 
        * dsa.c (generate): Add arg TRANSIENT_KEY and use it to detrmine
index d11a7d0..100710f 100644 (file)
@@ -46,6 +46,15 @@ typedef struct
 } DSA_secret_key;
 
 
+/* A structure used to hold domain parameters.  */
+typedef struct
+{
+  gcry_mpi_t p;            /* prime */
+  gcry_mpi_t q;            /* group order */
+  gcry_mpi_t g;            /* group generator */
+} dsa_domain_t;
+
+
 /* A sample 1024 bit DSA key used for the selftests.  */
 static const char sample_secret_key[] =
 "(private-key"
@@ -92,6 +101,7 @@ static gpg_err_code_t generate (DSA_secret_key *sk,
                                 unsigned int nbits,
                                 unsigned int qbits,
                                 int transient_key,
+                                dsa_domain_t *domain,
                                 gcry_mpi_t **ret_factors);
 static void sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
                   DSA_secret_key *skey);
@@ -235,7 +245,7 @@ test_keys (DSA_secret_key *sk, unsigned int qbits)
  */
 static gpg_err_code_t
 generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
-          int transient_key,  gcry_mpi_t **ret_factors )
+          int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors )
 {
   gcry_mpi_t p;    /* the prime */
   gcry_mpi_t q;    /* the 160 bit prime factor */
@@ -274,33 +284,45 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
         return GPG_ERR_INV_VALUE;
     }
 
-  /* Generate the primes.  */
-  p = _gcry_generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
-  /* get q out of factors */
-  q = mpi_copy((*ret_factors)[0]);
-  if( mpi_get_nbits(q) != qbits )
-    BUG();
-
-  /* Find a generator g (h and e are helpers).
-     e = (p-1)/q */
-  e = mpi_alloc( mpi_get_nlimbs(p) );
-  mpi_sub_ui( e, p, 1 );
-  mpi_fdiv_q( e, e, q );
-  g = mpi_alloc( mpi_get_nlimbs(p) );
-  h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
-  do
+  if (domain->p && domain->q && domain->g)
     {
-      mpi_add_ui( h, h, 1 );
-      /* g = h^e mod p */
-      gcry_mpi_powm( g, h, e, p );
-    } 
-  while( !mpi_cmp_ui( g, 1 ) );  /* continue until g != 1 */
+      /* Domain parameters are given; use them.  */
+      p = mpi_copy (domain->p);
+      q = mpi_copy (domain->q);
+      g = mpi_copy (domain->g);
+      gcry_assert (mpi_get_nbits (p) == nbits);
+      gcry_assert (mpi_get_nbits (q) == qbits);
+      h = mpi_alloc (0);
+      e = NULL;
+    }
+  else
+    {
+      /* Generate new domain parameters.  */
+      p = _gcry_generate_elg_prime (1, nbits, qbits, NULL, ret_factors);
+      /* Get q out of factors.  */
+      q = mpi_copy ((*ret_factors)[0]);
+      gcry_assert (mpi_get_nbits (q) == qbits);
+
+      /* Find a generator g (h and e are helpers).
+         e = (p-1)/q */
+      e = mpi_alloc (mpi_get_nlimbs (p));
+      mpi_sub_ui (e, p, 1);
+      mpi_fdiv_q (e, e, q);
+      g = mpi_alloc (mpi_get_nlimbs (p));
+      h = mpi_alloc_set_ui (1); /* (We start with 2.) */
+      do
+        {
+          mpi_add_ui (h, h, 1);
+          /* g = h^e mod p */
+          gcry_mpi_powm (g, h, e, p);
+        } 
+      while (!mpi_cmp_ui (g, 1));  /* Continue until g != 1. */
+    }
 
-  /* Select a random number which has these properties:
+  /* Select a random number X with the property:
    *    0 < x < q-1
-   * This must be a very good random number because this
-   * is the secret part. */
-  /* The random quality depends on the transient_key flag.  */
+   * This must be a very good random number because this is the secret
+   * part.  The random quality depends on the transient_key flag.  */
   random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
   if (DBG_CIPHER)
     log_debug("choosing a random x%s", transient_key? " (transient-key)":"");
@@ -368,10 +390,13 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
 /* Generate a DSA key pair with a key of size NBITS using the
    algorithm given in FIPS-186-3.  If USE_FIPS186_2 is true,
    FIPS-186-2 is used and thus the length is restricted to 1024/160.
-   If DERIVEPARMS are not NULL the may contain a seed value. */
+   If DERIVEPARMS is not NULL it may contain a seed value.  If domain
+   parameters are specified in DOMAIN, DERIVEPARMS may not be given
+   and NBITS and QBITS must match the specified domain parameters.  */
 static gpg_err_code_t
 generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
                   gcry_sexp_t deriveparms, int use_fips186_2,
+                  dsa_domain_t *domain,
                   int *r_counter, void **r_seed, size_t *r_seedlen,
                   gcry_mpi_t *r_h)
 {
@@ -419,48 +444,65 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
   else
     return GPG_ERR_INV_VALUE;
 
-  /* Get an initial seed value.  */
-  if (deriveparms)
+  if (domain->p && domain->q && domain->g)
     {
-      initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0);
-      if (initial_seed.sexp)
-        initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1,
-                                                &initial_seed.seedlen);
+      /* Domain parameters are given; use them.  */
+      prime_p = mpi_copy (domain->p);
+      prime_q = mpi_copy (domain->q);
+      value_g = mpi_copy (domain->g);
+      gcry_assert (mpi_get_nbits (prime_p) == nbits);
+      gcry_assert (mpi_get_nbits (prime_q) == qbits);
+      gcry_assert (!deriveparms);
+      ec = 0;
     }
-
-  /* Fixme: Enable 186-3 after it has been approved and after fixing
-     the generation function.  */
-/*   if (use_fips186_2) */
-  (void)use_fips186_2;
-    ec = _gcry_generate_fips186_2_prime (nbits, qbits, 
-                                         initial_seed.seed, 
-                                         initial_seed.seedlen,
-                                         &prime_q, &prime_p, 
-                                         r_counter,
-                                         r_seed, r_seedlen);
-/*   else */
-/*     ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */
-/*                                          &prime_q, &prime_p, */
-/*                                          r_counter, */
-/*                                          r_seed, r_seedlen, NULL); */
-  gcry_sexp_release (initial_seed.sexp);
-  if (ec)
-    goto leave;
-
-  /* Find a generator g (h and e are helpers).
-     e = (p-1)/q */
-  value_e = mpi_alloc_like (prime_p);
-  mpi_sub_ui (value_e, prime_p, 1);
-  mpi_fdiv_q (value_e, value_e, prime_q );
-  value_g = mpi_alloc_like (prime_p);
-  value_h = mpi_alloc_set_ui (1); 
-  do
+  else
     {
-      mpi_add_ui (value_h, value_h, 1);
-      /* g = h^e mod p */
-      mpi_powm (value_g, value_h, value_e, prime_p);
-    } 
-  while (!mpi_cmp_ui (value_g, 1));  /* Continue until g != 1.  */
+      /* Generate new domain parameters.  */
+
+      /* Get an initial seed value.  */
+      if (deriveparms)
+        {
+          initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0);
+          if (initial_seed.sexp)
+            initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1,
+                                                    &initial_seed.seedlen);
+        }
+      
+      /* Fixme: Enable 186-3 after it has been approved and after fixing
+         the generation function.  */
+      /*   if (use_fips186_2) */
+      (void)use_fips186_2;
+      ec = _gcry_generate_fips186_2_prime (nbits, qbits, 
+                                           initial_seed.seed, 
+                                           initial_seed.seedlen,
+                                           &prime_q, &prime_p, 
+                                           r_counter,
+                                           r_seed, r_seedlen);
+      /*   else */
+      /*     ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */
+      /*                                          &prime_q, &prime_p, */
+      /*                                          r_counter, */
+      /*                                          r_seed, r_seedlen, NULL); */
+      gcry_sexp_release (initial_seed.sexp);
+      if (ec)
+        goto leave;
+
+      /* Find a generator g (h and e are helpers).
+         e = (p-1)/q */
+      value_e = mpi_alloc_like (prime_p);
+      mpi_sub_ui (value_e, prime_p, 1);
+      mpi_fdiv_q (value_e, value_e, prime_q );
+      value_g = mpi_alloc_like (prime_p);
+      value_h = mpi_alloc_set_ui (1); 
+      do
+        {
+          mpi_add_ui (value_h, value_h, 1);
+          /* g = h^e mod p */
+          mpi_powm (value_g, value_h, value_e, prime_p);
+        } 
+      while (!mpi_cmp_ui (value_g, 1));  /* Continue until g != 1.  */
+    }
+
 
   /* Select a random number x with:  0 < x < q  */
   value_x = gcry_mpi_snew (qbits);
@@ -648,13 +690,17 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
   int transient_key = 0;
   int use_fips186_2 = 0;
   int use_fips186 = 0;
-  
-
+  dsa_domain_t domain;
   (void)algo;    /* No need to check it.  */
   (void)evalue;  /* Not required for DSA. */
 
+  memset (&domain, 0, sizeof domain);
+
   if (genparms)
     {
+      gcry_sexp_t domainsexp;
+  
       /* Parse the optional qbits element.  */
       l1 = gcry_sexp_find_token (genparms, "qbits", 0);
       if (l1)
@@ -699,6 +745,48 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
           use_fips186_2 = 1;
           gcry_sexp_release (l1);
         }
+
+      /* Check whether domain parameters are given.  */
+      domainsexp = gcry_sexp_find_token (genparms, "domain", 0);
+      if (domainsexp)
+        {
+          /* DERIVEPARMS can't be used together with domain
+             parameters.  NBITS abnd QBITS may not be specified
+             because there values are derived from the domain
+             parameters.  */
+          if (deriveparms || qbits || nbits)
+            {
+              gcry_sexp_release (domainsexp);
+              gcry_sexp_release (deriveparms);
+              return GPG_ERR_INV_VALUE;
+            }
+          
+          /* Put all domain parameters into the domain object.  */
+          l1 = gcry_sexp_find_token (domainsexp, "p", 0);
+          domain.p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+          gcry_sexp_release (l1);
+          l1 = gcry_sexp_find_token (domainsexp, "q", 0);
+          domain.q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+          gcry_sexp_release (l1);
+          l1 = gcry_sexp_find_token (domainsexp, "g", 0);
+          domain.g = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+          gcry_sexp_release (l1);
+          gcry_sexp_release (domainsexp);
+
+          /* Check that all domain parameters are available.  */
+          if (!domain.p || !domain.q || !domain.g)
+            {
+              gcry_mpi_release (domain.p);
+              gcry_mpi_release (domain.q);
+              gcry_mpi_release (domain.g);
+              gcry_sexp_release (deriveparms);
+              return GPG_ERR_MISSING_VALUE;
+            }
+
+          /* Get NBITS and QBITS from the domain parameters.  */
+          nbits = mpi_get_nbits (domain.p);
+          qbits = mpi_get_nbits (domain.q);
+        }
     }
 
   if (deriveparms || use_fips186 || use_fips186_2 || fips_mode ())
@@ -709,10 +797,13 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
       gcry_mpi_t h_value;
 
       ec = generate_fips186 (&sk, nbits, qbits, deriveparms, use_fips186_2,
+                             &domain,
                              &counter, &seed, &seedlen, &h_value);
       gcry_sexp_release (deriveparms);
-      if (!ec)
+      if (!ec && h_value)
         {
+          /* Format the seed-values unless domain parameters are used
+             for which a H_VALUE of NULL is an indication.  */
           ec = gpg_err_code (gcry_sexp_build 
                              (&seedinfo, NULL,
                               "(seed-values(counter %d)(seed %b)(h %m))",
@@ -731,8 +822,13 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
     }
   else
     {
-      ec = generate (&sk, nbits, qbits, transient_key, retfactors);
+      ec = generate (&sk, nbits, qbits, transient_key, &domain, retfactors);
     }
+
+  gcry_mpi_release (domain.p);
+  gcry_mpi_release (domain.q);
+  gcry_mpi_release (domain.g);
+
   if (!ec)
     {
       skey[0] = sk.p;
index cb8e7fc..d43b349 100644 (file)
@@ -1174,6 +1174,8 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
 static const char *rijndael_names[] =
   {
     "RIJNDAEL",
+    "AES128",
+    "AES-128",
     NULL
   };
 
@@ -1199,6 +1201,7 @@ cipher_extra_spec_t _gcry_cipher_extraspec_aes =
 static const char *rijndael192_names[] =
   {
     "RIJNDAEL192",
+    "AES-192",
     NULL
   };
 
@@ -1224,6 +1227,7 @@ cipher_extra_spec_t _gcry_cipher_extraspec_aes192 =
 static const char *rijndael256_names[] =
   {
     "RIJNDAEL256",
+    "AES-256",
     NULL
   };
 
index 69207bd..027a147 100644 (file)
@@ -1,3 +1,8 @@
+2008-12-10  Werner Koch  <wk@g10code.com>
+
+       * gcrypt.texi (Cryptographic Functions): Explain the domain
+       parameter for key generation.
+
 2008-12-05  Werner Koch  <wk@g10code.com>
 
        * gcrypt.texi: Updates for pubkey generation.
index 4ccaae8..83ba617 100644 (file)
@@ -2726,21 +2726,20 @@ currently only implemented for DSA using this format:
     (domain
       (p @var{p-mpi})
       (q @var{q-mpi})
-      (g @var{q-mpi})
-      (seed @var{seed-mpi})
-      (counter @var{counter-mpi})
-      (h @var{h-mpi}))))
+      (g @var{q-mpi}))))
 @end example
 
-The @code{seed}, @code{counter} and @code{h} domain parameters are
-optional and currently not used.
+@code{nbits} and @code{qbits} may not be specified because they are
+derived from the domain parameters.
 
 @item derive-parms
-This is currently only meaningful for RSA keys.  If given, it is used
-to derive the RSA keys using the given parameters.  This is in general
-only useful for key generation tests.  If given for an RSA key the
-X9.31 key generation algorithm is used even if libgcrypt is not in
-FIPS mode.
+This is currently only implemented for RSA and DSA keys.  It is not
+allowed to use this together with a @code{domain} specification.  If
+given, it is used to derive the keys using the given parameters.
+
+If given for an RSA key the X9.31 key generation algorithm is used
+even if libgcrypt is not in FIPS mode.  If given for a DSA key, the
+FIPS 186 algorithm is used even if libgcrypt is not in FIPS mode.
 
 @example
 (genkey
@@ -2762,6 +2761,15 @@ FIPS mode.
             321DE34A#))))
 @end example
 
+@example
+(genkey
+  (dsa
+    (nbits 4:1024)
+    (derive-parms
+      (seed @var{seed-mpi}))))
+@end example
+
+
 @item use-x931
 @cindex X9.31
 Force the use of the ANSI X9.31 key generation algorithm instead of
index d8c059b..c802a78 100644 (file)
@@ -19,7 +19,7 @@
 
 /* 
     This is a standalone HMAC-SHA-256 implementation based on the code
-    from ../cipher/sha256.c.  It is a second implementarion to allow
+    from ../cipher/sha256.c.  It is a second implementation to allow
     comparing against the standard implementations and to be used for
     internal consistency checks.  It should not be used for sensitive
     data because no mechanisms to clear the stack etc are used.
index 1da5666..ce98770 100644 (file)
@@ -1,3 +1,13 @@
+2008-12-10  Werner Koch  <wk@g10code.com>
+
+       * pubkey.c (get_dsa_key_with_domain_new): New.
+       (get_dsa_key_fips186_with_domain_new): New.
+       (check_run): Call them.
+
+2008-12-08  Werner Koch  <wk@g10code.com>
+
+       * fipsdrv.c [W32]: Include fcntl.h.
+
 2008-12-05  Werner Koch  <wk@g10code.com>
 
        * pubkey.c (get_dsa_key_new): Add arg transient_key.
index 31e624d..cdaadaf 100644 (file)
@@ -26,7 +26,9 @@
 #include <stdarg.h>
 #include <errno.h>
 #include <ctype.h>
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
+# include <fcntl.h> /* We need setmode().  */
+#else
 # include <signal.h>
 #endif
 #include <assert.h>
index f02d7a3..1fe0202 100644 (file)
@@ -418,6 +418,92 @@ get_dsa_key_fips186_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   *skey = sec_key;
 }
 
+
+static void
+get_dsa_key_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
+{
+  gcry_sexp_t key_spec, key, pub_key, sec_key;
+  int rc;
+
+  rc = gcry_sexp_new 
+    (&key_spec, 
+     "(genkey (dsa (transient-key)(domain"
+     "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921"
+     "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7"
+     "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0"
+     "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)"
+     "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)"
+     "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab"
+     "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad"
+     "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e"
+     "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)"
+     ")))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gcry_strerror (rc));
+  rc = gcry_pk_genkey (&key, key_spec);
+  gcry_sexp_release (key_spec);
+  if (rc)
+    die ("error generating DSA key: %s\n", gcry_strerror (rc));
+    
+  if (verbose > 1)
+    show_sexp ("generated DSA key:\n", key);
+
+  pub_key = gcry_sexp_find_token (key, "public-key", 0);
+  if (!pub_key)
+    die ("public part missing in key\n");
+
+  sec_key = gcry_sexp_find_token (key, "private-key", 0);
+  if (!sec_key)
+    die ("private part missing in key\n");
+
+  gcry_sexp_release (key);
+  *pkey = pub_key;
+  *skey = sec_key;
+}
+
+static void
+get_dsa_key_fips186_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
+{
+  gcry_sexp_t key_spec, key, pub_key, sec_key;
+  int rc;
+
+  rc = gcry_sexp_new 
+    (&key_spec, 
+     "(genkey (dsa (transient-key)(use-fips186)(domain"
+     "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921"
+     "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7"
+     "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0"
+     "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)"
+     "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)"
+     "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab"
+     "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad"
+     "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e"
+     "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)"
+     ")))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gcry_strerror (rc));
+  rc = gcry_pk_genkey (&key, key_spec);
+  gcry_sexp_release (key_spec);
+  if (rc)
+    die ("error generating DSA key: %s\n", gcry_strerror (rc));
+    
+  if (verbose > 1)
+    show_sexp ("generated DSA key:\n", key);
+
+  pub_key = gcry_sexp_find_token (key, "public-key", 0);
+  if (!pub_key)
+    die ("public part missing in key\n");
+
+  sec_key = gcry_sexp_find_token (key, "private-key", 0);
+  if (!sec_key)
+    die ("private part missing in key\n");
+
+  gcry_sexp_release (key);
+  *pkey = pub_key;
+  *skey = sec_key;
+}
+
+
 static void
 check_run (void)
 {
@@ -492,6 +578,20 @@ check_run (void)
   /* Fixme:  Add a check function for DSA keys.  */
   gcry_sexp_release (pkey);
   gcry_sexp_release (skey);
+
+  if (verbose)
+    fprintf (stderr, "Generating DSA key with given domain.\n");
+  get_dsa_key_with_domain_new (&pkey, &skey);
+  /* Fixme:  Add a check function for DSA keys.  */
+  gcry_sexp_release (pkey);
+  gcry_sexp_release (skey);
+
+  if (verbose)
+    fprintf (stderr, "Generating DSA key with given domain (FIPS 186).\n");
+  get_dsa_key_fips186_with_domain_new (&pkey, &skey);
+  /* Fixme:  Add a check function for DSA keys.  */
+  gcry_sexp_release (pkey);
+  gcry_sexp_release (skey);
 }