summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/err/openssl.txt13
-rw-r--r--crypto/include/internal/rand_int.h2
-rw-r--r--crypto/init.c2
-rw-r--r--crypto/rand/drbg_lib.c311
-rw-r--r--crypto/rand/drbg_rand.c4
-rw-r--r--crypto/rand/rand_err.c21
-rw-r--r--crypto/rand/rand_lcl.h87
-rw-r--r--crypto/rand/rand_lib.c520
-rw-r--r--crypto/rand/rand_unix.c127
-rw-r--r--crypto/rand/rand_vms.c13
-rw-r--r--crypto/rand/rand_win.c84
-rw-r--r--doc/man3/RAND_add.pod89
-rw-r--r--include/internal/rand.h45
-rw-r--r--include/openssl/ossl_typ.h1
-rw-r--r--include/openssl/rand.h1
-rw-r--r--include/openssl/randerr.h13
-rw-r--r--ssl/ssl_lib.c9
-rw-r--r--test/drbgtest.c2
-rw-r--r--util/libcrypto.num15
19 files changed, 1032 insertions, 327 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 67f708602b..1749a7037f 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -876,14 +876,21 @@ PKCS7_F_PKCS7_SIMPLE_SMIMECAP:119:PKCS7_simple_smimecap
PKCS7_F_PKCS7_VERIFY:117:PKCS7_verify
RAND_F_DRBG_BYTES:101:drbg_bytes
RAND_F_DRBG_GET_ENTROPY:105:drbg_get_entropy
+RAND_F_DRBG_SETUP:117:drbg_setup
RAND_F_GET_ENTROPY:106:get_entropy
RAND_F_RAND_BYTES:100:RAND_bytes
RAND_F_RAND_DRBG_GENERATE:107:RAND_DRBG_generate
RAND_F_RAND_DRBG_INSTANTIATE:108:RAND_DRBG_instantiate
RAND_F_RAND_DRBG_NEW:109:RAND_DRBG_new
RAND_F_RAND_DRBG_RESEED:110:RAND_DRBG_reseed
+RAND_F_RAND_DRBG_RESTART:102:rand_drbg_restart
RAND_F_RAND_DRBG_SET:104:RAND_DRBG_set
RAND_F_RAND_LOAD_FILE:111:RAND_load_file
+RAND_F_RAND_POOL_ADD:103:RAND_POOL_add
+RAND_F_RAND_POOL_ADD_BEGIN:113:RAND_POOL_add_begin
+RAND_F_RAND_POOL_ADD_END:114:RAND_POOL_add_end
+RAND_F_RAND_POOL_BYTES_NEEDED:115:RAND_POOL_bytes_needed
+RAND_F_RAND_POOL_NEW:116:RAND_POOL_new
RAND_F_RAND_WRITE_FILE:112:RAND_write_file
RSA_F_CHECK_PADDING_MD:140:check_padding_md
RSA_F_ENCODE_PKCS1:146:encode_pkcs1
@@ -2137,13 +2144,18 @@ PKCS7_R_WRONG_CONTENT_TYPE:113:wrong content type
PKCS7_R_WRONG_PKCS7_TYPE:114:wrong pkcs7 type
RAND_R_ADDITIONAL_INPUT_TOO_LONG:102:additional input too long
RAND_R_ALREADY_INSTANTIATED:103:already instantiated
+RAND_R_ARGUMENT_OUT_OF_RANGE:105:argument out of range
RAND_R_CANNOT_OPEN_FILE:121:Cannot open file
RAND_R_DRBG_NOT_INITIALISED:104:drbg not initialised
+RAND_R_ENTROPY_INPUT_TOO_LONG:106:entropy input too long
+RAND_R_ENTROPY_OUT_OF_RANGE:124:entropy out of range
+RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED:127:error entropy pool was ignored
RAND_R_ERROR_INITIALISING_DRBG:107:error initialising drbg
RAND_R_ERROR_INSTANTIATING_DRBG:108:error instantiating drbg
RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT:109:error retrieving additional input
RAND_R_ERROR_RETRIEVING_ENTROPY:110:error retrieving entropy
RAND_R_ERROR_RETRIEVING_NONCE:111:error retrieving nonce
+RAND_R_FAILED_TO_CREATE_LOCK:126:failed to create lock
RAND_R_FUNC_NOT_IMPLEMENTED:101:Function not implemented
RAND_R_FWRITE_ERROR:123:Error writing file
RAND_R_GENERATE_ERROR:112:generate error
@@ -2153,6 +2165,7 @@ RAND_R_NOT_A_REGULAR_FILE:122:Not a regular file
RAND_R_NOT_INSTANTIATED:115:not instantiated
RAND_R_PERSONALISATION_STRING_TOO_LONG:116:personalisation string too long
RAND_R_PRNG_NOT_SEEDED:100:PRNG not seeded
+RAND_R_RANDOM_POOL_OVERFLOW:125:random pool overflow
RAND_R_REQUEST_TOO_LARGE_FOR_DRBG:117:request too large for drbg
RAND_R_RESEED_ERROR:118:reseed error
RAND_R_SELFTEST_FAILURE:119:selftest failure
diff --git a/crypto/include/internal/rand_int.h b/crypto/include/internal/rand_int.h
index d0999f28ad..fc1abd97bc 100644
--- a/crypto/include/internal/rand_int.h
+++ b/crypto/include/internal/rand_int.h
@@ -18,5 +18,5 @@
#include <openssl/rand.h>
void rand_cleanup_int(void);
-void rand_cleanup_drbg_int(void);
+void rand_drbg_cleanup_int(void);
void rand_fork(void);
diff --git a/crypto/init.c b/crypto/init.c
index 3eda1c987d..8daf4e31cf 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -503,7 +503,7 @@ void OPENSSL_cleanup(void)
* obj_cleanup_int() must be called last
*/
rand_cleanup_int();
- rand_cleanup_drbg_int();
+ rand_drbg_cleanup_int();
conf_modules_free_int();
#ifndef OPENSSL_NO_ENGINE
engine_cleanup_int();
diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c
index b7f7e4c341..eef5e11cc5 100644
--- a/crypto/rand/drbg_lib.c
+++ b/crypto/rand/drbg_lib.c
@@ -18,6 +18,9 @@
static RAND_DRBG rand_drbg; /* The default global DRBG. */
static RAND_DRBG priv_drbg; /* The global private-key DRBG. */
+/* NIST SP 800-90A DRBG recommends the use of a personalization string. */
+static const char ossl_pers_string[] = "OpenSSL NIST SP 800-90A DRBG";
+
/*
* Support framework for NIST SP 800-90A DRBG, AES-CTR mode.
* The RAND_DRBG is OpenSSL's pointer to an instance of the DRBG.
@@ -30,7 +33,9 @@ static RAND_DRBG priv_drbg; /* The global private-key DRBG. */
* a much bigger deal than just re-setting an allocated resource.)
*/
-static CRYPTO_ONCE rand_init_drbg = CRYPTO_ONCE_STATIC_INIT;
+static CRYPTO_ONCE rand_drbg_init = CRYPTO_ONCE_STATIC_INIT;
+
+static int drbg_setup(RAND_DRBG *drbg, const char *name);
/*
* Set/initialize |drbg| to be of type |nid|, with optional |flags|.
@@ -76,15 +81,14 @@ RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent)
RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE);
goto err;
}
- drbg->size = RANDOMNESS_NEEDED;
drbg->fork_count = rand_fork_count;
drbg->parent = parent;
if (RAND_DRBG_set(drbg, type, flags) < 0)
goto err;
if (parent != NULL) {
- if (!RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_parent,
- drbg_release_entropy,
+ if (!RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy,
+ rand_drbg_cleanup_entropy,
NULL, NULL))
goto err;
}
@@ -101,8 +105,7 @@ err:
*/
void RAND_DRBG_free(RAND_DRBG *drbg)
{
- /* The global DRBG is free'd by rand_cleanup_drbg_int() */
- if (drbg == NULL || drbg == &rand_drbg)
+ if (drbg == NULL)
return;
ctr_uninstantiate(drbg);
@@ -136,7 +139,8 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg,
if (drbg->get_entropy != NULL)
entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
drbg->min_entropylen, drbg->max_entropylen);
- if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) {
+ if (entropylen < drbg->min_entropylen
+ || entropylen > drbg->max_entropylen) {
RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY);
goto end;
}
@@ -145,7 +149,8 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg,
noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2,
drbg->min_noncelen, drbg->max_noncelen);
if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) {
- RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE);
+ RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
+ RAND_R_ERROR_RETRIEVING_NONCE);
goto end;
}
}
@@ -164,6 +169,15 @@ end:
drbg->cleanup_entropy(drbg, entropy, entropylen);
if (nonce != NULL && drbg->cleanup_nonce!= NULL )
drbg->cleanup_nonce(drbg, nonce, noncelen);
+ if (drbg->pool != NULL) {
+ if (drbg->state == DRBG_READY) {
+ RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
+ RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED);
+ drbg->state = DRBG_ERROR;
+ }
+ RAND_POOL_free(drbg->pool);
+ drbg->pool = NULL;
+ }
if (drbg->state == DRBG_READY)
return 1;
return 0;
@@ -182,7 +196,7 @@ int RAND_DRBG_uninstantiate(RAND_DRBG *drbg)
}
/*
- * Mix in the specified data to reseed |drbg|.
+ * Reseed |drbg|, mixing in the specified data
*/
int RAND_DRBG_reseed(RAND_DRBG *drbg,
const unsigned char *adin, size_t adinlen)
@@ -210,7 +224,8 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg,
if (drbg->get_entropy != NULL)
entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
drbg->min_entropylen, drbg->max_entropylen);
- if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) {
+ if (entropylen < drbg->min_entropylen
+ || entropylen > drbg->max_entropylen) {
RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY);
goto end;
}
@@ -229,22 +244,132 @@ end:
}
/*
+ * Restart |drbg|, using the specified entropy or additional input
+ *
+ * Tries its best to get the drbg instantiated by all means,
+ * regardless of its current state.
+ *
+ * Optionally, a |buffer| of |len| random bytes can be passed,
+ * which is assumed to contain at least |entropy| bits of entropy.
+ *
+ * If |entropy| > 0, the buffer content is used as entropy input.
+ *
+ * If |entropy| == 0, the buffer content is used as additional input
+ *
+ * Returns 1 on success, 0 on failure.
+ *
+ * This function is used internally only.
+ */
+int rand_drbg_restart(RAND_DRBG *drbg,
+ const unsigned char *buffer, size_t len, size_t entropy)
+{
+ int reseeded = 0;
+ const unsigned char *adin = NULL;
+ size_t adinlen = 0;
+
+ if (drbg->pool != NULL) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR);
+ RAND_POOL_free(drbg->pool);
+ drbg->pool = NULL;
+ }
+
+ if (buffer != NULL) {
+ if (entropy > 0) {
+ if (drbg->max_entropylen < len) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART,
+ RAND_R_ENTROPY_INPUT_TOO_LONG);
+ return 0;
+ }
+
+ if (entropy > 8 * len) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE);
+ return 0;
+ }
+
+ /* will be picked up by the rand_drbg_get_entropy() callback */
+ drbg->pool = RAND_POOL_new(entropy, len, len);
+ if (drbg->pool == NULL)
+ return 0;
+
+ RAND_POOL_add(drbg->pool, buffer, len, entropy);
+ } else {
+ if (drbg->max_adinlen < len) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART,
+ RAND_R_ADDITIONAL_INPUT_TOO_LONG);
+ return 0;
+ }
+ adin = buffer;
+ adinlen = len;
+ }
+ }
+
+ /* repair error state */
+ if (drbg->state == DRBG_ERROR)
+ RAND_DRBG_uninstantiate(drbg);
+
+ /* repair uninitialized state */
+ if (drbg->state == DRBG_UNINITIALISED) {
+ drbg_setup(drbg, NULL);
+ /* already reseeded. prevent second reseeding below */
+ reseeded = (drbg->state == DRBG_READY);
+ }
+
+ /* refresh current state if entropy or additional input has been provided */
+ if (drbg->state == DRBG_READY) {
+ if (adin != NULL) {
+ /*
+ * mix in additional input without reseeding
+ *
+ * Similar to RAND_DRBG_reseed(), but the provided additional
+ * data |adin| is mixed into the current state without pulling
+ * entropy from the trusted entropy source using get_entropy().
+ * This is not a reseeding in the strict sense of NIST SP 800-90A.
+ */
+ ctr_reseed(drbg, adin, adinlen, NULL, 0);
+ } else if (reseeded == 0) {
+ /* do a full reseeding if it has not been done yet above */
+ RAND_DRBG_reseed(drbg, NULL, 0);
+ }
+ }
+
+ /* check whether a given entropy pool was cleared properly during reseed */
+ if (drbg->pool != NULL) {
+ drbg->state = DRBG_ERROR;
+ RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR);
+ RAND_POOL_free(drbg->pool);
+ drbg->pool = NULL;
+ return 0;
+ }
+
+ return drbg->state == DRBG_READY;
+}
+
+/*
* Generate |outlen| bytes into the buffer at |out|. Reseed if we need
* to or if |prediction_resistance| is set. Additional input can be
* sent in |adin| and |adinlen|.
+ *
+ * Returns 1 on success, 0 on failure.
+ *
*/
int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
int prediction_resistance,
const unsigned char *adin, size_t adinlen)
{
- if (drbg->state == DRBG_ERROR) {
- RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE);
- return 0;
- }
- if (drbg->state == DRBG_UNINITIALISED) {
- RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED);
- return 0;
+ if (drbg->state != DRBG_READY) {
+ /* try to recover from previous errors */
+ rand_drbg_restart(drbg, NULL, 0, 0);
+
+ if (drbg->state == DRBG_ERROR) {
+ RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE);
+ return 0;
+ }
+ if (drbg->state == DRBG_UNINITIALISED) {
+ RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED);
+ return 0;
+ }
}
+
if (outlen > drbg->max_request) {
RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG);
return 0;
@@ -285,21 +410,55 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
}
/*
- * Set the callbacks for entropy and nonce. We currently don't use
- * the nonce; that's mainly for the KATs
+ * Set the RAND_DRBG callbacks for obtaining entropy and nonce.
+ *
+ * In the following, the signature and the semantics of the
+ * get_entropy() and cleanup_entropy() callbacks are explained.
+ *
+ * GET_ENTROPY
+ *
+ * size_t get_entropy(RAND_DRBG *ctx,
+ * unsigned char **pout,
+ * int entropy,
+ * size_t min_len, size_t max_len);
+ *
+ * This is a request to allocate and fill a buffer of size
+ * |min_len| <= size <= |max_len| (in bytes) which contains
+ * at least |entropy| bits of randomness. The buffer's address is
+ * to be returned in |*pout| and the number of collected
+ * randomness bytes (which may be less than the allocated size
+ * of the buffer) as return value.
+ *
+ * If the callback fails to acquire at least |entropy| bits of
+ * randomness, it shall return a buffer length of 0.
+ *
+ * CLEANUP_ENTROPY
+ *
+ * void cleanup_entropy(RAND_DRBG *ctx,
+ * unsigned char *out, size_t outlen);
+ *
+ * A request to clear and free the buffer allocated by get_entropy().
+ * The values |out| and |outlen| are expected to be the random buffer's
+ * address and length, as returned by the get_entropy() callback.
+ *
+ * GET_NONCE, CLEANUP_NONCE
+ *
+ * Signature and semantics of the get_nonce() and cleanup_nonce()
+ * callbacks are analogous to get_entropy() and cleanup_entropy().
+ * Currently, the nonce is used only for the known answer tests.
*/
int RAND_DRBG_set_callbacks(RAND_DRBG *drbg,
- RAND_DRBG_get_entropy_fn cb_get_entropy,
- RAND_DRBG_cleanup_entropy_fn cb_cleanup_entropy,
- RAND_DRBG_get_nonce_fn cb_get_nonce,
- RAND_DRBG_cleanup_nonce_fn cb_cleanup_nonce)
+ RAND_DRBG_get_entropy_fn get_entropy,
+ RAND_DRBG_cleanup_entropy_fn cleanup_entropy,
+ RAND_DRBG_get_nonce_fn get_nonce,
+ RAND_DRBG_cleanup_nonce_fn cleanup_nonce)
{
if (drbg->state != DRBG_UNINITIALISED)
return 0;
- drbg->get_entropy = cb_get_entropy;
- drbg->cleanup_entropy = cb_cleanup_entropy;
- drbg->get_nonce = cb_get_nonce;
- drbg->cleanup_nonce = cb_cleanup_nonce;
+ drbg->get_entropy = get_entropy;
+ drbg->cleanup_entropy = cleanup_entropy;
+ drbg->get_nonce = get_nonce;
+ drbg->cleanup_nonce = cleanup_nonce;
return 1;
}
@@ -334,23 +493,40 @@ void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx)
*/
/*
- * Creates a global DRBG with default settings.
+ * Initializes the DRBG with default settings.
+ * For global DRBGs a global lock is created with the given name
* Returns 1 on success, 0 on failure
*/
-static int setup_drbg(RAND_DRBG *drbg, const char *name)
+static int drbg_setup(RAND_DRBG *drbg, const char *name)
{
int ret = 1;
- drbg->lock = CRYPTO_THREAD_glock_new(name);
- ret &= drbg->lock != NULL;
- drbg->size = RANDOMNESS_NEEDED;
- drbg->secure = CRYPTO_secure_malloc_initialized();
- /* If you change these parameters, see RANDOMNESS_NEEDED */
+ if (name != NULL) {
+ if (drbg->lock != NULL) {
+ RANDerr(RAND_F_DRBG_SETUP, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ drbg->lock = CRYPTO_THREAD_glock_new(name);
+ if (drbg->lock == NULL) {
+ RANDerr(RAND_F_DRBG_SETUP, RAND_R_FAILED_TO_CREATE_LOCK);
+ return 0;
+ }
+ }
+
ret &= RAND_DRBG_set(drbg,
- NID_aes_128_ctr, RAND_DRBG_FLAG_CTR_USE_DF) == 1;
- ret &= RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_system,
- drbg_release_entropy, NULL, NULL) == 1;
- ret &= RAND_DRBG_instantiate(drbg, NULL, 0) == 1;
+ RAND_DRBG_NID, RAND_DRBG_FLAG_CTR_USE_DF) == 1;
+ ret &= RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy,
+ rand_drbg_cleanup_entropy, NULL, NULL) == 1;
+ /*
+ * Ignore instantiation error so support just-in-time instantiation.
+ *
+ * The state of the drbg will be checked in RAND_DRBG_generate() and
+ * an automatic recovery is attempted.
+ */
+ RAND_DRBG_instantiate(drbg,
+ (const unsigned char *) ossl_pers_string,
+ sizeof(ossl_pers_string) - 1);
return ret;
}
@@ -358,30 +534,31 @@ static int setup_drbg(RAND_DRBG *drbg, const char *name)
* Initialize the global DRBGs on first use.
* Returns 1 on success, 0 on failure.
*/
-DEFINE_RUN_ONCE_STATIC(do_rand_init_drbg)
+DEFINE_RUN_ONCE_STATIC(do_rand_drbg_init)
{
int ret = 1;
- ret &= setup_drbg(&rand_drbg, "rand_drbg");
- ret &= setup_drbg(&priv_drbg, "priv_drbg");
+ ret &= drbg_setup(&rand_drbg, "rand_drbg");
+ ret &= drbg_setup(&priv_drbg, "priv_drbg");
return ret;
}
-/* Clean up a DRBG and free it */
-static void free_drbg(RAND_DRBG *drbg)
+/* Cleans up the given global DRBG */
+static void drbg_cleanup(RAND_DRBG *drbg)
{
CRYPTO_THREAD_lock_free(drbg->lock);
RAND_DRBG_uninstantiate(drbg);
}
/* Clean up the global DRBGs before exit */
-void rand_cleanup_drbg_int(void)
+void rand_drbg_cleanup_int(void)
{
- free_drbg(&rand_drbg);
- free_drbg(&priv_drbg);
+ drbg_cleanup(&rand_drbg);
+ drbg_cleanup(&priv_drbg);
}
+/* Implements the default OpenSSL RAND_bytes() method */
static int drbg_bytes(unsigned char *out, int count)
{
int ret = 0;
@@ -410,34 +587,44 @@ err:
return ret;
}
+/* Implements the default OpenSSL RAND_add() method */
static int drbg_add(const void *buf, int num, double randomness)
{
- unsigned char *in = (unsigned char *)buf;
- unsigned char *out, *end;
+ int ret = 0;
+ RAND_DRBG *drbg = RAND_DRBG_get0_global();
- CRYPTO_THREAD_write_lock(rand_bytes.lock);
- out = &rand_bytes.buff[rand_bytes.curr];
- end = &rand_bytes.buff[rand_bytes.size];
+ if (drbg == NULL)
+ return 0;
- /* Copy whatever fits into the end of the buffer. */
- for ( ; --num >= 0 && out < end; rand_bytes.curr++)
- *out++ = *in++;
+ if (num < 0 || randomness < 0.0)
+ return 0;
- /* XOR any the leftover. */
- while (num > 0) {
- for (out = rand_bytes.buff; --num >= 0 && out < end; )
- *out++ ^= *in++;
+ if (randomness > (double)drbg->max_entropylen) {
+ /*
+ * The purpose of this check is to bound |randomness| by a
+ * relatively small value in order to prevent an integer
+ * overflow when multiplying by 8 in the rand_drbg_restart()
+ * call below.
+ */
+ return 0;
}
- CRYPTO_THREAD_unlock(rand_bytes.lock);
- return 1;
+ CRYPTO_THREAD_write_lock(drbg->lock);
+ ret = rand_drbg_restart(drbg, buf,
+ (size_t)(unsigned int)num,
+ (size_t)(8*randomness));
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
+/* Implements the default OpenSSL RAND_seed() method */
static int drbg_seed(const void *buf, int num)
{
return drbg_add(buf, num, num);
}
+/* Implements the default OpenSSL RAND_status() method */
static int drbg_status(void)
{
int ret;
@@ -458,7 +645,7 @@ static int drbg_status(void)
*/
RAND_DRBG *RAND_DRBG_get0_global(void)
{
- if (!RUN_ONCE(&rand_init_drbg, do_rand_init_drbg))
+ if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))
return NULL;
return &rand_drbg;
@@ -470,7 +657,7 @@ RAND_DRBG *RAND_DRBG_get0_global(void)
*/
RAND_DRBG *RAND_DRBG_get0_priv_global(void)
{
- if (!RUN_ONCE(&rand_init_drbg, do_rand_init_drbg))
+ if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))
return NULL;
return &priv_drbg;
diff --git a/crypto/rand/drbg_rand.c b/crypto/rand/drbg_rand.c
index 83f1ad876f..f45ef1424c 100644
--- a/crypto/rand/drbg_rand.c
+++ b/crypto/rand/drbg_rand.c
@@ -341,9 +341,9 @@ int ctr_init(RAND_DRBG *drbg)
AES_set_encrypt_key(df_key, drbg->strength, &ctr->df_ks);
drbg->min_entropylen = ctr->keylen;
- drbg->max_entropylen = DRBG_MAX_LENGTH;
+ drbg->max_entropylen = DRBG_MINMAX_FACTOR * drbg->min_entropylen;
drbg->min_noncelen = drbg->min_entropylen / 2;
- drbg->max_noncelen = DRBG_MAX_LENGTH;
+ drbg->max_noncelen = DRBG_MINMAX_FACTOR * drbg->min_noncelen;
drbg->max_perslen = DRBG_MAX_LENGTH;
drbg->max_adinlen = DRBG_MAX_LENGTH;
} else {
diff --git a/crypto/rand/rand_err.c b/crypto/rand/rand_err.c
index 707f010e4c..dc6140c075 100644
--- a/crypto/rand/rand_err.c
+++ b/crypto/rand/rand_err.c
@@ -16,6 +16,7 @@
static const ERR_STRING_DATA RAND_str_functs[] = {
{ERR_PACK(ERR_LIB_RAND, RAND_F_DRBG_BYTES, 0), "drbg_bytes"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_DRBG_GET_ENTROPY, 0), "drbg_get_entropy"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_DRBG_SETUP, 0), "drbg_setup"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_GET_ENTROPY, 0), "get_entropy"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_BYTES, 0), "RAND_bytes"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_GENERATE, 0),
@@ -24,8 +25,16 @@ static const ERR_STRING_DATA RAND_str_functs[] = {
"RAND_DRBG_instantiate"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_NEW, 0), "RAND_DRBG_new"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_RESEED, 0), "RAND_DRBG_reseed"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_RESTART, 0), "rand_drbg_restart"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_SET, 0), "RAND_DRBG_set"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_LOAD_FILE, 0), "RAND_load_file"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD, 0), "RAND_POOL_add"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD_BEGIN, 0),
+ "RAND_POOL_add_begin"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD_END, 0), "RAND_POOL_add_end"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_BYTES_NEEDED, 0),
+ "RAND_POOL_bytes_needed"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_NEW, 0), "RAND_POOL_new"},
{ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_WRITE_FILE, 0), "RAND_write_file"},
{0, NULL}
};
@@ -35,9 +44,17 @@ static const ERR_STRING_DATA RAND_str_reasons[] = {
"additional input too long"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ALREADY_INSTANTIATED),
"already instantiated"},
+ {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ARGUMENT_OUT_OF_RANGE),
+ "argument out of range"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_CANNOT_OPEN_FILE), "Cannot open file"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_DRBG_NOT_INITIALISED),
"drbg not initialised"},
+ {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ENTROPY_INPUT_TOO_LONG),
+ "entropy input too long"},
+ {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ENTROPY_OUT_OF_RANGE),
+ "entropy out of range"},
+ {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED),
+ "error entropy pool was ignored"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_INITIALISING_DRBG),
"error initialising drbg"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_INSTANTIATING_DRBG),
@@ -48,6 +65,8 @@ static const ERR_STRING_DATA RAND_str_reasons[] = {
"error retrieving entropy"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_RETRIEVING_NONCE),
"error retrieving nonce"},
+ {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FAILED_TO_CREATE_LOCK),
+ "failed to create lock"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FUNC_NOT_IMPLEMENTED),
"Function not implemented"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FWRITE_ERROR), "Error writing file"},
@@ -60,6 +79,8 @@ static const ERR_STRING_DATA RAND_str_reasons[] = {
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PERSONALISATION_STRING_TOO_LONG),
"personalisation string too long"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PRNG_NOT_SEEDED), "PRNG not seeded"},
+ {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_RANDOM_POOL_OVERFLOW),
+ "random pool overflow"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG),
"request too large for drbg"},
{ERR_PACK(ERR_LIB_RAND, 0, RAND_R_RESEED_ERROR), "reseed error"},
diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h
index 498b7e687e..10a6f00a2d 100644
--- a/crypto/rand/rand_lcl.h
+++ b/crypto/rand/rand_lcl.h
@@ -17,28 +17,24 @@
# include <openssl/ec.h>
# include "internal/rand.h"
-/*
- * Amount of randomness (in bytes) we want for initial seeding.
- * This is based on the fact that we use AES-128 as the CRBG, and
- * that we use the derivation function. If either of those changes,
- * (see rand_init() in rand_lib.c), change this.
- */
-# define RANDOMNESS_NEEDED 16
-
/* How many times to read the TSC as a randomness source. */
# define TSC_READ_COUNT 4
-/* Maximum amount of randomness to hold in RAND_BYTES_BUFFER. */
-# define MAX_RANDOMNESS_HELD (4 * RANDOMNESS_NEEDED)
-
/* Maximum count allowed in reseeding */
# define MAX_RESEED (1 << 24)
-/* How often we call RAND_poll() in drbg_entropy_from_system */
-# define RAND_POLL_RETRIES 8
+/* Max size of additional input and personalization string. */
+# define DRBG_MAX_LENGTH 4096
-/* Max size of entropy, addin, etc. Larger than any reasonable value */
-# define DRBG_MAX_LENGTH 0x7ffffff0
+/*
+ * The quotient between max_{entropy,nonce}len and min_{entropy,nonce}len
+ *
+ * The current factor is large enough that the RAND_POOL can store a
+ * random input which has a lousy entropy rate of 0.0625 bits per byte.
+ * This input will be sent through the derivation function which 'compresses'
+ * the low quality input into a high quality output.
+ */
+# define DRBG_MINMAX_FACTOR 128
/* DRBG status values */
@@ -51,22 +47,6 @@ typedef enum drbg_status_e {
/*
- * A buffer of random bytes to be fed as "entropy" into the DRBG. RAND_add()
- * adds data to the buffer, and the drbg_entropy_from_system() pulls data from
- * the buffer. We have a separate data structure because of the way the
- * API is defined; otherwise we'd run into deadlocks (RAND_bytes ->
- * RAND_DRBG_generate* -> drbg_entropy_from_system -> RAND_poll -> RAND_add ->
- * drbg_add*; the functions with an asterisk lock).
- */
-typedef struct rand_bytes_buffer_st {
- CRYPTO_RWLOCK *lock;
- unsigned char *buff;
- size_t size;
- size_t curr;
- int secure;
-} RAND_BYTES_BUFFER;
-
-/*
* The state of a DRBG AES-CTR.
*/
typedef struct rand_drbg_ctr_st {
@@ -94,30 +74,34 @@ struct rand_drbg_st {
int nid; /* the underlying algorithm */
int fork_count;
unsigned short flags; /* various external flags */
- char secure;
+
/*
- * This is a fixed-size buffer, but we malloc to make it a little
- * harder to find; a classic security/performance trade-off.
+ * The random pool 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).
*/
- int size;
+ RAND_POOL *pool;
- /*
+ /*
* The following parameters are setup by the per-type "init" function.
*
* Currently the only type is CTR_DRBG, its init function is ctr_init().
*
- * The parameters are closely related to the ones described in
+ * 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
+ * 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
+ * the 'len' suffix has been added to all buffer sizes for
* clarification.
*/
-
+
int strength;
size_t max_request;
size_t min_entropylen, max_entropylen;
@@ -143,23 +127,24 @@ struct rand_drbg_st {
/* The global RAND method, and the global buffer and DRBG instance. */
extern RAND_METHOD rand_meth;
-extern RAND_BYTES_BUFFER rand_bytes;
/* How often we've forked (only incremented in child). */
extern int rand_fork_count;
/* Hardware-based seeding functions. */
-void rand_read_tsc(RAND_poll_cb rand_add, void *arg);
-int rand_read_cpu(RAND_poll_cb rand_add, void *arg);
+size_t rand_acquire_entropy_from_tsc(RAND_POOL *pool);
+size_t rand_acquire_entropy_from_cpu(RAND_POOL *pool);
/* DRBG entropy callbacks. */
-void drbg_release_entropy(RAND_DRBG *drbg, unsigned char *out, size_t outlen);
-size_t drbg_entropy_from_parent(RAND_DRBG *drbg,
- unsigned char **pout,
- int entropy, size_t min_len, size_t max_len);
-size_t drbg_entropy_from_system(RAND_DRBG *drbg,
- unsigned char **pout,
- int entropy, size_t min_len, size_t max_len);
+size_t rand_drbg_get_entropy(RAND_DRBG *drbg,
+ unsigned char **pout,
+ int entropy, size_t min_len, size_t max_len);
+void rand_drbg_cleanup_entropy(RAND_DRBG *drbg,
+ unsigned char *out, size_t outlen);
+
+/* DRBG helpers */
+int rand_drbg_restart(RAND_DRBG *drbg,
+ const unsigned char *buffer, size_t len, size_t entropy);
/* DRBG functions implementing AES-CTR */
int ctr_init(RAND_DRBG *drbg);
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index 2f2ab6a86d..6f8deca1f9 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -24,7 +24,7 @@ static CRYPTO_RWLOCK *rand_engine_lock;
static CRYPTO_RWLOCK *rand_meth_lock;
static const RAND_METHOD *default_RAND_meth;
static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;
-RAND_BYTES_BUFFER rand_bytes;
+
int rand_fork_count;
#ifdef OPENSSL_RAND_SEED_RDTSC
@@ -37,12 +37,15 @@ int rand_fork_count;
# error "RDTSC enabled? Should not be possible!"
/*
+ * Acquire entropy from high-speed cloc