Implement FIPS 186-2 key generation.
authorWerner Koch <wk@gnupg.org>
Tue, 25 Nov 2008 21:09:55 +0000 (21:09 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 25 Nov 2008 21:09:55 +0000 (21:09 +0000)
NEWS
cipher/ChangeLog
cipher/dsa.c
cipher/primegen.c
cipher/rsa.c
doc/gcrypt.texi
src/g10lib.h
tests/pubkey.c

diff --git a/NEWS b/NEWS
index 74ec8c7..37ea62b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@ Noteworthy changes in version 1.4.4
 
  * Fixed HMAC for SHA-384 and SHA-512 with keys longer than 64 bytes.
 
+ * In fips mode, RSA keys are now generated using the X9.31 algorithm
+   and DSA keys using the FIPS 186-2 algorithm.
+
 
 Noteworthy changes in version 1.4.3 (2008-09-18)
 ------------------------------------------------
index bfb20ae..db149c2 100644 (file)
@@ -1,3 +1,10 @@
+2008-11-25  Werner Koch  <wk@g10code.com>
+
+       * dsa.c (generate_fips186): New.
+       (dsa_generate_ext): Use new function if derive-parms are given or
+       if in FIPS mode.
+       * primegen.c (_gcry_generate_fips186_2_prime): New.
+
 2008-11-24  Werner Koch  <wk@g10code.com>
 
        * pubkey.c (gcry_pk_genkey): Insert code to output extrainfo.
index 639c1a9..cda4e52 100644 (file)
@@ -325,11 +325,11 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
   if( DBG_CIPHER ) 
     {
       progress('\n');
-      log_mpidump("dsa  p", p );
-      log_mpidump("dsa  q", q );
-      log_mpidump("dsa  g", g );
-      log_mpidump("dsa  y", y );
-      log_mpidump("dsa  x", x );
+      log_mpidump("dsa  p", p );
+      log_mpidump("dsa  q", q );
+      log_mpidump("dsa  g", g );
+      log_mpidump("dsa  y", y );
+      log_mpidump("dsa  x", x );
     }
 
   /* Copy the stuff to the key structures. */
@@ -354,6 +354,146 @@ 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.  At the time of implementation FIPS
+   186-3 was not released; the Draft from November 2008 was used
+   instead to avoid limiting ourself to FIPS 186-2.  */
+static gpg_err_code_t
+generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
+                  int *r_counter, void **r_seed, size_t *r_seedlen,
+                  gcry_mpi_t *r_h)
+{
+  gpg_err_code_t ec;
+  gcry_mpi_t prime_q = NULL; 
+  gcry_mpi_t prime_p = NULL; 
+  gcry_mpi_t value_g = NULL; /* The generator. */
+  gcry_mpi_t value_y = NULL; /* g^x mod p */
+  gcry_mpi_t value_x = NULL; /* The secret exponent. */
+  gcry_mpi_t value_h = NULL; /* Helper.  */
+  gcry_mpi_t value_e = NULL; /* Helper.  */
+
+  /* Preset return values.  */
+  *r_counter = 0;
+  *r_seed = NULL;
+  *r_seedlen = 0;
+  *r_h = NULL;
+
+  /* Derive QBITS from NBITS if requested  */
+  if (!qbits)
+    {
+      if (nbits == 1024)
+        qbits = 160;
+      else if (nbits == 2048)
+        qbits = 224;
+      else if (nbits == 3072)
+        qbits = 256;
+    }
+
+  /* Check that QBITS and NBITS match the standard.  Note that FIPS
+     186-3 uses N for QBITS and L for NBITS.  */
+  if (nbits == 1024 && qbits == 160)
+    ;
+  else if (nbits == 2048 && qbits == 224)
+    ;
+  else if (nbits == 2048 && qbits == 256)
+    ;
+  else if (nbits == 2048 && qbits == 256)
+    ;
+  else
+    return GPG_ERR_INV_VALUE;
+
+  /* Note that we currently do not yet support 186-3 for prime
+     generation becuase it is not clear whether CAVS is prepared for
+     it.  */
+  ec = _gcry_generate_fips186_2_prime (nbits, qbits, NULL, 0,
+                                       &prime_q, &prime_p, 
+                                       r_counter,
+                                       r_seed, r_seedlen);
+  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);
+  do 
+    {
+      if( DBG_CIPHER )
+        progress('.');
+      gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM);
+      mpi_clear_highbit (value_x, qbits+1);
+    } 
+  while (!(mpi_cmp_ui (value_x, 0) > 0 && mpi_cmp (value_x, prime_q) < 0));
+
+  /* y = g^x mod p */
+  value_y = mpi_alloc_like (prime_p);
+  gcry_mpi_powm (value_y, value_g, value_x, prime_p);
+
+  if (DBG_CIPHER) 
+    {
+      progress('\n');
+      log_mpidump("dsa  p", prime_p );
+      log_mpidump("dsa  q", prime_q );
+      log_mpidump("dsa  g", value_g );
+      log_mpidump("dsa  y", value_y );
+      log_mpidump("dsa  x", value_x );
+      log_mpidump("dsa  h", value_h );
+    }
+
+  /* Copy the stuff to the key structures. */
+  sk->p = prime_p; prime_p = NULL;
+  sk->q = prime_q; prime_q = NULL;
+  sk->g = value_g; value_g = NULL;
+  sk->y = value_y; value_y = NULL;
+  sk->x = value_x; value_x = NULL;
+  *r_h = value_h; value_h = NULL;
+
+ leave:
+  gcry_mpi_release (prime_p);
+  gcry_mpi_release (prime_q);
+  gcry_mpi_release (value_g);
+  gcry_mpi_release (value_y);
+  gcry_mpi_release (value_x);
+  gcry_mpi_release (value_h);
+  gcry_mpi_release (value_e);
+
+  /* As a last step test this keys (this should never fail of course). */
+  if (!ec && test_keys (sk, qbits) )
+    {
+      gcry_mpi_release (sk->p); sk->p = NULL;
+      gcry_mpi_release (sk->q); sk->q = NULL;
+      gcry_mpi_release (sk->g); sk->g = NULL;
+      gcry_mpi_release (sk->y); sk->y = NULL;
+      gcry_mpi_release (sk->x); sk->x = NULL;
+      fips_signal_error ("self-test after key generation failed");
+      ec = GPG_ERR_SELFTEST_FAILED;
+    }
+
+  if (ec)
+    {
+      *r_counter = 0;
+      gcry_free (*r_seed); *r_seed = NULL;
+      *r_seedlen = 0;
+      gcry_mpi_release (*r_h); *r_h = NULL;
+    }
+
+  return ec;
+}
+
+
 
 /*
    Test whether the secret key is valid.
@@ -468,13 +608,17 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
   DSA_secret_key sk;
   gcry_sexp_t l1;
   unsigned int qbits = 0;
+  gcry_sexp_t deriveparms = NULL;
+  gcry_sexp_t seedinfo = NULL;
+  int use_fips186 = 0;
+  
 
   (void)algo;    /* No need to check it.  */
   (void)evalue;  /* Not required for DSA. */
 
