[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-76-g7607ab8

by Werner Koch cvs at cvs.gnupg.org
Mon Dec 3 22:20:47 CET 2012


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  7607ab81504ce44060ed0b331d309606f5da1e75 (commit)
       via  f17e4d920c8a18007a98830dd13163ff19616202 (commit)
       via  76c622e24a07f7c826812be173aa173b4334776b (commit)
       via  75760021b511ba438606af746431223357e7a155 (commit)
       via  c324644aa14e54fc7051983b38222db32b8ab227 (commit)
      from  f851b9a932ee64fa5a06000d1ac763ba4349f07d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 7607ab81504ce44060ed0b331d309606f5da1e75
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Dec 3 20:41:28 2012 +0100

    random: Add a RNG selection interface and system RNG wrapper.
    
    * random/random-system.c: New.
    * random/Makefile.am (librandom_la_SOURCES): Add new module.
    * random/random.c (struct rng_types): New.
    (_gcry_set_preferred_rng_type, _gcry_get_rng_type): New.
    (_gcry_random_initialize, gcry_random_add_bytes, do_randomize)
    (_gcry_set_random_seed_file, _gcry_update_random_seed_file)
    (_gcry_fast_random_poll): Dispatch to the actual RNG.
    * src/gcrypt.h.in (GCRYCTL_SET_PREFERRED_RNG_TYPE): New.
    GCRYCTL_GET_CURRENT_RNG_TYPE): New.
    (gcry_rng_types): New.
    * src/global.c (print_config): Print the TNG type.
    (global_init, _gcry_vcontrol): Implement the new control codes.
    * doc/gcrypt.texi (Controlling the library): Document the new control
    codes.
    
    * tests/benchmark.c (main): Add options to test the RNG types.
    * tests/random.c (main): Add new options.
    (print_hex): Print to stderr.
    (progress_cb, rng_type): New.
    (check_rng_type_switching, check_early_rng_type_switching): New.
    (run_all_rng_tests): New.
    --
    
    The purpose of this change is to allow applications with moderate
    random requirements to use the system's RNG (e.g. /dev/urandom).  The
    type switching logic makes sure that existing applications won't be
    affected by this change.  A library is in almost all cases not able to
    degrade the quality of the RNG.  The definition of "degrade" comes
    from our own assertion of the quality/trustworthiness of the RNGs:
    
    The most trustworthy RNG is the CSPRNG which dates back to the early
    GnuPG days.  It is quite conservative and often requires more seeding
    than might be justified.  GCRY_RNG_TYPE_STANDARD is the default unless
    the process is in FIPS mode.
    
    The second trustworthy RNG is the FIPS recommended X9.81 AES based
    implementation.  It is seeded by the system's RNG.  GCRY_RNG_TYPE_FIPS
    is the only available RNG if running in FIPS mode.
    
    The third trustworthy RNG is a mere wrapper around the system's native
    RNG.  Thus there is no extra step on top of what, for example,
    /dev/random provides.  GCRY_RNG_TYPE_SYSTEM may be used by
    applications which would use /dev/random or /dev/urandom instead.

diff --git a/NEWS b/NEWS
index a0fd09b..45b892f 100644
--- a/NEWS
+++ b/NEWS
@@ -9,7 +9,10 @@ Noteworthy changes in version 1.6.0 (unreleased)
  * The deprecated message digest debug macros have been removed.  Use
    gcry_md_debug instead.
 
- * Add support for the IDEA cipher algorithm.
+ * Added support for the IDEA cipher algorithm.
+
+ * Added a random number generator to directly use the system's RNG.
+   Also added an interface to prefer the use of a specified RNG.
 
  * Interface changes relative to the 1.5.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -28,6 +31,11 @@ Noteworthy changes in version 1.6.0 (unreleased)
  gcry_md_start_debug    REMOVED (macro).
  gcry_md_stop_debug     REMOVED (macro).
  GCRYCTL_SET_ENFORCED_FIPS_FLAG  NEW.
+ GCRYCTL_SET_PREFERRED_RNG_TYPE  NEW.
+ GCRYCTL_GET_CURRENT_RNG_TYPE    NEW.
+ GCRY_RNG_TYPE_STANDARD          NEW.
+ GCRY_RNG_TYPE_FIPS              NEW.
+ GCRY_RNG_TYPE_SYSTEM            NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 66a05d5..fa24def 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -849,6 +849,37 @@ the library such as @code{gcry_check_version}. Note that Libgcrypt will
 reject an attempt to switch to the enforced fips mode during or after
 the intialization.
 
+ at item GCRYCTL_SET_PREFERRED_RNG_TYPE; Arguments: int
+These are advisory commands to select a certain random number
+generator.  They are only advisory because libraries may not know what
+an application actually wants or vice versa.  Thus Libgcrypt employs a
+priority check to select the actually used RNG.  If an applications
+selects a lower priority RNG but a library requests a higher priority
+RNG Libgcrypt will switch to the higher priority RNG.  Applications
+and libaries should use these control codes before
+ at code{gcry_check_version}.  The available generators are:
+ at table @code
+ at item GCRY_RNG_TYPE_STANDARD
+A conservative standard generator based on the ``Continuously Seeded
+Pseudo Random Number Generator'' designed by Peter Gutmann.
+ at item GCRY_RNG_TYPE_FIPS
+A deterministic random number generator conforming to he document
+``NIST-Recommended Random Number Generator Based on ANSI X9.31
+Appendix A.2.4 Using the 3-Key Triple DES and AES Algorithms''
+(2005-01-31).  This implementation uses the AES variant.
+ at item GCRY_RNG_TYPE_SYSTEM
+A wrapper around the system's native RNG.  On Unix system these are
+usually the /dev/random and /dev/urandom devices.
+ at end table
+The default is @code{GCRY_RNG_TYPE_STANDARD} unless FIPS mode as been
+enabled; in which case @code{GCRY_RNG_TYPE_FIPS} is used and locked
+against further changes.
+
+ at item GCRYCTL_GETT_CURRENT_RNG_TYPE; Arguments: int *
+This command stores the type of the currently used RNG as an integer
+value at the provided address.
+
+
 @item GCRYCTL_SELFTEST; Arguments: none
 This may be used at anytime to have the library run all implemented
 self-tests.  It works in standard and in FIPS mode.  Returns 0 on
diff --git a/random/Makefile.am b/random/Makefile.am
index 603226d..c9d587a 100644
--- a/random/Makefile.am
+++ b/random/Makefile.am
@@ -35,6 +35,7 @@ random.c random.h \
 rand-internal.h \
 random-csprng.c \
 random-fips.c \
+random-system.c \
 rndhw.c
 
 if USE_RANDOM_DAEMON
