[PATCH 2/2] Remove ANSI X9.31 DRNG

Stephan Mueller smueller at chronox.de
Tue Feb 16 22:04:53 CET 2016


The ANSI X9.31 DRNG is removed as it is completely replaced with the
SP800-90A DRBG.

Signed-off-by: Stephan Mueller <smueller at chronox.de>
---
 random/Makefile.am     |    1 -
 random/rand-internal.h |   25 --
 random/random-fips.c   | 1124 ------------------------------------------------
 3 files changed, 1150 deletions(-)
 delete mode 100644 random/random-fips.c

diff --git a/random/Makefile.am b/random/Makefile.am
index e073fa4..0bf3879 100644
--- a/random/Makefile.am
+++ b/random/Makefile.am
@@ -34,7 +34,6 @@ librandom_la_SOURCES = \
 random.c random.h \
 rand-internal.h \
 random-csprng.c \
-random-fips.c \
 drbg.c \
 random-system.c \
 rndhw.c
diff --git a/random/rand-internal.h b/random/rand-internal.h
index 475351a..30a270a 100644
--- a/random/rand-internal.h
+++ b/random/rand-internal.h
@@ -63,31 +63,6 @@ void _gcry_rngcsprng_set_seed_file (const char *name);
 void _gcry_rngcsprng_update_seed_file (void);
 void _gcry_rngcsprng_fast_poll (void);
 
-/*-- random-fips.c --*/
-void _gcry_rngfips_initialize (int full);
-void _gcry_rngfips_close_fds (void);
-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_randomize (void *buffer, size_t length,
-                                enum gcry_random_level level);
-void _gcry_rngfips_create_nonce (void *buffer, size_t length);
-
-gcry_error_t _gcry_rngfips_selftest (selftest_report_func_t report);
-
-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);
-gcry_err_code_t _gcry_rngfips_run_external_test (void *context,
-                                                 char *buffer, size_t buflen);
-void _gcry_rngfips_deinit_external_test (void *context);
-
 /* drbg.c */
 void _gcry_drbg_init(int full);
 void _gcry_drbg_close_fds(void);
