Cleaned up the public key module calling conventions.
authorWerner Koch <wk@gnupg.org>
Mon, 24 Nov 2008 16:37:50 +0000 (16:37 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 24 Nov 2008 16:37:50 +0000 (16:37 +0000)
Add a way to derive RSA keys according to X9.31.

16 files changed:
cipher/ChangeLog
cipher/dsa.c
cipher/ecc.c
cipher/elgamal.c
cipher/primegen.c
cipher/pubkey.c
cipher/rsa.c
doc/gcrypt.texi
src/ChangeLog
src/cipher-proto.h
src/cipher.h
src/g10lib.h
tests/ChangeLog
tests/cavs_driver.pl
tests/fipsdrv.c
tests/pubkey.c

index 91422ed..b93ac02 100644 (file)
@@ -1,3 +1,38 @@
+2008-11-24  Werner Koch  <wk@g10code.com>
+
+       * pubkey.c (gcry_pk_genkey): Remove parsing of almost all
+       parameters and pass the parameter S-expression to pubkey_generate.
+       (pubkey_generate): Simplify by requitring modules to parse the
+       parameters. Remove the special cases for Elgamal and ECC.
+       (sexp_elements_extract_ecc): Add arg EXTRASPEC and use it.  Fix
+       small memory leak.
+       (sexp_to_key): Pass EXTRASPEC to sexp_elements_extract_ecc.
+       (pubkey_table) [USE_ELGAMAL]: Add real extraspec.
+       * rsa.c (rsa_generate_ext): Adjust for new calling convention.
+       * dsa.c (dsa_generate_ext): Ditto.
+       * elgamal.c (_gcry_elg_generate): Ditto. Rename to elg_generate_ext.
+       (elg_generate): New.
+       (_gcry_elg_generate_using_x): Remove after merging code with
+       elg_generate_ext.
+       (_gcry_pubkey_extraspec_elg): New.
+       (_gcry_elg_check_secret_key, _gcry_elg_encrypt, _gcry_elg_sign) 
+       (_gcry_elg_verify, _gcry_elg_get_nbits): Make static and remove
+       _gcry_ prefix.
+       * ecc.c (_gcry_ecc_generate): Rename to ecc_generate_ext and
+       adjust for new calling convention.
+       (_gcry_ecc_get_param): Rename to ecc_get_param and make static.
+       (_gcry_pubkey_extraspec_ecdsa): Add ecc_generate_ext and
+       ecc_get_param.
+       
+2008-11-20  Werner Koch  <wk@g10code.com>
+
+       * pubkey.c (pubkey_generate): Add arg DERIVEPARMS.
+       (gcry_pk_genkey): Parse derive-parms and pass it to above.
+       * rsa.c (generate_x931): New.
+       (rsa_generate_ext): Add arg DERIVEPARMS and call new function in
+       fips mode or if DERIVEPARMS is given.
+       * primegen.c (_gcry_derive_x931_prime, find_x931_prime): New.
+
 2008-11-19  Werner Koch  <wk@g10code.com>
 
        * rsa.c (rsa_decrypt): Use gcry_create_nonce for blinding.
index fe210fa..fb5654e 100644 (file)
@@ -459,20 +459,40 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey )
  *********************************************/
 
 static gcry_err_code_t
-dsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits, 
-                  unsigned long use_e,
-                  const char *name, const gcry_sexp_t domain,
-                  unsigned int keygen_flags,
+dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
+                  const gcry_sexp_t genparms,
                   gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
   gpg_err_code_t ec;
   DSA_secret_key sk;
+  gcry_sexp_t l1;
+  unsigned int qbits = 0;
 
-  (void)algo;
-  (void)use_e;
-  (void)name;
-  (void)domain;
-  (void)keygen_flags;
+  (void)algo;    /* No need to check it.  */
+  (void)evalue;  /* Not required for DSA. */
+
+  /* Parse the optional qbits element. */
+  if (genparms)
+    {
+      l1 = gcry_sexp_find_token (genparms, "qbits", 0);
+      if (l1)
+        {
+          char buf[50];
+          const char *s;
+          size_t n;
+          
+          s = gcry_sexp_nth_data (l1, 1, &n);
+          if (!s || n >= DIM (buf) - 1 )
+            {
+              gcry_sexp_release (l1);
+              return GPG_ERR_INV_OBJ; /* No value or value too large.  */
+            }
+          memcpy (buf, s, n);
+          buf[n] = 0;
+          qbits = (unsigned int)strtoul (buf, NULL, 0);
+          gcry_sexp_release (l1);
+        }
+    }
 
   ec = generate (&sk, nbits, qbits, retfactors);
   if (!ec)
@@ -489,11 +509,11 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits,
 
 
 static gcry_err_code_t
-dsa_generate (int algo, unsigned int nbits, unsigned long dummy,
+dsa_generate (int algo, unsigned int nbits, unsigned long evalue,
               gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
-  (void)dummy;
-  return dsa_generate_ext (algo, nbits, 0, 0, NULL, NULL, 0, skey, retfactors);
+  (void)evalue;
+  return dsa_generate_ext (algo, nbits, 0, NULL, skey, retfactors);
 }
 
 
index c90391f..5df22b0 100644 (file)
@@ -949,35 +949,47 @@ os2ec (mpi_point_t *result, gcry_mpi_t value)
   return 0;
 }
 
-/* Extended version of ecc_generate which is called directly by
-   pubkey.c.  If CURVE is not NULL, that name will be used to select
-   the domain parameters.  NBITS is not used in this case.  */
-gcry_err_code_t
-_gcry_ecc_generate (int algo, unsigned int nbits, const char *curve,
-                    gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+
+/* Extended version of ecc_generate.  */
+static gcry_err_code_t
+ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
+                  const gcry_sexp_t genparms,
+                  gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
-  gpg_err_code_t err;
+  gpg_err_code_t ec;
   ECC_secret_key sk;
   gcry_mpi_t g_x, g_y, q_x, q_y;
+  char *curve_name = NULL;
+  gcry_sexp_t l1;
 
   (void)algo;
+  (void)evalue;
 
-  /* Make an empty list of factors.  */
-  *retfactors = gcry_calloc ( 1, sizeof **retfactors );
-  if (!*retfactors)
-    return gpg_err_code_from_syserror ();
+  if (genparms)
+    {
+      /* Parse the optional "curve" parameter. */
+      l1 = gcry_sexp_find_token (genparms, "curve", 0);
+      if (l1)
+        {
+          curve_name = _gcry_sexp_nth_string (l1, 1);
+          gcry_sexp_release (l1);
+          if (!curve_name)
+            return GPG_ERR_INV_OBJ; /* No curve name or value too large. */
+        }
+    }
+
+  /* NBITS is required if no curve name has been given.  */
+  if (!nbits && !curve_name)
+    return GPG_ERR_NO_OBJ; /* No NBITS parameter. */
 
   g_x = mpi_new (0);
   g_y = mpi_new (0);
   q_x = mpi_new (0);
   q_y = mpi_new (0);
-  err = generate_key (&sk, nbits, curve, g_x, g_y, q_x, q_y);
-  if (err)
-    {
-      gcry_free (*retfactors);
-      *retfactors = NULL;
-      return err;
-    }
+  ec = generate_key (&sk, nbits, curve_name, g_x, g_y, q_x, q_y);
+  gcry_free (curve_name);
+  if (ec)
+    return ec;
 
   skey[0] = sk.E.p;
   skey[1] = sk.E.a;
@@ -992,12 +1004,27 @@ _gcry_ecc_generate (int algo, unsigned int nbits, const char *curve,
   point_free (&sk.E.G);
   point_free (&sk.Q);
 
+  /* Make an empty list of factors.  */
+  *retfactors = gcry_calloc ( 1, sizeof **retfactors );
+  if (!*retfactors)
+    return gpg_err_code_from_syserror ();
+
   return 0;
 }
 
+
+static gcry_err_code_t
+ecc_generate (int algo, unsigned int nbits, unsigned long evalue,
+              gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+{
+  (void)evalue;
+  return ecc_generate_ext (algo, nbits, 0, NULL, skey, retfactors);
+}
+
+
 /* Return the parameters of the curve NAME.  */
-gcry_err_code_t
-_gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey)
+static gcry_err_code_t
+ecc_get_param (const char *name, gcry_mpi_t *pkey)
 {
   gpg_err_code_t err;
   unsigned int nbits;
@@ -1027,14 +1054,6 @@ _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey)
   return 0;
 }
 