-  /* Parse the optional qbits element. */
   if (genparms)
     {
+      /* Parse the optional qbits element.  */
       l1 = gcry_sexp_find_token (genparms, "qbits", 0);
       if (l1)
         {
@@ -493,9 +637,50 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
           qbits = (unsigned int)strtoul (buf, NULL, 0);
           gcry_sexp_release (l1);
         }
+
+      deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0);
+
+      /* Parse the optional "use-fips186" flag.  */
+      l1 = gcry_sexp_find_token (genparms, "use-fips186", 0);
+      if (l1)
+        {
+          use_fips186 = 1;
+          gcry_sexp_release (l1);
+        }
     }
 
-  ec = generate (&sk, nbits, qbits, retfactors);
+  if (deriveparms || use_fips186 || fips_mode ())
+    {
+      int counter;
+      void *seed;
+      size_t seedlen;
+      gcry_mpi_t h_value;
+
+      ec = generate_fips186 (&sk, nbits, qbits, 
+                             &counter, &seed, &seedlen, &h_value);
+      gcry_sexp_release (deriveparms);
+      if (!ec)
+        {
+          ec = gpg_err_code (gcry_sexp_build 
+                             (&seedinfo, NULL,
+                              "(seed-values(counter %d)(seed %b)(h %m))",
+                              counter, (int)seedlen, seed, h_value));
+          if (ec)
+            {
+              gcry_mpi_release (sk.p); sk.p = NULL;
+              gcry_mpi_release (sk.q); sk.q = NULL;
+              gcry_mpi_release (sk.g); sk.g = NULL;
+              gcry_mpi_release (sk.y); sk.y = NULL;
+              gcry_mpi_release (sk.x); sk.x = NULL;
+            }
+          gcry_free (seed);
+          gcry_mpi_release (h_value);
+        }
+    }
+  else
+    {
+      ec = generate (&sk, nbits, qbits, retfactors);
+    }
   if (!ec)
     {
       skey[0] = sk.p;
@@ -509,9 +694,9 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
           /* Old style interface - return the factors - if any - at
              retfactors.  */
         }
