File libgcrypt-fips_rsa_keygen.patch of Package libgcrypt

Index: libgcrypt-1.6.1/cipher/rsa.c
===================================================================
--- libgcrypt-1.6.1.orig/cipher/rsa.c	2015-02-16 17:17:27.281576283 +0100
+++ libgcrypt-1.6.1/cipher/rsa.c	2015-02-16 18:21:08.946056697 +0100
@@ -421,6 +421,279 @@ gen_x931_parm_xi (void)
 }
 
 
+/****************
+ * Generate a key pair with a key of size NBITS.
+ * USE_E = 0 let Libcgrypt decide what exponent to use.
+ *       = 1 request the use of a "secure" exponent; this is required by some
+ *           specification to be 65537.
+ *       > 2 Use this public exponent.  If the given exponent
+ *           is not odd one is internally added to it.
+ * TESTPARMS: If set, do not generate but test whether the p,q is probably prime
+ *            Returns key with zeroes to not break code calling this function.
+ * TRANSIENT_KEY:  If true, generate the primes using the standard RNG.
+ * Returns: 2 structures filled with all needed values
+ */
+static gpg_err_code_t
+generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
+               gcry_sexp_t testparms, int *swapped)
+{
+  gcry_mpi_t p, q; /* the two primes */
+  gcry_mpi_t d;    /* the private key */
+  gcry_mpi_t u;
+  gcry_mpi_t p1, q1;
+  gcry_mpi_t n;    /* the public key */
+  gcry_mpi_t e;    /* the exponent */
+  gcry_mpi_t g;
+  gcry_mpi_t minp;
+  gcry_mpi_t diff, mindiff;
+  gcry_random_level_t random_level;
+  unsigned int pbits = nbits/2;
+  unsigned int i;
+  int pqswitch;
+  gpg_err_code_t ec = GPG_ERR_NO_PRIME;
+
+  if (nbits < 1024 || (nbits & 0x1FF))
+      return GPG_ERR_INV_VALUE;
+  if (fips_mode() && nbits != 2048 && nbits != 3072)
+      return GPG_ERR_INV_VALUE;
+
+  random_level = GCRY_VERY_STRONG_RANDOM;
+
+  if (testparms)
+      {
+        /* Parameters to derive the key are given.  */
+        /* Note that we explicitly need to setup the values of tbl
+           because some compilers (e.g. OpenWatcom, IRIX) don't allow
+           to initialize a structure with automatic variables.  */
+        struct { const char *name; gcry_mpi_t *value; } tbl[] = {
+          { "e" },
+          { "p" },
+          { "q" },
+          { NULL }
+        };
+        int idx;
+        gcry_sexp_t oneparm;
+
+        tbl[0].value = &e;
+        tbl[1].value = &p;
+        tbl[2].value = &q;
+
+        for (idx=0; tbl[idx].name; idx++)
+          {
+            oneparm = sexp_find_token (testparms, tbl[idx].name, 0);
+            if (oneparm)
+              {
+                *tbl[idx].value = sexp_nth_mpi (oneparm, 1,
+                                                     GCRYMPI_FMT_USG);
+                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;
+          }
+      }
+  else
+      {
+        if (use_e < 65537)
+          use_e = 65537;  /* This is the smallest value allowed by FIPS */
+
+        e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+
+        use_e |= 1; /* make sure this is odd */
+        mpi_set_ui (e, use_e);
+
+        p = mpi_snew (pbits);
+        q = mpi_snew (pbits);
+      }
+
+  n = mpi_new (nbits);
+  d = mpi_snew (nbits);
+  u = mpi_snew (nbits);
+
+  /* prepare approximate minimum p and q */
+  minp = mpi_new (pbits);
+  mpi_set_ui (minp, 0xB504F334);
+  mpi_lshift (minp, minp, pbits - 32);
+
+  /* prepare minimum p and q difference */
+  diff = mpi_new (pbits);
+  mindiff = mpi_new (pbits - 99);
+  mpi_set_ui (mindiff, 1);
+  mpi_lshift (mindiff, mindiff, pbits - 100);
+
+  p1 = mpi_snew (pbits);
+  q1 = mpi_snew (pbits);
+  g  = mpi_snew (pbits);
+
+retry:
+  /* generate p and q */
+  for (i = 0; i < 5 * pbits; i++)
+    {
+    ploop:
+      if (!testparms)
+        {
+          _gcry_mpi_randomize (p, pbits, random_level);
+        }
+      if (mpi_cmp (p, minp) < 0)
+        {
+          if (testparms) goto err;
+          goto ploop;
+        }
+
+      mpi_sub_ui (p1, p, 1);
+      if (mpi_gcd (g, p1, e))
+        {
+          if (_gcry_fips186_4_prime_check (p, pbits) != GPG_ERR_NO_ERROR)
+            {
+              /* not a prime */
+              if (testparms) goto err;
+            }
+          else
+            break;
+        }
+      else if (testparms) goto err;
+    }
+  if (i >= 5 * pbits)
+    goto err;
+
+  for (i = 0; i < 5 * pbits; i++)
+    {
+    qloop:
+      if (!testparms)
+        {
+          _gcry_mpi_randomize (q, pbits, random_level);
+        }
+      if (mpi_cmp (q, minp) < 0)
+        {
+          if (testparms) goto err;
+          goto qloop;
+        }
+      if (mpi_cmp (p, q) < 0)
+        {
+          pqswitch = 1;
+          mpi_sub (diff, q, p);
+        }
+      else
+        {
+          pqswitch = 0;
+          mpi_sub (diff, p, q);
+        }
+      if (mpi_cmp (diff, mindiff) < 0)
+        {
+          if (testparms) goto err;
+          goto qloop;
+        }
+
+      mpi_sub_ui (q1, q, 1);
+      if (mpi_gcd (g, q1, e))
+        {
+          if (_gcry_fips186_4_prime_check (q, pbits) != GPG_ERR_NO_ERROR)
+            {
+              /* not a prime */
+              if (testparms) goto err;
+            }
+          else
+            break;
+        }
+      else if (testparms) goto err;
+    }
+  if (i >= 5 * pbits)
+    goto err;
+
+  if (testparms)
+    {
+       mpi_clear (p);
+       mpi_clear (q);
+    }
+  else
+    {
+      gcry_mpi_t f;
+      gcry_mpi_t phi;
+
+      f = mpi_snew (nbits);
+      phi = mpi_snew (nbits);
+
+      if (pqswitch)
+        {
+          mpi_swap(p, q);
+        }
+
+      /* calculate the modulus */
+      mpi_mul(n, p, q);
+
+      /* Compute the Euler totient:  phi = (p-1)(q-1)  */
+      mpi_mul (phi, p1, q1);
+
+      /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */
+      mpi_gcd (g, p1, q1);
+      mpi_fdiv_q (f, phi, g);
+      _gcry_mpi_release (phi); phi = NULL;
+
+      /* Compute the secret key:  d = e^{-1} mod lcm(p-1,q-1) */
+      mpi_invm (d, e, f);
+      _gcry_mpi_release (f);
+
+      if (mpi_get_nbits (d) < pbits) goto retry;
+
+      /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+      mpi_invm(u, p, q );
+    }
+
+  ec = 0;
+
+  if( DBG_CIPHER )
+    {
+      log_mpidump("  p= ", p );
+      log_mpidump("  q= ", q );
+      log_mpidump("  n= ", n );
+      log_mpidump("  e= ", e );
+      log_mpidump("  d= ", d );
+      log_mpidump("  u= ", u );
+    }
+
+err:
+
+  _gcry_mpi_release (p1);
+  _gcry_mpi_release (q1);
+  _gcry_mpi_release (g);
+  _gcry_mpi_release (minp);
+  _gcry_mpi_release (mindiff);
+  _gcry_mpi_release (diff);
+
+  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 (ec || (!testparms && 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;
+      if (!ec)
+        {
+          fips_signal_error ("self-test after key generation failed");
+          return GPG_ERR_SELFTEST_FAILED;
+        }
+    }
+
+  return ec;
+}
+
+
 static gpg_err_code_t
 fips_186_4_prime_check(gcry_mpi_t x, unsigned int nbits, gcry_mpi_t e)
 {
@@ -441,6 +714,8 @@ fips_186_4_prime_check(gcry_mpi_t x, uns
   return rc;
 }
 
+
+
 /* 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
@@ -913,7 +1188,7 @@ rsa_generate (const gcry_sexp_t genparms
         }
     }
 
-  if (deriveparms || (flags & PUBKEY_FLAG_USE_X931) || fips_mode ())
+  if (deriveparms || (flags & PUBKEY_FLAG_USE_X931))
     {
       int swapped;
       ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped);
@@ -933,9 +1208,16 @@ rsa_generate (const gcry_sexp_t genparms
               sexp_release (l1);
             }
         }
+      deriveparms = (genparms?
+                 sexp_find_token (genparms, "test-parms", 0) : NULL);
+
       /* Generate.  */
-      ec = generate_std (&sk, nbits, evalue,
-                         !!(flags & PUBKEY_FLAG_TRANSIENT_KEY));
+      if (deriveparms || fips_mode())
+        ec = generate_fips (&sk, nbits, evalue, deriveparms, 0);
+      else
+        ec = generate_std (&sk, nbits, evalue, !!(flags & PUBKEY_FLAG_TRANSIENT_KEY));
+
+      sexp_release (deriveparms);
     }
 
   if (!ec)
Index: libgcrypt-1.6.1/cipher/primegen.c
===================================================================
--- libgcrypt-1.6.1.orig/cipher/primegen.c	2015-02-16 16:43:58.418615762 +0100
+++ libgcrypt-1.6.1/cipher/primegen.c	2015-02-16 17:54:47.425359088 +0100
@@ -913,6 +913,22 @@ check_prime( gcry_mpi_t prime, gcry_mpi_
   return 0;
 }
 
+/* Check whether the number X is prime according to FIPS 186-4 table C.2.  */
+gcry_err_code_t
+_gcry_fips186_4_prime_check (gcry_mpi_t x, unsigned int bits)
+{
+  gcry_err_code_t ec = GPG_ERR_NO_ERROR;
+  gcry_mpi_t val_2 = mpi_alloc_set_ui (2);
+/* Used by the Fermat test. */
+
+  /* We use 5 or 4 rounds as specified in table C.2 */
+  if (! check_prime (x, val_2, bits > 1024 ? 4 : 5, NULL, NULL))
+    ec = GPG_ERR_NO_PRIME;
+
+  mpi_free (val_2);
+
+  return ec;
+}
 
 /*
  * Return true if n is probably a prime
openSUSE Build Service is sponsored by