-static gcry_err_code_t
-ecc_generate (int algo, unsigned int nbits, unsigned long dummy,
-              gcry_mpi_t *skey, gcry_mpi_t **retfactors)
-{
-  (void)dummy;
-  return _gcry_ecc_generate (algo, nbits, NULL, skey, retfactors);
-}
-
 
 static gcry_err_code_t
 ecc_check_secret_key (int algo, gcry_mpi_t *skey)
@@ -1230,7 +1249,7 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
           ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
           goto leave;
         }
-      ec = _gcry_ecc_get_param (curve, tmpvalues);
+      ec = ecc_get_param (curve, tmpvalues);
       gcry_free (curve);
       if (ec)
         goto leave;
@@ -1358,10 +1377,12 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecdsa =
     ecc_verify,
     ecc_get_nbits
   };
+
 pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa = 
   {
     run_selftests,
-    NULL,
-    compute_keygrip
+    ecc_generate_ext,
+    compute_keygrip,
+    ecc_get_param
   };
 
index 04ad6fa..a3eaf2a 100644 (file)
@@ -1,10 +1,11 @@
 /* Elgamal.c  -  Elgamal Public Key encryption
- * Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000, 2001, 2002, 2003,
+ *               2008  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
  * Libgcrypt is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser general Public License as
+ * it under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
@@ -14,8 +15,7 @@
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * For a description of the algorithm, see:
  *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
@@ -612,50 +612,70 @@ verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey )
  **************  interface  ******************
  *********************************************/
 
-gcry_err_code_t
-_gcry_elg_generate (int algo, unsigned int nbits, unsigned long dummy,
-                    gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+static gpg_err_code_t
+elg_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
+                  const gcry_sexp_t genparms,
+                  gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
+  gpg_err_code_t ec;
   ELG_secret_key sk;
+  gcry_mpi_t xvalue = NULL;
+  gcry_sexp_t l1;
 
   (void)algo;
-  (void)dummy;
+  (void)evalue;
+
+  if (genparms)
+    {
+      /* Parse the optional xvalue element. */
+      l1 = gcry_sexp_find_token (genparms, "xvalue", 0);
+      if (l1)
+        {
+          xvalue = gcry_sexp_nth_mpi (l1, 1, 0);
+          gcry_sexp_release (l1);
+          if (!xvalue)
+            return GPG_ERR_BAD_MPI;
+        }
+    }
+
+  if (xvalue)
+    ec = generate_using_x (&sk, nbits, xvalue, retfactors);
+  else
+    {
+      generate (&sk, nbits, retfactors);
+      ec = 0;
+    }
 
-  generate (&sk, nbits, retfactors);
   skey[0] = sk.p;
   skey[1] = sk.g;
   skey[2] = sk.y;
   skey[3] = sk.x;
   
-  return GPG_ERR_NO_ERROR;
+  return ec;
 }
 
 
