X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Frand%2Frand_lib.c;h=29d93a829bf60727daa317f508606fc5385d0755;hp=5ae51a16a224a53b7b0dcc82dacc7ef2261e0748;hb=f3f7f1a826617af80a92f58d494ec2c8348251a5;hpb=5bc6bcf82d2adce982e04837b0810b1a6cd55a19 diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index 5ae51a16a2..29d93a829b 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -31,6 +31,8 @@ int rand_fork_count; static CRYPTO_RWLOCK *rand_nonce_lock; static int rand_nonce_count; +static int rand_cleaning_up = 0; + #ifdef OPENSSL_RAND_SEED_RDTSC /* * IMPORTANT NOTE: It is not currently possible to use this code @@ -87,7 +89,7 @@ size_t rand_acquire_entropy_from_cpu(RAND_POOL *pool) size_t bytes_needed; unsigned char *buffer; - bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/); + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); if (bytes_needed > 0) { buffer = rand_pool_add_begin(pool, bytes_needed); @@ -144,21 +146,17 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, return 0; } - pool = rand_pool_new(entropy, min_len, max_len); - if (pool == NULL) - return 0; - - if (drbg->pool) { - rand_pool_add(pool, - rand_pool_buffer(drbg->pool), - rand_pool_length(drbg->pool), - rand_pool_entropy(drbg->pool)); - rand_pool_free(drbg->pool); - drbg->pool = NULL; + if (drbg->pool != NULL) { + pool = drbg->pool; + pool->entropy_requested = entropy; + } else { + pool = rand_pool_new(entropy, min_len, max_len); + if (pool == NULL) + return 0; } if (drbg->parent) { - size_t bytes_needed = rand_pool_bytes_needed(pool, 8); + size_t bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); unsigned char *buffer = rand_pool_add_begin(pool, bytes_needed); if (buffer != NULL) { @@ -174,7 +172,7 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, if (RAND_DRBG_generate(drbg->parent, buffer, bytes_needed, prediction_resistance, - (unsigned char *)drbg, sizeof(*drbg)) != 0) + NULL, 0) != 0) bytes = bytes_needed; rand_drbg_unlock(drbg->parent); @@ -204,6 +202,10 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, } err: + /* we need to reset drbg->pool in the error case */ + if (ret == 0 && drbg->pool != NULL) + drbg->pool = NULL; + rand_pool_free(pool); return ret; } @@ -215,7 +217,10 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, void rand_drbg_cleanup_entropy(RAND_DRBG *drbg, unsigned char *out, size_t outlen) { - OPENSSL_secure_clear_free(out, outlen); + if (drbg->pool == NULL) + OPENSSL_secure_clear_free(out, outlen); + else + drbg->pool = NULL; } @@ -303,40 +308,72 @@ void rand_drbg_cleanup_additional_data(unsigned char *out, size_t outlen) OPENSSL_secure_clear_free(out, outlen); } -void rand_fork() +void rand_fork(void) { rand_fork_count++; } DEFINE_RUN_ONCE_STATIC(do_rand_init) { - int ret = 1; - #ifndef OPENSSL_NO_ENGINE rand_engine_lock = CRYPTO_THREAD_lock_new(); - ret &= rand_engine_lock != NULL; + if (rand_engine_lock == NULL) + return 0; #endif + rand_meth_lock = CRYPTO_THREAD_lock_new(); - ret &= rand_meth_lock != NULL; + if (rand_meth_lock == NULL) + goto err1; rand_nonce_lock = CRYPTO_THREAD_lock_new(); - ret &= rand_meth_lock != NULL; + if (rand_nonce_lock == NULL) + goto err2; - return ret; + if (!rand_cleaning_up && !rand_pool_init()) + goto err3; + + return 1; + +err3: + rand_pool_cleanup(); +err2: + CRYPTO_THREAD_lock_free(rand_meth_lock); + rand_meth_lock = NULL; +err1: +#ifndef OPENSSL_NO_ENGINE + CRYPTO_THREAD_lock_free(rand_engine_lock); + rand_engine_lock = NULL; +#endif + return 0; } void rand_cleanup_int(void) { const RAND_METHOD *meth = default_RAND_meth; + rand_cleaning_up = 1; + if (meth != NULL && meth->cleanup != NULL) meth->cleanup(); RAND_set_rand_method(NULL); + rand_pool_cleanup(); #ifndef OPENSSL_NO_ENGINE CRYPTO_THREAD_lock_free(rand_engine_lock); + rand_engine_lock = NULL; #endif CRYPTO_THREAD_lock_free(rand_meth_lock); + rand_meth_lock = NULL; CRYPTO_THREAD_lock_free(rand_nonce_lock); + rand_nonce_lock = NULL; +} + +/* + * RAND_close_seed_files() ensures that any seed file decriptors are + * closed after use. + */ +void RAND_keep_random_devices_open(int keep) +{ + rand_pool_keep_random_devices_open(keep); } /* @@ -371,7 +408,7 @@ int RAND_poll(void) /* fill random pool and seed the current legacy RNG */ pool = rand_pool_new(RAND_DRBG_STRENGTH, RAND_DRBG_STRENGTH / 8, - DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8)); + RAND_POOL_MAX_LENGTH); if (pool == NULL) return 0; @@ -396,17 +433,18 @@ err: * Allocate memory and initialize a new random pool */ -RAND_POOL *rand_pool_new(int entropy, size_t min_len, size_t max_len) +RAND_POOL *rand_pool_new(int entropy_requested, size_t min_len, size_t max_len) { RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool)); if (pool == NULL) { RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE); - goto err; + return NULL; } pool->min_len = min_len; - pool->max_len = max_len; + pool->max_len = (max_len > RAND_POOL_MAX_LENGTH) ? + RAND_POOL_MAX_LENGTH : max_len; pool->buffer = OPENSSL_secure_zalloc(pool->max_len); if (pool->buffer == NULL) { @@ -414,7 +452,7 @@ RAND_POOL *rand_pool_new(int entropy, size_t min_len, size_t max_len) goto err; } - pool->requested_entropy = entropy; + pool->entropy_requested = entropy_requested; return pool; @@ -423,6 +461,38 @@ err: 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->len; + pool->entropy = entropy; + + return pool; +} + /* * Free |pool|, securely erasing its buffer. */ @@ -431,7 +501,14 @@ void rand_pool_free(RAND_POOL *pool) if (pool == NULL) return; - OPENSSL_secure_clear_free(pool->buffer, pool->max_len); + /* + * 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) + OPENSSL_secure_clear_free(pool->buffer, pool->max_len); OPENSSL_free(pool); } @@ -473,11 +550,11 @@ unsigned char *rand_pool_detach(RAND_POOL *pool) /* - * If every byte of the input contains |entropy_per_bytes| bits of entropy, - * how many bytes does one need to obtain at least |bits| bits of entropy? + * 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_per_bytes) \ - (((bits) + ((entropy_per_bytes) - 1))/(entropy_per_bytes)) +#define ENTROPY_TO_BYTES(bits, entropy_factor) \ + (((bits) * (entropy_factor) + 7) / 8) /* @@ -490,7 +567,7 @@ unsigned char *rand_pool_detach(RAND_POOL *pool) */ size_t rand_pool_entropy_available(RAND_POOL *pool) { - if (pool->entropy < pool->requested_entropy) + if (pool->entropy < pool->entropy_requested) return 0; if (pool->len < pool->min_len) @@ -506,29 +583,29 @@ size_t rand_pool_entropy_available(RAND_POOL *pool) size_t rand_pool_entropy_needed(RAND_POOL *pool) { - if (pool->entropy < pool->requested_entropy) - return pool->requested_entropy - pool->entropy; + if (pool->entropy < pool->entropy_requested) + return pool->entropy_requested - pool->entropy; return 0; } /* * Returns the number of bytes needed to fill the pool, assuming - * the input has 'entropy_per_byte' entropy bits per byte. + * 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_per_byte) +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_per_byte < 1 || entropy_per_byte > 8) { + 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_per_byte); + bytes_needed = ENTROPY_TO_BYTES(entropy_needed, entropy_factor); if (bytes_needed > pool->max_len - pool->len) { /* not enough space left */