diff --git a/random/rand-internal.h b/random/rand-internal.h
index a72d88c..f59a102 100644
--- a/random/rand-internal.h
+++ b/random/rand-internal.h
@@ -87,6 +87,14 @@ gcry_err_code_t _gcry_rngfips_run_external_test (void *context,
 void _gcry_rngfips_deinit_external_test (void *context);
 
 
+/*-- random-system.c --*/
+void _gcry_rngsystem_initialize (int full);
+void _gcry_rngsystem_dump_stats (void);
+int  _gcry_rngsystem_is_faked (void);
+gcry_error_t _gcry_rngsystem_add_bytes (const void *buf, size_t buflen,
+                                        int quality);
+void _gcry_rngsystem_randomize (void *buffer, size_t length,
+                                enum gcry_random_level level);
 
 
 
diff --git a/random/random-system.c b/random/random-system.c
new file mode 100644
index 0000000..0ef9d24
--- /dev/null
+++ b/random/random-system.c
@@ -0,0 +1,243 @@
+/* random-system.c - wrapper around the system's RNG
+ * Copyright (C) 2012  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
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+   This RNG is merely wrapper around the system's native RNG.  For
+   example on Unix systems it directly uses /dev/{u,}random.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+
+#include "g10lib.h"
+#include "random.h"
+#include "rand-internal.h"
+#include "ath.h"
+
+/* This is the lock we use to serialize access to this RNG.  The extra
+   integer variable is only used to check the locking state; that is,
+   it is not meant to be thread-safe but merely as a failsafe feature
+   to assert proper locking.  */
+static ath_mutex_t system_rng_lock;
+static int system_rng_is_locked;
+
+
+/* --- Local prototypes ---  */
+
+
+
+
+/* --- Functions  --- */
+
+/* Basic initialization is required to initialize mutexes and
+   do a few checks on the implementation.  */
+static void
+basic_initialization (void)
+{
+  static int initialized;
+  int my_errno;
+
+  if (initialized)
+    return;
+  initialized = 1;
+
+  my_errno = ath_mutex_init (&system_rng_lock);
+  if (my_errno)
+    log_fatal ("failed to create the System RNG lock: %s\n",
+               strerror (my_errno));
+  system_rng_is_locked = 0;
+
+  /* Make sure that we are still using the values we traditionally
+     used for the random levels.  */
+  gcry_assert (GCRY_WEAK_RANDOM == 0
+               && GCRY_STRONG_RANDOM == 1
+               && GCRY_VERY_STRONG_RANDOM == 2);
+
+}
+
+
+/* Acquire the system_rng_lock.  */
+static void
+lock_rng (void)
+{
+  int my_errno;
+
+  my_errno = ath_mutex_lock (&system_rng_lock);
+  if (my_errno)
+    log_fatal ("failed to acquire the System RNG lock: %s\n",
+               strerror (my_errno));
+  system_rng_is_locked = 1;
+}
+
+
+/* Release the system_rng_lock.  */
+static void
+unlock_rng (void)
+{
+  int my_errno;
+
+  system_rng_is_locked = 0;
+  my_errno = ath_mutex_unlock (&system_rng_lock);
+  if (my_errno)
+    log_fatal ("failed to release the System RNG lock: %s\n",
+               strerror (my_errno));
+}
+
+
+/* Helper variables for read_cb().
+
+   The _gcry_rnd*_gather_random interface does not allow to provide a
+   data pointer.  Thus we need to use a global variable for
+   communication.  However, the then required locking is anyway a good
+   idea because it does not make sense to have several readers of (say
+   /dev/random).  It is easier to serve them one after the other.  */
+static unsigned char *read_cb_buffer;   /* The buffer.  */
+static size_t         read_cb_size;     /* Size of the buffer.  */
+static size_t         read_cb_len;      /* Used length.  */
+
+
+/* Callback for _gcry_rnd*_gather_random.  */
+static void
+read_cb (const void *buffer, size_t length, enum random_origins origin)
+{
+  const unsigned char *p = buffer;
+
+  (void)origin;
+
+  gcry_assert (system_rng_is_locked);
+  gcry_assert (read_cb_buffer);
+
+  /* Note that we need to protect against gatherers returning more
+     than the requested bytes (e.g. rndw32).  */
+  while (length-- && read_cb_len < read_cb_size)
+    {
+      read_cb_buffer[read_cb_len++] = *p++;
+    }
+}
+
+
+/* Fill BUFFER with LENGTH bytes of random at quality LEVEL.  The
+   function either succeeds or terminates the process in case of a
+   fatal error. */
+static void
+get_random (void *buffer, size_t length, int level)
+{
+  int rc;
+
+  gcry_assert (buffer);
+
+  read_cb_buffer = buffer;
+  read_cb_size   = length;
+  read_cb_len    = 0;
+
+#if USE_RNDLINUX
+  rc = _gcry_rndlinux_gather_random (read_cb, 0, length, level);
+#elif USE_RNDUNIX
+  rc = _gcry_rndunix_gather_random (read_cb, 0, length, level);
+#elif USE_RNDW32
+  do
+    {
+      rc = _gcry_rndw32_gather_random (read_cb, 0, length, level);
+    }
+  while (rc >= 0 && read_cb_len < read_cb_size);
+#else
+  rc = -1;
+#endif
+
+  if (rc < 0 || read_cb_len != read_cb_size)
+    {
+      log_fatal ("error reading random from system RNG (rc=%d)\n", rc);
+    }
+}
+
+
+
+/* --- Public Functions --- */
+
+/* Initialize this random subsystem.  If FULL is false, this function
+   merely calls the basic initialization of the module and does not do
+   anything more.  Doing this is not really required but when running
+   in a threaded environment we might get a race condition
+   otherwise. */
+void
+_gcry_rngsystem_initialize (int full)
+{
+  basic_initialization ();
+  if (!full)
+    return;
+  /* Nothing more to initialize.  */
+  return;
+}
+
+
+/* Print some statistics about the RNG.  */
+void
+_gcry_rngsystem_dump_stats (void)
+{
+  /* Not yet implemented.  */
+}
+
+
+/* This function returns true if no real RNG is available or the
+   quality of the RNG has been degraded for test purposes.  */
+int
+_gcry_rngsystem_is_faked (void)
+{
+  return 0;  /* Faked random is not supported.  */
+}
+
+
+/* Add BUFLEN bytes from BUF to the internal random pool.  QUALITY
+   should be in the range of 0..100 to indicate the goodness of the
+   entropy added, or -1 for goodness not known. */
+gcry_error_t
+_gcry_rngsystem_add_bytes (const void *buf, size_t buflen, int quality)
+{
+  (void)buf;
+  (void)buflen;
+  (void)quality;
+  return 0;  /* Not implemented. */
+}
+
+
+/* Public function to fill the buffer with LENGTH bytes of
+   cryptographically strong random bytes.  Level GCRY_WEAK_RANDOM is
+   here mapped to GCRY_STRONG_RANDOM, GCRY_STRONG_RANDOM is strong
+   enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key
+   generation stuff but may be very slow.  */
+void
+_gcry_rngsystem_randomize (void *buffer, size_t length,
+                           enum gcry_random_level level)
+{
+  _gcry_rngsystem_initialize (1);  /* Auto-initialize if needed.  */
+
+  if (level != GCRY_VERY_STRONG_RANDOM)
+    level = GCRY_STRONG_RANDOM;
+
+  lock_rng ();
+  get_random (buffer, length, level);
+  unlock_rng ();
+}
diff --git a/random/random.c b/random/random.c
index 9a5b166..e56eb8a 100644
--- a/random/random.c
+++ b/random/random.c
@@ -43,6 +43,15 @@
 static void (*progress_cb) (void *,const char*,int,int, int );
 static void *progress_cb_data;
 
+/* Flags indicating the requested RNG types.  */
+static struct
+{
+  int standard;
+  int fips;
+  int system;
+} rng_types;
+
+
 /* This is the lock we use to protect the buffer used by the nonce
    generation.  */
 static ath_mutex_t nonce_buffer_lock;
@@ -73,6 +82,55 @@ _gcry_random_progress (const char *what, int printchar, int current, int total)
 }
 
 