-      else if (r_extrainfo && !*retfactors)
+      else if (!*retfactors && !seedinfo)
         {
-          /* No factors, thus there is nothing to return.  */
+          /* No factors and no seedinfo, thus there is nothing to return.  */
           *r_extrainfo = NULL;
         }
       else
@@ -520,36 +705,46 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
              to make use of the new interface.  Note that the factors
              are not confidential thus we can store them in standard
              memory.  */
-          int nfactors, i;
+          int nfactors, i, j;
           char *p;
           char *format = NULL;
           void **arg_list = NULL;
 
-          for (nfactors=0; (*retfactors)[nfactors]; nfactors++)
+          for (nfactors=0; *retfactors && (*retfactors)[nfactors]; nfactors++)
             ;
           /* Allocate space for the format string:
-               "(misc-key-info(pm1-factors%m))"
-             with one "%m" for each factor and build the string  */
-          format = gcry_malloc (40 + 2*nfactors);
+               "(misc-key-info%S(pm1-factors%m))"
+             with one "%m" for each factor and construct it.  */
+          format = gcry_malloc (50 + 2*nfactors);
           if (!format)
             ec = gpg_err_code_from_syserror ();
           else
             {
-              p = stpcpy (format, "(misc-key-info(pm1-factors");
-              for (i=0; i < nfactors; i++)
-                p = stpcpy (p, "%m");
-              p = stpcpy (p, "))");
+              p = stpcpy (format, "(misc-key-info");
+              if (seedinfo)
+                p = stpcpy (p, "%S");
+              if (nfactors)
+                {
+                  p = stpcpy (p, "(pm1-factors");
+                  for (i=0; i < nfactors; i++)
+                    p = stpcpy (p, "%m");
+                  p = stpcpy (p, ")");
+                }
+              p = stpcpy (p, ")");
               
-              /* Allocate space for the argument list plus an extra
-                 NULL entry for safety and fill it with the
-                 factors.  */
-              arg_list = gcry_calloc (nfactors+1, sizeof *arg_list);
+              /* Allocate space for the list of factors plus one for
+                 an S-expression plus an extra NULL entry for safety
+                 and fill it with the factors.  */
+              arg_list = gcry_calloc (nfactors+1+1, sizeof *arg_list);
               if (!arg_list)
                 ec = gpg_err_code_from_syserror ();
               else
                 {
-                  for (i=0; i < nfactors; i++)
-                    arg_list[i] = (*retfactors) + i;
+                  i = 0;
+                  if (seedinfo)
+                    arg_list[i++] = &seedinfo;
+                  for (j=0; j < nfactors; j++)
+                    arg_list[i++] = (*retfactors) + j;
                   arg_list[i] = NULL;
                   
                   ec = gpg_err_code (gcry_sexp_build_array 
@@ -576,6 +771,7 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
         }
     }
 
+  gcry_sexp_release (seedinfo);
   return ec;
 }
 