-/* This is a specila generate function which is not called via the
-   module interface.  */
-gcry_err_code_t
-_gcry_elg_generate_using_x (int algo, unsigned int nbits, gcry_mpi_t x,
-                            gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+static gcry_err_code_t
+elg_generate (int algo, unsigned int nbits, unsigned long evalue,
+              gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
-  gcry_err_code_t ec;
   ELG_secret_key sk;
 
   (void)algo;
+  (void)evalue;
 
-  ec = generate_using_x (&sk, nbits, x, retfactors);
-  if (!ec)
-    {
-      skey[0] = sk.p;
-      skey[1] = sk.g;
-      skey[2] = sk.y;
-      skey[3] = sk.x;
-    }
-  return ec;
+  generate (&sk, nbits, retfactors);
+  skey[0] = sk.p;
+  skey[1] = sk.g;
+  skey[2] = sk.y;
+  skey[3] = sk.x;
+  
+  return GPG_ERR_NO_ERROR;
 }
 
 
-gcry_err_code_t
-_gcry_elg_check_secret_key (int algo, gcry_mpi_t *skey)
+static gcry_err_code_t
+elg_check_secret_key (int algo, gcry_mpi_t *skey)
 {
   gcry_err_code_t err = GPG_ERR_NO_ERROR;
   ELG_secret_key sk;
@@ -679,9 +699,9 @@ _gcry_elg_check_secret_key (int algo, gcry_mpi_t *skey)
 }
 
 
-gcry_err_code_t
-_gcry_elg_encrypt (int algo, gcry_mpi_t *resarr,
-                   gcry_mpi_t data, gcry_mpi_t *pkey, int flags)
+static gcry_err_code_t
+elg_encrypt (int algo, gcry_mpi_t *resarr,
+             gcry_mpi_t data, gcry_mpi_t *pkey, int flags)
 {
   gcry_err_code_t err = GPG_ERR_NO_ERROR;
   ELG_public_key pk;
@@ -704,9 +724,9 @@ _gcry_elg_encrypt (int algo, gcry_mpi_t *resarr,
 }
 
 
-gcry_err_code_t
-_gcry_elg_decrypt (int algo, gcry_mpi_t *result,
-                   gcry_mpi_t *data, gcry_mpi_t *skey, int flags)
+static gcry_err_code_t
+elg_decrypt (int algo, gcry_mpi_t *result,
+             gcry_mpi_t *data, gcry_mpi_t *skey, int flags)
 {
   gcry_err_code_t err = GPG_ERR_NO_ERROR;
   ELG_secret_key sk;
@@ -730,8 +750,8 @@ _gcry_elg_decrypt (int algo, gcry_mpi_t *result,
 }
 
 
-gcry_err_code_t
-_gcry_elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
+static gcry_err_code_t
+elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
 {
   gcry_err_code_t err = GPG_ERR_NO_ERROR;
   ELG_secret_key sk;
@@ -755,9 +775,10 @@ _gcry_elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
   return err;
 }
 
-gcry_err_code_t
-_gcry_elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
-                 int (*cmp) (void *, gcry_mpi_t), void *opaquev)
+
+static gcry_err_code_t
+elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
+            int (*cmp) (void *, gcry_mpi_t), void *opaquev)
 {
   gcry_err_code_t err = GPG_ERR_NO_ERROR;
   ELG_public_key pk;
@@ -782,14 +803,15 @@ _gcry_elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
 }
 
 
-unsigned int
-_gcry_elg_get_nbits (int algo, gcry_mpi_t *pkey)
+static unsigned int
+elg_get_nbits (int algo, gcry_mpi_t *pkey)
 {
   (void)algo;
 
   return mpi_get_nbits (pkey[0]);
 }
 
+
 static const char *elg_names[] =
   {
     "elg",
@@ -804,11 +826,19 @@ gcry_pk_spec_t _gcry_pubkey_spec_elg =
     "ELG", elg_names,
     "pgy", "pgyx", "ab", "rs", "pgy",
     GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR,
-    _gcry_elg_generate,
-    _gcry_elg_check_secret_key,
-    _gcry_elg_encrypt,
-    _gcry_elg_decrypt,
-    _gcry_elg_sign,
-    _gcry_elg_verify,
-    _gcry_elg_get_nbits,
+    elg_generate,
+    elg_check_secret_key,
+    elg_encrypt,
+    elg_decrypt,
+    elg_sign,
+    elg_verify,
+    elg_get_nbits
   };
+
+pk_extra_spec_t _gcry_pubkey_extraspec_elg = 
+  {
+    NULL,
+    elg_generate_ext,
+    NULL
+  };
+
index 9434868..d523a89 100644 (file)
@@ -1,6 +1,6 @@
 /* primegen.c - prime number generator
  * Copyright (C) 1998, 2000, 2001, 2002, 2003
- *               2004 Free Software Foundation, Inc.
+ *               2004, 2008 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -1272,3 +1272,142 @@ gcry_prime_release_factors (gcry_mpi_t *factors)
       gcry_free (factors);
     }
 }
+
+
+/* Helper for _gcry_generate_x931_prime.  */
+static gcry_mpi_t
+find_x931_prime (const gcry_mpi_t pfirst)
+{
+  gcry_mpi_t val_2 = mpi_alloc_set_ui (2); 
+  gcry_mpi_t prime;
+  
+  prime = gcry_mpi_copy (pfirst);
+  /* If P is even add 1.  */ 
+  mpi_set_bit (prime, 0);
+
+  /* We use 64 Rabin-Miller rounds which is better and thus
+     sufficient.  We do not have a Lucas test implementaion thus we
+     can't do it in the X9.31 preferred way of running a few
+     Rabin-Miller followed by one Lucas test.  */
+  while ( !check_prime (prime, val_2, 64, NULL, NULL) )
+    mpi_add_ui (prime, prime, 2);
+
+  mpi_free (val_2);
+
+  return prime;
+}
+
+
+/* Generate a prime using the algorithm from X9.31 appendix B.4. 
+
+   This function requires that the provided public exponent E is odd.
+   XP, XP1 and XP2 are the seed values.  All values are mandatory.
+
+   On success the prime is returned.  If R_P1 or R_P2 are given the
+   internal values P1 and P2 are saved at these addresses.  On error
+   NULL is returned.  */
+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)
+{
+  gcry_mpi_t p1, p2, p1p2, yp0;
+
+  if (!xp || !xp1 || !xp2)
+    return NULL;
+  if (!e || !mpi_test_bit (e, 0))
+    return NULL;  /* We support only odd values for E.  */
+
+  p1 = find_x931_prime (xp1);
+  p2 = find_x931_prime (xp2);
+  p1p2 = mpi_alloc_like (xp);
+  mpi_mul (p1p2, p1, p2);
+
+  {
+    gcry_mpi_t r1, tmp;
+  
+    /* r1 = (p2^{-1} mod p1)p2 - (p1^{-1} mod p2) */
+    tmp = mpi_alloc_like (p1);
+    mpi_invm (tmp, p2, p1);
+    mpi_mul (tmp, tmp, p2);
+    r1 = tmp;
+    
+    tmp = mpi_alloc_like (p2);
+    mpi_invm (tmp, p1, p2);
+    mpi_mul (tmp, tmp, p1);
+    mpi_sub (r1, r1, tmp);
+
+    /* Fixup a negative value.  */
+    if (mpi_is_neg (r1)) 
+      mpi_add (r1, r1, p1p2);
+
+    /* yp0 = xp + (r1 - xp mod p1*p2)  */
+    yp0 = tmp; tmp = NULL;
+    mpi_subm (yp0, r1, xp, p1p2);
+    mpi_add (yp0, yp0, xp);
+    mpi_free (r1);
+
+    /* Fixup a negative value.  */
+    if (mpi_cmp (yp0, xp) < 0 ) 
+      mpi_add (yp0, yp0, p1p2);
+  }
+
+  /* yp0 is now the first integer greater than xp with p1 being a
+     large prime factor of yp0-1 and p2 a large prime factor of yp0+1.  */
+
+  /* Note that the first example from X9.31 (D.1.1) which uses
+       (Xq1 #1A5CF72EE770DE50CB09ACCEA9#)
+       (Xq2 #134E4CAA16D2350A21D775C404#)
+       (Xq  #CC1092495D867E64065DEE3E7955F2EBC7D47A2D
+             7C9953388F97DDDC3E1CA19C35CA659EDC2FC325
+             6D29C2627479C086A699A49C4C9CEE7EF7BD1B34
+             321DE34A#))))
+     returns an yp0 of
+            #CC1092495D867E64065DEE3E7955F2EBC7D47A2D
+             7C9953388F97DDDC3E1CA19C35CA659EDC2FC4E3
+             BF20CB896EE37E098A906313271422162CB6C642
+             75C1201F#
+     and not
+            #CC1092495D867E64065DEE3E7955F2EBC7D47A2D
+             7C9953388F97DDDC3E1CA19C35CA659EDC2FC2E6
+             C88FE299D52D78BE405A97E01FD71DD7819ECB91
+             FA85A076#
+     as stated in the standard.  This seems to be a bug in X9.31.
+   */
+
+  {
+    gcry_mpi_t val_2 = mpi_alloc_set_ui (2); 
+    gcry_mpi_t gcdtmp = mpi_alloc_like (yp0);
+    int gcdres;
+  
+    mpi_sub_ui (p1p2, p1p2, 1); /* Adjust for loop body.  */
+    mpi_sub_ui (yp0, yp0, 1);   /* Ditto.  */
+    for (;;)
+      {
+        gcdres = gcry_mpi_gcd (gcdtmp, e, yp0);
+        mpi_add_ui (yp0, yp0, 1);
+        if (!gcdres)
+          progress ('/');  /* gcd (e, yp0-1) != 1  */
+        else if (check_prime (yp0, val_2, 64, NULL, NULL))
+          break; /* Found.  */
+        /* We add p1p2-1 because yp0 is incremented after the gcd test.  */
+        mpi_add (yp0, yp0, p1p2);
+      }
+    mpi_free (gcdtmp);
+    mpi_free (val_2);
+  }
+
+  mpi_free (p1p2);
+
+  progress('\n');
+  if (r_p1)
+    *r_p1 = p1;
+  else
+    mpi_free (p1);
+  if (r_p2)
+    *r_p2 = p2;
+  else
+    mpi_free (p2);
+  return yp0;
+}
index 1d7e1d0..6bc248c 100644 (file)
@@ -64,9 +64,9 @@ static struct pubkey_table_entry
 #endif
 #if USE_ELGAMAL
     { &_gcry_pubkey_spec_elg,
-      &dummy_extra_spec,             GCRY_PK_ELG   },
+      &_gcry_pubkey_extraspec_elg,    GCRY_PK_ELG   },
     { &_gcry_pubkey_spec_elg,
-      &dummy_extra_spec,             GCRY_PK_ELG_E },
+      &_gcry_pubkey_extraspec_elg,    GCRY_PK_ELG_E },
 #endif
 #if USE_DSA
     { &_gcry_pubkey_spec_dsa,
@@ -530,17 +530,18 @@ pubkey_get_nenc (int algorithm)
 
 
 /* Generate a new public key with algorithm ALGORITHM of size NBITS
-   and return it at SKEY. The use of the arguments QBITS, USE_E,
-   XVALUE, CURVE_NAME and DOMAIN depend on the ALGORITHM.  RETFACTOR
-   is used by some algorithms to return certain additional information
-   which are in general not required.
+   and return it at SKEY.  USE_E depends on the ALGORITHM.  GENPARMS
+   is passed to the algorithm module if it features an extended
+   generation function.  RETFACTOR is used by some algorithms to
+   return certain additional information which are in general not
+   required.
 
    The function returns the error code number or 0 on success. */
 static gcry_err_code_t
-pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits,
-                 unsigned long use_e, gcry_mpi_t xvalue,
-                 const char *curve_name, gcry_sexp_t domain,
-                 unsigned int keygen_flags,
+pubkey_generate (int algorithm,
+                 unsigned int nbits,
+                 unsigned long use_e,
+                 gcry_sexp_t genparms,
                  gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
   gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO;
@@ -554,43 +555,11 @@ pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits,
     {
       pk_extra_spec_t *extraspec = pubkey->extraspec;
 
-      if (keygen_flags && (!extraspec || !extraspec->ext_generate))
+      if (extraspec && extraspec->ext_generate)
         {
-          /* A keygen flag has been given but the module does not
-             provide an ext_generate function.  We don't want to
-             ignore such a condition as it might eventually be
-             security sensitive..  */
-          ec = GPG_ERR_INV_FLAG;
-        }
-#ifdef USE_ELGAMAL
-      else if (xvalue && pubkey->spec == &_gcry_pubkey_spec_elg)
-        {
-          /* Fixme: Merge this into an ext_generate fucntion.  */
-          ec = _gcry_elg_generate_using_x
-            (algorithm, nbits, xvalue, skey, retfactors);
-        }
-#endif /*USE_ELGAMAL*/
-#ifdef USE_ECC
-      else if (curve_name && pubkey->spec == &_gcry_pubkey_spec_ecdsa)
-        {
-          /* Fixme: Merge this into an ext_generate fucntion.  */
-          ec = _gcry_ecc_generate
-            (algorithm, nbits, curve_name, skey, retfactors);
-        }
-#endif /*USE_ECC*/
-      else if (extraspec && extraspec->ext_generate)
-        {
-          /* Use the extended generate function if available.  */
-          ec = extraspec->ext_generate (algorithm, nbits, qbits, use_e,
-                                        NULL, domain, keygen_flags,
-                                        skey, retfactors);
-        }
-      else if (qbits || domain)
-        {
-          /* A qbits or domain parameter is specified but the
-             algorithm does not feature an extended generation
-             function.  */
-          ec = GPG_ERR_INV_PARAMETER;
+          /* Use the extended generate function.  */
+          ec = extraspec->ext_generate 
+            (algorithm, nbits, use_e, genparms, skey, retfactors);
         }
       else
         {
@@ -605,6 +574,7 @@ pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits,
   return ec;
 }
 
+
 static gcry_err_code_t
 pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey)
 {
@@ -868,11 +838,13 @@ sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
   return err;
 }
 
+
 /* Internal function used for ecc.  Note, that this function makes use
    of its intimate knowledge about the ECC parameters from ecc.c. */
 static gcry_err_code_t
 sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
-                           gcry_mpi_t *elements)
+                           gcry_mpi_t *elements, pk_extra_spec_t *extraspec)
+
 {
   gcry_err_code_t err = 0;
   int idx;
@@ -907,35 +879,41 @@ sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
   list = gcry_sexp_find_token (key_sexp, "curve", 5);
   if (list)
     {
-#if USE_ECC
-      char *curve;
-      gcry_mpi_t params[6];
-
-      for (idx = 0; idx < DIM(params); idx++)
-        params[idx] = NULL;
-
-      curve = _gcry_sexp_nth_string (list, 1);
-      if (!curve)
+      if (extraspec->get_param)
         {
-          err = GPG_ERR_INV_OBJ; /* No curve name given (or out of core). */
-          goto leave;
+          char *curve;
+          gcry_mpi_t params[6];
+          
+          for (idx = 0; idx < DIM(params); idx++)
+            params[idx] = NULL;
+          
+          curve = _gcry_sexp_nth_string (list, 1);
+          gcry_sexp_release (list);
+          if (!curve)
+            {
+              /* No curve name given (or out of core). */
+              err = GPG_ERR_INV_OBJ; 
+              goto leave;
+            }
+          err = extraspec->get_param (curve, params);
+          gcry_free (curve);
+          if (err)
+            goto leave;
+          
+          for (idx = 0; idx < DIM(params); idx++)
+            {
+              if (!elements[idx])
+                elements[idx] = params[idx];
+              else
+                mpi_free (params[idx]);
+            }
         }
-      err = _gcry_ecc_get_param (curve, params);
-      gcry_free (curve);
-      if (err)
-        goto leave;
-
-      for (idx = 0; idx < DIM(params); idx++)
+      else
         {
-          if (!elements[idx])
-            elements[idx] = params[idx];
-          else
-            mpi_free (params[idx]);
+          gcry_sexp_release (list);
+          err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
+          goto leave;
         }
-#else /* !USE_ECC */
-      err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
-      goto leave;
-#endif /* !USE_ECC */
     }
 
   /* Check that all parameters are known.  */
@@ -1001,6 +979,7 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray,
   gcry_mpi_t *array;
   gcry_module_t module;
   gcry_pk_spec_t *pubkey;
+  pk_extra_spec_t *extraspec;
   int is_ecc;
 
   /* Check that the first element is valid.  */
@@ -1038,7 +1017,10 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray,
       return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
     }
   else