+/* Set the preferred RNG type.  This may be called at any time even
+   before gcry_check_version.  Thus we can't assume any thread system
+   initialization.  A type of 0 is used to indicate that any Libgcrypt
+   initialization has been done.*/
+void
+_gcry_set_preferred_rng_type (int type)
+{
+  static int any_init;
+
+  if (!type)
+    {
+      any_init = 1;
+    }
+  else if (type == GCRY_RNG_TYPE_STANDARD)
+    {
+      rng_types.standard = 1;
+    }
+  else if (any_init)
+    {
+      /* After any initialization has been done we only allow to
+         upgrade to the standard RNG (handled above).  All other
+         requests are ignored.  The idea is that the application needs
+         to declare a preference for a weaker RNG as soon as possible
+         and before any library sets a preference.  We assume that a
+         library which uses Libgcrypt calls an init function very
+         early.  This way --- even if the library gets initialized
+         early by the application --- it is unlikely that it can
+         select a lower priority RNG.
+
+         This scheme helps to ensure that existing unmodified
+         applications (e.g. gpg2), which don't known about the new RNG
+         selection system, will continue to use the standard RNG and
+         not be tricked by some library to use a lower priority RNG.
+         There are some loopholes here but at least most GnuPG stuff
+         should be save because it calls src_c{gcry_control
+         (GCRYCTL_SUSPEND_SECMEM_WARN);} quite early and thus inhibits
+         switching to a low priority RNG.
+       */
+    }
+  else if (type == GCRY_RNG_TYPE_FIPS)
+    {
+      rng_types.fips = 1;
+    }
+  else if (type == GCRY_RNG_TYPE_SYSTEM)
+    {
+      rng_types.system = 1;
+    }
+}
+
 
 /* Initialize this random subsystem.  If FULL is false, this function
    merely calls the basic initialization of the module and does not do
@@ -96,11 +154,39 @@ _gcry_random_initialize (int full)
 
   if (fips_mode ())
     _gcry_rngfips_initialize (full);
+  else if (rng_types.standard)
+    _gcry_rngcsprng_initialize (full);
+  else if (rng_types.fips)
+    _gcry_rngfips_initialize (full);
+  else if (rng_types.system)
+    _gcry_rngsystem_initialize (full);
   else
     _gcry_rngcsprng_initialize (full);
 }
 
 
+/* Return the current RNG type.  IGNORE_FIPS_MODE is a flag used to
+   skip the test for FIPS.  This is useful, so that we are able to
+   return the type of the RNG even before we have setup FIPS mode
+   (note that FIPS mode is enabled by default until it is switched off
+   by the initialization).  This is mostly useful for the regression
+   test.  */
+int
+_gcry_get_rng_type (int ignore_fips_mode)
+{
+  if (!ignore_fips_mode && fips_mode ())
+    return GCRY_RNG_TYPE_FIPS;
+  else if (rng_types.standard)
+    return GCRY_RNG_TYPE_STANDARD;
+  else if (rng_types.fips)
+    return GCRY_RNG_TYPE_FIPS;
+  else if (rng_types.system)
+    return GCRY_RNG_TYPE_SYSTEM;
+  else
+    return GCRY_RNG_TYPE_STANDARD;
+}
+
+
 void
 _gcry_random_dump_stats (void)
 {
@@ -178,7 +264,13 @@ gcry_random_add_bytes (const void *buf, size_t buflen, int quality)
 {
   if (fips_mode ())
     return 0; /* No need for this in fips mode.  */
-  else
+  else if (rng_types.standard)
+    return _gcry_rngcsprng_add_bytes (buf, buflen, quality);
+  else if (rng_types.fips)
+    return 0;
+  else if (rng_types.system)
+    return 0;
+  else /* default */
     return _gcry_rngcsprng_add_bytes (buf, buflen, quality);
 }
 
@@ -189,7 +281,13 @@ do_randomize (void *buffer, size_t length, enum gcry_random_level level)
 {
   if (fips_mode ())
     _gcry_rngfips_randomize (buffer, length, level);
-  else
+  else if (rng_types.standard)
+    _gcry_rngcsprng_randomize (buffer, length, level);
+  else if (rng_types.fips)
+    _gcry_rngfips_randomize (buffer, length, level);
+  else if (rng_types.system)
+    _gcry_rngsystem_randomize (buffer, length, level);
+  else /* default */
     _gcry_rngcsprng_randomize (buffer, length, level);
 }
 
@@ -244,7 +342,13 @@ _gcry_set_random_seed_file (const char *name)
 {
   if (fips_mode ())
     ; /* No need for this in fips mode.  */
-  else
+  else if (rng_types.standard)
+    _gcry_rngcsprng_set_seed_file (name);
+  else if (rng_types.fips)
+    ;
+  else if (rng_types.system)
+    ;
+  else /* default */
     _gcry_rngcsprng_set_seed_file (name);
 }
 
@@ -256,7 +360,13 @@ _gcry_update_random_seed_file (void)
 {
   if (fips_mode ())
     ; /* No need for this in fips mode.  */
-  else
+  else if (rng_types.standard)
+    _gcry_rngcsprng_update_seed_file ();
+  else if (rng_types.fips)
+    ;
+  else if (rng_types.system)
+    ;
+  else /* default */
     _gcry_rngcsprng_update_seed_file ();
 }
 
@@ -274,7 +384,13 @@ _gcry_fast_random_poll (void)
 {
   if (fips_mode ())
     ; /* No need for this in fips mode.  */
-  else
+  else if (rng_types.standard)
+    _gcry_rngcsprng_fast_poll ();
+  else if (rng_types.fips)
+    ;
+  else if (rng_types.system)
+    ;
+  else /* default */
     _gcry_rngcsprng_fast_poll ();
 }
 
diff --git a/random/random.h b/random/random.h
index 5f6a42c..aae07ab 100644
--- a/random/random.h
+++ b/random/random.h
@@ -26,7 +26,9 @@
 void _gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
                                      void *cb_data );
 
+void _gcry_set_preferred_rng_type (int type);
 void _gcry_random_initialize (int full);
+int  _gcry_get_rng_type (int ignore_fips_mode);
 void _gcry_random_dump_stats(void);
 void _gcry_secure_random_alloc(void);
 void _gcry_enable_quick_random_gen (void);
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 4d34567..dae8d1c 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -288,7 +288,9 @@ enum gcry_ctl_cmds
     GCRYCTL_SELFTEST = 57,
     /* Note: 58 .. 62 are used internally.  */
     GCRYCTL_DISABLE_HWF = 63,
