Use quick key generation.
authorWerner Koch <wk@gnupg.org>
Tue, 14 Mar 2006 13:13:11 +0000 (13:13 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 14 Mar 2006 13:13:11 +0000 (13:13 +0000)
Cleaned up output; i.e. take care of --verbose.

13 files changed:
ChangeLog
NEWS
TODO
cipher/ChangeLog
cipher/random.c
configure.ac
tests/ChangeLog
tests/ac-data.c
tests/ac.c
tests/basic.c
tests/keygen.c
tests/pkbench.c
tests/pubkey.c

index 46aecf7..198a019 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2006-03-14  Werner Koch  <wk@g10code.com>
+
+       * configure.ac: Check for fctnl and ftruncate.
+
 2005-12-08  Werner Koch  <wk@g10code.com>
 
        * configure.ac: Changed the random device names for netbsd.  From
@@ -1032,7 +1036,7 @@ Fri Feb 13 19:43:41 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
        
  Copyright 1998, 1999, 2000, 2001, 2002, 2003,
-          2004 Free Software Foundation, Inc.
+          2004, 2006 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
diff --git a/NEWS b/NEWS
index d43f255..bd68be2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,11 @@ Noteworthy changes in version 1.3.0 (unreleased)
    general a good idea to spread this macro into the application code
    to make sure that these polls happen often enough.
 
+ * Reading and writing the random seed file is now protected by a
+   fcntl style file lock on systems that provide this function.
+
+ * Support for SHA-224 and HMAC using SHA-384 and SHA-512.
+
  * Interface changes relative to the 1.2.0 release:
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 gcry_fast_random_poll  NEW
diff --git a/TODO b/TODO
index 6d6355f..5986ddc 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
 What's left to do                                 -*- outline -*-
 
-* Add more tests.  Even basic is very minimal.
+* Add more tests.
 
 * udiv-qrnbd.o should get build as *.lo [HPUX]
 
@@ -26,9 +26,6 @@ What's left to do                                 -*- outline -*-
   with the ac interface (i.e. by using ac's `data sets') and the pk
   interface could be changed to be a wrapper for the ac interface.
 
-* HMAC won't work with sha-512 due to the different block size.  OTOH,
-  I can imagine no cryptographic reason to use it.
-
 * cipher/pubkey.c and pubkey implementaions.
   Don't rely on the secure memory based wiping function but add an
   extra wiping.
@@ -39,3 +36,15 @@ What's left to do                                 -*- outline -*-
 
 * Use builtin bit functions of gcc 3.4
 
+* Consider using a daemon to maintain he random pool
+
+  The down side of this is that we can't assume that the random das
+  has always been stored in "secure memory".  And we rely on that
+  sniffing of Unix domain sockets is not possible.  We can implement
+  this simply by detecting a special prefixed random seed name and
+  divert in this case to the daemon.  There are several benefits with
+  such an approach: We keep the state of the RNG over invocations of
+  libgcrypt based applications, don't need time consuming
+  initialization of the pool and in case the entropy collectros need
+  to run that bunch of Unix utilities we don't waste their precious
+  results.
index a1b5b8c..dd17b99 100644 (file)
@@ -1,3 +1,12 @@
+2006-03-14  Werner Koch  <wk@g10code.com>
+
+       * random.c (lock_seed_file): New.
+       (read_seed_file, _gcry_update_random_seed_file): Use it.
+
+       * random.c (gcry_create_nonce):  Detect a fork and re-seed.
+       (read_pool): Fixed the fork detection; it used to work only for
+       multi-threaded processes.
+
 2006-03-12  Brad Hards  <bradh@frogmouth.net>  (wk)
 
        * md.c (md_open): Use new variable macpads_Bsize instead of
index 177cd6f..9b9869b 100644 (file)
@@ -1,6 +1,6 @@
 /* random.c  - random number generator
  * Copyright (C) 1998, 2000, 2001, 2002, 2003,
- *               2004  Free Software Foundation, Inc.
+ *               2004, 2005, 2006  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
 #define RAND_MAX 32767
 #endif
 
+/* Check whether we can lock the seed file read write. */
+#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM)
+#define LOCK_SEED_FILE 1
+#else
+#define LOCK_SEED_FILE 0
+#endif
+
 
 #if SIZEOF_UNSIGNED_LONG == 8
 #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
@@ -259,7 +266,8 @@ get_random_bytes ( size_t nbytes, int level, int secure)
   byte *buf, *p;
   int err;
 
-  /* First a hack toavoid the strong random using our regression test suite. */
+  /* First a hack to avoid the strong random using our regression test
+     suite. */
   if (quick_test && level > 1)
     level = 1;
 
@@ -531,6 +539,45 @@ _gcry_set_random_seed_file( const char *name )
 }
 
 
