Remove macro hacks for internal vs. external functions. Part 1.
[libgcrypt.git] / random / random-fips.c
index 077679d..c8100a2 100644 (file)
    The core of this deterministic random number generator is
    implemented according to the 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) and uses the AES
-   variant.
-
+   Triple DES and AES Algorithms" (2005-01-31).  This implementation
+   uses the AES variant.
+
+   There are 3 random context which map to the different levels of
+   random quality:
+
+   Generator                Seed and Key        Kernel entropy (init/reseed)
+   ------------------------------------------------------------
+   GCRY_VERY_STRONG_RANDOM  /dev/random         256/128 bits
+   GCRY_STRONG_RANDOM       /dev/random         256/128 bits
+   gcry_create_nonce        GCRY_STRONG_RANDOM  n/a
+
+   All random generators return their data in 128 bit blocks.  If the
+   caller requested less bits, the extra bits are not used.  The key
+   for each generator is only set once at the first time a generator
+   is used.  The seed value is set with the key and again after 1000
+   (SEED_TTL) output blocks; the re-seeding is disabled in test mode.
+
+   The GCRY_VERY_STRONG_RANDOM and GCRY_STRONG_RANDOM generators are
+   keyed and seeded from the /dev/random device.  Thus these
+   generators may block until the kernel has collected enough entropy.
+
+   The gcry_create_nonce generator is keyed and seeded from the
+   GCRY_STRONG_RANDOM generator.  It may also block if the
+   GCRY_STRONG_RANDOM generator has not yet been used before and thus
+   gets initialized on the first use by gcry_create_nonce.  This
+   special treatment is justified by the weaker requirements for a
+   nonce generator and to save precious kernel entropy for use by the
+   real random generators.
 
  */
 
@@ -46,7 +72,7 @@
    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 fips_rng_lock = ATH_MUTEX_INITIALIZER;
+static ath_mutex_t fips_rng_lock;
 static int fips_rng_is_locked;
 
 
@@ -61,6 +87,11 @@ static int fips_rng_is_locked;
 static unsigned char *tempvalue_for_x931_aes_driver;
 
 
+/* After having retrieved this number of blocks from the RNG, we want
+   to do a reseeding.  */
+#define SEED_TTL 1000
+
+
 /* The length of the key we use:  16 bytes (128 bit) for AES128.  */
 #define X931_AES_KEYLEN  16
 /* A global buffer used to communicate between the x931_generate_key
@@ -85,10 +116,6 @@ struct rng_context
      established.  */
   gcry_cipher_hd_t cipher_hd;
 
-  /* If this flag is true, this context requires strong entropy;
-     i.e. from /dev/random.  */
-  int need_strong_entropy:1;
-
   /* If this flag is true, the SEED_V buffer below carries a valid
      seed.  */
   int is_seeded:1;
@@ -98,6 +125,9 @@ struct rng_context
      is available.  */
   int compare_value_valid:1;
 
+  /* A counter used to trigger re-seeding.  */
+  unsigned int use_counter;
+
   unsigned char guard_1[1];
 
   /* The buffer containing the seed value V.  */
@@ -105,18 +135,31 @@ struct rng_context
 
   unsigned char guard_2[1];
 
-  /* The last result from the x931_aes fucntion.  Only valid if
+  /* The last result from the x931_aes function.  Only valid if
      compare_value_valid is set.  */
   unsigned char compare_value[16];
 
   unsigned char guard_3[1];
 
+  /* The external test may want to suppress the duplicate bock check.
+     This is done if the this flag is set.  */
+  unsigned char test_no_dup_check;
+  /* To implement a KAT we need to provide a know DT value.  To
+     accomplish this the x931_get_dt function checks whether this
+     field is not NULL and then uses the 16 bytes at this address for
+     the DT value.  However the last 4 bytes are replaced by the
+     value of field TEST_DT_COUNTER which will be incremented after
+     each invocation of x931_get_dt. We use a pointer and not a buffer
+     because there is no need to put this value into secure memory.  */
+  const unsigned char *test_dt_ptr;
+  u32 test_dt_counter;
+
   /* We need to keep track of the process which did the initialization
      so that we can detect a fork.  The volatile modifier is required
      so that the compiler does not optimize it away in case the getpid
-     function is badly attributed.  */ 
-   pid_t key_init_pid;
-   pid_t seed_init_pid;
+     function is badly attributed.  */
+  pid_t key_init_pid;
+  pid_t seed_init_pid;
 };
 typedef struct rng_context *rng_context_t;
 
@@ -132,6 +175,11 @@ static rng_context_t std_rng_context;
 static rng_context_t strong_rng_context;
 
 
+/* --- Local prototypes ---  */
+static void x931_reseed (rng_context_t rng_ctx);
+static void get_random (void *buffer, size_t length, rng_context_t rng_ctx);
+
+
 
 \f
 /* --- Functions  --- */