-    GCRYCTL_SET_ENFORCED_FIPS_FLAG = 64
+    GCRYCTL_SET_ENFORCED_FIPS_FLAG = 64,
+    GCRYCTL_SET_PREFERRED_RNG_TYPE = 65,
+    GCRYCTL_GET_CURRENT_RNG_TYPE = 66
   };
 
 /* Perform various operations defined by CMD. */
@@ -1119,6 +1121,14 @@ gpg_error_t gcry_kdf_derive (const void *passphrase, size_t passphraselen,
  *                                  *
  ************************************/
 
+/* The type of the random number generator.  */
+enum gcry_rng_types
+  {
+    GCRY_RNG_TYPE_STANDARD   = 1, /* The default CSPRNG generator.  */
+    GCRY_RNG_TYPE_FIPS       = 2, /* The FIPS X9.31 AES generator.  */
+    GCRY_RNG_TYPE_SYSTEM     = 3  /* The system's native generator. */
+  };
+
 /* The possible values for the random quality.  The rule of thumb is
    to use STRONG for session keys and VERY_STRONG for key material.
    WEAK is usually an alias for STRONG and should not be used anymore
diff --git a/src/global.c b/src/global.c
index 4ce869a..f280a7b 100644
--- a/src/global.c
+++ b/src/global.c
@@ -1,6 +1,7 @@
 /* global.c  -	global control functions
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- *               2004, 2005, 2006, 2008, 2011  Free Software Foundation, Inc.
+ *               2004, 2005, 2006, 2008, 2011,
+ *               2012  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -101,6 +102,9 @@ global_init (void)
     return;
   any_init_done = 1;
 
+  /* Tell the random module that we have seen an init call.  */
+  _gcry_set_preferred_rng_type (0);
+
   /* Initialize our portable thread/mutex wrapper.  */
   err = ath_init ();
   if (err)
@@ -308,6 +312,21 @@ print_config ( int (*fnc)(FILE *fp, const char *format, ...), FILE *fp)
   fnc (fp, "fips-mode:%c:%c:\n",
        fips_mode ()? 'y':'n',
        _gcry_enforced_fips_mode ()? 'y':'n' );
+  /* The currently used RNG type.  */
+  {
+    const char *s;
+
+    i = _gcry_get_rng_type (0);
+    switch (i)
+      {
+      case GCRY_RNG_TYPE_STANDARD: s = "standard"; break;
+      case GCRY_RNG_TYPE_FIPS:     s = "fips"; break;
+      case GCRY_RNG_TYPE_SYSTEM:   s = "system"; break;
+      default: BUG ();
+      }
+    fnc (fp, "rng-type:%s:%d:\n", s, i);
+  }
+
 }
 
 
@@ -328,6 +347,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       break;
 
     case GCRYCTL_ENABLE_QUICK_RANDOM:
+      _gcry_set_preferred_rng_type (0);
       _gcry_enable_quick_random_gen ();
       break;
 
@@ -373,16 +393,19 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       break;
 
     case GCRYCTL_DISABLE_SECMEM_WARN:
+      _gcry_set_preferred_rng_type (0);
       _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
 			       | GCRY_SECMEM_FLAG_NO_WARNING));
       break;
 
     case GCRYCTL_SUSPEND_SECMEM_WARN:
+      _gcry_set_preferred_rng_type (0);
       _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
 			       | GCRY_SECMEM_FLAG_SUSPEND_WARNING));
       break;
 
     case GCRYCTL_RESUME_SECMEM_WARN:
+      _gcry_set_preferred_rng_type (0);
       _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
 			       & ~GCRY_SECMEM_FLAG_SUSPEND_WARNING));
       break;
@@ -393,15 +416,18 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       break;
 
     case GCRYCTL_SET_RANDOM_SEED_FILE:
+      _gcry_set_preferred_rng_type (0);
       _gcry_set_random_seed_file (va_arg (arg_ptr, const char *));
       break;
 
     case GCRYCTL_UPDATE_RANDOM_SEED_FILE:
+      _gcry_set_preferred_rng_type (0);
       if ( fips_is_operational () )
         _gcry_update_random_seed_file ();
       break;
 
     case GCRYCTL_SET_VERBOSITY:
+      _gcry_set_preferred_rng_type (0);
       _gcry_set_log_verbosity (va_arg (arg_ptr, int));
       break;
 
@@ -447,12 +473,14 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       break;
 
     case GCRYCTL_SET_THREAD_CBS:
+      _gcry_set_preferred_rng_type (0);
       err = ath_install (va_arg (arg_ptr, void *));
       if (!err)
 	global_init ();
       break;
 
     case GCRYCTL_FAST_POLL:
+      _gcry_set_preferred_rng_type (0);
       /* We need to do make sure that the random pool is really
          initialized so that the poll function is not a NOP. */
       _gcry_random_initialize (1);
@@ -463,6 +491,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
 
     case GCRYCTL_SET_RNDEGD_SOCKET:
 #if USE_RNDEGD
+      _gcry_set_preferred_rng_type (0);
       err = _gcry_rndegd_set_socket_name (va_arg (arg_ptr, const char *));
 #else
       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
@@ -470,12 +499,14 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       break;
 
     case GCRYCTL_SET_RANDOM_DAEMON_SOCKET:
+      _gcry_set_preferred_rng_type (0);
       _gcry_set_random_daemon_socket (va_arg (arg_ptr, const char *));
       break;
 
     case GCRYCTL_USE_RANDOM_DAEMON:
       /* We need to do make sure that the random pool is really
          initialized so that the poll function is not a NOP. */
+      _gcry_set_preferred_rng_type (0);
       _gcry_random_initialize (1);
       _gcry_use_random_daemon (!! va_arg (arg_ptr, int));
       break;
@@ -487,6 +518,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
     case GCRYCTL_PRINT_CONFIG:
       {
         FILE *fp = va_arg (arg_ptr, FILE *);
+        _gcry_set_preferred_rng_type (0);
         print_config (fp?fprintf:_gcry_log_info_with_dummy_fp, fp);
       }
       break;
@@ -494,6 +526,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
     case GCRYCTL_OPERATIONAL_P:
       /* Returns true if the library is in an operational state.  This
          is always true for non-fips mode.  */
+      _gcry_set_preferred_rng_type (0);
       if (_gcry_fips_test_operational ())
         err = GPG_ERR_GENERAL; /* Used as TRUE value */
       break;
@@ -510,6 +543,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
          the library has already been initialized into fips mode, a
          selftest is triggered.  It is not possible to put the libraty
          into fips mode after having passed the initialization. */
+      _gcry_set_preferred_rng_type (0);
       if (!any_init_done)
         {
           /* Not yet intialized at all.  Set a flag so that we are put
@@ -602,14 +636,34 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
     case GCRYCTL_SET_ENFORCED_FIPS_FLAG:
       if (!any_init_done)
         {
-          /* Not yet intialized at all.  Set the enforced fips mode flag */
+          /* Not yet initialized at all.  Set the enforced fips mode flag */
+          _gcry_set_preferred_rng_type (0);
           _gcry_set_enforced_fips_mode ();
         }
       else
         err = GPG_ERR_GENERAL;
       break;
 