+/* Lock an open file identified by file descriptor FD and wait a
+   reasonable time to succeed.  With FOR_WRITE set to true a write
+   lock will be taken.  FNAME is used only for diagnostics. Returns 0
+   on success or -1 on error. */
+static int
+lock_seed_file (int fd, const char *fname, int for_write)
+{
+#if LOCK_SEED_FILE
+  struct flock lck;
+  struct timeval tv;
+  int backoff=0;
+
+  /* We take a lock on the entire file. */
+  memset (&lck, 0, sizeof lck);
+  lck.l_type = for_write? F_WRLCK : F_RDLCK;
+  lck.l_whence = SEEK_SET;
+
+  while (fcntl (fd, F_SETLK, &lck) == -1)
+    {
+      if (errno != EAGAIN && errno != EACCES)
+        {
+          log_info (_("can't lock `%s': %s\n"), fname, strerror (errno));
+          return -1;
+        }
+
+      if (backoff > 2) /* Show the first message after ~2.25 seconds. */
+        log_info( _("waiting for lock on `%s'...\n"), fname);
+      
+      tv.tv_sec = backoff;
+      tv.tv_usec = 250000;
+      select (0, NULL, NULL, NULL, &tv);
+      if (backoff < 10)
+        backoff++ ;
+    }
+#endif /*LOCK_SEED_FILE*/
+  return 0;
+}
+
+
 /*
   Read in a seed form the random_seed file
   and return true if this was successful.
@@ -564,6 +611,11 @@ read_seed_file (void)
       log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
       return 0;
     }
+  if (lock_seed_file (fd, seed_file_name, 0))
+    {
+      close (fd);
+      return 0;
+    }
   if (fstat( fd, &sb ) )
     {
       log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
@@ -652,7 +704,7 @@ _gcry_update_random_seed_file()
     log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
   pool_is_locked = 1;
 
-  /* copy the entropy pool to a scratch pool and mix both of them */
+  /* Copy the entropy pool to a scratch pool and mix both of them. */
   for (i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
        i < POOLWORDS; i++, dp++, sp++ ) 
     {
@@ -661,28 +713,41 @@ _gcry_update_random_seed_file()
   mix_pool(rndpool); rndstats.mixrnd++;
   mix_pool(keypool); rndstats.mixkey++;
 
-#ifdef HAVE_DOSISH_SYSTEM
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
   fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
              S_IRUSR|S_IWUSR );
 #else
-  fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# if LOCK_SEED_FILE
+    fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
+# else
+    fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# endif
 #endif
 
   if (fd == -1 )
     log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+  else if (lock_seed_file (fd, seed_file_name, 1))
+    {
+      close (fd);
+    }
+#if LOCK_SEED_FILE
+  else if (ftruncate (fd, 0))
+    {
+      log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno));
+      close (fd);
+    }
+#endif /*LOCK_SEED_FILE*/
   else 
     {
       do
         {
           i = write (fd, keypool, POOLSIZE );
         } 
-      while( i == -1 && errno == EINTR );
+      while (i == -1 && errno == EINTR);
       if (i != POOLSIZE) 
-        log_info (_("can't write `%s': %s\n"),
-                  seed_file_name, strerror(errno) );
+        log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno));
       if (close(fd))
-        log_info(_("can't close `%s': %s\n"),
-                 seed_file_name, strerror(errno) );
+        log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno));
     }
   
   pool_is_locked = 0;
@@ -694,21 +759,39 @@ _gcry_update_random_seed_file()
 
 
 /* Read random out of the pool. This function is the core of the
-   public random fucntions.  Note that Level 0 is not anymore handeld
-   special and in fact an alias for level 1. */
+   public random functions.  Note that Level 0 is not anymore handeld
+   special and in fact an alias for level 1.  Must be called with the
+   pool already locked.  */
 static void
 read_pool (byte *buffer, size_t length, int level)
 {
   int i;
   unsigned long *sp, *dp;
-  volatile pid_t my_pid; /* The volatile is there to make sure the
-                            compiler does not optimize the code away
-                            in case the getpid function is badly
-                            attributed. */
+  /* The volatile is there to make sure the compiler does not optimize
+     the code away in case the getpid function is badly attributed.
+     Note that we keep a pid in a static variable as well as in a
+     stack based one; the latter is to detect ill behaving thread
+     libraries, ignoring the pool mutexes. */
+  static volatile pid_t my_pid = (pid_t)(-1); 
+  volatile pid_t my_pid2;
+
 
  retry:
   /* Get our own pid, so that we can detect a fork. */
-  my_pid = getpid ();
+  my_pid2 = getpid ();
+  if (my_pid == (pid_t)(-1))                                
+    my_pid = my_pid2;
+  if ( my_pid != my_pid2 )
+    {
+      /* We detected a plain fork; i.e. we are now the child.  Update
+         the static pid and add some randomness. */
+      pid_t x;
+
+      my_pid = my_pid2;
+      x = my_pid;
+      add_randomness (&x, sizeof(x), 0);
+      just_mixed = 0; /* Make sure it will get mixed. */
+    }
 
   assert (pool_is_locked);
 
@@ -756,7 +839,7 @@ read_pool (byte *buffer, size_t length, int level)
       pool_balance += needed;
     }
 