index d523a89..c8dbdab 100644 (file)
@@ -1274,7 +1274,8 @@ gcry_prime_release_factors (gcry_mpi_t *factors)
 }
 
 
-/* Helper for _gcry_generate_x931_prime.  */
+\f
+/* Helper for _gcry_derive_x931_prime.  */
 static gcry_mpi_t
 find_x931_prime (const gcry_mpi_t pfirst)
 {
@@ -1411,3 +1412,207 @@ _gcry_derive_x931_prime (const gcry_mpi_t xp,
     mpi_free (p2);
   return yp0;
 }
+
+
+\f
+/* Generate the two prime used for DSA using the algorithm specified
+   in FIPS 186-2.  PBITS is the desired length of the prime P and a
+   QBIST the length of the prime Q.  If SEED is not supplied and
+   SEEDLEN is 0 the function generates an appropriate SEED.  On
+   success the generated primes are stored at R_Q and R_P, the counter
+   value is stored at R_COUNTER and the seed actually used for
+   generation is stored at R_SEED and R_SEEDVALUE.  */
+gpg_err_code_t
+_gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits,
+                                const void *seed, size_t seedlen,
+                                gcry_mpi_t *r_q, gcry_mpi_t *r_p,
+                                int *r_counter,
+                                void **r_seed, size_t *r_seedlen)
+{
+  gpg_err_code_t ec;
+  unsigned char seed_help_buffer[160/8];  /* Used to hold a generated SEED. */
+  unsigned char *seed_plus;     /* Malloced buffer to hold SEED+x.  */
+  unsigned char digest[160/8];  /* Helper buffer for SHA-1 digest.  */
+  gcry_mpi_t val_2 = NULL;      /* Helper for the prime test.  */
+  gcry_mpi_t tmpval = NULL;     /* Helper variable.  */
+  int i;
+
+  unsigned char value_u[160/8];
+  int value_n, value_b, value_k;
+  int counter;
+  gcry_mpi_t value_w = NULL;
+  gcry_mpi_t value_x = NULL;
+  gcry_mpi_t prime_q = NULL;
+  gcry_mpi_t prime_p = NULL;
+
+  /* FIPS 186-2 allows only for 1024/160 bit.  */
+  if (pbits != 1024 || qbits != 160)
+    return GPG_ERR_INV_KEYLEN;
+
+  if (!seed && !seedlen)
+    ; /* No seed value given:  We are asked to generate it.  */
+  else if (!seed || seedlen < qbits/8)
+    return GPG_ERR_INV_ARG;
+  
+  /* Allocate a buffer to later compute SEED+some_increment. */
+  seed_plus = gcry_malloc (seedlen < 20? 20:seedlen);
+  if (!seed_plus)
+    {
+      ec = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+
+  val_2   = mpi_alloc_set_ui (2);
+  value_n = (pbits - 1) / qbits;
+  value_b = (pbits - 1) - value_n * qbits;
+  value_w = gcry_mpi_new (pbits);
+  value_x = gcry_mpi_new (pbits);
+
+ restart:  
+  /* Generate Q.  */
+  for (;;)
+    {
+      /* Step 1: Generate a (new) seed unless one has been supplied.  */
+      if (!seed)
+        {
+          seedlen = sizeof seed_help_buffer;
+          gcry_create_nonce (seed_help_buffer, seedlen);
+          seed = seed_help_buffer;
+        }
+      
+      /* Step 2: U = sha1(seed) ^ sha1((seed+1) mod 2^{qbits})  */
+      memcpy (seed_plus, seed, seedlen);
+      for (i=seedlen-1; i >= 0; i--)
+        {
+          seed_plus[i]++;
+          if (seed_plus[i])
+            break;
+        }
+      gcry_md_hash_buffer (GCRY_MD_SHA1, value_u, seed, seedlen);
+      gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen);
+      for (i=0; i < sizeof value_u; i++)
+        value_u[i] ^= digest[i];
+  
+      /* Step 3:  Form q from U  */
+      gcry_mpi_release (prime_q); prime_q = NULL;
+      ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, 
+                                        value_u, sizeof value_u, NULL));
+      if (ec)
+        goto leave;
+      mpi_set_highbit (prime_q, qbits-1 );
+      mpi_set_bit (prime_q, 0);
+      
+      /* Step 4:  Test whether Q is prime using 64 round of Rabin-Miller.  */
+      if (check_prime (prime_q, val_2, 64, NULL, NULL))
+        break; /* Yes, Q is prime.  */
+
+      /* Step 5.  */
+      seed = NULL;  /* Force a new seed at Step 1.  */
+    }
+  
+  /* Step 6.  Note that we do no use an explicit offset but increment
+     SEED_PLUS accordingly.  SEED_PLUS is currently SEED+1.  */
+  counter = 0;
+
+  /* Generate P. */
+  prime_p = gcry_mpi_new (pbits);
+  for (;;)
+    {
+      /* Step 7: For k = 0,...n let 
+                   V_k = sha1(seed+offset+k) mod 2^{qbits}  
+         Step 8: W = V_0 + V_1*2^160 + 
+                         ... 
+                         + V_{n-1}*2^{(n-1)*160}
+                         + (V_{n} mod 2^b)*2^{n*160}                
+       */
+      mpi_set_ui (value_w, 0);
+      for (value_k=0; value_k <= value_n; value_k++)
+        {
+          /* There is no need to have an explicit offset variable:  In
+             the first round we shall have an offset of 2, this is
+             achieved by using SEED_PLUS which is already at SEED+1,
+             thus we just need to increment it once again.  The
+             requirement for the next round is to update offset by N,
+             which we implictly did at the end of this loop, and then
+             to add one; this one is the same as in the first round.  */
+          for (i=seedlen-1; i >= 0; i--)
+            {
+              seed_plus[i]++;
+              if (seed_plus[i])
+                break;
+            }
+          gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen);
+          
+          gcry_mpi_release (tmpval); tmpval = NULL;
+          ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG,
+                                            digest, sizeof digest, NULL));
+          if (ec)
+            goto leave;
+          if (value_k == value_n)
+            mpi_clear_highbit (tmpval, value_b+1); /* (V_n mod 2^b) */
+          mpi_lshift (tmpval, tmpval, value_k*qbits);
+          mpi_add (value_w, value_w, tmpval);
+        }
+
+      /* Step 8 continued: X = W + 2^{L-1}  */
+      mpi_set_ui (value_x, 0);
+      mpi_set_highbit (value_x, pbits-1);
+      mpi_add (value_x, value_x, value_w);
+
+      /* Step 9:  c = X mod 2q,  p = X - (c - 1)  */
+      mpi_mul_2exp (tmpval, prime_q, 1);
+      mpi_mod (tmpval, value_x, tmpval);
+      mpi_sub_ui (tmpval, tmpval, 1);
+      mpi_sub (prime_p, value_x, tmpval);
+
+      /* Step 10: If  p < 2^{L-1}  skip the primality test.  */
+      /* Step 11 and 12: Primality test.  */
+      if (mpi_get_nbits (prime_p) >= pbits-1
+          && check_prime (prime_p, val_2, 64, NULL, NULL) )
+        break; /* Yes, P is prime, continue with Step 15.  */
+      
+      /* Step 13: counter = counter + 1, offset = offset + n + 1. */
+      counter++;
+
+      /* Step 14: If counter >= 2^12  goto Step 1.  */
+      if (counter >= 4096)
+        goto restart;
+    }
+
+  /* Step 15:  Save p, q, counter and seed.  */
+/*   log_debug ("fips186-2 nbits p=%u q=%u counter=%d\n", */
+/*              mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */
+/*   log_printhex("fips186-2 seed:", seed, seedlen);  */
+/*   log_mpidump ("fips186-2 prime p", prime_p); */
+/*   log_mpidump ("fips186-2 prime q", prime_q); */
+  if (r_q)
+    {
+      *r_q = prime_q;
+      prime_q = NULL;
+    }
+  if (r_p)
+    {
+      *r_p = prime_p;
+      prime_p = NULL;
+    }
+  if (r_counter)
+    *r_counter = counter;
+  if (r_seed && r_seedlen)
+    {
+      memcpy (seed_plus, seed, seedlen);
+      *r_seed = seed_plus;
+      seed_plus = NULL;
+      *r_seedlen = seedlen;
+    }
+
+
+ leave:
+  gcry_mpi_release (tmpval);
+  gcry_mpi_release (value_x);
+  gcry_mpi_release (value_w);
+  gcry_mpi_release (prime_p);
+  gcry_mpi_release (prime_q);
+  gcry_free (seed_plus);
+  gcry_mpi_release (val_2);
+  return ec;
+}
index 967b693..cf278c2 100644 (file)
@@ -793,7 +793,7 @@ rsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
                  gcry_sexp_find_token (genparms, "derive-parms", 0) : NULL);
   if (!deriveparms)
     {
-      /* Parse the optional "rsa-use-x931" flag. */
+      /* Parse the optional "use-x931" flag. */
       l1 = gcry_sexp_find_token (genparms, "use-x931", 0);
       if (l1)
         {
index 04f174c..f6ae050 100644 (file)
@@ -2755,8 +2755,16 @@ FIPS mode.
 @item use-x931
 Force the use of the ANSI X9.31 key generation algorithm instead of
 the default algorithm. This flag is only meaningful for RSA and
-usullat not required.  Note that this algorithm is implicitly used if
-either @code{derive-parms} are given or Libgcrypt is in FIPS mode.
+usually not required.  Note that this algorithm is implicitly used if
+either @code{derive-parms} is given or Libgcrypt is in FIPS mode.
+
+@item use-fips186
+Force the use of the FIPS 186-2 key generation algorithm instead of
+the default algorithm.  This flag is only meaningful for DSA and
+usually not required.  Note that this algorithm is implicitly used if
+either @code{derive-parms} is given or Libgcrypt is in FIPS mode.
+This implementation may be changed in future to use the forthcoming
+FIPS 186-3 algorithm.
 
 
 @end table
index f7ea781..9faa26d 100644 (file)
@@ -179,6 +179,12 @@ gcry_mpi_t _gcry_derive_x931_prime (const gcry_mpi_t xp,
                                     const gcry_mpi_t xp1, const gcry_mpi_t xp2,
                                     const gcry_mpi_t e,
                                     gcry_mpi_t *r_p1, gcry_mpi_t *r_p2);
+gpg_err_code_t _gcry_generate_fips186_2_prime
+                 (unsigned int pbits, unsigned int qbits,
+                  const void *seed, size_t seedlen,
+                  gcry_mpi_t *r_q, gcry_mpi_t *r_p,
+                  int *r_counter,
+                  void **r_seed, size_t *r_seedlen);
 
 
 /* replacements of missing functions (missing-string.c)*/
index 6c6d1c6..0e6efd9 100644 (file)
@@ -364,7 +364,7 @@ get_dsa_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   rc = gcry_pk_genkey (&key, key_spec);
   gcry_sexp_release (key_spec);
   if (rc)
-    die ("error generating Elgamal key: %s\n", gcry_strerror (rc));
+    die ("error generating DSA key: %s\n", gcry_strerror (rc));
     
   if (verbose > 1)
     show_sexp ("generated DSA key:\n", key);
@@ -384,6 +384,37 @@ get_dsa_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
 
 
 static void
+get_dsa_key_fips186_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 (nbits 4:1024)(use-fips186)))",  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 (fips 186):\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)
 {
   gpg_error_t err;
@@ -440,6 +471,13 @@ 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 (FIPS 186).\n");
+  get_dsa_key_fips186_new (&pkey, &skey);
+  /* Fixme:  Add a check function for DSA keys.  */
+  gcry_sexp_release (pkey);
+  gcry_sexp_release (skey);
 }
 
 
@@ -684,7 +722,7 @@ main (int argc, char **argv)
   for (i=0; i < 2; i++)
     check_run ();
 
-  for (i=0; i < 4; i++) 
+  for (i=0; i < 4; i++)
     check_x931_derived_key (i);
   
   return 0;