+    case GCRYCTL_SET_PREFERRED_RNG_TYPE:
+      /* This may be called before gcry_check_version.  */
+      {
+        int i = va_arg (arg_ptr, int);
+        /* Note that we may not pass 0 to _gcry_set_preferred_rng_type.  */
+        if (i > 0)
+          _gcry_set_preferred_rng_type (i);
+      }
+      break;
+
+    case GCRYCTL_GET_CURRENT_RNG_TYPE:
+      {
+        int *ip = va_arg (arg_ptr, int*);
+        if (ip)
+          *ip = _gcry_get_rng_type (!any_init_done);
+      }
+      break;
+
     default:
+      _gcry_set_preferred_rng_type (0);
       /* A call to make sure that the dummy code is linked in.  */
       _gcry_compat_identification ();
       err = GPG_ERR_INV_OP;
diff --git a/tests/benchmark.c b/tests/benchmark.c
index 106e01b..61badd5 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -1151,6 +1151,23 @@ main( int argc, char **argv )
           use_random_daemon = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--prefer-standard-rng"))
+        {
+          /* This is anyway the default, but we may want to use it for
+             debugging. */
+          gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--prefer-fips-rng"))
+        {
+          gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--prefer-system-rng"))
+        {
+          gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--no-blinding"))
         {
           no_blinding = 1;
diff --git a/tests/random.c b/tests/random.c
index 3e25363..a46d754 100644
--- a/tests/random.c
+++ b/tests/random.c
@@ -32,7 +32,12 @@
 
 #include "../src/gcrypt.h"
 
+#define PGM "random"
+
+
 static int verbose;
+static int debug;
+static int with_progress;
 
 static void
 die (const char *format, ...)
@@ -40,6 +45,7 @@ die (const char *format, ...)
   va_list arg_ptr;
 
   va_start (arg_ptr, format);
+  fputs ( PGM ": ", stderr);
   vfprintf (stderr, format, arg_ptr);
   va_end (arg_ptr);
   exit (1);
@@ -52,6 +58,7 @@ inf (const char *format, ...)
   va_list arg_ptr;
 
   va_start (arg_ptr, format);
+  fputs ( PGM ": ", stderr);
   vfprintf (stderr, format, arg_ptr);
   va_end (arg_ptr);
 }
@@ -62,13 +69,25 @@ print_hex (const char *text, const void *buf, size_t n)
 {
   const unsigned char *p = buf;
 
-  fputs (text, stdout);
+  inf ("%s", text);
   for (; n; n--, p++)
-    printf ("%02X", *p);
-  putchar ('\n');
+    fprintf (stderr, "%02X", *p);
+  putc ('\n', stderr);
+}
+
+
+static void
+progress_cb (void *cb_data, const char *what, int printchar,
+             int current, int total)
+{
+  (void)cb_data;
+
+  inf ("progress (%s %c %d %d)\n", what, printchar, current, total);
+  fflush (stderr);
 }
 
 
+
 static int
 writen (int fd, const void *buf, size_t nbytes)
 {
@@ -251,34 +270,270 @@ check_nonce_forking (void)
 }
 
 
+static int
+rng_type (void)
+{
+  int rngtype;
+  if (gcry_control (GCRYCTL_GET_CURRENT_RNG_TYPE, &rngtype))
+    die ("retrieving RNG type failed\n");
+  return rngtype;
+}
+
+
+static void
+check_rng_type_switching (void)
+{
+  int rngtype, initial;
+  char tmp1[4];
+
+  if (verbose)
+    inf ("checking whether RNG type switching works\n");
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  initial = rngtype;
+  gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+  if (debug)
+    print_hex ("  sample: ", tmp1, sizeof tmp1);
+  if (rngtype != rng_type ())
+    die ("RNG type unexpectedly changed\n");
+
+  gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  if (rngtype != initial)
+    die ("switching to System RNG unexpectedly succeeded\n");
+  gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+  if (debug)
+    print_hex ("  sample: ", tmp1, sizeof tmp1);
+  if (rngtype != rng_type ())
+    die ("RNG type unexpectedly changed\n");
+
+  gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  if (rngtype != initial)
+    die ("switching to FIPS RNG unexpectedly succeeded\n");
+  gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+  if (debug)
+    print_hex ("  sample: ", tmp1, sizeof tmp1);
+  if (rngtype != rng_type ())
+    die ("RNG type unexpectedly changed\n");
+
+  gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  if (rngtype != GCRY_RNG_TYPE_STANDARD)
+    die ("switching to standard RNG failed\n");
+  gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+  if (debug)
+    print_hex ("  sample: ", tmp1, sizeof tmp1);
+  if (rngtype != rng_type ())
+    die ("RNG type unexpectedly changed\n");
+}
+
+
+static void
+check_early_rng_type_switching (void)
+{
+  int rngtype, initial;
+
+  if (verbose)
+    inf ("checking whether RNG type switching works in the early stage\n");
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  initial = rngtype;
+
+  gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  if (initial >= GCRY_RNG_TYPE_SYSTEM && rngtype != GCRY_RNG_TYPE_SYSTEM)
+    die ("switching to System RNG failed\n");
+
+  gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  if (initial >= GCRY_RNG_TYPE_FIPS && rngtype != GCRY_RNG_TYPE_FIPS)
+    die ("switching to FIPS RNG failed\n");
+
+  gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+
+  rngtype = rng_type ();
+  if (debug)
+    inf ("rng type: %d\n", rngtype);
+  if (rngtype != GCRY_RNG_TYPE_STANDARD)
+    die ("switching to standard RNG failed\n");
+}
 
 
+/* Because we want to check initialization behaviour, we need to
+   fork/exec this program with several command line arguments.  We use
+   system, so that these tests work also on Windows.  */
+static void
+run_all_rng_tests (const char *program)
+{
+  static const char *options[] = {
+    "--early-rng-check",
+    "--early-rng-check --prefer-standard-rng",
+    "--early-rng-check --prefer-fips-rng",
+    "--early-rng-check --prefer-system-rng",
+    "--prefer-standard-rng",
+    "--prefer-fips-rng",
+    "--prefer-system-rng",
+    NULL
+  };
+  int idx;
+  size_t len, maxlen;
+  char *cmdline;
+
+  maxlen = 0;
+  for (idx=0; options[idx]; idx++)
+    {
+      len = strlen (options[idx]);
+      if (len > maxlen)
+        maxlen = len;
+    }
+  maxlen += strlen (program);
+  maxlen += strlen (" --in-recursion --verbose --debug --progress");
+  maxlen++;
+  cmdline = malloc (maxlen + 1);
+  if (!cmdline)
+    die ("out of core\n");
+
+  for (idx=0; options[idx]; idx++)
+    {
+      if (verbose)
+        inf ("now running with options '%s'\n", options[idx]);
+      strcpy (cmdline, program);
+      strcat (cmdline, " --in-recursion");
+      if (verbose)
+        strcat (cmdline, " --verbose");
+      if (debug)
+        strcat (cmdline, " --debug");
+      if (with_progress)
+        strcat (cmdline, " --progress");
+      strcat (cmdline, " ");
+      strcat (cmdline, options[idx]);
+      if (system (cmdline))
+        die ("running '%s' failed\n", cmdline);
+    }
 
+  free (cmdline);
+}
 
 int
 main (int argc, char **argv)
 {
-  int debug = 0;
+  int last_argc = -1;
+  int early_rng = 0;
+  int in_recursion = 0;
+  const char *program = NULL;
+
+  if (argc)
+    {
+      program = *argv;
+      argc--; argv++;
+    }
+  else
+    die ("argv[0] missing\n");
 
-  if ((argc > 1) && (! strcmp (argv[1], "--verbose")))
-    verbose = 1;
-  else if ((argc > 1) && (! strcmp (argv[1], "--debug")))
-    verbose = debug = 1;
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: random [options]\n", stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          debug = verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--progress"))
+        {
+          argc--; argv++;
+          with_progress = 1;
+        }
+      else if (!strcmp (*argv, "--in-recursion"))
+        {
+          in_recursion = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--early-rng-check"))
+        {
+          early_rng = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--prefer-standard-rng"))
+        {
+          /* This is anyway the default, but we may want to use it for
+             debugging. */
+          gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--prefer-fips-rng"))
+        {
+          gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--prefer-system-rng"))
+        {
+          gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+          argc--; argv++;
+        }
+    }
 
 #ifndef HAVE_W32_SYSTEM
   signal (SIGPIPE, SIG_IGN);
 #endif
 
+  if (early_rng)
+    check_early_rng_type_switching ();
+
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
 
+  if (with_progress)
+    gcry_set_progress_handler (progress_cb, NULL);
+
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
 
-  check_forking ();
-  check_nonce_forking ();
+  if (!in_recursion)
+    {
+      check_forking ();
+      check_nonce_forking ();
+    }
+  check_rng_type_switching ();
+
+  if (!in_recursion)
+    run_all_rng_tests (program);
 
   return 0;
 }

commit f17e4d920c8a18007a98830dd13163ff19616202
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Dec 3 20:17:48 2012 +0100

    Update the copyright years.
    
    --

diff --git a/README b/README
index bbbd0db..1778951 100644
--- a/README
+++ b/README
@@ -5,7 +5,7 @@
             !!! THIS IS A DEVELOPMENT VERSION VERSION !!!
 
     Copyright 2000, 2002, 2003, 2004, 2007, 2008, 2009,
-              2011 Free Software Foundation, Inc.
+              2011, 2012 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/compat/compat.c b/compat/compat.c
index e2a0393..96889d3 100644
--- a/compat/compat.c
+++ b/compat/compat.c
@@ -29,7 +29,7 @@ _gcry_compat_identification (void)
     "\n\n"
     "This is Libgcrypt " PACKAGE_VERSION " - The GNU Crypto Library\n"
     "Copyright 2000, 2002, 2003, 2004, 2007, 2008, 2009,\n"
-    "          2010, 2011 Free Software Foundation, Inc.\n"
+    "          2010, 2011, 2012 Free Software Foundation, Inc.\n"
     "\n\n";
   return blurb;
 }
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 3bd2686..66a05d5 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -12,7 +12,8 @@ This manual is for Libgcrypt
 (version @value{VERSION}, @value{UPDATED}),
 which is GNU's library of cryptographic building blocks.
 
-Copyright @copyright{} 2000, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
+Copyright @copyright{} 2000, 2002, 2003, 2004, 2006, 2007, 2008, 2009,
+2011, 2012 Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 1e9d11d..4d34567 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1,23 +1,25 @@
 /* gcrypt.h -  GNU Cryptographic Library Interface              -*- c -*-
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
-                 2007, 2008, 2009, 2010, 2011  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
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   Libgcrypt is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   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, see <http://www.gnu.org/licenses/>.
-
-   File: @configure_input@ */
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ *               2006, 2007, 2008, 2009, 2010, 2011,
+ *               2012  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
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * File: @configure_input@
+ */
 
 #ifndef _GCRYPT_H
 #define _GCRYPT_H

commit 76c622e24a07f7c826812be173aa173b4334776b
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Dec 3 16:18:56 2012 +0100

    tests: Allow use of random.c under Windows.
    
    * tests/Makefile.am (TESTS): Always include random.c
    * tests/random.c [!W32]: Include sys/wait.h.
    (inf): New.
    (check_forking, check_nonce_forking): Print a notice what will be done.
    (main) [W32]: Do not call signal.
    --
    
    This change help to run future tests under Windows.  The current two
    tests are not applicable to Windows.

diff --git a/tests/Makefile.am b/tests/Makefile.am
index f1f9e6f..d337840 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,14 +20,9 @@
 
 TESTS = version t-mpi-bit prime basic \
         mpitests tsexp keygen pubkey hmac keygrip fips186-dsa aeswrap \
-	curves t-kdf pkcs1v2
+	curves t-kdf pkcs1v2 random
 
 
-# random.c uses fork() thus a test for W32 does not make any sense.
-if !HAVE_W32_SYSTEM
-TESTS += random
-endif
-
 # The last test to run.
 TESTS += benchmark
 
diff --git a/tests/random.c b/tests/random.c
index a243529..3e25363 100644
--- a/tests/random.c
+++ b/tests/random.c
@@ -24,9 +24,11 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/wait.h>
+#ifndef HAVE_W32_SYSTEM
+# include <signal.h>
+# include <unistd.h>
+# include <sys/wait.h>
+#endif
 
 #include "../src/gcrypt.h"
 
@@ -45,6 +47,17 @@ die (const char *format, ...)
 
 
 static void
+inf (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+}
+
+
+static void
 print_hex (const char *text, const void *buf, size_t n)
 {
   const unsigned char *p = buf;
@@ -111,12 +124,19 @@ readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
 static void
 check_forking (void)
 {
+#ifdef HAVE_W32_SYSTEM
+  if (verbose)
+    inf ("check_forking skipped: not applicable on Windows\n");
+#else /*!HAVE_W32_SYSTEM*/
   pid_t pid;
   int rp[2];
   int i, status;
   size_t nread;
   char tmp1[16], tmp1c[16], tmp1p[16];
 
+  if (verbose)
+    inf ("checking that a fork won't cause the same random output\n");
+
   /* We better make sure that the RNG has been initialzied. */
   gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
   if (verbose)
@@ -160,6 +180,7 @@ check_forking (void)
 
   if (!memcmp (tmp1p, tmp1c, sizeof tmp1c))
     die ("parent and child got the same random number\n");
+#endif  /*!HAVE_W32_SYSTEM*/
 }
 
 
@@ -168,12 +189,19 @@ check_forking (void)
 static void
 check_nonce_forking (void)
 {
+#ifdef HAVE_W32_SYSTEM
+  if (verbose)
+    inf ("check_nonce_forking skipped: not applicable on Windows\n");
+#else /*!HAVE_W32_SYSTEM*/
   pid_t pid;
   int rp[2];
   int i, status;
   size_t nread;
   char nonce1[10], nonce1c[10], nonce1p[10];
 
+  if (verbose)
+    inf ("checking that a fork won't cause the same nonce output\n");
+
   /* We won't get the same nonce back if we never initialized the
      nonce subsystem, thus we get one nonce here and forget about
      it. */
@@ -219,6 +247,7 @@ check_nonce_forking (void)
 
   if (!memcmp (nonce1p, nonce1c, sizeof nonce1c))
     die ("parent and child got the same nonce\n");
+#endif  /*!HAVE_W32_SYSTEM*/
 }
 
 
@@ -236,7 +265,9 @@ main (int argc, char **argv)
   else if ((argc > 1) && (! strcmp (argv[1], "--debug")))
     verbose = debug = 1;
 
+#ifndef HAVE_W32_SYSTEM
   signal (SIGPIPE, SIG_IGN);
+#endif
 
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   if (!gcry_check_version (GCRYPT_VERSION))

commit 75760021b511ba438606af746431223357e7a155
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Dec 3 15:15:49 2012 +0100

    Make random-fips.c work multi-threaded.
    
    * random/random-fips.c (basic_initialization): Fix reversed logic.
    --
    
    The module never initialized the mutex at all.  Probably this was never
    an issue before commit 38fcd59 which removed static lock init.

diff --git a/random/random-fips.c b/random/random-fips.c
index e0ae968..7f205d2 100644
--- a/random/random-fips.c
+++ b/random/random-fips.c
@@ -192,7 +192,7 @@ basic_initialization (void)
   static int initialized;
   int my_errno;
 
-  if (!initialized)
+  if (initialized)
     return;
   initialized = 1;
 

commit c324644aa14e54fc7051983b38222db32b8ab227
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Nov 30 18:16:34 2012 +0100

    Move nonce creation from csprng backend to random main module.
    
    * random/random-csprng.c (_gcry_rngcsprng_create_nonce): Remove.
    (nonce_buffer_lock): Remove.
    (initialize_basics): Remove init of nonce_buffer_lock.
    * random/random.c: Add a few header files.
    (nonce_buffer_lock):  New.
    (_gcry_random_initialize): Init nonce_buffer_lock.
    (gcry_create_nonce): Add code from _gcry_rngcsprng_create_nonce.
    
    * random/random-daemon.c (_gcry_daemon_create_nonce): Remove.
    --
    
    The nonce generation code is useful for all RNG types and thus it
    should be in random.c.  The only exception is the fips-mode, which
    requires the use of the fips nonce generator.

diff --git a/random/rand-internal.h b/random/rand-internal.h
index a04a2d4..a72d88c 100644
--- a/random/rand-internal.h
+++ b/random/rand-internal.h
@@ -61,18 +61,13 @@ void _gcry_rngcsprng_randomize (void *buffer, size_t length,
 void _gcry_rngcsprng_set_seed_file (const char *name);
 void _gcry_rngcsprng_update_seed_file (void);
 void _gcry_rngcsprng_fast_poll (void);
-void _gcry_rngcsprng_create_nonce (void *buffer, size_t length);
 
-/*-- random-rngcsprng.c --*/
+/*-- random-fips.c --*/
 void _gcry_rngfips_initialize (int full);
 void _gcry_rngfips_dump_stats (void);
 int  _gcry_rngfips_is_faked (void);
 gcry_error_t _gcry_rngfips_add_bytes (const void *buf, size_t buflen,
                                         int quality);
-void *_gcry_rngfips_get_bytes (size_t nbytes,
-                               enum gcry_random_level level);
-void *_gcry_rngfips_get_bytes_secure (size_t nbytes,
-                                      enum gcry_random_level level);
 void _gcry_rngfips_randomize (void *buffer, size_t length,
                                 enum gcry_random_level level);
 void _gcry_rngfips_create_nonce (void *buffer, size_t length);
diff --git a/random/random-csprng.c b/random/random-csprng.c
index 50357d1..9921c4f 100644
--- a/random/random-csprng.c
+++ b/random/random-csprng.c
@@ -1,6 +1,6 @@
 /* random-csprng.c - CSPRNG style random number generator (libgcrypt classic)
  * Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- *               2007, 2008, 2010  Free Software Foundation, Inc.
+ *               2007, 2008, 2010, 2012  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -189,10 +189,6 @@ static ath_mutex_t pool_lock;
    test suite.  */
 static int pool_is_locked;
 
-/* This is the lock we use to protect the buffer used by the nonce
-   generation.  */
-static ath_mutex_t nonce_buffer_lock;
-
 
 /* We keep some counters in this structure for the sake of the
    _gcry_random_dump_stats () function.  */
@@ -272,11 +268,6 @@ initialize_basics(void)
       if (err)
         log_fatal ("failed to create the pool lock: %s\n", strerror (err) );
 
-      err = ath_mutex_init (&nonce_buffer_lock);
-      if (err)
-        log_fatal ("failed to create the nonce buffer lock: %s\n",
-                   strerror (err) );
-
 #ifdef USE_RANDOM_DAEMON
       _gcry_daemon_initialize_basics ();
 #endif /*USE_RANDOM_DAEMON*/
@@ -1320,89 +1311,3 @@ gather_faked (void (*add)(const void*, size_t, enum random_origins),
   gcry_free (buffer);
   return 0; /* okay */
 }
-
-
-/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
-void
-_gcry_rngcsprng_create_nonce (void *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. */
-  volatile pid_t apid;
-  unsigned char *p;
-  size_t n;
-  int err;
-
-  /* Make sure we are initialized. */
-  initialize ();
-
-#ifdef USE_RANDOM_DAEMON
-  if (allow_daemon
-      && !_gcry_daemon_create_nonce (daemon_socket_name, buffer, length))
-    return; /* The daemon succeeded. */
-  allow_daemon = 0; /* Daemon failed - switch off. */
-#endif /*USE_RANDOM_DAEMON*/
-
-  /* Acquire the nonce buffer lock. */
-  err = ath_mutex_lock (&nonce_buffer_lock);
-  if (err)
-    log_fatal ("failed to acquire the nonce buffer lock: %s\n",
-               strerror (err));
-
-  apid = getpid ();
-  /* The first time initialize our buffer. */
-  if (!nonce_buffer_initialized)
-    {
-      time_t atime = time (NULL);
-      pid_t xpid = apid;
-
-      my_pid = apid;
-
-      if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
-        BUG ();
-
-      /* Initialize the first 20 bytes with a reasonable value so that
-         a failure of gcry_randomize won't affect us too much.  Don't
-         care about the uninitialized remaining bytes. */
-      p = nonce_buffer;
-      memcpy (p, &xpid, sizeof xpid);
-      p += sizeof xpid;
-      memcpy (p, &atime, sizeof atime);
-
-      /* Initialize the never changing private part of 64 bits. */
-      gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
-
-      nonce_buffer_initialized = 1;
-    }
-  else if ( my_pid != apid )
-    {
-      /* 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);
-      /* Update the pid so that we won't run into here again and
-         again. */
-      my_pid = apid;
-    }
-
-  /* Create the nonce by hashing the entire buffer, returning the hash
-     and updating the first 20 bytes of the buffer with this hash. */
-  for (p = buffer; length > 0; length -= n, p += n)
-    {
-      _gcry_sha1_hash_buffer (nonce_buffer,
-                              nonce_buffer, sizeof nonce_buffer);
-      n = length > 20? 20 : length;
-      memcpy (p, nonce_buffer, n);
-    }
-
-
-  /* Release the nonce buffer lock. */
-  err = ath_mutex_unlock (&nonce_buffer_lock);
-  if (err)
-    log_fatal ("failed to release the nonce buffer lock: %s\n",
-               strerror (err));
-
-}
diff --git a/random/random-daemon.c b/random/random-daemon.c
index 9422e85..26d77f8 100644
--- a/random/random-daemon.c
+++ b/random/random-daemon.c
@@ -345,17 +345,4 @@ _gcry_daemon_randomize (const char *socketname,
   return err ? -1 : 0;
 }
 
-
-/* Internal function to fill BUFFER with NBYTES of data usable for a
-   nonce.  Returns 0 on success. */
-int
-_gcry_daemon_create_nonce (const char *socketname, void *buffer, size_t length)
-{
-  gcry_error_t err;
-
-  err = call_daemon (socketname, buffer, length, 1, 0);
-
-  return err ? -1 : 0;
-}
-
 /* END */
diff --git a/random/random.c b/random/random.c
index 40661ab..9a5b166 100644
--- a/random/random.c
+++ b/random/random.c
@@ -1,5 +1,5 @@
 /* random.c - Random number switch
- * Copyright (C) 2008  Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2006, 2008, 2012  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -26,10 +26,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "g10lib.h"
 #include "random.h"
 #include "rand-internal.h"
+#include "cipher.h"         /* For _gcry_sha1_hash_buffer().  */
 #include "ath.h"
 
 
@@ -39,6 +43,9 @@
 static void (*progress_cb) (void *,const char*,int,int, int );
 static void *progress_cb_data;
 
+/* This is the lock we use to protect the buffer used by the nonce
+   generation.  */
+static ath_mutex_t nonce_buffer_lock;
 
 
 
@@ -75,6 +82,18 @@ _gcry_random_progress (const char *what, int printchar, int current, int total)
 void
 _gcry_random_initialize (int full)
 {
+  static int nonce_initialized;
+  int err;
+
+  if (!nonce_initialized)
+    {
+      nonce_initialized = 1;
+      err = ath_mutex_init (&nonce_buffer_lock);
+      if (err)
+        log_fatal ("failed to create the nonce buffer lock: %s\n",
+                   strerror (err) );
+    }
+
   if (fips_mode ())
     _gcry_rngfips_initialize (full);
   else
@@ -265,10 +284,90 @@ _gcry_fast_random_poll (void)
 void
 gcry_create_nonce (void *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. */
+  volatile pid_t apid;
+  unsigned char *p;
+  size_t n;
+  int err;
+
+  /* First check whether we shall use the FIPS nonce generator.  This
+     is only done in FIPS mode, in all other modes, we use our own
+     nonce generator which is seeded by the RNG actual in use.  */
   if (fips_mode ())
-    _gcry_rngfips_create_nonce (buffer, length);
-  else
-    _gcry_rngcsprng_create_nonce (buffer, length);
+    {
+      _gcry_rngfips_create_nonce (buffer, length);
+      return;
+    }
+
+  /* This is the nonce generator, which formerly lived in
+     random-csprng.c.  It is now used by all RNG types except when in
+     FIPS mode (not that this means it is also used if the FIPS RNG
+     has been selected but we are not in fips mode).  */
+
+  /* Make sure we are initialized. */
+  _gcry_random_initialize (1);
+
+  /* Acquire the nonce buffer lock. */
+  err = ath_mutex_lock (&nonce_buffer_lock);
+  if (err)
+    log_fatal ("failed to acquire the nonce buffer lock: %s\n",
+               strerror (err));
+
+  apid = getpid ();
+  /* The first time initialize our buffer. */
+  if (!nonce_buffer_initialized)
+    {
+      time_t atime = time (NULL);
+      pid_t xpid = apid;
+
+      my_pid = apid;
+
+      if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
+        BUG ();
+
+      /* Initialize the first 20 bytes with a reasonable value so that
+         a failure of gcry_randomize won't affect us too much.  Don't
+         care about the uninitialized remaining bytes. */
+      p = nonce_buffer;
+      memcpy (p, &xpid, sizeof xpid);
+      p += sizeof xpid;
+      memcpy (p, &atime, sizeof atime);
+
+      /* Initialize the never changing private part of 64 bits. */
+      gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
+
+      nonce_buffer_initialized = 1;
+    }
+  else if ( my_pid != apid )
+    {
+      /* We forked. Need to reseed the buffer - doing this for the
+         private part should be sufficient. */
+      do_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
+      /* Update the pid so that we won't run into here again and
+         again. */
+      my_pid = apid;
+    }
+
+  /* Create the nonce by hashing the entire buffer, returning the hash
+     and updating the first 20 bytes of the buffer with this hash. */
+  for (p = buffer; length > 0; length -= n, p += n)
+    {
+      _gcry_sha1_hash_buffer (nonce_buffer,
+                              nonce_buffer, sizeof nonce_buffer);
+      n = length > 20? 20 : length;
+      memcpy (p, nonce_buffer, n);
+    }
+
+  /* Release the nonce buffer lock. */
+  err = ath_mutex_unlock (&nonce_buffer_lock);
+  if (err)
+    log_fatal ("failed to release the nonce buffer lock: %s\n",
+               strerror (err));
 }
 
 
diff --git a/random/random.h b/random/random.h
index 7a9585c..5f6a42c 100644
--- a/random/random.h
+++ b/random/random.h
@@ -61,8 +61,6 @@ void _gcry_daemon_initialize_basics (void);
 int _gcry_daemon_randomize (const char *socketname,
                             void *buffer, size_t length,
                             enum gcry_random_level level);
-int _gcry_daemon_create_nonce (const char *socketname,
-                               void *buffer, size_t length);
 #endif /*USE_RANDOM_DAEMON*/
 
 #endif /*G10_RANDOM_H*/

-----------------------------------------------------------------------

Summary of changes:
 NEWS                   |   10 ++-
 README                 |    2 +-
 compat/compat.c        |    2 +-
 doc/gcrypt.texi        |   34 +++++-
 random/Makefile.am     |    1 +
 random/rand-internal.h |   15 ++-
 random/random-csprng.c |   97 +---------------
 random/random-daemon.c |   13 --
 random/random-fips.c   |    2 +-
 random/random-system.c |  243 +++++++++++++++++++++++++++++++++++++
 random/random.c        |  233 ++++++++++++++++++++++++++++++++++--
 random/random.h        |    4 +-
 src/gcrypt.h.in        |   52 +++++---
 src/global.c           |   58 +++++++++-
 tests/Makefile.am      |    7 +-
 tests/benchmark.c      |   17 +++
 tests/random.c         |  312 ++++++++++++++++++++++++++++++++++++++++++++++--
 17 files changed, 930 insertions(+), 172 deletions(-)
 create mode 100644 random/random-system.c


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org




More information about the Gnupg-commits mailing list