diff --git a/random/random-fips.c b/random/random-fips.c deleted file mode 100644 index 5c251684..00000000 --- a/random/random-fips.c +++ /dev/null @@ -1,1131 +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 . - */ - -/* - 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 -#include -#include -#include -#include -#include -#ifdef HAVE_GETTIMEOFDAY -#include -#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_RNDGETENTROPY - rc = _gcry_rndgetentropy_gather_random (entropy_collect_cb, 0, - X931_AES_KEYLEN, - GCRY_VERY_STRONG_RANDOM); -#elif 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_RNDGETENTROPY - _gcry_rndgetentropy_gather_random (NULL, 0, 0, 0); -#endif -#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_RNDGETENTROPY) || 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_RNDGETENTROPY||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); - } -}