-  /* make sure the pool is filled */
+  /* Make sure the pool is filled. */
   while (!pool_filled)
     random_poll();
 
@@ -765,7 +848,10 @@ read_pool (byte *buffer, size_t length, int level)
   
   /* Mix the pid in so that we for sure won't deliver the same random
      after a fork. */
-  add_randomness (&my_pid, sizeof (my_pid), 0);
+  {
+    pid_t apid = my_pid;
+    add_randomness (&apid, sizeof (apid), 0);
+  }
 
   /* Mix the pool (if add_randomness() didn't it). */
   if (!just_mixed)
@@ -783,8 +869,8 @@ read_pool (byte *buffer, size_t length, int level)
   mix_pool(rndpool); rndstats.mixrnd++;
   mix_pool(keypool); rndstats.mixkey++;
 
-  /* Read the required data.  We use a readpointer to read from a
-     different position each time */
+  /* Read the requested data.  We use a read pointer to read from a
+     different position each time */
   while (length--)
     {
       *buffer++ = keypool[pool_readpos++];
@@ -801,17 +887,14 @@ read_pool (byte *buffer, size_t length, int level)
 
   /* We need to detect whether a fork has happened.  A fork might have
      an identical pool and thus the child and the parent could emit
-     the very same random number.  Obviously this can only happen when
-     running multi-threaded and the pool lock should even catch this.
-     However things do get wrong and thus we better check and retry it
-     here.  We assume that the thread library has no other fatal
-     faults, though.
-   */
-  if ( getpid () != my_pid )
+     the very same random number.  This test here is to detect forks
+     in a multi-threaded process. */
+  if ( getpid () != my_pid2 )
     {
       pid_t x = getpid();
       add_randomness (&x, sizeof(x), 0);
       just_mixed = 0; /* Make sure it will get mixed. */
+      my_pid = x;     /* Also update the static pid. */
       goto retry;
     }
 }
@@ -1101,6 +1184,10 @@ gcry_create_nonce (unsigned char *buffer, size_t length)
 {
   static unsigned char nonce_buffer[20+8];
   static int nonce_buffer_initialized = 0;
+  static volatile pid_t my_pid; /* The volatile is there to make sure the
+                                   compiler does not optimize the code away
+                                   in case the getpid function is badly
+                                   attributed. */
   unsigned char *p;
   size_t n;
   int err;
@@ -1121,6 +1208,8 @@ gcry_create_nonce (unsigned char *buffer, size_t length)
       pid_t apid = getpid ();
       time_t atime = time (NULL);
 
+      my_pid = apid;
+
       if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
         BUG ();
 
@@ -1137,6 +1226,12 @@ gcry_create_nonce (unsigned char *buffer, size_t length)
 
       nonce_buffer_initialized = 1;
     }
+  else if ( my_pid != getpid () )
+    {
+      /* We forked. Need to reseed the buffer - doing this for the
+         private part should be sufficient. */
+      gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
+    }
 
   /* Create the nonce by hashing the entire buffer, returning the hash
      and updating the first 20 bytes of the buffer with this hash. */
index f90ec84..d677538 100644 (file)
@@ -1,6 +1,6 @@
 # Configure.ac script for Libgcrypt
 # Copyright (C) 1998, 1999, 2000, 2001, 2002
-#               2003, 2004 Free Software Foundation, Inc.
+#               2003, 2004, 2006 Free Software Foundation, Inc.
 #
 # This file is part of Libgcrypt.
 #
@@ -484,6 +484,7 @@ AC_CHECK_FUNCS(strtoul memmove stricmp atexit raise)
 # Other checks
 AC_CHECK_FUNCS(strerror rand mmap getpagesize waitpid wait4)
 AC_CHECK_FUNCS(gettimeofday getrusage gethrtime clock_gettime)
