diff options
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.c | 1118 |
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); + } +} + + |