diff --git a/random/random-fips.c b/random/random-fips.c
deleted file mode 100644
index 3a641b2..0000000
--- a/random/random-fips.c
+++ /dev/null
@@ -1,1124 +0,0 @@
-/* random-fips.c - FIPS style random number generator
- * Copyright (C) 2008  Free Software Foundation, Inc.
- *
- * This file is part of Libgcrypt.
- *
- * Libgcrypt is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * 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/>.
- */
-
-/*
-   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).  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.
-
- */
-
-#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"
-
-/* 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.  */
-GPGRT_LOCK_DEFINE (fips_rng_lock);
-static int fips_rng_is_locked;
-
-
-/* The required size for the temporary buffer of the x931_aes_driver
-   function and the buffer itself which will be allocated in secure
-   memory.  This needs to be global variable for proper initialization
-   and to allow shutting down the RNG without leaking memory.  May
-   only be used while holding the FIPS_RNG_LOCK.
-
-   This variable is also used to avoid duplicate initialization.  */
-#define TEMPVALUE_FOR_X931_AES_DRIVER_SIZE 48
-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
-   and x931_generate_seed functions and the entropy_collect_cb
-   function.  It may only be used by these functions. */
-static unsigned char *entropy_collect_buffer;  /* Buffer.  */
-static size_t entropy_collect_buffer_len;      /* Used length.  */
-static size_t entropy_collect_buffer_size;     /* Allocated length.  */
-
-
-/* This random context type is used to track properties of one random
-   generator. Thee context are usually allocated in secure memory so
-   that the seed value is well protected.  There are a couble of guard
-   fields to help detecting applications accidentally overwriting parts
-   of the memory. */
-struct rng_context
-{
-  unsigned char guard_0[1];
-
-  /* The handle of the cipher used by the RNG.  If this one is not
-     NULL a cipher handle along with a random key has been
-     established.  */
-  gcry_cipher_hd_t cipher_hd;
-
-  /* If this flag is true, the SEED_V buffer below carries a valid
-     seed.  */
-  int is_seeded:1;
-
-  /* The very first block generated is used to compare the result
-     against the last result.  This flag indicates that such a block
-     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.  */
-  unsigned char seed_V[16];
-
-  unsigned char guard_2[1];
-
-  /* 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;
-};
-typedef struct rng_context *rng_context_t;
-
-
-/* The random context used for the nonce generator.  May only be used
-   while holding the FIPS_RNG_LOCK.  */
-static rng_context_t nonce_context;
-/* The random context used for the standard random generator.  May
-   only be used while holding the FIPS_RNG_LOCK.  */
-static rng_context_t std_rng_context;
-/* The random context used for the very strong random generator.  May
-   only be used while holding the FIPS_RNG_LOCK.  */
-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);
-
-
-
-
-/* --- Functions  --- */
-
-/* Basic initialization is required to initialize mutexes and
-   do a few checks on the implementation.  */
-static void
-basic_initialization (void)
-{
-  static int initialized;
-
-  if (initialized)
-    return;
-  initialized = 1;
-
-  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_STRONG_RANDOM == 1
-               && GCRY_VERY_STRONG_RANDOM == 2);
-
-}
-
-
-/* Acquire the fips_rng_lock.  */
-static void
-lock_rng (void)
-{
-  gpg_err_code_t rc;
-
-  rc = gpgrt_lock_lock (&fips_rng_lock);
-  if (rc)
-    log_fatal ("failed to acquire the RNG lock: %s\n", gpg_strerror (rc));
-  fips_rng_is_locked = 1;
-}
-
-
-/* Release the fips_rng_lock.  */
-static void
-unlock_rng (void)
-{
-  gpg_err_code_t rc;
-
-  fips_rng_is_locked = 0;
-  rc = gpgrt_lock_unlock (&fips_rng_lock);
-  if (rc)
-    log_fatal ("failed to release the RNG lock: %s\n", gpg_strerror (rc));
-}
-
-static void
-setup_guards (rng_context_t rng_ctx)
-{
-  /* Set the guards to some arbitrary values.  */
-  rng_ctx->guard_0[0] = 17;
-  rng_ctx->guard_1[0] = 42;
-  rng_ctx->guard_2[0] = 137;
-  rng_ctx->guard_3[0] = 252;
-}
-
-static void
-check_guards (rng_context_t rng_ctx)
-{
-  if ( rng_ctx->guard_0[0] != 17
-       || rng_ctx->guard_1[0] != 42
-       || rng_ctx->guard_2[0] != 137
-       || rng_ctx->guard_3[0] != 252 )
-    log_fatal ("memory corruption detected in RNG context %p\n", 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. 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 -------------------/    |       |
-   counter1 ------------------------/       |
-   counter0 --------------------------------/
-
-   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, 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;
-
-    if (!last_sec)
-      {
-        /* This is the very first time we are called: Set the counters
-           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
-      }
-
-
-    if (gettimeofday (&tv, NULL))
-      log_fatal ("gettimeofday() failed: %s\n", strerror (errno));
-
-    /* The microseconds part is always less than 1 million (0x0f4240).
-       Thus we don't care about the MSB and in addition shift it to
-       the left by 4 bits.  */
-    usec = tv.tv_usec;
-    usec <<= 4;
-    /* If we got the same time as by the last invocation, bump up
-       counter2 and save the time for the next invocation.  */
-    if (tv.tv_sec == last_sec && usec == last_usec)
-      {
-        counter2++;
-        counter2 &= 0x0fff;
-      }
-    else
-      {
-        counter2 = 0;
-        last_sec = tv.tv_sec;
-        last_usec = usec;
-      }
-    /* Fill the buffer with the timestamp.  */
-    buffer[0] = ((tv.tv_sec >> 24) & 0xff);
-    buffer[1] = ((tv.tv_sec >> 16) & 0xff);
-    buffer[2] = ((tv.tv_sec >> 8) & 0xff);
-    buffer[3] = (tv.tv_sec & 0xff);
-    buffer[4] = ((usec >> 16) & 0xff);
-    buffer[5] = ((usec >> 8) & 0xff);
-    buffer[6] = ((usec & 0xf0) | ((counter2 >> 8) & 0x0f));
-    buffer[7] = (counter2 & 0xff);
-    /* Add the free running counter.  */
-    buffer[8]  = ((counter1 >> 24) & 0xff);
-    buffer[9]  = ((counter1 >> 16) & 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[15] = ((counter0) & 0xff);
-    /* Bump up that counter.  */
-    if (!++counter0)
-      ++counter1;
-  }
-#else
-  log_fatal ("gettimeofday() not available on this system\n");
-#endif
-
-  /* log_printhex ("x931_get_dt: ", buffer, 16); */
-}
-
-
-/* XOR the buffers A and B which are each of LENGTH bytes and store
-   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,
-            const unsigned char *a, const unsigned char *b, size_t length)
-{
-  for ( ; length; length--, a++, b++, r++)
-    *r = (*a ^ *b);
-}
-
-
-/* Encrypt LENGTH bytes of INPUT to OUTPUT using KEY.  LENGTH
-   needs to be 16. */
-static void
-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);
-  if (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, 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 datetime_DT[16], unsigned char seed_V[16],
-          gcry_cipher_hd_t key,
-          unsigned char intermediate_I[16], unsigned char temp_xor[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.
-
-     I = ede*K(DT)  */
-  encrypt_aes (key, intermediate_I, datetime_DT, 16);
-
-  /* R = ede*K(I XOR V) */
-  xor_buffer (temp_xor, intermediate_I, seed_V, 16);
-  encrypt_aes (key, result_R, temp_xor, 16);
-
-  /* V = ede*K(R XOR I).  */
-  xor_buffer (temp_xor, result_R, intermediate_I, 16);
-  encrypt_aes (key, seed_V, temp_xor, 16);
-
-  /* Zero out temporary values.  */
-  wipememory (intermediate_I, 16);
-  wipememory (temp_xor, 16);
-}
-
-
-/* The high level driver to x931_aes.  This one does the required
-   tests and calls the core function until the entire buffer has been
-   filled.  OUTPUT is a caller provided buffer of LENGTH bytes to
-   receive the random, RNG_CTX is the context of the RNG.  The context
-   must be properly initialized.  Returns 0 on success. */
-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;
-
-  gcry_assert (fips_rng_is_locked);
-  gcry_assert (rng_ctx->cipher_hd);
-  gcry_assert (rng_ctx->is_seeded);
-
-  gcry_assert (tempvalue_for_x931_aes_driver);
-  gcry_assert (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE == 48);
-  intermediate_I = tempvalue_for_x931_aes_driver;
-  temp_buffer    = tempvalue_for_x931_aes_driver + 16;
-  result_buffer  = tempvalue_for_x931_aes_driver + 32;
-
-  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_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++;
-
-      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)
-        {
-          /* This is a test context which does not want the duplicate
-             block check. */
-        }
-      else
-        {
-          /* 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);
-        }
-
-      /* Append to outbut.  */
-      memcpy (output, result_buffer, nbytes);
-      wipememory (result_buffer, 16);
-      output += nbytes;
-      length -= nbytes;
-    }
-
-  return 0;
-}
-
-
-/* Callback for x931_generate_key. Note that this callback uses the
-   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)
-{
-  const unsigned char *p = buffer;
-
-  (void)origin;
-
-  gcry_assert (fips_rng_is_locked);
-  gcry_assert (entropy_collect_buffer);
-
-  /* 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)
-    {
-      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 = 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)
-    {
-      xfree (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 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 for_nonce)
-{
-  gcry_cipher_hd_t hd;
-  gpg_err_code_t rc;
-  void *buffer;
-
-  gcry_assert (fips_rng_is_locked);
-
-  /* Allocate a cipher context.  */
-  rc = _gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
-                          GCRY_CIPHER_SECURE);
-  if (rc)
-    {
-      log_error ("error creating cipher context for RNG: %s\n",
-                 _gcry_strerror (rc));
-      return NULL;
-    }
-
-  /* Get a key from the standard RNG or from the entropy source.  */
-  if (for_nonce)
-    {
-      buffer = xmalloc (X931_AES_KEYLEN);
-      get_random (buffer, X931_AES_KEYLEN, std_rng_context);
-    }
-  else
-    {
-      buffer = get_entropy (X931_AES_KEYLEN);
-    }
-
-  /* Set the key and delete the buffer because the key is now part of
-     the cipher context.  */
-  rc = _gcry_cipher_setkey (hd, buffer, X931_AES_KEYLEN);
-  wipememory (buffer, X931_AES_KEYLEN);
-  xfree (buffer);
-  if (rc)
-    {
-      log_error ("error creating key for RNG: %s\n", _gcry_strerror (rc));
-      _gcry_cipher_close (hd);
-      return NULL;
-    }
-
-  return hd;
-}
-
-
-/* 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)
-{
-  void *buffer;
-
-  gcry_assert (fips_rng_is_locked);
-  gcry_assert (length == 16);
-
-  buffer = get_entropy (X931_AES_KEYLEN);
-
-  memcpy (seed_buffer, buffer, X931_AES_KEYLEN);
-  wipememory (buffer, X931_AES_KEYLEN);
-  xfree (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)
-    {
-      /* 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 ();
-    }
-}
-
-
-/* Core random function.  This is used for both nonce and random
-   generator.  The actual RNG to be used depends on the random context
-   RNG_CTX passed.  Note that this function is called with the RNG not
-   yet locked.  */
-static void
-get_random (void *buffer, size_t length, rng_context_t rng_ctx)
-{
-  gcry_assert (buffer);
-  gcry_assert (rng_ctx);
-
-  check_guards (rng_ctx);
-
-  /* Initialize the cipher handle and thus setup the key if needed.  */
-  if (!rng_ctx->cipher_hd)
-    {
-      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 ();
-    }
-
-  /* Initialize the seed value if needed.  */
-  if (!rng_ctx->is_seeded)
-    x931_reseed (rng_ctx);
-
-  if (rng_ctx->key_init_pid != getpid ()
-      || rng_ctx->seed_init_pid != getpid ())
-    {
-      /* We are in a child of us.  Because we have no way yet to do
-         proper re-initialization (including self-checks etc), the
-         only chance we have is to bail out.  Obviusly a fork/exec
-         won't harm because the exec overwrites the old image. */
-      fips_signal_error ("fork without proper re-initialization "
-                         "detected in RNG");
-      goto bailout;
-    }
-
-  if (x931_aes_driver (buffer, length, rng_ctx))
-    goto bailout;
-
-  check_guards (rng_ctx);
-  return;
-
- bailout:
-  log_fatal ("severe error getting random\n");
-  /*NOTREACHED*/
-}
-
-
-
-/* --- 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_rngfips_initialize (int full)
-{
-  basic_initialization ();
-  if (!full)
-    return;
-
-  /* Allocate temporary buffers.  If that buffer already exists we
-     know that we are already initialized.  */
-  lock_rng ();
-  if (!tempvalue_for_x931_aes_driver)
-    {
-      tempvalue_for_x931_aes_driver
-        = xmalloc_secure (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE);
-
-      /* Allocate the random contexts.  Note that we do not need to use
-         secure memory for the nonce context.  */
-      nonce_context = xcalloc (1, sizeof *nonce_context);
-      setup_guards (nonce_context);
-
-      std_rng_context = xcalloc_secure (1, sizeof *std_rng_context);
-      setup_guards (std_rng_context);
-
-      strong_rng_context = xcalloc_secure (1, sizeof *strong_rng_context);
-      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 ();
-}
-
-
-/* Try to close the FDs of the random gather module.  This is
-   currently only implemented for rndlinux. */
-void
-_gcry_rngfips_close_fds (void)
-{
-  lock_rng ();
-#if USE_RNDLINUX
-  _gcry_rndlinux_gather_random (NULL, 0, 0, 0);
-#endif
-  unlock_rng ();
-}
-
-
-/* Print some statistics about the RNG.  */
-void
-_gcry_rngfips_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_rngfips_is_faked (void)
-{
-  return 0;  /* Faked random is not allowed.  */
-}
-
-
-/* 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_rngfips_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_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 ();
-}
-
-
-/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
-void
-_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 = 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);
-  xfree (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 = xtrycalloc (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);
-      xfree (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);
-      xfree (test_ctx);
-    }
-}
-- 
2.5.0





More information about the Gcrypt-devel mailing list