+AC_CHECK_FUNCS(fcntl ftruncate)
 
 GNUPG_CHECK_MLOCK
 
index 881cb64..2b75b78 100644 (file)
@@ -1,3 +1,15 @@
+2006-03-14  Werner Koch  <wk@g10code.com>
+
+       * ac-data.c (check_sexp_conversion, check_run): Take care of VERBOSE.
+       * basic.c (main): Speed up test key generation.
+       (main): use progress handler only in verbose mode.
+       * ac.c (main): Ditto.
+       * pubkey.c (main): Ditto.
+       * keygen.c (main): Ditto.
+       (check_rsa_keys): Print key only in verbose mode.
+
+       * pkbench.c (main): Ditto.
+
 2006-03-10  Brad Hards  <bradh@frogmouth.net>  (wk, patch 2006-02-18)
 
        * basic.c (check_one_hmac, check_hmac): New.
index 08ddba9..9313da1 100644 (file)
@@ -63,7 +63,8 @@ check_sexp_conversion (gcry_ac_data_t data, const char **identifiers)
 
   err = gcry_ac_data_to_sexp (data, &sexp, identifiers);
   assert_err (err);
-  gcry_sexp_dump (sexp);
+  if (verbose)
+    gcry_sexp_dump (sexp);
   err = gcry_ac_data_from_sexp (&data2, sexp, identifiers);
   assert_err (err);
 
@@ -128,7 +129,8 @@ check_run (void)
   check_sexp_conversion (data, identifiers_null);
   check_sexp_conversion (data, NULL);
 
-  printf ("data-set-test-0 succeeded\n");
+  if (verbose)
+    printf ("data-set-test-0 succeeded\n");
 
   gcry_ac_data_clear (data);
 
@@ -161,8 +163,9 @@ check_run (void)
   assert_err (err);
   gcry_free ((void *) label1); /* FIXME!! */
   gcry_mpi_release (mpi1);
-    
-  printf ("data-set-test-1 succeeded\n");
+
+  if (verbose)
+    printf ("data-set-test-1 succeeded\n");
 
   gcry_ac_data_clear (data);
   assert (! gcry_ac_data_length (data));
@@ -170,7 +173,8 @@ check_run (void)
   check_sexp_conversion (data, identifiers_null);
   check_sexp_conversion (data, NULL);
 
-  printf ("data-set-test-2 succeeded\n");
+  if (verbose)
+    printf ("data-set-test-2 succeeded\n");
  
   gcry_ac_data_destroy (data);
  
index 75fe2da..d734360 100644 (file)
@@ -152,6 +152,8 @@ main (int argc, char **argv)
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+  /* No valuable keys are create, so we can speed up our RNG. */
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
   for (; i > 0; i--)
     check_run ();
index 0246632..cb8b6aa 100644 (file)
@@ -1096,7 +1096,7 @@ check_digests (void)
       { GCRY_MD_SHA1, "!" /* kludge for "a"*1000000 */ ,
        "\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E"
        "\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" },
-      // From RFC3874
+      /* From RFC3874 */
       {        GCRY_MD_SHA224, "abc",
        "\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3"
        "\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7" },
@@ -1920,12 +1920,16 @@ main (int argc, char **argv)
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
 
-  gcry_set_progress_handler (progress_handler, NULL);
+  if (verbose)
+    gcry_set_progress_handler (progress_handler, NULL);
   
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+  /* No valuable keys are create, so we can speed up our RNG. */
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
   check_ciphers ();
   check_aes128_cbc_cts_cipher ();
   check_cbc_mac_cipher ();
index d1d01fd..abe8881 100644 (file)
@@ -139,8 +139,9 @@ check_rsa_keys (void)
   {
     char buffer[20000];
     gcry_sexp_sprint (key, GCRYSEXP_FMT_ADVANCED, buffer, sizeof buffer);
-    printf ("=============================\n%s\n"
-            "=============================\n", buffer);
+    if (verbose)
+      printf ("=============================\n%s\n"
+              "=============================\n", buffer);
   }
   gcry_sexp_release (key);
   exit (0);
index d69bc5f..372fa0c 100644 (file)
@@ -335,6 +335,9 @@ main (int argc, char **argv)
       char *algorithm = NULL;
       char *key_size = NULL;
 
+      /* No valuable keys are create, so we can speed up our RNG. */
+      gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
       if (argv[2])
        {
          algorithm = argv[2];
index e383f47..f71590d 100644 (file)
@@ -247,6 +247,8 @@ main (int argc, char **argv)
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+  /* No valuable keys are create, so we can speed up our RNG. */
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
   for (; i > 0; i--)
     check_run ();