-    pubkey = (gcry_pk_spec_t *) module->spec;
+    {
+      pubkey = (gcry_pk_spec_t *) module->spec;
+      extraspec = module->extraspec;
+    }
 
   elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey;
   array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
@@ -1047,7 +1029,7 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray,
   if (!err)
     {
       if (is_ecc)
-        err = sexp_elements_extract_ecc (list, elems, array);
+        err = sexp_elements_extract_ecc (list, elems, array, extraspec);
       else
         err = sexp_elements_extract (list, elems, array, pubkey->name);
     }
@@ -2084,7 +2066,9 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
 {
   gcry_pk_spec_t *pubkey = NULL;
   gcry_module_t module = NULL;
-  gcry_sexp_t list = NULL, l2 = NULL;
+  gcry_sexp_t list = NULL;
+  gcry_sexp_t l2 = NULL;
+  gcry_sexp_t l3 = NULL;
   char *name = NULL;
   size_t n;
   gcry_err_code_t rc = GPG_ERR_NO_ERROR;
@@ -2095,10 +2079,6 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   gcry_mpi_t skey[12], *factors = NULL;
   unsigned int nbits = 0;
   unsigned long use_e = 0;
-  unsigned int qbits;
-  gcry_mpi_t xvalue = NULL;
-  char *curve = NULL;
-  unsigned int keygen_flags = 0;
 
   skey[0] = NULL;
   *r_key = NULL;
@@ -2150,7 +2130,9 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   if (strlen (sec_elems) >= DIM(skey))
     BUG ();
 
-  /* Handle the optional rsa-use-e element. */
+  /* Handle the optional rsa-use-e element.  Actually this belong into
+     the algorithm module but we have this parameter in the public
+     moudle API, so we need to parse it right here.  */
   l2 = gcry_sexp_find_token (list, "rsa-use-e", 0);
   if (l2)
     {
@@ -2172,81 +2154,15 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   else
     use_e = 65537; /* Not given, use the value generated by old versions. */
 
-  /* Handle the optional qbits element. */
-  l2 = gcry_sexp_find_token (list, "qbits", 0);
-  if (l2)
-    {
-      char buf[50];
-      const char *s;
 
-      s = gcry_sexp_nth_data (l2, 1, &n);
-      if (!s || n >= DIM (buf) - 1 )
-        {
-          rc = GPG_ERR_INV_OBJ; /* No value or value too large.  */
-          goto leave;
-        }
-      memcpy (buf, s, n);
-      buf[n] = 0;
-      qbits = (unsigned int)strtoul (buf, NULL, 0);
-      gcry_sexp_release (l2);
-      l2 = NULL;
-    }
-  else
-    qbits = 0;
-
-  /* Parse the optional xvalue element. */
-  l2 = gcry_sexp_find_token (list, "xvalue", 0);
-  if (l2)
-    {
-      xvalue = gcry_sexp_nth_mpi (l2, 1, 0);
-      if (!xvalue)
-        {
-          rc = GPG_ERR_BAD_MPI;
-          goto leave;
-        }
-    }
-
-  /* Parse the optional "curve" parameter. */
-  l2 = gcry_sexp_find_token (list, "curve", 0);
-  if (l2)
-    {
-      curve = _gcry_sexp_nth_string (l2, 1);
-      if (!curve)
-        {
-          rc = GPG_ERR_INV_OBJ; /* No curve name or value too large. */
-          goto leave;
-        }
-      gcry_sexp_release (l2);
-      l2 = NULL;
-    }
-
-  /* Parse the optional "transient-key" flag. */
-  l2 = gcry_sexp_find_token (list, "transient-key", 0);
-  if (l2)
-    {
-      keygen_flags |= PUBKEY_FLAG_TRANSIENT_KEY;
-      gcry_sexp_release (l2);
-      l2 = NULL;
-    }
-
-
-  /* Unless a curve name has been given, the "nbits" parameter is
-     required.  */
+  /* Get the "nbits" parameter.  */
   l2 = gcry_sexp_find_token (list, "nbits", 0);
-  gcry_sexp_release (list);
-  list = l2;
-  l2 = NULL;
-  if (!list && !curve)
-    {
-      rc = GPG_ERR_NO_OBJ; /* No nbits parameter. */
-      goto leave;
-    }
-  if (list)
+  if (l2)
     {
       char buf[50];
       const char *s;
 
-      s = gcry_sexp_nth_data (list, 1, &n);
+      s = gcry_sexp_nth_data (l2, 1, &n);
       if (!s || n >= DIM (buf) - 1 )
         {
           rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr.  */
@@ -2255,18 +2171,18 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       memcpy (buf, s, n);
       buf[n] = 0;
       nbits = (unsigned int)strtoul (buf, NULL, 0);
+      gcry_sexp_release (l2); l2 = NULL;
     }
   else 
     nbits = 0;
 
-  /* Extract the optional domain parameter and call the key generation.  */
-  l2 = gcry_sexp_find_token (list, "domain", 0);
-  rc = pubkey_generate (module->mod_id, nbits, qbits, use_e, xvalue,
-                        curve, l2, keygen_flags, skey, &factors);
-  gcry_sexp_release (l2);
+  /* Pass control to the algorithm module. */
+  rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey, &factors);
+  gcry_sexp_release (list); list = NULL;
   if (rc)
     goto leave;
 
+  /* Key generation succeeded: Build an S-expression.  */
   {
     char *string, *p;
     size_t nelem=0, nelem_cp = 0, needed=0;
@@ -2312,7 +2228,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       }
     p = stpcpy (p, "))");
 
-    /* Very ugly hack to make release_mpi_array() work FIXME */
+    /* Hack to make release_mpi_array() work.  */
     skey[i] = NULL;
 
     if (factors[0])
@@ -2359,22 +2275,18 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
 
  leave:
   gcry_free (name);
-  gcry_free (curve);
   release_mpi_array (skey);
-  /* Don't free SKEY itself, it is a static array. */
+  /* Don't free SKEY itself, it is an stack allocated array. */
 
-  gcry_mpi_release (xvalue);
-  
   if (factors)
     {
       release_mpi_array ( factors );
       gcry_free (factors);
     }
   
-  if (l2)
-    gcry_sexp_release (l2);
-  if (list)
-    gcry_sexp_release (list);
+  gcry_sexp_release (l3);
+  gcry_sexp_release (l2);
+  gcry_sexp_release (list);
 
   if (module)
     {
index f18feba..8823af7 100644 (file)
@@ -207,8 +207,8 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
   if ( (nbits&1) )
     nbits++; 
 
-  if (use_e == 1)   /* Alias for a secure value. */
-    use_e = 65537;  /* as demanded by Spinx. */
+  if (use_e == 1)   /* Alias for a secure value */
+    use_e = 65537;  /* as demanded by Sphinx. */
 
   /* Public exponent:
      In general we use 41 as this is quite fast and more secure than the
@@ -328,6 +328,191 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
 }
 
 
+/* Variant of the standard key generation code using the algorithm
+   from X9.31.  Using this algorithm has the advantage that the
+   generation can be made deterministic which is required for CAVS
+   testing.  */
+static gpg_err_code_t
+generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value,
+               gcry_sexp_t deriveparms, int *swapped)
+{
+  gcry_mpi_t p, q; /* The two primes.  */
+  gcry_mpi_t e;    /* The public exponent.  */
+  gcry_mpi_t n;    /* The public key.  */
+  gcry_mpi_t d;    /* The private key */
+  gcry_mpi_t u;    /* The inverse of p and q.  */
+  gcry_mpi_t pm1;  /* p - 1  */
+  gcry_mpi_t qm1;  /* q - 1  */
+  gcry_mpi_t phi;  /* Euler totient.  */
+  gcry_mpi_t f, g; /* Helper.  */
+
+  *swapped = 0;
+
+  if (e_value == 1)   /* Alias for a secure value. */
+    e_value = 65537; 
+
+  /* Point 1 of section 4.1:  k = 1024 + 256s with S >= 0  */
+  if (nbits < 1024 || (nbits % 256))
+    return GPG_ERR_INV_VALUE;
+  
+  /* Point 2:  2 <= bitlength(e) < 2^{k-2}
+     Note that we do not need to check the upper bound because we use
+     an unsigned long for E and thus there is no way for E to reach
+     that limit.  */
+  if (e_value < 3)
+    return GPG_ERR_INV_VALUE;
+     
+  /* Our implementaion requires E to be odd.  */
+  if (!(e_value & 1))
+    return GPG_ERR_INV_VALUE;
+
+  /* Point 3:  e > 0 or e 0 if it is to be randomly generated.
+     We support only a fixed E and thus there is no need for an extra test.  */
+
+
+  /* Compute or extract the derive parameters.  */
+  {
+    gcry_mpi_t xp1 = NULL;
+    gcry_mpi_t xp2 = NULL;
+    gcry_mpi_t xp  = NULL;
+    gcry_mpi_t xq1 = NULL;
+    gcry_mpi_t xq2 = NULL;
+    gcry_mpi_t xq  = NULL;
+
+    if (!deriveparms)
+      {
+        /* Fixme: Create them.  */
+        return GPG_ERR_INV_VALUE;
+      }
+    else
+      {
+        struct { const char *name; gcry_mpi_t *value; } tbl[] = {
+          { "Xp1", &xp1 },
+          { "Xp2", &xp2 },
+          { "Xp",  &xp  },
+          { "Xq1", &xq1 },
+          { "Xq2", &xq2 },
+          { "Xq",  &xq  },
+          { NULL,  NULL }
+        };
+        int idx;
+        gcry_sexp_t oneparm;
+        
+        for (idx=0; tbl[idx].name; idx++)
+          {
+            oneparm = gcry_sexp_find_token (deriveparms, tbl[idx].name, 0);
+            if (oneparm)
+              {
+                *tbl[idx].value = gcry_sexp_nth_mpi (oneparm, 1,
+                                                     GCRYMPI_FMT_USG);
+                gcry_sexp_release (oneparm);
+              }
+          }
+        for (idx=0; tbl[idx].name; idx++)
+          if (!*tbl[idx].value)
+            break;
+        if (tbl[idx].name)
+          {
+            /* At least one parameter is missing.  */
+            for (idx=0; tbl[idx].name; idx++)
+              gcry_mpi_release (*tbl[idx].value);
+            return GPG_ERR_MISSING_VALUE;
+          }
+      }
+    
+    e = mpi_alloc_set_ui (e_value); 
+
+    /* Find two prime numbers.  */
+    p = _gcry_derive_x931_prime (xp, xp1, xp2, e, NULL, NULL);
+    q = _gcry_derive_x931_prime (xq, xq1, xq2, e, NULL, NULL);
+    gcry_mpi_release (xp);  xp  = NULL;
+    gcry_mpi_release (xp1); xp1 = NULL;
+    gcry_mpi_release (xp2); xp2 = NULL;
+    gcry_mpi_release (xq);  xq  = NULL; 
+    gcry_mpi_release (xq1); xq1 = NULL;
+    gcry_mpi_release (xq2); xq2 = NULL;
+    if (!p || !q)
+      {
+        gcry_mpi_release (p);
+        gcry_mpi_release (q);
+        gcry_mpi_release (e);
+        return GPG_ERR_NO_PRIME;
+      }
+  }
+
+
+  /* Compute the public modulus.  We make sure that p is smaller than
+     q to allow the use of the CRT.  */
+  if (mpi_cmp (p, q) > 0 )
+    {
+      mpi_swap (p, q);
+      *swapped = 1;
+    }
+  n = gcry_mpi_new (nbits);
+  mpi_mul (n, p, q);
+
+  /* Compute the Euler totient:  phi = (p-1)(q-1)  */
+  pm1 = gcry_mpi_snew (nbits/2);
+  qm1 = gcry_mpi_snew (nbits/2);
+  phi = gcry_mpi_snew (nbits);
+  mpi_sub_ui (pm1, p, 1);
+  mpi_sub_ui (qm1, q, 1);
+  mpi_mul (phi, pm1, qm1);
+
+  g = gcry_mpi_snew (nbits);
+  gcry_assert (gcry_mpi_gcd (g, e, phi));
+
+  /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */
+  gcry_mpi_gcd (g, pm1, qm1);
+  f = pm1; pm1 = NULL;
+  gcry_mpi_release (qm1); qm1 = NULL;
+  mpi_fdiv_q (f, phi, g);
+  gcry_mpi_release (phi); phi = NULL;
+  d = g; g = NULL;
+  /* Compute the secret key:  d = e^{-1} mod lcm(p-1,q-1) */
+  mpi_invm (d, e, f);
+
+  /* Compute the inverse of p and q.  */
+  u = f; f = NULL;
+  mpi_invm (u, p, q );
+
+  if( DBG_CIPHER )
+    {
+      if (swapped)
+        log_debug ("p and q are swapped\n");
+      log_mpidump("  p", p );
+      log_mpidump("  q", q );
+      log_mpidump("  n", n );
+      log_mpidump("  e", e );
+      log_mpidump("  d", d );
+      log_mpidump("  u", u );
+    }
+
+
+  sk->n = n;
+  sk->e = e;
+  sk->p = p;
+  sk->q = q;
+  sk->d = d;
+  sk->u = u;
+
+  /* Now we can test our keys. */
+  if (test_keys (sk, nbits - 64))
+    {
+      gcry_mpi_release (sk->n); sk->n = NULL;
+      gcry_mpi_release (sk->e); sk->e = NULL;
+      gcry_mpi_release (sk->p); sk->p = NULL;
+      gcry_mpi_release (sk->q); sk->q = NULL;
+      gcry_mpi_release (sk->d); sk->d = NULL;
+      gcry_mpi_release (sk->u); sk->u = NULL;
+      fips_signal_error ("self-test after key generation failed");
+      return GPG_ERR_SELFTEST_FAILED;
+    }
+
+  return 0;
+}
+
+
 /****************
  * Test wether the secret key is valid.
  * Returns: true if this is a valid key.
@@ -530,23 +715,42 @@ rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n)
  *********************************************/
 
 static gcry_err_code_t
-rsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits,
-                  unsigned long use_e,
-                  const char *name, const gcry_sexp_t domain,
-                  unsigned int keygen_flags,
+rsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
+                  const gcry_sexp_t genparms,
                   gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
   RSA_secret_key sk;
   gpg_err_code_t ec;
+  gcry_sexp_t deriveparms;
+  int transient_key = 0;
+  gcry_sexp_t l1;
+  int swapped;
   int i;
 
   (void)algo;
-  (void)qbits;
-  (void)name;
-  (void)domain;
 
-  ec = generate_std (&sk, nbits, use_e,
-                     !!(keygen_flags & PUBKEY_FLAG_TRANSIENT_KEY) );
+  deriveparms = (genparms?
+                 gcry_sexp_find_token (genparms, "derive-parms", 0) : NULL);
+
+  if (deriveparms || fips_mode ())
+    {
+      ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped);
+      gcry_sexp_release (deriveparms);
+    }
+  else
+    {
+      /* Parse the optional "transient-key" flag. */
+      l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
+      if (l1)
+        {
+          transient_key = 1;
+          gcry_sexp_release (l1);
+          l1 = NULL;
+        }
+      /* Generate.  */
+      ec = generate_std (&sk, nbits, evalue, transient_key);
+    }
+
   if (!ec)
     {
       skey[0] = sk.n;
@@ -576,11 +780,10 @@ rsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits,
 
 
 static gcry_err_code_t
-rsa_generate (int algo, unsigned int nbits, unsigned long use_e,
+rsa_generate (int algo, unsigned int nbits, unsigned long evalue,
               gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
-  return rsa_generate_ext (algo, nbits, 0, use_e, NULL, NULL, 0,
-                           skey, retfactors);
+  return rsa_generate_ext (algo, nbits, evalue, NULL, skey, retfactors);
 }
 
 
index 87fb9ce..e8d85b8 100644 (file)
@@ -2725,6 +2725,33 @@ currently only implemented for DSA using this format:
 The @code{seed}, @code{counter} and @code{h} domain parameters are
 optional and currently not used.
 
+@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.
+
+@example
+(genkey
+  (rsa
+    (nbits 4:1024)
+    (rsa-use-e 1:3)
+    (derive-parms
+      (Xp1 #1A1916DDB29B4EB7EB6732E128#)
+      (Xp2 #192E8AAC41C576C822D93EA433#)
+      (Xp  #D8CD81F035EC57EFE822955149D3BFF70C53520D
+            769D6D76646C7A792E16EBD89FE6FC5B605A6493
+            39DFC925A86A4C6D150B71B9EEA02D68885F5009
+            B98BD984#)
+      (Xq1 #1A5CF72EE770DE50CB09ACCEA9#)
+      (Xq2 #134E4CAA16D2350A21D775C404#)
+      (Xq  #CC1092495D867E64065DEE3E7955F2EBC7D47A2D
+            7C9953388F97DDDC3E1CA19C35CA659EDC2FC325
+            6D29C2627479C086A699A49C4C9CEE7EF7BD1B34
+            321DE34A#))))
+@end example
+
 @end table
 @c end table of parameters
 
@@ -2750,16 +2777,17 @@ As an example, here is what the Elgamal key generation returns:
       (y @var{y-mpi})
       (x @var{x-mpi})))
   (misc-key-info
-    (pm1-factors @var{n1 n2 ... nn})))
+    (pm1-factors @var{n1 n2 ... nn}))
 @end example
 
 @noindent
-As you can see, some of the information is duplicated, but this provides
-an easy way to extract either the public or the private key.  Note that
-the order of the elements is not defined, e.g. the private key may be
-stored before the public key. @var{n1 n2 ... nn} is a list of prime
-numbers used to composite @var{p-mpi}; this is in general not a very
-useful information.
+As you can see, some of the information is duplicated, but this
+provides an easy way to extract either the public or the private key.
+Note that the order of the elements is not defined, e.g. the private
+key may be stored before the public key. @var{n1 n2 ... nn} is a list
+of prime numbers used to composite @var{p-mpi}; this is in general not
+a very useful information and only available if the key generation
+algorithm provides them.  
 @end deftypefun
 @c end gcry_pk_genkey
 
index c255fda..d503dd3 100644 (file)
@@ -1,3 +1,11 @@
+2008-11-24  Werner Koch  <wk@g10code.com>
+
+       * cipher-proto.h (pk_ext_generate_t): Simplify. 
+       (pk_get_param): New.
+       (pk_extra_spec_t): Add field GET_PARAM.
+       * cipher.h (PUBKEY_FLAG_TRANSIENT_KEY): Remove.
+       (_gcry_pubkey_extraspec_elg): New.
+
 2008-11-05  Werner Koch  <wk@g10code.com>
 
        * cipher.h (CIPHER_INFO_NO_WEAK_KEY): New.
index 975a2a1..31bf6ba 100644 (file)
@@ -43,18 +43,19 @@ typedef gpg_err_code_t (*selftest_func_t)
 typedef gcry_err_code_t (*pk_ext_generate_t)
      (int algo,
       unsigned int nbits,
-      unsigned int qbits,
-      unsigned long use_e,
-      const char *name,
-      gcry_sexp_t domain,
-      unsigned int keygen_flags, 
+      unsigned long evalue,
+      gcry_sexp_t genparms,
       gcry_mpi_t *skey,
       gcry_mpi_t **retfactors);
 
-/* The type is used to compute the keygrip.  */
+/* The type used to compute the keygrip.  */
 typedef gpg_err_code_t (*pk_comp_keygrip_t)
      (gcry_md_hd_t md, gcry_sexp_t keyparm);
 
+/* The type used to quert ECC curve parameters.  */
+typedef gcry_err_code_t (*pk_get_param_t)
+     (const char *name, gcry_mpi_t *pkey);
+
 /* The type used to convey additional information to a cipher.  */
 typedef gpg_err_code_t (*cipher_set_extra_info_t)
      (void *c, int what, const void *buffer, size_t buflen);
@@ -79,6 +80,7 @@ typedef struct pk_extra_spec
   selftest_func_t selftest;
   pk_ext_generate_t ext_generate;
   pk_comp_keygrip_t comp_keygrip;
+  pk_get_param_t get_param;
 } pk_extra_spec_t;
 
 
index f84d9ad..62ca745 100644 (file)
@@ -27,7 +27,6 @@
 #include "../random/random.h"
 
 #define PUBKEY_FLAG_NO_BLINDING    (1 << 0)
-#define PUBKEY_FLAG_TRANSIENT_KEY  (1 << 1)
 
 #define CIPHER_INFO_NO_WEAK_KEY    1
 
@@ -62,18 +61,11 @@ void _gcry_register_pk_dsa_progress (gcry_handler_progress_t cbc, void *cb_data)
 /*-- elgamal.c --*/
 void _gcry_register_pk_elg_progress (gcry_handler_progress_t cb,
                                      void *cb_data);
-gcry_err_code_t _gcry_elg_generate_using_x (int algo, unsigned int nbits,
-                                            gcry_mpi_t x, 
-                                            gcry_mpi_t *skey,
-                                            gcry_mpi_t **retfactors);
+
 
 /*-- ecc.c --*/
 void _gcry_register_pk_ecc_progress (gcry_handler_progress_t cbc,
                                      void *cb_data);
-gcry_err_code_t _gcry_ecc_generate (int algo, unsigned int nbits,
-                                    const char *curve,
-                                    gcry_mpi_t *skey, gcry_mpi_t **retfactors);
-gcry_err_code_t _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey);
 
 
 /*-- primegen.c --*/
@@ -138,6 +130,7 @@ extern gcry_pk_spec_t _gcry_pubkey_spec_ecdsa;
 
 extern pk_extra_spec_t _gcry_pubkey_extraspec_rsa; 
 extern pk_extra_spec_t _gcry_pubkey_extraspec_dsa; 
+extern pk_extra_spec_t _gcry_pubkey_extraspec_elg; 
 extern pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa; 
 
 
index 22f9acf..f7ea781 100644 (file)
@@ -175,6 +175,10 @@ gcry_mpi_t _gcry_generate_public_prime (unsigned int nbits,
 gcry_mpi_t _gcry_generate_elg_prime (int mode, 
                                      unsigned int pbits, unsigned int qbits,
                                      gcry_mpi_t g, gcry_mpi_t **factors);
+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);
 
 
 /* replacements of missing functions (missing-string.c)*/
index 74a21a0..9867c27 100644 (file)
@@ -1,3 +1,7 @@
+2008-11-24  Werner Koch  <wk@g10code.com>
+
+       * pubkey.c (check_x931_derived_key): New.
+
 2008-11-07  Werner Koch  <wk@g10code.com>
 
        * fipsdrv.c (run_cipher_mct_loop, get_current_iv): New.
index b6542fd..8b4079c 100755 (executable)
@@ -1035,6 +1035,7 @@ sub crypto_mct($$$$$$$$) {
                 my $old_calc_data;
                 my $old_old_calc_data;
                 my $ov;
+                my $iv_arg;
 
                $out .= "COUNT = $i\n";
                if (defined($key2)) {
@@ -1059,10 +1060,15 @@ sub crypto_mct($$$$$$$$) {
                         $out .= "CIPHERTEXT = ". bin2hex($source_data). "\n";
                 }
 
+                # Need to provide a dummy IV in case of ECB mode.
+                $iv_arg =  (defined($iv) && $iv ne "")
+                             ? bin2hex($iv)
+                             : "00"x(length($source_data)); 
+
                 print $CI "1\n"
                           .$iloop."\n"
                           .bin2hex($key1)."\n"
-                          .bin2hex($iv)."\n"
+                          .$iv_arg."\n"
                           .bin2hex($source_data)."\n\n" or die;
                 
                 # fixme: We should skip over empty lines here.
@@ -1130,7 +1136,7 @@ sub crypto_mct($$$$$$$$) {
                }
 
                 if ($ciph =~ /des/) {
-                    $iv = $ov;
+                    $iv = $ov if (defined($iv) && $iv ne "");
                     if ($cipher =~ /des-ede3-ofb/) {
                         $source_data = $source_data ^ $next_source;
                     } else {
index 9d3d5ba..e27b84c 100644 (file)
@@ -240,6 +240,8 @@ read_textline (FILE *fp)
       any = 1;
     }
   while (*line == '#');  /* Always skip comment lines.  */
+  if (verbose > 1)
+    fprintf (stderr, PGM ": received line: %s\n", line);
   return gcry_xstrdup (line);
 }
 
@@ -800,6 +802,8 @@ print_buffer (const void *buffer, size_t length)
     {
       const unsigned char *p = buffer;
       
+      if (verbose > 1)
+        showhex ("sent line", buffer, length);
       while (length-- && !ferror (stdout) )
         printf ("%02X", *p++);
       if (ferror (stdout))
@@ -1099,6 +1103,8 @@ run_cipher_mct_loop (int encrypt_mode, int cipher_algo, int cipher_mode,
   putchar ('\n');
   print_buffer (input, blocklen);   /* Next input text. */
   putchar ('\n');
+  if (verbose > 1)
+    showhex ("sent line", "", 0);
   putchar ('\n');
   fflush (stdout);
 
index f3e6515..d5b0a7c 100644 (file)
@@ -114,6 +114,23 @@ die (const char *format, ...)
 }
 
 static void
+show_sexp (const char *prefix, gcry_sexp_t a)
+{
+  char *buf;
+  size_t size;
+
+  if (prefix)
+    fputs (prefix, stderr);
+  size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+  buf = gcry_xmalloc (size);
+
+  gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+  fprintf (stderr, "%.*s", (int)size, buf);
+  gcry_free (buf);
+}
+
+
+static void
 check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey,
                  gcry_sexp_t plain0, gpg_err_code_t decrypt_fail_code)
 {
@@ -296,6 +313,7 @@ get_elg_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int fixed_x)
   *skey = sec_key;
 }
 
+
 static void
 check_run (void)
 {
@@ -342,6 +360,219 @@ check_run (void)
 }
 
 
+
+static gcry_mpi_t
+key_param_from_sexp (gcry_sexp_t sexp, const char *topname, const char *name)
+{
+  gcry_sexp_t l1, l2;
+  gcry_mpi_t result;
+
+  l1 = gcry_sexp_find_token (sexp, topname, 0);
+  if (!l1)
+    return NULL;
+
+  l2 = gcry_sexp_find_token (l1, name, 0);
+  if (!l2)
+    {
+      gcry_sexp_release (l1);
+      return NULL;
+    }
+  result = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l2);
+  gcry_sexp_release (l1);
+  return result;
+}
+
+
+static void
+check_x931_derived_key (int what)
+{
+  static struct {
+    const char *param;
+    const char *expected_d;
+  } testtable[] = {
+    { /* First example from X9.31 (D.1.1).  */
+      "(genkey\n"
+      "  (rsa\n"
+      "    (nbits 4:1024)\n"
+      "    (rsa-use-e 1:3)\n"
+      "    (derive-parms\n"
+      "      (Xp1 #1A1916DDB29B4EB7EB6732E128#)\n"
+      "      (Xp2 #192E8AAC41C576C822D93EA433#)\n"
+      "      (Xp  #D8CD81F035EC57EFE822955149D3BFF70C53520D\n"
+      "            769D6D76646C7A792E16EBD89FE6FC5B605A6493\n"
+      "            39DFC925A86A4C6D150B71B9EEA02D68885F5009\n"
+      "            B98BD984#)\n"
+      "      (Xq1 #1A5CF72EE770DE50CB09ACCEA9#)\n"
+      "      (Xq2 #134E4CAA16D2350A21D775C404#)\n"
+      "      (Xq  #CC1092495D867E64065DEE3E7955F2EBC7D47A2D\n"
+      "            7C9953388F97DDDC3E1CA19C35CA659EDC2FC325\n"
+      "            6D29C2627479C086A699A49C4C9CEE7EF7BD1B34\n"
+      "            321DE34A#))))\n",
+      "1CCDA20BCFFB8D517EE9666866621B11822C7950D55F4BB5BEE37989A7D173"
+      "12E326718BE0D79546EAAE87A56623B919B1715FFBD7F16028FC4007741961"
+      "C88C5D7B4DAAAC8D36A98C9EFBB26C8A4A0E6BC15B358E528A1AC9D0F042BE"
+      "B93BCA16B541B33F80C933A3B769285C462ED5677BFE89DF07BED5C127FD13"
+      "241D3C4B"
+    },
+    
+    { /* Second example from X9.31 (D.2.1).  */
+      "(genkey\n"
+      "  (rsa\n"
+      "    (nbits 4:1536)\n"
+      "    (rsa-use-e 1:3)\n"
+      "    (derive-parms\n"
+      "      (Xp1 #18272558B61316348297EACA74#)\n"
+      "      (Xp2 #1E970E8C6C97CEF91F05B0FA80#)\n"
+      "      (Xp  #F7E943C7EF2169E930DCF23FE389EF7507EE8265\n"
+      "            0D42F4A0D3A3CEFABE367999BB30EE680B2FE064\n"
+      "            60F707F46005F8AA7CBFCDDC4814BBE7F0F8BC09\n"
+      "            318C8E51A48D134296E40D0BBDD282DCCBDDEE1D\n"
+      "            EC86F0B1C96EAFF5CDA70F9AEB6EE31E#)\n"
+      "      (Xq1 #11FDDA6E8128DC1629F75192BA#)\n"
+      "      (Xq2 #18AB178ECA907D72472F65E480#)\n"
+      "      (Xq  #C47560011412D6E13E3E7D007B5C05DBF5FF0D0F\n"
+      "            CFF1FA2070D16C7ABA93EDFB35D8700567E5913D\n"
+      "            B734E3FBD15862EBC59FA0425DFA131E549136E8\n"
+      "            E52397A8ABE4705EC4877D4F82C4AAC651B33DA6\n"
+      "            EA14B9D5F2A263DC65626E4D6CEAC767#))))\n",
+      "1FB56069985F18C4519694FB71055721A01F14422DC901C35B03A64D4A5BD1"
+      "259D573305F5B056AC931B82EDB084E39A0FD1D1A86CC5B147A264F7EF4EB2"
+      "0ED1E7FAAE5CAE4C30D5328B7F74C3CAA72C88B70DED8EDE207B8629DA2383"
+      "B78C3CE1CA3F9F218D78C938B35763AF2A8714664CC57F5CECE2413841F5E9"
+      "EDEC43B728E25A41BF3E1EF8D9EEE163286C9F8BF0F219D3B322C3E4B0389C"
+      "2E8BB28DC04C47DA2BF38823731266D2CF6CC3FC181738157624EF051874D0"
+      "BBCCB9F65C83"
+      /* Note that this example in X9.31 gives this value for D:
+
+        "7ED581A6617C6311465A53EDC4155C86807C5108B724070D6C0E9935296F44"
+        "96755CCC17D6C15AB24C6E0BB6C2138E683F4746A1B316C51E8993DFBD3AC8"
+        "3B479FEAB972B930C354CA2DFDD30F2A9CB222DC37B63B7881EE18A7688E0E"
+        "DE30F38728FE7C8635E324E2CD5D8EBCAA1C51993315FD73B38904E107D7A7"
+        "B7B10EDCA3896906FCF87BE367BB858CA1B27E2FC3C8674ECC8B0F92C0E270"
+        "BA2ECA3701311F68AFCE208DCC499B4B3DB30FF0605CE055D893BC1461D342"
+        "EF32E7D9720B" 
+
+        This is a bug in X9.31, obviously introduced by using
+
+           d = e^{-1} mod (p-1)(q-1)
+          
+         instead of using the universal exponent as required by 4.1.3:
+
+           d = e^{-1} mod lcm(p-1,q-1)
+
+         The examples in X9.31 seem to be pretty buggy, see
+         cipher/primegen.c for another bug.  Not only that I had to
+         spend 100 USD for the 66 pages of the document, it also took
+         me several hours to figure out that the bugs are in the
+         document and not in my code.
+       */
+    },  
+
+    { /* First example from NIST RSAVS (B.1.1).  */
+      "(genkey\n"
+      "  (rsa\n"
+      "    (nbits 4:1024)\n"
+      "    (rsa-use-e 1:3)\n"
+      "    (derive-parms\n"
+      "      (Xp1 #1ed3d6368e101dab9124c92ac8#)\n"
+      "      (Xp2 #16e5457b8844967ce83cab8c11#)\n"
+      "      (Xp  #b79f2c2493b4b76f329903d7555b7f5f06aaa5ea\n"
+      "            ab262da1dcda8194720672a4e02229a0c71f60ae\n"
+      "            c4f0d2ed8d49ef583ca7d5eeea907c10801c302a\n"
+      "            cab44595#)\n"
+      "      (Xq1 #1a5d9e3fa34fb479bedea412f6#)\n"
+      "      (Xq2 #1f9cca85f185341516d92e82fd#)\n"
+      "      (Xq  #c8387fd38fa33ddcea6a9de1b2d55410663502db\n"
+      "            c225655a9310cceac9f4cf1bce653ec916d45788\n"
+      "            f8113c46bc0fa42bf5e8d0c41120c1612e2ea8bb\n"
+      "            2f389eda#))))\n",
+      "17ef7ad4fd96011b62d76dfb2261b4b3270ca8e07bc501be954f8719ef586b"
+      "f237e8f693dd16c23e7adecc40279dc6877c62ab541df5849883a5254fccfd"
+      "4072a657b7f4663953930346febd6bbd82f9a499038402cbf97fd5f068083a"
+      "c81ad0335c4aab0da19cfebe060a1bac7482738efafea078e21df785e56ea0"
+      "dc7e8feb"
+    },
+
+    { /* Second example from NIST RSAVS (B.1.1).  */
+      "(genkey\n"
+      "  (rsa\n"
+      "    (nbits 4:1536)\n"
+      "    (rsa-use-e 1:3)\n"
+      "    (derive-parms\n"
+      "      (Xp1 #1e64c1af460dff8842c22b64d0#)\n"
+      "      (Xp2 #1e948edcedba84039c81f2ac0c#)\n"
+      "      (Xp  #c8c67df894c882045ede26a9008ab09ea0672077\n"
+      "            d7bc71d412511cd93981ddde8f91b967da404056\n"
+      "            c39f105f7f239abdaff92923859920f6299e82b9\n"
+      "            5bd5b8c959948f4a034d81613d6235a3953b49ce\n"
+      "            26974eb7bb1f14843841281b363b9cdb#)\n"
+      "      (Xq1 #1f3df0f017ddd05611a97b6adb#)\n"
+      "      (Xq2 #143edd7b22d828913abf24ca4d#)\n"
+      "      (Xq  #f15147d0e7c04a1e3f37adde802cdc610999bf7a\n"
+      "            b0088434aaeda0c0ab3910b14d2ce56cb66bffd9\n"
+      "            7552195fae8b061077e03920814d8b9cfb5a3958\n"
+      "            b3a82c2a7fc97e55db543948d3396289245336ec\n"
+      "            9e3cb308cc655aebd766340da8921383#))))\n",
+      "1f8b19f3f5f2ac9fc599f110cad403dcd9bdf5f7f00fb2790e78e820398184"
+      "1f3fb3dd230fb223d898f45719d9b2d3525587ff2b8bcc7425e40550a5b536"
+      "1c8e9c1d26e83fbd9c33c64029c0e878b829d55def12912b73d94fd758c461"
+      "0f473e230c41b5e4c86e27c5a5029d82c811c88525d0269b95bd2ff272994a"
+      "dbd80f2c2ecf69065feb8abd8b445b9c6d306b1585d7d3d7576d49842bc7e2"
+      "8b4a2f88f4a47e71c3edd35fdf83f547ea5c2b532975c551ed5268f748b2c4"
+      "2ccf8a84835b"
+    }
+  };
+  gpg_error_t err;
+  gcry_sexp_t key_spec, key, pub_key, sec_key;
+  gcry_mpi_t d_expected, d_have;
+
+  if (what < 0 && what >= sizeof testtable)
+    die ("invalid WHAT value\n");
+
+  err = gcry_sexp_new (&key_spec, testtable[what].param, 0, 1);
+  if (err)
+    die ("error creating S-expression [%d]: %s\n", what, gpg_strerror (err));
+
+  err = gcry_pk_genkey (&key, key_spec);
+  gcry_sexp_release (key_spec);
+  if (err)
+    die ("error generating RSA key [%d]: %s\n", what, gpg_strerror (err));
+    
+  pub_key = gcry_sexp_find_token (key, "public-key", 0);
+  if (!pub_key)
+    die ("public part missing in key [%d]\n", what);
+
+  sec_key = gcry_sexp_find_token (key, "private-key", 0);
+  if (!sec_key)
+    die ("private part missing in key [%d]\n", what);
+
+  err = gcry_mpi_scan 
+    (&d_expected, GCRYMPI_FMT_HEX, testtable[what].expected_d, 0, NULL);
+  if (err)
+    die ("error converting string [%d]\n", what);
+
+  if (verbose)
+    show_sexp ("generated private key:\n", sec_key);
+  d_have = key_param_from_sexp (sec_key, "rsa", "d");
+  if (!d_have)
+    die ("parameter d not found in RSA secret key [%d]\n", what);
+  if (gcry_mpi_cmp (d_expected, d_have))
+    {
+      show_sexp (NULL, sec_key);
+      die ("parameter d does match expected value [%d]\n", what); 
+    }
+  gcry_mpi_release (d_expected);
+  gcry_mpi_release (d_have);
+
+  gcry_sexp_release (key);
+  gcry_sexp_release (pub_key);
+  gcry_sexp_release (sec_key);
+}
+
+
+
+
 int
 main (int argc, char **argv)
 {
@@ -364,6 +595,9 @@ main (int argc, char **argv)
 
   for (i=0; i < 2; i++)
     check_run ();
+
+  for (i=0; i < 4; i++) 
+    check_x931_derived_key (i);
   
   return 0;
 }