@@ -144,7 +192,7 @@ basic_initialization (void)
   static int initialized;
   int my_errno;
 
-  if (!initialized)
+  if (initialized)
     return;
   initialized = 1;
 
@@ -152,10 +200,10 @@ basic_initialization (void)
   if (my_errno)
     log_fatal ("failed to create the RNG lock: %s\n", strerror (my_errno));
   fips_rng_is_locked = 0;
-      
+
   /* Make sure that we are still using the values we have
      traditionally used for the random levels.  */
-  gcry_assert (GCRY_WEAK_RANDOM == 0 
+  gcry_assert (GCRY_WEAK_RANDOM == 0
                && GCRY_STRONG_RANDOM == 1
                && GCRY_VERY_STRONG_RANDOM == 2);
 
@@ -210,11 +258,11 @@ check_guards (rng_context_t rng_ctx)
 
 /* Get the DT vector for use with the core PRNG function.  Buffer
    needs to be provided by the caller with a size of at least LENGTH
-   bytes.  The 16 byte timestamp we construct is made up the real time
-   and three counters:
+   bytes. RNG_CTX needs to be passed to allow for a KAT.  The 16 byte
+   timestamp we construct is made up the real time and three counters:
 
    Buffer:       00112233445566778899AABBCCDDEEFF
-                 !--+---!!-+-!!+!!--+---!!--+---!     
+                 !--+---!!-+-!!+!!--+---!!--+---!
    seconds ---------/      |   |    |       |
    microseconds -----------/   |    |       |
    counter2 -------------------/    |       |
@@ -224,18 +272,36 @@ check_guards (rng_context_t rng_ctx)
    Counter 2 is just 12 bits wide and used to track fractions of
    milliseconds whereas counters 1 and 0 are combined to a free
    running 64 bit counter.  */
-static void 
-x931_get_dt (unsigned char *buffer, size_t length)
+static void
+x931_get_dt (unsigned char *buffer, size_t length, rng_context_t rng_ctx)
 {
   gcry_assert (length == 16); /* This length is required for use with AES.  */
   gcry_assert (fips_rng_is_locked);
 
+  /* If the random context indicates that a test DT should be used,
+     take the DT value from the context.  For safety reasons we do
+     this only if the context is not one of the regular contexts.  */
+  if (rng_ctx->test_dt_ptr
+      && rng_ctx != nonce_context
+      && rng_ctx != std_rng_context
+      && rng_ctx != strong_rng_context)
+    {
+      memcpy (buffer, rng_ctx->test_dt_ptr, 16);
+      buffer[12] = (rng_ctx->test_dt_counter >> 24);
+      buffer[13] = (rng_ctx->test_dt_counter >> 16);
+      buffer[14] = (rng_ctx->test_dt_counter >> 8);
+      buffer[15] = rng_ctx->test_dt_counter;
+      rng_ctx->test_dt_counter++;
+      return;
+    }
+
+
 #if HAVE_GETTIMEOFDAY
   {
     static u32 last_sec, last_usec;
     static u32 counter1, counter0;
     static u16 counter2;
-    
+
     unsigned int usec;
     struct timeval tv;
 
@@ -245,7 +311,9 @@ x931_get_dt (unsigned char *buffer, size_t length)
            to an not so easy predictable value to avoid always
            starting at 0.  Not really needed but it doesn't harm.  */
         counter1 = (u32)getpid ();
+#ifndef HAVE_W32_SYSTEM
         counter0 = (u32)getppid ();
+#endif
       }
 
 
@@ -282,11 +350,11 @@ x931_get_dt (unsigned char *buffer, size_t length)
     /* Add the free running counter.  */
     buffer[8]  = ((counter1 >> 24) & 0xff);
     buffer[9]  = ((counter1 >> 16) & 0xff);
-    buffer[10] = ((counter1 >> 8) & 0xff); 
+    buffer[10] = ((counter1 >> 8) & 0xff);
     buffer[11] = ((counter1) & 0xff);
     buffer[12] = ((counter0 >> 24) & 0xff);
     buffer[13] = ((counter0 >> 16) & 0xff);
-    buffer[14] = ((counter0 >> 8) & 0xff); 
+    buffer[14] = ((counter0 >> 8) & 0xff);
     buffer[15] = ((counter0) & 0xff);
     /* Bump up that counter.  */
     if (!++counter0)
@@ -304,7 +372,7 @@ x931_get_dt (unsigned char *buffer, size_t length)
    the result at R.  R needs to be provided by the caller with a size
    of at least LENGTH bytes.  */
 static void
-xor_buffer (unsigned char *r, 
+xor_buffer (unsigned char *r,
             const unsigned char *a, const unsigned char *b, size_t length)
 {
   for ( ; length; length--, a++, b++, r++)
@@ -315,43 +383,41 @@ xor_buffer (unsigned char *r,
 /* Encrypt LENGTH bytes of INPUT to OUTPUT using KEY.  LENGTH
    needs to be 16. */
 static void
-encrypt_aes (gcry_cipher_hd_t key, 
+encrypt_aes (gcry_cipher_hd_t key,
              unsigned char *output, const unsigned char *input, size_t length)
 {
   gpg_error_t err;
 
   gcry_assert (length == 16);
 
-  err = gcry_cipher_encrypt (key, output, length, input, length);
+  err = _gcry_cipher_encrypt (key, output, length, input, length);
   if (err)
-    log_fatal ("AES encryption in RNG failed: %s\n", gcry_strerror (err));
+    log_fatal ("AES encryption in RNG failed: %s\n", _gcry_strerror (err));
 }
 
 
 /* The core ANSI X9.31, Appendix A.2.4 function using AES.  The caller
-   needs to pass a 16 byte buffer for the result and the 16 byte seed
-   value V.  The caller also needs to pass an appropriate KEY and make
-   sure to pass a valid seed_V.  The caller also needs to provide two
-   16 bytes buffer for intermediate results, they may be reused by the
-   caller later.
+   needs to pass a 16 byte buffer for the result, the 16 byte
+   datetime_DT value and the 16 byte seed value V.  The caller also
+   needs to pass an appropriate KEY and make sure to pass a valid
+   seed_V.  The caller also needs to provide two 16 bytes buffer for
+   intermediate results, they may be reused by the caller later.
 
    On return the result is stored at RESULT_R and the SEED_V is
    updated.  May only be used while holding the lock.  */
 static void
-x931_aes (unsigned char result_R[16], unsigned char seed_V[16],
+x931_aes (unsigned char result_R[16],
+          unsigned char datetime_DT[16], unsigned char seed_V[16],
           gcry_cipher_hd_t key,
           unsigned char intermediate_I[16], unsigned char temp_xor[16])
 {
-  unsigned char datetime_DT[16];
-
   /* Let ede*X(Y) represent the AES encryption of Y under the key *X.
 
      Let V be a 128-bit seed value which is also kept secret, and XOR
      be the exclusive-or operator. Let DT be a date/time vector which
-     is updated on each iteration. I is a intermediate value. 
+     is updated on each iteration. I is a intermediate value.
 
      I = ede*K(DT)  */
-  x931_get_dt (datetime_DT, 16);
   encrypt_aes (key, intermediate_I, datetime_DT, 16);
 
   /* R = ede*K(I XOR V) */
@@ -376,6 +442,7 @@ x931_aes (unsigned char result_R[16], unsigned char seed_V[16],
 static int
 x931_aes_driver (unsigned char *output, size_t length, rng_context_t rng_ctx)
 {
+  unsigned char datetime_DT[16];
   unsigned char *intermediate_I, *temp_buffer, *result_buffer;
   size_t nbytes;
 
@@ -391,34 +458,58 @@ x931_aes_driver (unsigned char *output, size_t length, rng_context_t rng_ctx)
 
   while (length)
     {
+      /* Unless we are running with a test context, we require a new
+         seed after some time.  */
+      if (!rng_ctx->test_dt_ptr && rng_ctx->use_counter > SEED_TTL)
+        {
+          x931_reseed (rng_ctx);
+          rng_ctx->use_counter = 0;
+        }
+
       /* Due to the design of the RNG, we always receive 16 bytes (128
          bit) of random even if we require less.  The extra bytes
          returned are not used.  Intheory we could save them for the
          next invocation, but that would make the control flow harder
          to read.  */
       nbytes = length < 16? length : 16;
-      x931_aes (result_buffer, rng_ctx->seed_V, rng_ctx->cipher_hd,
+
+      x931_get_dt (datetime_DT, 16, rng_ctx);
+      x931_aes (result_buffer,
+                datetime_DT, rng_ctx->seed_V, rng_ctx->cipher_hd,
                 intermediate_I, temp_buffer);
+      rng_ctx->use_counter++;
 
-      /* Do a basic check on the output to avoid a stuck generator.  */
-      if (!rng_ctx->compare_value_valid)
+      if (rng_ctx->test_no_dup_check
+          && rng_ctx->test_dt_ptr
+          && rng_ctx != nonce_context
+          && rng_ctx != std_rng_context
+          && rng_ctx != strong_rng_context)
         {
-          /* First time used, only save the result.  */
-          memcpy (rng_ctx->compare_value, result_buffer, 16);
-          rng_ctx->compare_value_valid = 1;
-          continue;
+          /* This is a test context which does not want the duplicate
+             block check. */
         }
-      if (!memcmp (rng_ctx->compare_value, result_buffer, 16))
+      else
         {
-          /* Ooops, we received the same 128 bit block - that should
-             in theory never happen.  The FIPS requirement says that
-             we need to put ourself into the error state in such
-             case.  */
-          fips_signal_error ("duplicate 128 bit block returned by RNG");
-          return -1;
+          /* Do a basic check on the output to avoid a stuck generator.  */
+          if (!rng_ctx->compare_value_valid)
+            {
+              /* First time used, only save the result.  */
+              memcpy (rng_ctx->compare_value, result_buffer, 16);
+              rng_ctx->compare_value_valid = 1;
+              continue;
+            }
+          if (!memcmp (rng_ctx->compare_value, result_buffer, 16))
+            {
+              /* Ooops, we received the same 128 bit block - that should
+                 in theory never happen.  The FIPS requirement says that
+                 we need to put ourself into the error state in such
+                 case.  */
+              fips_signal_error ("duplicate 128 bit block returned by RNG");
+              return -1;
+            }
+          memcpy (rng_ctx->compare_value, result_buffer, 16);
         }
-      memcpy (rng_ctx->compare_value, result_buffer, 16);
-      
+
       /* Append to outbut.  */
       memcpy (output, result_buffer, nbytes);
       wipememory (result_buffer, 16);
@@ -431,9 +522,9 @@ x931_aes_driver (unsigned char *output, size_t length, rng_context_t rng_ctx)
 
 
 /* Callback for x931_generate_key. Note that this callback uses the
-   global ENTROPY_COLLECT_BUFFER which has been setup by
-   x931_generate_key.  ORIGIN is not used but required due to the
-   emtropy gathering module. */
+   global ENTROPY_COLLECT_BUFFER which has been setup by get_entropy.
+   ORIGIN is not used but required due to the design of entropy
+   gathering module. */
 static void
 entropy_collect_cb (const void *buffer, size_t length,
                     enum random_origins origin)
@@ -444,68 +535,101 @@ entropy_collect_cb (const void *buffer, size_t length,
 
   gcry_assert (fips_rng_is_locked);
   gcry_assert (entropy_collect_buffer);
-  
-  while (length--)
+
+  /* Note that we need to protect against gatherers returning more
+     than the requested bytes (e.g. rndw32).  */
+  while (length-- && entropy_collect_buffer_len < entropy_collect_buffer_size)
     {
-      gcry_assert (entropy_collect_buffer_len < entropy_collect_buffer_size);
       entropy_collect_buffer[entropy_collect_buffer_len++] ^= *p++;
     }
 }
 
+
+/* Get NBYTES of entropy from the kernel device.  The callers needs to
+   free the returned buffer.  The function either succeeds or
+   terminates the process in case of a fatal error. */
+static void *
+get_entropy (size_t nbytes)
+{
+  void *result;
+  int rc;
+
+  gcry_assert (!entropy_collect_buffer);
+  entropy_collect_buffer = gcry_xmalloc_secure (nbytes);
+  entropy_collect_buffer_size = nbytes;
+  entropy_collect_buffer_len = 0;
+
+#if USE_RNDLINUX
+  rc = _gcry_rndlinux_gather_random (entropy_collect_cb, 0,
+                                     X931_AES_KEYLEN,
+                                     GCRY_VERY_STRONG_RANDOM);
+#elif USE_RNDW32
+  do
+    {
+      rc = _gcry_rndw32_gather_random (entropy_collect_cb, 0,
+                                       X931_AES_KEYLEN,
+                                       GCRY_VERY_STRONG_RANDOM);
+    }
+  while (rc >= 0 && entropy_collect_buffer_len < entropy_collect_buffer_size);
+#else
+  rc = -1;
+#endif
+
+  if (rc < 0 || entropy_collect_buffer_len != entropy_collect_buffer_size)
+    {
+      gcry_free (entropy_collect_buffer);
+      entropy_collect_buffer = NULL;
+      log_fatal ("error getting entropy data\n");
+    }
+  result = entropy_collect_buffer;
+  entropy_collect_buffer = NULL;
+  return result;
+}
+
+
 /* Generate a key for use with x931_aes.  The function returns a
    handle to the cipher context readily prepared for ECB encryption.
-   If VERY_STRONG is true the key is read from /dev/random, otherwise
-   from /dev/urandom.  On error NULL is returned.  */
+   If FOR_NONCE is true, the key is retrieved by readong random from
+   the standard generator.  On error NULL is returned.  */
 static gcry_cipher_hd_t
-x931_generate_key (int very_strong)
+x931_generate_key (int for_nonce)
 {
   gcry_cipher_hd_t hd;
-  gpg_error_t err;
+  gpg_err_code_t rc;
+  void *buffer;
 
   gcry_assert (fips_rng_is_locked);
 
   /* Allocate a cipher context.  */
-  err = gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
+  rc = _gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
                           GCRY_CIPHER_SECURE);
-  if (err)
+  if (rc)
     {
       log_error ("error creating cipher context for RNG: %s\n",
-                 gcry_strerror (err));
+                 _gcry_strerror (rc));
       return NULL;
     }
 
-  /* Get a key from the entropy source.  */
-#if USE_RNDLINUX
-  gcry_assert (!entropy_collect_buffer);
-  entropy_collect_buffer = gcry_xmalloc_secure (X931_AES_KEYLEN);
-  entropy_collect_buffer_size = X931_AES_KEYLEN;
-  entropy_collect_buffer_len = 0;
-  if (_gcry_rndlinux_gather_random (entropy_collect_cb, 0, X931_AES_KEYLEN,
-                                    (very_strong
-                                     ? GCRY_VERY_STRONG_RANDOM
-                                     : GCRY_STRONG_RANDOM)
-                                    ) < 0
-      || entropy_collect_buffer_len != entropy_collect_buffer_size)
+  /* Get a key from the standard RNG or from the entropy source.  */
+  if (for_nonce)
     {
-      gcry_free (entropy_collect_buffer);
-      entropy_collect_buffer = NULL;
-      gcry_cipher_close (hd);
-      log_fatal ("error getting entropy data for the RNG key\n");
+      buffer = gcry_xmalloc (X931_AES_KEYLEN);
+      get_random (buffer, X931_AES_KEYLEN, std_rng_context);
+    }
+  else
+    {
+      buffer = get_entropy (X931_AES_KEYLEN);
     }
-#else
-  log_fatal ("/dev/random support is not compiled in\n");
-#endif
 
   /* Set the key and delete the buffer because the key is now part of
      the cipher context.  */
-  err = gcry_cipher_setkey (hd, entropy_collect_buffer, X931_AES_KEYLEN);
-  wipememory (entropy_collect_buffer, X931_AES_KEYLEN);
-  gcry_free (entropy_collect_buffer);
-  entropy_collect_buffer = NULL;
-  if (err)
+  rc = _gcry_cipher_setkey (hd, buffer, X931_AES_KEYLEN);
+  wipememory (buffer, X931_AES_KEYLEN);
+  gcry_free (buffer);
+  if (rc)
     {
-      log_error ("error creating key for RNG: %s\n", gcry_strerror (err));
-      gcry_cipher_close (hd);
+      log_error ("error creating key for RNG: %s\n", _gcry_strerror (rc));
+      _gcry_cipher_close (hd);
       return NULL;
     }
 
@@ -516,33 +640,43 @@ x931_generate_key (int very_strong)
 /* Generate a key for use with x931_aes.  The function copies a seed
    of LENGTH bytes into SEED_BUFFER. LENGTH needs to by given as 16.  */
 static void
-x931_generate_seed (unsigned char *seed_buffer, size_t length, int very_strong)
+x931_generate_seed (unsigned char *seed_buffer, size_t length)
 {
+  void *buffer;
+
   gcry_assert (fips_rng_is_locked);
   gcry_assert (length == 16);
 
-  /* Get a seed from the entropy source.  */
-#if USE_RNDLINUX
-  gcry_assert (!entropy_collect_buffer);
-  entropy_collect_buffer = gcry_xmalloc_secure (X931_AES_KEYLEN);
-  entropy_collect_buffer_size = X931_AES_KEYLEN;
-  entropy_collect_buffer_len = 0;
-  if (_gcry_rndlinux_gather_random (entropy_collect_cb, 0, X931_AES_KEYLEN,
-                                    (very_strong
-                                     ? GCRY_VERY_STRONG_RANDOM
-                                     : GCRY_STRONG_RANDOM)
-                                    ) < 0
-      || entropy_collect_buffer_len != entropy_collect_buffer_size)
+  buffer = get_entropy (X931_AES_KEYLEN);
+
+  memcpy (seed_buffer, buffer, X931_AES_KEYLEN);
+  wipememory (buffer, X931_AES_KEYLEN);
+  gcry_free (buffer);
+}
+
+
+
+/* Reseed a generator.  This is also used for the initial seeding. */
+static void
+x931_reseed (rng_context_t rng_ctx)
+{
+  gcry_assert (fips_rng_is_locked);
+
+  if (rng_ctx == nonce_context)
     {
-      gcry_free (entropy_collect_buffer);
-      entropy_collect_buffer = NULL;
-      log_fatal ("error getting entropy data for the RNG seed\n");
+      /* The nonce context is special.  It will be seeded using the
+         standard random generator.  */
+      get_random (rng_ctx->seed_V, 16, std_rng_context);
+      rng_ctx->is_seeded = 1;
+      rng_ctx->seed_init_pid = getpid ();
+    }
+  else
+    {
+      /* The other two generators are seeded from /dev/random.  */
+      x931_generate_seed (rng_ctx->seed_V, 16);
+      rng_ctx->is_seeded = 1;
+      rng_ctx->seed_init_pid = getpid ();
     }
-#else
-  log_fatal ("/dev/random support is not compiled in\n");
-#endif
-  gcry_free (entropy_collect_buffer);
-  entropy_collect_buffer = NULL;
 }
 
 
@@ -556,13 +690,15 @@ get_random (void *buffer, size_t length, rng_context_t rng_ctx)
   gcry_assert (buffer);
   gcry_assert (rng_ctx);
 
-  lock_rng ();
   check_guards (rng_ctx);
 
   /* Initialize the cipher handle and thus setup the key if needed.  */
   if (!rng_ctx->cipher_hd)
     {
-      rng_ctx->cipher_hd = x931_generate_key (rng_ctx->need_strong_entropy);
+      if (rng_ctx == nonce_context)
+        rng_ctx->cipher_hd = x931_generate_key (1);
+      else
+        rng_ctx->cipher_hd = x931_generate_key (0);
       if (!rng_ctx->cipher_hd)
         goto bailout;
       rng_ctx->key_init_pid = getpid ();
@@ -570,11 +706,7 @@ get_random (void *buffer, size_t length, rng_context_t rng_ctx)
 
   /* Initialize the seed value if needed.  */
   if (!rng_ctx->is_seeded)
-    {
-      x931_generate_seed (rng_ctx->seed_V, 16, rng_ctx->need_strong_entropy);
-      rng_ctx->is_seeded = 1;
-      rng_ctx->seed_init_pid = getpid ();
-    }
+    x931_reseed (rng_ctx);
 
   if (rng_ctx->key_init_pid != getpid ()
       || rng_ctx->seed_init_pid != getpid ())
@@ -592,16 +724,17 @@ get_random (void *buffer, size_t length, rng_context_t rng_ctx)
     goto bailout;
 
   check_guards (rng_ctx);
-  unlock_rng ();
   return;
 
  bailout:
-  unlock_rng ();
   log_fatal ("severe error getting random\n");
   /*NOTREACHED*/
 }
 
 
+\f
+/* --- 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
@@ -629,19 +762,29 @@ _gcry_rngfips_initialize (int full)
 
       std_rng_context = gcry_xcalloc_secure (1, sizeof *std_rng_context);
       setup_guards (std_rng_context);
-      
+
       strong_rng_context = gcry_xcalloc_secure (1, sizeof *strong_rng_context);
-      strong_rng_context->need_strong_entropy = 1;
       setup_guards (strong_rng_context);
     }
-
+  else
+    {
+      /* Already initialized. Do some sanity checks.  */
+      gcry_assert (!nonce_context->test_dt_ptr);
+      gcry_assert (!std_rng_context->test_dt_ptr);
+      gcry_assert (!strong_rng_context->test_dt_ptr);
+      check_guards (nonce_context);
+      check_guards (std_rng_context);
+      check_guards (strong_rng_context);
+    }
   unlock_rng ();
 }
 
 
+/* Print some statistics about the RNG.  */
 void
 _gcry_rngfips_dump_stats (void)
 {
+  /* Not yet implemented.  */
 }
 
 
@@ -656,17 +799,20 @@ _gcry_rngfips_is_faked (void)
 
 /* 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.  */
+   entropy added, or -1 for goodness not known. */
 gcry_error_t
 _gcry_rngfips_add_bytes (const void *buf, size_t buflen, int quality)
 {
-  return 0;
-}   
+  (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_STRING_RANDOM, GCRY_STRONG_RANDOM is strong
+   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
@@ -674,11 +820,13 @@ _gcry_rngfips_randomize (void *buffer, size_t length,
                          enum gcry_random_level level)
 {
   _gcry_rngfips_initialize (1);  /* Auto-initialize if needed.  */
-  
+
+  lock_rng ();
   if (level == GCRY_VERY_STRONG_RANDOM)
     get_random (buffer, length, strong_rng_context);
   else
     get_random (buffer, length, std_rng_context);
+  unlock_rng ();
 }
 
 
@@ -688,6 +836,281 @@ _gcry_rngfips_create_nonce (void *buffer, size_t length)
 {
   _gcry_rngfips_initialize (1);  /* Auto-initialize if needed.  */
 
+  lock_rng ();
   get_random (buffer, length, nonce_context);
+  unlock_rng ();
 }
 
+
+/* Run a Know-Answer-Test using a dedicated test context.  Note that
+   we can't use the samples from the NISR RNGVS document because they
+   don't take the requirement to throw away the first block and use
+   that for duplicate check in account.  Thus we made up our own test
+   vectors. */
+static gcry_err_code_t
+selftest_kat (selftest_report_func_t report)
+{
+  static struct
+  {
+    const unsigned char key[16];
+    const unsigned char dt[16];
+    const unsigned char v[16];
+    const unsigned char r[3][16];
+  } tv[] =
+    {
+      { { 0xb9, 0xca, 0x7f, 0xd6, 0xa0, 0xf5, 0xd3, 0x42,
+          0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe },
+        { 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
+          0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x25, 0x00 },
+        { 0x52, 0x17, 0x8d, 0x29, 0xa2, 0xd5, 0x84, 0x12,
+          0x9d, 0x89, 0x9a, 0x45, 0x82, 0x02, 0xf7, 0x77 },
+        { { 0x42, 0x9c, 0x08, 0x3d, 0x82, 0xf4, 0x8a, 0x40,
+            0x66, 0xb5, 0x49, 0x27, 0xab, 0x42, 0xc7, 0xc3 },
+          { 0x0e, 0xb7, 0x61, 0x3c, 0xfe, 0xb0, 0xbe, 0x73,
+            0xf7, 0x6e, 0x6d, 0x6f, 0x1d, 0xa3, 0x14, 0xfa },
+          { 0xbb, 0x4b, 0xc1, 0x0e, 0xc5, 0xfb, 0xcd, 0x46,
+            0xbe, 0x28, 0x61, 0xe7, 0x03, 0x2b, 0x37, 0x7d } } },
+      { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+        { { 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7,
+            0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc },
+          { 0xc8, 0xd1, 0xe5, 0x11, 0x59, 0x52, 0xf7, 0xfa,
+            0x37, 0x38, 0xb4, 0xc5, 0xce, 0xb2, 0xb0, 0x9a },
+          { 0x0d, 0x9c, 0xc5, 0x0d, 0x16, 0xe1, 0xbc, 0xed,
+            0xcf, 0x60, 0x62, 0x09, 0x9d, 0x20, 0x83, 0x7e } } },
+      { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+          0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+        { 0x80, 0x00, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03,
+          0xa0, 0x20, 0xa1, 0x21, 0xa2, 0x22, 0xa3, 0x23 },
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+        { { 0x96, 0xed, 0xcc, 0xc3, 0xdd, 0x04, 0x7f, 0x75,
+            0x63, 0x19, 0x37, 0x6f, 0x15, 0x22, 0x57, 0x56 },
+          { 0x7a, 0x14, 0x76, 0x77, 0x95, 0x17, 0x7e, 0xc8,
+            0x92, 0xe8, 0xdd, 0x15, 0xcb, 0x1f, 0xbc, 0xb1 },
+          { 0x25, 0x3e, 0x2e, 0xa2, 0x41, 0x1b, 0xdd, 0xf5,
+            0x21, 0x48, 0x41, 0x71, 0xb3, 0x8d, 0x2f, 0x4c } } }
+    };
+  int tvidx, ridx;
+  rng_context_t test_ctx;
+  gpg_err_code_t rc;
+  const char *errtxt = NULL;
+  unsigned char result[16];
+
+  gcry_assert (tempvalue_for_x931_aes_driver);
+
+  test_ctx = gcry_xcalloc (1, sizeof *test_ctx);
+  setup_guards (test_ctx);
+
+  lock_rng ();
+
+  for (tvidx=0; tvidx < DIM (tv); tvidx++)
+    {
+      /* Setup the key.  */
+      rc = _gcry_cipher_open (&test_ctx->cipher_hd,
+                              GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
+                              GCRY_CIPHER_SECURE);
+      if (rc)
+        {
+          errtxt = "error creating cipher context for RNG";
+          goto leave;
+        }
+
+      rc = _gcry_cipher_setkey (test_ctx->cipher_hd, tv[tvidx].key, 16);
+      if (rc)
+        {
+          errtxt = "error setting key for RNG";
+          goto leave;
+        }
+      test_ctx->key_init_pid = getpid ();
+
+      /* Setup the seed.  */
+      memcpy (test_ctx->seed_V, tv[tvidx].v, 16);
+      test_ctx->is_seeded = 1;
+      test_ctx->seed_init_pid = getpid ();
+
+      /* Setup a DT value.  */
+      test_ctx->test_dt_ptr = tv[tvidx].dt;
+      test_ctx->test_dt_counter = ( (tv[tvidx].dt[12] << 24)
+                                   |(tv[tvidx].dt[13] << 16)
+                                   |(tv[tvidx].dt[14] << 8)
+                                   |(tv[tvidx].dt[15]) );
+
+      /* Get and compare the first three results.  */
+      for (ridx=0; ridx < 3; ridx++)
+        {
+          /* Compute the next value.  */
+          if (x931_aes_driver (result, 16, test_ctx))
+            {
+              errtxt = "X9.31 RNG core function failed";
+              goto leave;
+            }
+
+          /* Compare it to the known value.  */
+          if (memcmp (result, tv[tvidx].r[ridx], 16))
+            {
+              /* log_printhex ("x931_aes got: ", result, 16); */
+              /* log_printhex ("x931_aes exp: ", tv[tvidx].r[ridx], 16); */
+              errtxt = "RNG output does not match known value";
+              goto leave;
+            }
+        }
+
+      /* This test is actual pretty pointless because we use a local test
+         context.  */
+      if (test_ctx->key_init_pid != getpid ()
+          || test_ctx->seed_init_pid != getpid ())
+        {
+          errtxt = "fork detection failed";
+          goto leave;
+        }
+
+      _gcry_cipher_close (test_ctx->cipher_hd);
+      test_ctx->cipher_hd = NULL;
+      test_ctx->is_seeded = 0;
+      check_guards (test_ctx);
+    }
+
+ leave:
+  unlock_rng ();
+  _gcry_cipher_close (test_ctx->cipher_hd);
+  check_guards (test_ctx);
+  gcry_free (test_ctx);
+  if (report && errtxt)
+    report ("random", 0, "KAT", errtxt);
+  return errtxt? GPG_ERR_SELFTEST_FAILED : 0;
+}
+
+
+/* Run the self-tests.  */
+gcry_error_t
+_gcry_rngfips_selftest (selftest_report_func_t report)
+{
+  gcry_err_code_t ec;
+
+#if defined(USE_RNDLINUX) || defined(USE_RNDW32)
+  {
+    char buffer[8];
+
+    /* Do a simple test using the public interface.  This will also
+       enforce full initialization of the RNG.  We need to be fully
+       initialized due to the global requirement of the
+       tempvalue_for_x931_aes_driver stuff. */
+    _gcry_randomize (buffer, sizeof buffer, GCRY_STRONG_RANDOM);
+  }
+
+  ec = selftest_kat (report);
+
+#else /*!(USE_RNDLINUX||USE_RNDW32)*/
+  report ("random", 0, "setup", "no entropy gathering module");
+  ec = GPG_ERR_SELFTEST_FAILED;
+#endif
+  return gpg_error (ec);
+}
+
+
+/* Create a new test context for an external RNG test driver.  On
+   success the test context is stored at R_CONTEXT; on failure NULL is
+   stored at R_CONTEXT and an error code is returned.  */
+gcry_err_code_t
+_gcry_rngfips_init_external_test (void **r_context, unsigned int flags,
+                                  const void *key, size_t keylen,
+                                  const void *seed, size_t seedlen,
+                                  const void *dt, size_t dtlen)
+{
+  gpg_err_code_t rc;
+  rng_context_t test_ctx;
+
+  _gcry_rngfips_initialize (1);  /* Auto-initialize if needed.  */
+
+  if (!r_context
+      || !key  || keylen  != 16
+      || !seed || seedlen != 16
+      || !dt   || dtlen   != 16 )
+    return GPG_ERR_INV_ARG;
+
+  test_ctx = gcry_calloc (1, sizeof *test_ctx + dtlen);
+  if (!test_ctx)
+    return gpg_err_code_from_syserror ();
+  setup_guards (test_ctx);
+
+  /* Setup the key.  */
+  rc = _gcry_cipher_open (&test_ctx->cipher_hd,
+                          GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
+                          GCRY_CIPHER_SECURE);
+  if (rc)
+    goto leave;
+
+  rc = _gcry_cipher_setkey (test_ctx->cipher_hd, key, keylen);
+  if (rc)
+    goto leave;
+
+  test_ctx->key_init_pid = getpid ();
+
+  /* Setup the seed.  */
+  memcpy (test_ctx->seed_V, seed, seedlen);
+  test_ctx->is_seeded = 1;
+  test_ctx->seed_init_pid = getpid ();
+
+  /* Setup a DT value.  Because our context structure only stores a
+     pointer we copy the DT value to the extra space we allocated in
+     the test_ctx and set the pointer to that address.  */
+  memcpy ((unsigned char*)test_ctx + sizeof *test_ctx, dt, dtlen);
+  test_ctx->test_dt_ptr = (unsigned char*)test_ctx + sizeof *test_ctx;
+  test_ctx->test_dt_counter = ( (test_ctx->test_dt_ptr[12] << 24)
+                               |(test_ctx->test_dt_ptr[13] << 16)
+                               |(test_ctx->test_dt_ptr[14] << 8)
+                               |(test_ctx->test_dt_ptr[15]) );
+
+  if ( (flags & 1) )
+    test_ctx->test_no_dup_check = 1;
+
+  check_guards (test_ctx);
+  /* All fine.  */
+  rc = 0;
+
+ leave:
+  if (rc)
+    {
+      _gcry_cipher_close (test_ctx->cipher_hd);
+      gcry_free (test_ctx);
+      *r_context = NULL;
+    }
+  else
+    *r_context = test_ctx;
+  return rc;
+}
+
+
+/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them
+   at BUFFER.  Return 0 on success or an error code.  */
+gcry_err_code_t
+_gcry_rngfips_run_external_test (void *context, char *buffer, size_t buflen)
+{
+  rng_context_t test_ctx = context;
+
+  if (!test_ctx || !buffer || buflen != 16)
+    return GPG_ERR_INV_ARG;
+
+  lock_rng ();
+  get_random (buffer, buflen, test_ctx);
+  unlock_rng ();
+  return 0;
+}
+
+/* Release the test CONTEXT.  */
+void
+_gcry_rngfips_deinit_external_test (void *context)
+{
+  rng_context_t test_ctx = context;
+
+  if (test_ctx)
+    {
+      _gcry_cipher_close (test_ctx->cipher_hd);
+      gcry_free (test_ctx);
+    }
+}