From: Pauli Date: Fri, 8 May 2020 00:25:03 +0000 (+1000) Subject: CRNGT: continuous DRBG tests for providers X-Git-Tag: openssl-3.0.0-alpha4~23 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=4bffc025fd1b75b690f50552f443cbd3b1f1cbaf;p=oweals%2Fopenssl.git CRNGT: continuous DRBG tests for providers Reviewed-by: Matthias St. Pierre (Merged from https://github.com/openssl/openssl/pull/11682) --- diff --git a/crypto/rand/build.info b/crypto/rand/build.info index c4e7476ef7..7840428045 100644 --- a/crypto/rand/build.info +++ b/crypto/rand/build.info @@ -1,16 +1,18 @@ LIBS=../../libcrypto -$COMMON=rand_lib.c rand_crng_test.c rand_unix.c rand_win.c \ - drbg_lib.c drbg_ctr.c drbg_hash.c drbg_hmac.c +$COMMON=rand_pool.c rand_lib.c drbg_lib.c drbg_ctr.c drbg_hash.c drbg_hmac.c +$CRYPTO=rand_unix.c rand_win.c randfile.c rand_err.c + IF[{- !$disabled{'egd'} -}] - $COMMON=$COMMON rand_egd.c + $CYPTO=$CYPTO rand_egd.c ENDIF IF[{- $config{target} =~ /vxworks/i -}] - $COMMON=$COMMON rand_vxworks.c + $CYPTO=$CYPTO rand_vxworks.c ENDIF IF[{- $config{target} =~ /vms/i -}] - $COMMON=$COMMON rand_vms.c + $CYPTO=$CYPTO rand_vms.c ENDIF -SOURCE[../../libcrypto]=$COMMON randfile.c rand_err.c + +SOURCE[../../libcrypto]=$COMMON $CRYPTO SOURCE[../../providers/libfips.a]=$COMMON diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c index cda13595e3..94a4e98d73 100644 --- a/crypto/rand/drbg_lib.c +++ b/crypto/rand/drbg_lib.c @@ -14,6 +14,7 @@ #include "rand_local.h" #include "internal/thread_once.h" #include "crypto/rand.h" +#include "crypto/rand_pool.h" #include "crypto/cryptlib.h" /* @@ -468,13 +469,8 @@ static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx, drbg->parent = parent; if (parent == NULL) { -#ifdef FIPS_MODULE - drbg->get_entropy = rand_crngt_get_entropy; - drbg->cleanup_entropy = rand_crngt_cleanup_entropy; -#else drbg->get_entropy = rand_drbg_get_entropy; drbg->cleanup_entropy = rand_drbg_cleanup_entropy; -#endif #ifndef RAND_DRBG_GET_RANDOM_NONCE drbg->get_nonce = rand_drbg_get_nonce; drbg->cleanup_nonce = rand_drbg_cleanup_nonce; diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index a5eb0bc7ae..a4c9e69472 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -110,7 +110,7 @@ size_t rand_acquire_entropy_from_cpu(RAND_POOL *pool) } #endif - +#if 0 /* * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks()) * @@ -237,6 +237,7 @@ void rand_drbg_cleanup_additional_data(RAND_POOL *pool, unsigned char *out) { rand_pool_reattach(pool, out); } +#endif #ifndef FIPS_MODULE DEFINE_RUN_ONCE_STATIC(do_rand_init) @@ -321,9 +322,9 @@ int RAND_poll(void) if (drbg == NULL) return 0; - rand_drbg_lock(drbg); +#if 0 ret = rand_drbg_restart(drbg, NULL, 0, 0); - rand_drbg_unlock(drbg); +#endif return ret; @@ -336,10 +337,10 @@ int RAND_poll(void) RAND_POOL_MAX_LENGTH); if (pool == NULL) return 0; - +#if 0 if (rand_pool_acquire_entropy(pool) == 0) goto err; - +#endif if (meth->add == NULL || meth->add(rand_pool_buffer(pool), rand_pool_length(pool), @@ -354,406 +355,7 @@ int RAND_poll(void) return ret; } -#endif /* FIPS_MODULE */ - -/* - * Allocate memory and initialize a new random pool - */ - -RAND_POOL *rand_pool_new(int entropy_requested, int secure, - size_t min_len, size_t max_len) -{ - RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool)); - size_t min_alloc_size = RAND_POOL_MIN_ALLOCATION(secure); - - if (pool == NULL) { - RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE); - return NULL; - } - - pool->min_len = min_len; - pool->max_len = (max_len > RAND_POOL_MAX_LENGTH) ? - RAND_POOL_MAX_LENGTH : max_len; - pool->alloc_len = min_len < min_alloc_size ? min_alloc_size : min_len; - if (pool->alloc_len > pool->max_len) - pool->alloc_len = pool->max_len; - - if (secure) - pool->buffer = OPENSSL_secure_zalloc(pool->alloc_len); - else - pool->buffer = OPENSSL_zalloc(pool->alloc_len); - - if (pool->buffer == NULL) { - RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE); - goto err; - } - - pool->entropy_requested = entropy_requested; - pool->secure = secure; - - return pool; - -err: - OPENSSL_free(pool); - return NULL; -} - -/* - * Attach new random pool to the given buffer - * - * This function is intended to be used only for feeding random data - * provided by RAND_add() and RAND_seed() into the DRBG. - */ -RAND_POOL *rand_pool_attach(const unsigned char *buffer, size_t len, - size_t entropy) -{ - RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool)); - - if (pool == NULL) { - RANDerr(RAND_F_RAND_POOL_ATTACH, ERR_R_MALLOC_FAILURE); - return NULL; - } - - /* - * The const needs to be cast away, but attached buffers will not be - * modified (in contrary to allocated buffers which are zeroed and - * freed in the end). - */ - pool->buffer = (unsigned char *) buffer; - pool->len = len; - - pool->attached = 1; - - pool->min_len = pool->max_len = pool->alloc_len = pool->len; - pool->entropy = entropy; - - return pool; -} - -/* - * Free |pool|, securely erasing its buffer. - */ -void rand_pool_free(RAND_POOL *pool) -{ - if (pool == NULL) - return; - - /* - * Although it would be advisable from a cryptographical viewpoint, - * we are not allowed to clear attached buffers, since they are passed - * to rand_pool_attach() as `const unsigned char*`. - * (see corresponding comment in rand_pool_attach()). - */ - if (!pool->attached) { - if (pool->secure) - OPENSSL_secure_clear_free(pool->buffer, pool->alloc_len); - else - OPENSSL_clear_free(pool->buffer, pool->alloc_len); - } - - OPENSSL_free(pool); -} - -/* - * Return the |pool|'s buffer to the caller (readonly). - */ -const unsigned char *rand_pool_buffer(RAND_POOL *pool) -{ - return pool->buffer; -} - -/* - * Return the |pool|'s entropy to the caller. - */ -size_t rand_pool_entropy(RAND_POOL *pool) -{ - return pool->entropy; -} - -/* - * Return the |pool|'s buffer length to the caller. - */ -size_t rand_pool_length(RAND_POOL *pool) -{ - return pool->len; -} - -/* - * Detach the |pool| buffer and return it to the caller. - * It's the responsibility of the caller to free the buffer - * using OPENSSL_secure_clear_free() or to re-attach it - * again to the pool using rand_pool_reattach(). - */ -unsigned char *rand_pool_detach(RAND_POOL *pool) -{ - unsigned char *ret = pool->buffer; - pool->buffer = NULL; - pool->entropy = 0; - return ret; -} - -/* - * Re-attach the |pool| buffer. It is only allowed to pass - * the |buffer| which was previously detached from the same pool. - */ -void rand_pool_reattach(RAND_POOL *pool, unsigned char *buffer) -{ - pool->buffer = buffer; - OPENSSL_cleanse(pool->buffer, pool->len); - pool->len = 0; -} - -/* - * If |entropy_factor| bits contain 1 bit of entropy, how many bytes does one - * need to obtain at least |bits| bits of entropy? - */ -#define ENTROPY_TO_BYTES(bits, entropy_factor) \ - (((bits) * (entropy_factor) + 7) / 8) - - -/* - * Checks whether the |pool|'s entropy is available to the caller. - * This is the case when entropy count and buffer length are high enough. - * Returns - * - * |entropy| if the entropy count and buffer size is large enough - * 0 otherwise - */ -size_t rand_pool_entropy_available(RAND_POOL *pool) -{ - if (pool->entropy < pool->entropy_requested) - return 0; - - if (pool->len < pool->min_len) - return 0; - - return pool->entropy; -} - -/* - * Returns the (remaining) amount of entropy needed to fill - * the random pool. - */ - -size_t rand_pool_entropy_needed(RAND_POOL *pool) -{ - if (pool->entropy < pool->entropy_requested) - return pool->entropy_requested - pool->entropy; - - return 0; -} - -/* Increase the allocation size -- not usable for an attached pool */ -static int rand_pool_grow(RAND_POOL *pool, size_t len) -{ - if (len > pool->alloc_len - pool->len) { - unsigned char *p; - const size_t limit = pool->max_len / 2; - size_t newlen = pool->alloc_len; - - if (pool->attached || len > pool->max_len - pool->len) { - RANDerr(RAND_F_RAND_POOL_GROW, ERR_R_INTERNAL_ERROR); - return 0; - } - - do - newlen = newlen < limit ? newlen * 2 : pool->max_len; - while (len > newlen - pool->len); - - if (pool->secure) - p = OPENSSL_secure_zalloc(newlen); - else - p = OPENSSL_zalloc(newlen); - if (p == NULL) { - RANDerr(RAND_F_RAND_POOL_GROW, ERR_R_MALLOC_FAILURE); - return 0; - } - memcpy(p, pool->buffer, pool->len); - if (pool->secure) - OPENSSL_secure_clear_free(pool->buffer, pool->alloc_len); - else - OPENSSL_clear_free(pool->buffer, pool->alloc_len); - pool->buffer = p; - pool->alloc_len = newlen; - } - return 1; -} - -/* - * Returns the number of bytes needed to fill the pool, assuming - * the input has 1 / |entropy_factor| entropy bits per data bit. - * In case of an error, 0 is returned. - */ - -size_t rand_pool_bytes_needed(RAND_POOL *pool, unsigned int entropy_factor) -{ - size_t bytes_needed; - size_t entropy_needed = rand_pool_entropy_needed(pool); - if (entropy_factor < 1) { - RANDerr(RAND_F_RAND_POOL_BYTES_NEEDED, RAND_R_ARGUMENT_OUT_OF_RANGE); - return 0; - } - - bytes_needed = ENTROPY_TO_BYTES(entropy_needed, entropy_factor); - - if (bytes_needed > pool->max_len - pool->len) { - /* not enough space left */ - RANDerr(RAND_F_RAND_POOL_BYTES_NEEDED, RAND_R_RANDOM_POOL_OVERFLOW); - return 0; - } - - if (pool->len < pool->min_len && - bytes_needed < pool->min_len - pool->len) - /* to meet the min_len requirement */ - bytes_needed = pool->min_len - pool->len; - - /* - * Make sure the buffer is large enough for the requested amount - * of data. This guarantees that existing code patterns where - * rand_pool_add_begin, rand_pool_add_end or rand_pool_add - * are used to collect entropy data without any error handling - * whatsoever, continue to be valid. - * Furthermore if the allocation here fails once, make sure that - * we don't fall back to a less secure or even blocking random source, - * as that could happen by the existing code patterns. - * This is not a concern for additional data, therefore that - * is not needed if rand_pool_grow fails in other places. - */ - if (!rand_pool_grow(pool, bytes_needed)) { - /* persistent error for this pool */ - pool->max_len = pool->len = 0; - return 0; - } - - return bytes_needed; -} - -/* Returns the remaining number of bytes available */ -size_t rand_pool_bytes_remaining(RAND_POOL *pool) -{ - return pool->max_len - pool->len; -} - -/* - * Add random bytes to the random pool. - * - * It is expected that the |buffer| contains |len| bytes of - * random input which contains at least |entropy| bits of - * randomness. - * - * Returns 1 if the added amount is adequate, otherwise 0 - */ -int rand_pool_add(RAND_POOL *pool, - const unsigned char *buffer, size_t len, size_t entropy) -{ - if (len > pool->max_len - pool->len) { - RANDerr(RAND_F_RAND_POOL_ADD, RAND_R_ENTROPY_INPUT_TOO_LONG); - return 0; - } - - if (pool->buffer == NULL) { - RANDerr(RAND_F_RAND_POOL_ADD, ERR_R_INTERNAL_ERROR); - return 0; - } - - if (len > 0) { - /* - * This is to protect us from accidentally passing the buffer - * returned from rand_pool_add_begin. - * The check for alloc_len makes sure we do not compare the - * address of the end of the allocated memory to something - * different, since that comparison would have an - * indeterminate result. - */ - if (pool->alloc_len > pool->len && pool->buffer + pool->len == buffer) { - RANDerr(RAND_F_RAND_POOL_ADD, ERR_R_INTERNAL_ERROR); - return 0; - } - /* - * We have that only for cases when a pool is used to collect - * additional data. - * For entropy data, as long as the allocation request stays within - * the limits given by rand_pool_bytes_needed this rand_pool_grow - * below is guaranteed to succeed, thus no allocation happens. - */ - if (!rand_pool_grow(pool, len)) - return 0; - memcpy(pool->buffer + pool->len, buffer, len); - pool->len += len; - pool->entropy += entropy; - } - - return 1; -} - -/* - * Start to add random bytes to the random pool in-place. - * - * Reserves the next |len| bytes for adding random bytes in-place - * and returns a pointer to the buffer. - * The caller is allowed to copy up to |len| bytes into the buffer. - * If |len| == 0 this is considered a no-op and a NULL pointer - * is returned without producing an error message. - * - * After updating the buffer, rand_pool_add_end() needs to be called - * to finish the update operation (see next comment). - */ -unsigned char *rand_pool_add_begin(RAND_POOL *pool, size_t len) -{ - if (len == 0) - return NULL; - - if (len > pool->max_len - pool->len) { - RANDerr(RAND_F_RAND_POOL_ADD_BEGIN, RAND_R_RANDOM_POOL_OVERFLOW); - return NULL; - } - - if (pool->buffer == NULL) { - RANDerr(RAND_F_RAND_POOL_ADD_BEGIN, ERR_R_INTERNAL_ERROR); - return NULL; - } - - /* - * As long as the allocation request stays within the limits given - * by rand_pool_bytes_needed this rand_pool_grow below is guaranteed - * to succeed, thus no allocation happens. - * We have that only for cases when a pool is used to collect - * additional data. Then the buffer might need to grow here, - * and of course the caller is responsible to check the return - * value of this function. - */ - if (!rand_pool_grow(pool, len)) - return NULL; - - return pool->buffer + pool->len; -} - -/* - * Finish to add random bytes to the random pool in-place. - * - * Finishes an in-place update of the random pool started by - * rand_pool_add_begin() (see previous comment). - * It is expected that |len| bytes of random input have been added - * to the buffer which contain at least |entropy| bits of randomness. - * It is allowed to add less bytes than originally reserved. - */ -int rand_pool_add_end(RAND_POOL *pool, size_t len, size_t entropy) -{ - if (len > pool->alloc_len - pool->len) { - RANDerr(RAND_F_RAND_POOL_ADD_END, RAND_R_RANDOM_POOL_OVERFLOW); - return 0; - } - - if (len > 0) { - pool->len += len; - pool->entropy += entropy; - } - - return 1; -} - -#ifndef FIPS_MODULE int RAND_set_rand_method(const RAND_METHOD *meth) { if (!RUN_ONCE(&rand_init, do_rand_init)) @@ -768,7 +370,7 @@ int RAND_set_rand_method(const RAND_METHOD *meth) CRYPTO_THREAD_unlock(rand_meth_lock); return 1; } -#endif +#endif /* FIPS_MODULE */ const RAND_METHOD *RAND_get_rand_method(void) { diff --git a/crypto/rand/rand_local.h b/crypto/rand/rand_local.h index 76e50fa2fa..85158df76f 100644 --- a/crypto/rand/rand_local.h +++ b/crypto/rand/rand_local.h @@ -18,12 +18,10 @@ # include # include "internal/tsan_assist.h" # include "crypto/rand.h" +# include "crypto/rand_pool.h" # include "internal/numbers.h" -/* How many times to read the TSC as a randomness source. */ -# define TSC_READ_COUNT 4 - /* Maximum reseed intervals */ # define MAX_RESEED_INTERVAL (1 << 24) # define MAX_RESEED_TIME_INTERVAL (1 << 20) /* approx. 12 days */ @@ -31,8 +29,8 @@ /* Default reseed intervals */ # define MASTER_RESEED_INTERVAL (1 << 8) # define SLAVE_RESEED_INTERVAL (1 << 16) -# define MASTER_RESEED_TIME_INTERVAL (60*60) /* 1 hour */ -# define SLAVE_RESEED_TIME_INTERVAL (7*60) /* 7 minutes */ +# define MASTER_RESEED_TIME_INTERVAL (60 * 60) /* 1 hour */ +# define SLAVE_RESEED_TIME_INTERVAL (7 * 60) /* 7 minutes */ /* * The number of bytes that constitutes an atomic lump of entropy with respect @@ -53,60 +51,6 @@ */ # define DRBG_MAX_LENGTH INT32_MAX -/* The default nonce */ -#ifdef CHARSET_EBCDIC -# define DRBG_DEFAULT_PERS_STRING { 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x53, \ - 0x4c, 0x20, 0x4e, 0x49, 0x53, 0x54, 0x20, 0x53, 0x50, 0x20, 0x38, 0x30, \ - 0x30, 0x2d, 0x39, 0x30, 0x41, 0x20, 0x44, 0x52, 0x42, 0x47, 0x00}; -#else -# define DRBG_DEFAULT_PERS_STRING "OpenSSL NIST SP 800-90A DRBG" -#endif - -/* - * Maximum allocation size for RANDOM_POOL buffers - * - * The max_len value for the buffer provided to the rand_drbg_get_entropy() - * callback is currently 2^31 bytes (2 gigabytes), if a derivation function - * is used. Since this is much too large to be allocated, the rand_pool_new() - * function chooses more modest values as default pool length, bounded - * by RAND_POOL_MIN_LENGTH and RAND_POOL_MAX_LENGTH - * - * The choice of the RAND_POOL_FACTOR is large enough such that the - * RAND_POOL can store a random input which has a lousy entropy rate of - * 8/256 (= 0.03125) bits per byte. This input will be sent through the - * derivation function which 'compresses' the low quality input into a - * high quality output. - * - * The factor 1.5 below is the pessimistic estimate for the extra amount - * of entropy required when no get_nonce() callback is defined. - */ -# define RAND_POOL_FACTOR 256 -# define RAND_POOL_MAX_LENGTH (RAND_POOL_FACTOR * \ - 3 * (RAND_DRBG_STRENGTH / 16)) -/* - * = (RAND_POOL_FACTOR * \ - * 1.5 * (RAND_DRBG_STRENGTH / 8)) - */ - -/* - * Initial allocation minimum. - * - * There is a distinction between the secure and normal allocation minimums. - * Ideally, the secure allocation size should be a power of two. The normal - * allocation size doesn't have any such restriction. - * - * The secure value is based on 128 bits of secure material, which is 16 bytes. - * Typically, the DRBGs will set a minimum larger than this so optimal - * allocation ought to take place (for full quality seed material). - * - * The normal value has been chosen by noticing that the rand_drbg_get_nonce - * function is usually the largest of the built in allocation (twenty four - * bytes and then appending another sixteen bytes). This means the buffer ends - * with 40 bytes. The value of forty eight is comfortably above this which - * allows some slack in the platform specific values used. - */ -# define RAND_POOL_MIN_ALLOCATION(secure) ((secure) ? 16 : 48) - /* DRBG status values */ typedef enum drbg_status_e { DRBG_UNINITIALISED, @@ -114,7 +58,6 @@ typedef enum drbg_status_e { DRBG_ERROR } DRBG_STATUS; - /* instantiate */ typedef int (*RAND_DRBG_instantiate_fn)(RAND_DRBG *ctx, const unsigned char *ent, @@ -139,82 +82,6 @@ typedef int (*RAND_DRBG_generate_fn)(RAND_DRBG *ctx, typedef int (*RAND_DRBG_uninstantiate_fn)(RAND_DRBG *ctx); -/* - * The DRBG methods - */ - -typedef struct rand_drbg_method_st { - RAND_DRBG_instantiate_fn instantiate; - RAND_DRBG_reseed_fn reseed; - RAND_DRBG_generate_fn generate; - RAND_DRBG_uninstantiate_fn uninstantiate; -} RAND_DRBG_METHOD; - -/* 888 bits from SP800-90Ar1 10.1 table 2 */ -#define HASH_PRNG_MAX_SEEDLEN (888/8) - -typedef struct rand_drbg_hash_st { - EVP_MD *md; - EVP_MD_CTX *ctx; - size_t blocklen; - unsigned char V[HASH_PRNG_MAX_SEEDLEN]; - unsigned char C[HASH_PRNG_MAX_SEEDLEN]; - /* Temporary value storage: should always exceed max digest length */ - unsigned char vtmp[HASH_PRNG_MAX_SEEDLEN]; -} RAND_DRBG_HASH; - -typedef struct rand_drbg_hmac_st { - EVP_MD *md; - HMAC_CTX *ctx; - size_t blocklen; - unsigned char K[EVP_MAX_MD_SIZE]; - unsigned char V[EVP_MAX_MD_SIZE]; -} RAND_DRBG_HMAC; - -/* - * The state of a DRBG AES-CTR. - */ -typedef struct rand_drbg_ctr_st { - EVP_CIPHER_CTX *ctx_ecb; - EVP_CIPHER_CTX *ctx_ctr; - EVP_CIPHER_CTX *ctx_df; - EVP_CIPHER *cipher_ecb; - EVP_CIPHER *cipher_ctr; - size_t keylen; - unsigned char K[32]; - unsigned char V[16]; - /* Temporary block storage used by ctr_df */ - unsigned char bltmp[16]; - size_t bltmp_pos; - unsigned char KX[48]; -} RAND_DRBG_CTR; - - -/* - * The 'random pool' acts as a dumb container for collecting random - * input from various entropy sources. The pool has no knowledge about - * whether its randomness is fed into a legacy RAND_METHOD via RAND_add() - * or into a new style RAND_DRBG. It is the callers duty to 1) initialize the - * random pool, 2) pass it to the polling callbacks, 3) seed the RNG, and - * 4) cleanup the random pool again. - * - * The random pool contains no locking mechanism because its scope and - * lifetime is intended to be restricted to a single stack frame. - */ -struct rand_pool_st { - unsigned char *buffer; /* points to the beginning of the random pool */ - size_t len; /* current number of random bytes contained in the pool */ - - int attached; /* true pool was attached to existing buffer */ - int secure; /* 1: allocated on the secure heap, 0: otherwise */ - - size_t min_len; /* minimum number of random bytes requested */ - size_t max_len; /* maximum number of random bytes (allocated buffer size) */ - size_t alloc_len; /* current number of bytes allocated */ - size_t entropy; /* current entropy count in bits */ - size_t entropy_requested; /* requested entropy count in bits */ -}; - /* * The state of all types of DRBGs, even though we only have CTR mode * right now. @@ -226,104 +93,13 @@ struct rand_drbg_st { RAND_DRBG *parent; int secure; /* 1: allocated on the secure heap, 0: otherwise */ int type; /* the nid of the underlying algorithm */ - /* - * Stores the return value of openssl_get_fork_id() as of when we last - * reseeded. The DRBG reseeds automatically whenever drbg->fork_id != - * openssl_get_fork_id(). Used to provide fork-safety and reseed this - * DRBG in the child process. - */ - int fork_id; unsigned short flags; /* various external flags */ - /* - * The random_data is used by RAND_add()/drbg_add() to attach random - * data to the global drbg, such that the rand_drbg_get_entropy() callback - * can pull it during instantiation and reseeding. This is necessary to - * reconcile the different philosophies of the RAND and the RAND_DRBG - * with respect to how randomness is added to the RNG during reseeding - * (see PR #4328). - */ - struct rand_pool_st *seed_pool; - - /* - * Auxiliary pool for additional data. - */ - struct rand_pool_st *adin_pool; - - /* - * The following parameters are setup by the per-type "init" function. - * - * The supported types and their init functions are: - * (1) CTR_DRBG: drbg_ctr_init(). - * (2) HMAC_DRBG: drbg_hmac_init(). - * (3) HASH_DRBG: drbg_hash_init(). - * - * The parameters are closely related to the ones described in - * section '10.2.1 CTR_DRBG' of [NIST SP 800-90Ar1], with one - * crucial difference: In the NIST standard, all counts are given - * in bits, whereas in OpenSSL entropy counts are given in bits - * and buffer lengths are given in bytes. - * - * Since this difference has lead to some confusion in the past, - * (see [GitHub Issue #2443], formerly [rt.openssl.org #4055]) - * the 'len' suffix has been added to all buffer sizes for - * clarification. - */ - - int strength; - size_t max_request; - size_t min_entropylen, max_entropylen; - size_t min_noncelen, max_noncelen; - size_t max_perslen, max_adinlen; - - /* - * Counts the number of generate requests since the last reseed - * (Starts at 1). This value is the reseed_counter as defined in - * NIST SP 800-90Ar1 - */ - unsigned int reseed_gen_counter; - /* - * Maximum number of generate requests until a reseed is required. - * This value is ignored if it is zero. - */ - unsigned int reseed_interval; - /* Stores the time when the last reseeding occurred */ - time_t reseed_time; - /* - * Specifies the maximum time interval (in seconds) between reseeds. - * This value is ignored if it is zero. - */ - time_t reseed_time_interval; - /* - * Counts the number of reseeds since instantiation. - * This value is ignored if it is zero. - * - * This counter is used only for seed propagation from the DRBG - * to its two children, the and DRBG. This feature is - * very special and its sole purpose is to ensure that any randomness which - * is added by RAND_add() or RAND_seed() will have an immediate effect on - * the output of RAND_bytes() resp. RAND_priv_bytes(). - */ - TSAN_QUALIFIER unsigned int reseed_prop_counter; - unsigned int reseed_next_counter; - - size_t seedlen; - DRBG_STATUS state; - -#ifndef FIPS_MODULE /* Application data, mainly used in the KATs. */ CRYPTO_EX_DATA ex_data; -#endif - - /* Implementation specific data */ - union { - RAND_DRBG_CTR ctr; - RAND_DRBG_HASH hash; - RAND_DRBG_HMAC hmac; - } data; - /* Implementation specific methods */ - RAND_DRBG_METHOD *meth; + /* Implementation */ + EVP_RAND_CTX *rand; /* Callback functions. See comments in rand_lib.c */ RAND_DRBG_get_entropy_fn get_entropy; @@ -341,16 +117,6 @@ extern RAND_METHOD rand_meth; int rand_drbg_restart(RAND_DRBG *drbg, const unsigned char *buffer, size_t len, size_t entropy); size_t rand_drbg_seedlen(RAND_DRBG *drbg); -/* locking api */ -int rand_drbg_lock(RAND_DRBG *drbg); -int rand_drbg_unlock(RAND_DRBG *drbg); -int rand_drbg_enable_locking(RAND_DRBG *drbg); - - -/* initializes the DRBG implementation */ -int drbg_ctr_init(RAND_DRBG *drbg); -int drbg_hash_init(RAND_DRBG *drbg); -int drbg_hmac_init(RAND_DRBG *drbg); /* * Entropy call back for the FIPS 140-2 section 4.9.2 Conditional Tests. diff --git a/providers/implementations/rands/build.info b/providers/implementations/rands/build.info index 29f7238c1a..00f62e523e 100644 --- a/providers/implementations/rands/build.info +++ b/providers/implementations/rands/build.info @@ -3,5 +3,5 @@ SOURCE[../../libfips.a]=drbg.c SOURCE[../../libnonfips.a]=drbg.c -# Missing: drbg_hmac.c crngt.c -SOURCE[../../libimplementations.a]=test_rng.c drbg_hash.c +# Missing: drbg_hmac.c +SOURCE[../../libimplementations.a]=test_rng.c drbg_hash.c crngt.c diff --git a/providers/implementations/rands/crngt.c b/providers/implementations/rands/crngt.c new file mode 100644 index 0000000000..2680f7b644 --- /dev/null +++ b/providers/implementations/rands/crngt.c @@ -0,0 +1,139 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Implementation of the FIPS 140-2 section 4.9.2 Conditional Tests. + */ + +#include +#include +#include +#include +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "internal/cryptlib.h" +#include "prov/rand_pool.h" +#include "drbg_local.h" +#include "seeding/seeding.h" + +typedef struct crng_test_global_st { + unsigned char crngt_prev[EVP_MAX_MD_SIZE]; + RAND_POOL *crngt_pool; +} CRNG_TEST_GLOBAL; + +static int crngt_get_entropy(OPENSSL_CTX *ctx, RAND_POOL *pool, + unsigned char *buf, unsigned char *md, + unsigned int *md_size) +{ + int r; + size_t n; + unsigned char *p; + EVP_MD *fmd; + + if (pool == NULL) + return 0; + + n = prov_pool_acquire_entropy(pool); + if (n >= CRNGT_BUFSIZ) { + fmd = EVP_MD_fetch(ctx, "SHA256", ""); + if (fmd == NULL) + return 0; + p = rand_pool_detach(pool); + r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, fmd, NULL); + if (r != 0) + memcpy(buf, p, CRNGT_BUFSIZ); + rand_pool_reattach(pool, p); + EVP_MD_free(fmd); + return r; + } + return 0; +} + +static void rand_crng_ossl_ctx_free(void *vcrngt_glob) +{ + CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob; + + rand_pool_free(crngt_glob->crngt_pool); + OPENSSL_free(crngt_glob); +} + +static void *rand_crng_ossl_ctx_new(OPENSSL_CTX *ctx) +{ + unsigned char buf[CRNGT_BUFSIZ]; + CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob)); + + if (crngt_glob == NULL) + return NULL; + + if ((crngt_glob->crngt_pool + = rand_pool_new(0, 1, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL) { + OPENSSL_free(crngt_glob); + return NULL; + } + if (crngt_get_entropy(ctx, crngt_glob->crngt_pool, buf, + crngt_glob->crngt_prev, NULL)) { + OPENSSL_cleanse(buf, sizeof(buf)); + return crngt_glob; + } + rand_pool_free(crngt_glob->crngt_pool); + OPENSSL_free(crngt_glob); + return NULL; +} + +static const OPENSSL_CTX_METHOD rand_crng_ossl_ctx_method = { + rand_crng_ossl_ctx_new, + rand_crng_ossl_ctx_free, +}; + +size_t prov_crngt_get_entropy(PROV_DRBG *drbg, + unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) +{ + unsigned char buf[CRNGT_BUFSIZ], md[EVP_MAX_MD_SIZE]; + unsigned int sz; + RAND_POOL *pool; + size_t q, r = 0, s, t = 0; + int attempts = 3; + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(drbg->provctx); + CRNG_TEST_GLOBAL *crngt_glob + = openssl_ctx_get_data(libctx, OPENSSL_CTX_RAND_CRNGT_INDEX, + &rand_crng_ossl_ctx_method); + + if (crngt_glob == NULL) + return 0; + + if ((pool = rand_pool_new(entropy, 1, min_len, max_len)) == NULL) + return 0; + + while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) { + s = q > sizeof(buf) ? sizeof(buf) : q; + if (!crngt_get_entropy(libctx, crngt_glob->crngt_pool, buf, md, + &sz) + || memcmp(crngt_glob->crngt_prev, md, sz) == 0 + || !rand_pool_add(pool, buf, s, s * 8)) + goto err; + memcpy(crngt_glob->crngt_prev, md, sz); + t += s; + attempts++; + } + r = t; + *pout = rand_pool_detach(pool); +err: + OPENSSL_cleanse(buf, sizeof(buf)); + rand_pool_free(pool); + return r; +} + +void prov_crngt_cleanup_entropy(PROV_DRBG *drbg, + unsigned char *out, size_t outlen) +{ + OPENSSL_secure_clear_free(out, outlen); +} diff --git a/providers/implementations/rands/rand_crng_test.c b/providers/implementations/rands/rand_crng_test.c deleted file mode 100644 index b348b40d82..0000000000 --- a/providers/implementations/rands/rand_crng_test.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -/* - * Implementation of the FIPS 140-2 section 4.9.2 Conditional Tests. - */ - -#include -#include -#include "crypto/rand.h" -#include "internal/thread_once.h" -#include "internal/cryptlib.h" -#include "crypto/rand_pool.h" -#include "drbg_local.h" -#include "crypto/rand_pool.h" -#include "seeding/seeding.h" - -typedef struct crng_test_global_st { - unsigned char crngt_prev[EVP_MAX_MD_SIZE]; - RAND_POOL *crngt_pool; -} CRNG_TEST_GLOBAL; - -static int crngt_get_entropy(OPENSSL_CTX *ctx, RAND_POOL *pool, - unsigned char *buf, unsigned char *md, - unsigned int *md_size) -{ - int r; - size_t n; - unsigned char *p; - - if (pool == NULL) - return 0; - - n = prov_pool_acquire_entropy(pool); - if (n >= CRNGT_BUFSIZ) { - EVP_MD *fmd = EVP_MD_fetch(ctx, "SHA256", ""); - if (fmd == NULL) - return 0; - p = rand_pool_detach(pool); - r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, fmd, NULL); - if (r != 0) - memcpy(buf, p, CRNGT_BUFSIZ); - rand_pool_reattach(pool, p); - EVP_MD_free(fmd); - return r; - } - return 0; -} - -static void rand_crng_ossl_ctx_free(void *vcrngt_glob) -{ - CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob; - - rand_pool_free(crngt_glob->crngt_pool); - OPENSSL_free(crngt_glob); -} - -static void *rand_crng_ossl_ctx_new(OPENSSL_CTX *ctx) -{ - unsigned char buf[CRNGT_BUFSIZ]; - CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob)); - - if (crngt_glob == NULL) - return NULL; - - if ((crngt_glob->crngt_pool - = rand_pool_new(0, 1, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL) { - OPENSSL_free(crngt_glob); - return NULL; - } - if (crngt_get_entropy(ctx, crngt_glob->crngt_pool, buf, - crngt_glob->crngt_prev, NULL)) { - OPENSSL_cleanse(buf, sizeof(buf)); - return crngt_glob; - } - rand_pool_free(crngt_glob->crngt_pool); - OPENSSL_free(crngt_glob); - return NULL; -} - -static const OPENSSL_CTX_METHOD rand_crng_ossl_ctx_method = { - rand_crng_ossl_ctx_new, - rand_crng_ossl_ctx_free, -}; - -int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx, - RAND_POOL *pool, - unsigned char *buf, - unsigned char *md, - unsigned int *md_size) -{ - int r; - size_t n; - unsigned char *p; - - if (pool == NULL) - return 0; - - n = rand_pool_acquire_entropy(pool); - if (n >= CRNGT_BUFSIZ) { - EVP_MD *fmd = EVP_MD_fetch(ctx, "SHA256", ""); - if (fmd == NULL) - return 0; - p = rand_pool_detach(pool); - r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, fmd, NULL); - if (r != 0) - memcpy(buf, p, CRNGT_BUFSIZ); - rand_pool_reattach(pool, p); - EVP_MD_free(fmd); - return r; - } - return 0; -} - -size_t rand_crngt_get_entropy(RAND_DRBG *drbg, - unsigned char **pout, - int entropy, size_t min_len, size_t max_len, - int prediction_resistance) -{ - unsigned char buf[CRNGT_BUFSIZ], md[EVP_MAX_MD_SIZE]; - unsigned int sz; - RAND_POOL *pool; - size_t q, r = 0, s, t = 0; - int attempts = 3; - CRNG_TEST_GLOBAL *crngt_glob - = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_RAND_CRNGT_INDEX, - &rand_crng_ossl_ctx_method); - - if (crngt_glob == NULL) - return 0; - - if ((pool = rand_pool_new(entropy, 1, min_len, max_len)) == NULL) - return 0; - - while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) { - s = q > sizeof(buf) ? sizeof(buf) : q; - if (!crngt_get_entropy(drbg->libctx, crngt_glob->crngt_pool, buf, md, - &sz) - || memcmp(crngt_glob->crngt_prev, md, sz) == 0 - || !rand_pool_add(pool, buf, s, s * 8)) - goto err; - memcpy(crngt_glob->crngt_prev, md, sz); - t += s; - attempts++; - } - r = t; - *pout = rand_pool_detach(pool); -err: - OPENSSL_cleanse(buf, sizeof(buf)); - rand_pool_free(pool); - return r; -} - -void rand_crngt_cleanup_entropy(RAND_DRBG *drbg, - unsigned char *out, size_t outlen) -{ - OPENSSL_secure_clear_free(out, outlen); -} - -#if 0 -const OSSL_DISPATCH crngt_functions[] = { - { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))crngt_new }, - { OSSL_FUNC_RAND_FREECTX, (void(*)(void))crngt_free }, - { OSSL_FUNC_RAND_INSTANTIATE, (void(*)(void))crngt_instantiate }, - { OSSL_FUNC_RAND_UNINSTANTIATE, (void(*)(void))crngt_uninstantiate }, - { OSSL_FUNC_RAND_GENERATE, (void(*)(void))crngt_generate }, - { OSSL_FUNC_RAND_RESEED, (void(*)(void))crngt_reseed }, - { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))drbg_enable_locking }, - { OSSL_FUNC_RAND_LOCK, (void(*)(void))drbg_lock }, - { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))drbg_unlock }, - { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, - (void(*)(void))crngt_settable_ctx_params }, - { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))crngt_set_ctx_params }, - { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, - (void(*)(void))crngt_gettable_ctx_params }, - { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))crngt_get_ctx_params }, - { 0, NULL } -}; -#endif