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
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);
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 (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) {
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);
}
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;
}
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;
}
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);
}
/*
/* 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;
* 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) {
goto err;
}
- pool->requested_entropy = entropy;
+ pool->entropy_requested = entropy_requested;
return 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 <master> 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.
*/
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);
}
/*
- * 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)
/*
*/
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)
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 */