summaryrefslogtreecommitdiff
path: root/plugins/MirOTR/libgcrypt-1.4.6/random/random-fips.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/MirOTR/libgcrypt-1.4.6/random/random-fips.c')
-rw-r--r--plugins/MirOTR/libgcrypt-1.4.6/random/random-fips.c1118
1 files changed, 1118 insertions, 0 deletions
diff --git a/plugins/MirOTR/libgcrypt-1.4.6/random/random-fips.c b/plugins/MirOTR/libgcrypt-1.4.6/random/random-fips.c
new file mode 100644
index 0000000000..2667e71fd8
--- /dev/null
+++ b/plugins/MirOTR/libgcrypt-1.4.6/random/random-fips.c
@@ -0,0 +1,1118 @@
+/* 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"
+#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 fips_rng_lock = ATH_MUTEX_INITIALIZER;
+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 accidently 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 fucntion. 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;
+ int my_errno;
+
+ if (!initialized)
+ return;
+ initialized = 1;
+
+ my_errno = ath_mutex_init (&fips_rng_lock);
+ 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_STRONG_RANDOM == 1
+ && GCRY_VERY_STRONG_RANDOM == 2);
+
+}
+
+
+/* Acquire the fips_rng_lock. */
+static void
+lock_rng (void)
+{
+ int my_errno;
+
+ my_errno = ath_mutex_lock (&fips_rng_lock);
+ if (my_errno)
+ log_fatal ("failed to acquire the RNG lock: %s\n", strerror (my_errno));
+ fips_rng_is_locked = 1;
+}
+
+
+/* Release the fips_rng_lock. */
+static void
+unlock_rng (void)
+{
+ int my_errno;
+
+ fips_rng_is_locked = 0;
+ my_errno = ath_mutex_unlock (&fips_rng_lock);
+ if (my_errno)
+ log_fatal ("failed to release the RNG lock: %s\n", strerror (my_errno));
+}
+
+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 millon (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 = 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 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_error_t err;
+ void *buffer;
+
+ gcry_assert (fips_rng_is_locked);
+
+ /* Allocate a cipher context. */
+ err = gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
+ GCRY_CIPHER_SECURE);
+ if (err)
+ {
+ log_error ("error creating cipher context for RNG: %s\n",
+ gcry_strerror (err));
+ return NULL;
+ }
+
+ /* Get a key from the standard RNG or from the entropy source. */
+ if (for_nonce)
+ {
+ buffer = gcry_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. */
+ err = gcry_cipher_setkey (hd, buffer, X931_AES_KEYLEN);
+ wipememory (buffer, X931_AES_KEYLEN);
+ gcry_free (buffer);
+ if (err)
+ {
+ log_error ("error creating key for RNG: %s\n", gcry_strerror (err));
+ 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);
+ 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)
+ {
+ /* 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
+ = gcry_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 = gcry_xcalloc (1, sizeof *nonce_context);
+ setup_guards (nonce_context);
+
+ 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);
+ 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. */
+}
+
+
+/* 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_error_t err;
+ 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. */
+ err = gcry_cipher_open (&test_ctx->cipher_hd,
+ GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
+ GCRY_CIPHER_SECURE);
+ if (err)
+ {
+ errtxt = "error creating cipher context for RNG";
+ goto leave;
+ }
+
+ err = gcry_cipher_setkey (test_ctx->cipher_hd, tv[tvidx].key, 16);
+ if (err)
+ {
+ 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 intialization 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_error_t err;
+ 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. */
+ err = gcry_cipher_open (&test_ctx->cipher_hd,
+ GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
+ GCRY_CIPHER_SECURE);
+ if (err)
+ goto leave;
+
+ err = gcry_cipher_setkey (test_ctx->cipher_hd, key, keylen);
+ if (err)
+ 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. */
+ err = 0;
+
+ leave:
+ if (err)
+ {
+ gcry_cipher_close (test_ctx->cipher_hd);
+ gcry_free (test_ctx);
+ *r_context = NULL;
+ }
+ else
+ *r_context = test_ctx;
+ return gcry_err_code (err);
+}
+
+
+/* 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);
+ }
+}
+
+