[openssl-commits] [openssl] master update

kaduk at mit.edu kaduk at mit.edu
Wed Oct 18 13:50:39 UTC 2017


The branch master has been updated
       via  2139145b72d084a3f974a94accd7d9812de286e4 (commit)
       via  e0b625f9db00509af9004b7907d44b78f332754a (commit)
       via  c16de9d8329d41a2433d0f273c080d9d06ad7a87 (commit)
      from  af1d638730bdfad85a7fa8c3f157b2828eda7c1d (commit)


- Log -----------------------------------------------------------------
commit 2139145b72d084a3f974a94accd7d9812de286e4
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date:   Wed Oct 11 19:25:26 2017 +0200

    Add missing RAND_DRBG locking
    
    The drbg's lock must be held across calls to RAND_DRBG_generate()
    to prevent simultaneous modification of internal state.
    
    This was observed in practice with simultaneous SSL_new() calls attempting
    to seed the (separate) per-SSL RAND_DRBG instances from the global
    rand_drbg instance; this eventually led to simultaneous calls to
    ctr_BCC_update() attempting to increment drbg->bltmp_pos for their
    respective partial final block, violating the invariant that bltmp_pos < 16.
    The AES operations performed in ctr_BCC_blocks() makes the race window
    quite easy to trigger.  A value of bltmp_pos greater than 16 induces
    catastrophic failure in ctr_BCC_final(), with subtraction overflowing
    and leading to an attempt to memset() to zero a very large range,
    which eventually reaches an unmapped page and segfaults.
    
    Provide the needed locking in get_entropy_from_parent(), as well as
    fixing a similar issue in RAND_priv_bytes().  There is also an
    unlocked call to RAND_DRBG_generate() in ssl_randbytes(), but the
    requisite serialization is already guaranteed by the requirements on
    the application's usage of SSL objects, and no further locking is
    needed for correct behavior.  In that case, leave a comment noting
    the apparent discrepancy and the reason for its safety (at present).
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    Reviewed-by: Kurt Roeckx <kurt at roeckx.be>
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/4328)

commit e0b625f9db00509af9004b7907d44b78f332754a
Author: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
Date:   Mon Oct 9 23:51:42 2017 +0200

    Remove unnecessary DRBG_RESEED state
    
    The DRBG_RESEED state plays an analogue role to the |reseed_required_flag| in
    Appendix B.3.4 of [NIST SP 800-90A Rev. 1]. The latter is a local variable,
    the scope of which is limited to the RAND_DRBG_generate() function. Hence there
    is no need for a DRBG_RESEED state outside of the generate function. This state
    was removed and replaced by a local variable |reseed_required|.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    Reviewed-by: Kurt Roeckx <kurt at roeckx.be>
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/4328)

commit c16de9d8329d41a2433d0f273c080d9d06ad7a87
Author: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
Date:   Thu Aug 31 23:16:22 2017 +0200

    Fix reseeding issues of the public RAND_DRBG
    
    Reseeding is handled very differently by the classic RAND_METHOD API
    and the new RAND_DRBG api. These differences led to some problems when
    the new RAND_DRBG was made the default OpenSSL RNG. In particular,
    RAND_add() did not work as expected anymore. These issues are discussed
    on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API'
    and in Pull Request #4328. This commit fixes the mentioned issues,
    introducing the following changes:
    
    - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which
      facilitates collecting entropy by the get_entropy() callback.
    - Don't use RAND_poll()/RAND_add() for collecting entropy from the
      get_entropy() callback anymore. Instead, replace RAND_poll() by
      RAND_POOL_acquire_entropy().
    - Add a new function rand_drbg_restart() which tries to get the DRBG
      in an instantiated state by all means, regardless of the current
      state (uninstantiated, error, ...) the DRBG is in. If the caller
      provides entropy or additional input, it will be used for reseeding.
    - Restore the original documented behaviour of RAND_add() and RAND_poll()
      (namely to reseed the DRBG immediately) by a new implementation based
      on rand_drbg_restart().
    - Add automatic error recovery from temporary failures of the entropy
      source to RAND_DRBG_generate() using the rand_drbg_restart() function.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    Reviewed-by: Kurt Roeckx <kurt at roeckx.be>
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/4328)

-----------------------------------------------------------------------

Summary of changes:
 crypto/err/openssl.txt             |  13 +
 crypto/include/internal/rand_int.h |   2 +-
 crypto/init.c                      |   2 +-
 crypto/rand/drbg_lib.c             | 333 ++++++++++++++++++-----
 crypto/rand/drbg_rand.c            |   4 +-
 crypto/rand/rand_err.c             |  21 ++
 crypto/rand/rand_lcl.h             |  88 +++---
 crypto/rand/rand_lib.c             | 539 +++++++++++++++++++++++++++++--------
 crypto/rand/rand_unix.c            | 127 ++++++---
 crypto/rand/rand_vms.c             |  13 +-
 crypto/rand/rand_win.c             |  84 +++---
 doc/man3/RAND_add.pod              |  89 ++++--
 include/internal/rand.h            |  45 ++++
 include/openssl/ossl_typ.h         |   1 +
 include/openssl/rand.h             |   1 -
 include/openssl/randerr.h          |  13 +
 ssl/ssl_lib.c                      |  26 +-
 test/drbgtest.c                    |   2 +-
 util/libcrypto.num                 |  15 +-
 19 files changed, 1078 insertions(+), 340 deletions(-)

diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 67f7086..1749a70 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 d0999f2..fc1abd9 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 3eda1c9..8daf4e3 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 b7f7e4c..c471b6e 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);
@@ -113,6 +116,8 @@ void RAND_DRBG_free(RAND_DRBG *drbg)
 /*
  * Instantiate |drbg|, after it has been initialized.  Use |pers| and
  * |perslen| as prediction-resistance input.
+ *
+ * Requires that drbg->lock is already locked for write, if non-null.
  */
 int RAND_DRBG_instantiate(RAND_DRBG *drbg,
                           const unsigned char *pers, size_t perslen)
@@ -136,7 +141,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 +151,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 +171,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;
@@ -171,6 +187,8 @@ end:
 
 /*
  * Uninstantiate |drbg|. Must be instantiated before it can be used.
+ *
+ * Requires that drbg->lock is already locked for write, if non-null.
  */
 int RAND_DRBG_uninstantiate(RAND_DRBG *drbg)
 {
@@ -182,7 +200,9 @@ int RAND_DRBG_uninstantiate(RAND_DRBG *drbg)
 }
 
 /*
- * Mix in the specified data to reseed |drbg|.
+ * Reseed |drbg|, mixing in the specified data
+ *
+ * Requires that drbg->lock is already locked for write, if non-null.
  */
 int RAND_DRBG_reseed(RAND_DRBG *drbg,
                      const unsigned char *adin, size_t adinlen)
@@ -210,7 +230,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 +250,136 @@ 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|.
+ *
+ * Requires that drbg->lock is already locked for write, if non-null.
+ *
+ * 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;
+    int reseed_required = 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;
@@ -256,13 +391,13 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
 
     if (drbg->fork_count != rand_fork_count) {
         drbg->fork_count = rand_fork_count;
-        drbg->state = DRBG_RESEED;
+        reseed_required = 1;
     }
 
     if (drbg->reseed_counter >= drbg->reseed_interval)
-        drbg->state = DRBG_RESEED;
+        reseed_required = 1;
 
-    if (drbg->state == DRBG_RESEED || prediction_resistance) {
+    if (reseed_required || prediction_resistance) {
         if (!RAND_DRBG_reseed(drbg, adin, adinlen)) {
             RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_RESEED_ERROR);
             return 0;
@@ -277,29 +412,61 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
         return 0;
     }
 
-    if (drbg->reseed_counter >= drbg->reseed_interval)
-        drbg->state = DRBG_RESEED;
-    else
-        drbg->reseed_counter++;
+    drbg->reseed_counter++;
+
     return 1;
 }
 
 /*
- * 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 +501,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 +542,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 +595,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 +653,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 +665,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 83f1ad8..f45ef14 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 707f010..dc6140c 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 498b7e6..5e319d8 100644
--- a/crypto/rand/rand_lcl.h
+++ b/crypto/rand/rand_lcl.h
@@ -17,56 +17,35 @@
 # 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 */
 typedef enum drbg_status_e {
     DRBG_UNINITIALISED,
     DRBG_READY,
-    DRBG_RESEED,
     DRBG_ERROR
 } DRBG_STATUS;
 
 
 /*
- * 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 +73,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 +126,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 2f2ab6a..a290e5c 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 clock
+ *
  * Since we get some randomness from the low-order bits of the
- * high-speec clock, it can help.  But don't return a status since
- * it's not sufficient to indicate whether or not the seeding was
- * done.
+ * high-speed clock, it can help.
+ *
+ * Returns the total entropy count, if it exceeds the requested
+ * entropy count. Otherwise, returns an entropy count of 0.
  */
-void rand_read_tsc(RAND_poll_cb rand_add, void *arg)
+size_t rand_acquire_entropy_from_tsc(RAND_POOL *pool)
 {
     unsigned char c;
     int i;
@@ -50,126 +53,149 @@ void rand_read_tsc(RAND_poll_cb rand_add, void *arg)
     if ((OPENSSL_ia32cap_P[0] & (1 << 4)) != 0) {
         for (i = 0; i < TSC_READ_COUNT; i++) {
             c = (unsigned char)(OPENSSL_rdtsc() & 0xFF);
-            rand_add(arg, &c, 1, 0.5);
+            RAND_POOL_add(pool, &c, 1, 4);
         }
     }
+    return RAND_POOL_entropy_available(pool);
 }
 #endif
 
 #ifdef OPENSSL_RAND_SEED_RDCPU
-size_t OPENSSL_ia32_rdseed_bytes(char *buf, size_t len);
-size_t OPENSSL_ia32_rdrand_bytes(char *buf, size_t len);
+size_t OPENSSL_ia32_rdseed_bytes(unsigned char *buf, size_t len);
+size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len);
 
 extern unsigned int OPENSSL_ia32cap_P[];
 
-int rand_read_cpu(RAND_poll_cb rand_add, void *arg)
+/*
+ * Acquire entropy using Intel-specific cpu instructions
+ *
+ * Uses the RDSEED instruction if available, otherwise uses
+ * RDRAND if available.
+ *
+ * For the differences between RDSEED and RDRAND, and why RDSEED
+ * is the preferred choice, see https://goo.gl/oK3KcN
+ *
+ * Returns the total entropy count, if it exceeds the requested
+ * entropy count. Otherwise, returns an entropy count of 0.
+ */
+size_t rand_acquire_entropy_from_cpu(RAND_POOL *pool)
 {
-    char buff[RANDOMNESS_NEEDED];
-
-    /* If RDSEED is available, use that. */
-    if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) {
-        if (OPENSSL_ia32_rdseed_bytes(buff, sizeof(buff)) == sizeof(buff)) {
-            rand_add(arg, buff, (int)sizeof(buff), sizeof(buff));
-            return 1;
-        }
-    }
-
-    /* Second choice is RDRAND. */
-    if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) {
-        if (OPENSSL_ia32_rdrand_bytes(buff, sizeof(buff)) == sizeof(buff)) {
-            rand_add(arg, buff, (int)sizeof(buff), sizeof(buff));
-            return 1;
+    size_t bytes_needed;
+    unsigned char *buffer;
+
+    bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
+    if (bytes_needed > 0) {
+        buffer = RAND_POOL_add_begin(pool, bytes_needed);
+
+        if (buffer != NULL) {
+
+            /* If RDSEED is available, use that. */
+            if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) {
+                if (OPENSSL_ia32_rdseed_bytes(buffer, bytes_needed)
+                    == bytes_needed)
+                    return RAND_POOL_add_end(pool,
+                                             bytes_needed,
+                                             8 * bytes_needed);
+            }
+
+            /* Second choice is RDRAND. */
+            if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) {
+                if (OPENSSL_ia32_rdrand_bytes(buffer, bytes_needed)
+                    == bytes_needed)
+                    return RAND_POOL_add_end(pool,
+                                             bytes_needed,
+                                             8 * bytes_needed);
+            }
+
+            return RAND_POOL_add_end(pool, 0, 0);
         }
     }
 
-    return 0;
+    return RAND_POOL_entropy_available(pool);
 }
 #endif
 
 
 /*
- * DRBG has two sets of callbacks; we only discuss the "entropy" one
- * here.  When the DRBG needs additional randomness bits (called entropy
- * in the NIST document), it calls the get_entropy callback which fills in
- * a pointer and returns the number of bytes. When the DRBG is finished with
- * the buffer, it calls the cleanup_entropy callback, with the value of
- * the buffer that the get_entropy callback filled in.
+ * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks())
+ *
+ * If the DRBG has a parent, then the required amount of entropy input
+ * is fetched using the parent's RAND_DRBG_generate().
  *
- * Get entropy from the system, via RAND_poll if needed.  The |entropy|
- * is the bits of randomness required, and is expected to fit into a buffer
- * of |min_len|..|max__len| size.  We assume we're getting high-quality
- * randomness from the system, and that |min_len| bytes will do.
+ * Otherwise, the entropy is polled from the system entropy sources
+ * using RAND_POOL_acquire_entropy().
+ *
+ * If a random pool has been added to the DRBG using RAND_add(), then
+ * its entropy will be used up first.
  */
-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)
 {
-    int i;
-    unsigned char *randomness;
+    size_t ret = 0;
+    size_t entropy_available = 0;
+    RAND_POOL *pool = RAND_POOL_new(entropy, min_len, max_len);
 
-    if (min_len > (size_t)drbg->size) {
-        /* Should not happen.  See comment near RANDOMNESS_NEEDED. */
-        min_len = drbg->size;
-    }
-
-    randomness = drbg->secure ? OPENSSL_secure_malloc(drbg->size)
-                                    : OPENSSL_malloc(drbg->size);
-
-    /* If we don't have enough, try to get more. */
-    CRYPTO_THREAD_write_lock(rand_bytes.lock);
-    for (i = RAND_POLL_RETRIES; rand_bytes.curr < min_len && --i >= 0; ) {
-        CRYPTO_THREAD_unlock(rand_bytes.lock);
-        RAND_poll();
-        CRYPTO_THREAD_write_lock(rand_bytes.lock);
-    }
+    if (pool == NULL)
+        return 0;
 
-    /* Get desired amount, but no more than we have. */
-    if (min_len > rand_bytes.curr)
-        min_len = rand_bytes.curr;
-    if (min_len != 0) {
-        memcpy(randomness, rand_bytes.buff, min_len);
-        /* Update amount left and shift it down. */
-        rand_bytes.curr -= min_len;
-        if (rand_bytes.curr != 0)
-            memmove(rand_bytes.buff, &rand_bytes.buff[min_len], rand_bytes.curr);
+    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;
     }
-    CRYPTO_THREAD_unlock(rand_bytes.lock);
-    *pout = randomness;
-    return min_len;
-}
 
-size_t drbg_entropy_from_parent(RAND_DRBG *drbg,
-                                unsigned char **pout,
-                                int entropy, size_t min_len, size_t max_len)
-{
-    int st;
-    unsigned char *randomness;
+    if (drbg->parent) {
+        size_t bytes_needed = RAND_POOL_bytes_needed(pool, 8);
+        unsigned char *buffer = RAND_POOL_add_begin(pool, bytes_needed);
+
+        if (buffer != NULL) {
+            size_t bytes = 0;
+
+            /*
+             * Get random from parent, include our state as additional input.
+             * Our lock is already held, but we need to lock our parent before
+             * generating bits from it.
+             */
+            if (drbg->parent->lock)
+                CRYPTO_THREAD_write_lock(drbg->parent->lock);
+            if (RAND_DRBG_generate(drbg->parent,
+                                   buffer, bytes_needed,
+                                   0,
+                                   (unsigned char *)drbg, sizeof(*drbg)) != 0)
+                bytes = bytes_needed;
+            if (drbg->parent->lock)
+                CRYPTO_THREAD_unlock(drbg->parent->lock);
+
+            entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
+        }
 
-    if (min_len > (size_t)drbg->size) {
-        /* Should not happen.  See comment near RANDOMNESS_NEEDED. */
-        min_len = drbg->size;
+    } else {
+        /* Get entropy by polling system entropy sources. */
+        entropy_available = RAND_POOL_acquire_entropy(pool);
     }
 
-    randomness = drbg->secure ? OPENSSL_secure_malloc(drbg->size)
-                                    : OPENSSL_malloc(drbg->size);
-
-    /* Get random from parent, include our state as additional input. */
-    st = RAND_DRBG_generate(drbg->parent, randomness, min_len, 0,
-                            (unsigned char *)drbg, sizeof(*drbg));
-    if (st == 0) {
-        drbg_release_entropy(drbg, randomness, min_len);
-        return 0;
+    if (entropy_available > 0) {
+        ret   = RAND_POOL_length(pool);
+        *pout = RAND_POOL_detach(pool);
     }
-    *pout = randomness;
-    return min_len;
+
+    RAND_POOL_free(pool);
+    return ret;
 }
 
-void drbg_release_entropy(RAND_DRBG *drbg, unsigned char *out, size_t outlen)
+
+/*
+ * Implements the cleanup_entropy() callback (see RAND_DRBG_set_callbacks())
+ *
+ */
+void rand_drbg_cleanup_entropy(RAND_DRBG *drbg,
+                               unsigned char *out, size_t outlen)
 {
-    if (drbg->secure)
-        OPENSSL_secure_clear_free(out, outlen);
-    else
-        OPENSSL_clear_free(out, outlen);
+    OPENSSL_secure_clear_free(out, outlen);
 }
 
 void rand_fork()
@@ -188,15 +214,6 @@ DEFINE_RUN_ONCE_STATIC(do_rand_init)
     rand_meth_lock = CRYPTO_THREAD_glock_new("rand_meth");
     ret &= rand_meth_lock != NULL;
 
-    rand_bytes.lock = CRYPTO_THREAD_glock_new("rand_bytes");
-    ret &= rand_bytes.lock != NULL;
-    rand_bytes.curr = 0;
-    rand_bytes.size = MAX_RANDOMNESS_HELD;
-    rand_bytes.secure = CRYPTO_secure_malloc_initialized();
-    rand_bytes.buff = rand_bytes.secure
-        ? OPENSSL_secure_malloc(rand_bytes.size)
-        : OPENSSL_malloc(rand_bytes.size);
-    ret &= rand_bytes.buff != NULL;
     return ret;
 }
 
@@ -211,25 +228,314 @@ void rand_cleanup_int(void)
     CRYPTO_THREAD_lock_free(rand_engine_lock);
 #endif
     CRYPTO_THREAD_lock_free(rand_meth_lock);
-    CRYPTO_THREAD_lock_free(rand_bytes.lock);
-    if (rand_bytes.secure)
-        OPENSSL_secure_clear_free(rand_bytes.buff, rand_bytes.size);
-    else
-        OPENSSL_clear_free(rand_bytes.buff, rand_bytes.size);
 }
 
 /*
- * RAND_poll_ex() gets a function pointer to call when it has random bytes.
- * RAND_poll() sets the function pointer to be a wrapper that calls RAND_add().
+ * RAND_poll() reseeds the default RNG using random input
+ *
+ * The random input is obtained from polling various entropy
+ * sources which depend on the operating system and are
+ * configurable via the --with-rand-seed configure option.
+ */
+int RAND_poll(void)
+{
+    int ret = 0;
+
+    RAND_POOL *pool = NULL;
+
+    const RAND_METHOD *meth = RAND_get_rand_method();
+
+    if (meth == RAND_OpenSSL()) {
+        /* fill random pool and seed the default DRBG */
+        RAND_DRBG *drbg = RAND_DRBG_get0_global();
+
+        if (drbg == NULL)
+            return 0;
+
+        CRYPTO_THREAD_write_lock(drbg->lock);
+        ret = rand_drbg_restart(drbg, NULL, 0, 0);
+        CRYPTO_THREAD_unlock(drbg->lock);
+
+        return ret;
+
+    } else {
+        /* 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));
+        if (pool == NULL)
+            return 0;
+
+        if (RAND_POOL_acquire_entropy(pool) == 0)
+            goto err;
+
+        if (meth->add == NULL
+            || meth->add(RAND_POOL_buffer(pool),
+                         RAND_POOL_length(pool),
+                         (RAND_POOL_entropy(pool) / 8.0)) == 0)
+            goto err;
+
+        ret = 1;
+    }
+
+err:
+    RAND_POOL_free(pool);
+    return ret;
+}
+
+/*
+ * 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 */
+
+    size_t min_len; /* minimum number of random bytes requested */
+    size_t max_len; /* maximum number of random bytes (allocated buffer size) */
+    size_t entropy; /* current entropy count in bits */
+    size_t requested_entropy; /* requested entropy count in bits */
+};
+
+/*
+ * Allocate memory and initialize a new random pool
  */
-static void call_rand_add(void* arg, const void *buf, int num, double r)
+
+RAND_POOL *RAND_POOL_new(int entropy, size_t min_len, size_t max_len)
 {
-    RAND_add(buf, num, r);
+    RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool));
+
+    if (pool == NULL) {
+        RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    pool->min_len = min_len;
+    pool->max_len = max_len;
+
+    pool->buffer = OPENSSL_secure_zalloc(pool->max_len);
+    if (pool->buffer == NULL) {
+        RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    pool->requested_entropy = entropy;
+
+    return pool;
+
+err:
+    OPENSSL_free(pool);
+    return NULL;
 }
 
-int RAND_poll(void)
+/*
+ * Free |pool|, securely erasing its buffer.
+ */
+void RAND_POOL_free(RAND_POOL *pool)
 {
-    return RAND_poll_ex(call_rand_add, NULL);
+    if (pool == NULL)
+        return;
+
+    OPENSSL_secure_clear_free(pool->buffer, pool->max_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().
+ */
+unsigned char *RAND_POOL_detach(RAND_POOL *pool)
+{
+    unsigned char *ret = pool->buffer;
+    pool->buffer = NULL;
+    return ret;
+}
+
+
+/*
+ * 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?
+ */
+#define ENTROPY_TO_BYTES(bits, entropy_per_bytes) \
+    (((bits) + ((entropy_per_bytes) - 1))/(entropy_per_bytes))
+
+
+/*
+ * 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->requested_entropy)
+        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->requested_entropy)
+        return pool->requested_entropy - 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.
+ * In case of an error, 0 is returned.
+ */
+
+size_t RAND_POOL_bytes_needed(RAND_POOL *pool, unsigned int entropy_per_byte)
+{
+    size_t bytes_needed;
+    size_t entropy_needed = RAND_POOL_entropy_needed(pool);
+
+    if (entropy_per_byte < 1 || entropy_per_byte > 8) {
+        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);
+
+    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;
+
+    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.
+ *
+ * Return available amount of entropy after this operation.
+ * (see RAND_POOL_entropy_available(pool))
+ */
+size_t 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 (len > 0) {
+        memcpy(pool->buffer + pool->len, buffer, len);
+        pool->len += len;
+        pool->entropy += entropy;
+    }
+
+    return RAND_POOL_entropy_available(pool);
+}
+
+/*
+ * 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 udpate 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;
+    }
+
+    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.
+ */
+size_t RAND_POOL_add_end(RAND_POOL *pool, size_t len, size_t entropy)
+{
+    if (len > pool->max_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 RAND_POOL_entropy_available(pool);
 }
 
 int RAND_set_rand_method(const RAND_METHOD *meth)
@@ -328,6 +634,7 @@ int RAND_priv_bytes(unsigned char *buf, int num)
 {
     const RAND_METHOD *meth = RAND_get_rand_method();
     RAND_DRBG *drbg;
+    int ret;
 
     if (meth != RAND_OpenSSL())
         return RAND_bytes(buf, num);
@@ -336,7 +643,11 @@ int RAND_priv_bytes(unsigned char *buf, int num)
     if (drbg == NULL)
         return 0;
 
-    return RAND_DRBG_generate(drbg, buf, num, 0, NULL, 0);
+    /* We have to lock the DRBG before generating bits from it. */
+    CRYPTO_THREAD_write_lock(drbg->lock);
+    ret = RAND_DRBG_generate(drbg, buf, num, 0, NULL, 0);
+    CRYPTO_THREAD_unlock(drbg->lock);
+    return ret;
 }
 
 int RAND_bytes(unsigned char *buf, int num)
diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c
index 08ea55f..f5a59cb 100644
--- a/crypto/rand/rand_unix.c
+++ b/crypto/rand/rand_unix.c
@@ -14,12 +14,18 @@
 #include "rand_lcl.h"
 #include <stdio.h>
 
-#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI))
+#ifdef OPENSSL_RAND_SEED_GETRANDOM
+# include <linux/random.h>
+#endif
 
-# if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \
+#if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \
         !defined(OPENSSL_RAND_SEED_NONE)
-#  error "UEFI and VXWorks only support seeding NONE"
-# endif
+# error "UEFI and VXWorks only support seeding NONE"
+#endif
+
+#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) \
+    || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \
+    || defined(OPENSSL_SYS_UEFI))
 
 # if defined(OPENSSL_SYS_VOS)
 
@@ -46,16 +52,16 @@
  * would be far more predictable.  This should only be used for legacy
  * platforms.
  *
- * As a precaution, we generate four times the required amount of seed
- * data.
+ * As a precaution, we assume only 2 bits of entropy per byte.
  */
-int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
+size_t RAND_POOL_acquire_entropy(RAND_POOL *pool)
 {
     short int code;
     gid_t curr_gid;
     pid_t curr_pid;
     uid_t curr_uid;
     int i, k;
+    size_t bytes_needed;
     struct timespec ts;
     unsigned char v;
 #  ifdef OPENSSL_SYS_VOS_HPPA
@@ -71,13 +77,15 @@ int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
      * different processes.
      */
     curr_gid = getgid();
-    rand_add(arg, &curr_gid, sizeof curr_gid, 0);
+    RAND_POOL_add(pool, &curr_gid, sizeof(curr_gid), 0);
     curr_pid = getpid();
-    rand_add(arg, &curr_pid, sizeof curr_pid, 0);
+    RAND_POOL_add(pool, &curr_pid, sizeof(curr_pid), 0);
     curr_uid = getuid();
-    rand_add(arg, &curr_uid, sizeof curr_uid, 0);
+    RAND_POOL_add(pool, &curr_uid, sizeof(curr_uid), 0);
 
-    for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) {
+    bytes_needed = RAND_POOL_bytes_needed(pool, 2 /*entropy_per_byte*/);
+
+    for (i = 0; i < bytes_needed; i++) {
         /*
          * burn some cpu; hope for interrupts, cache collisions, bus
          * interference, etc.
@@ -98,9 +106,9 @@ int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
         /* Get wall clock time, take 8 bits. */
         clock_gettime(CLOCK_REALTIME, &ts);
         v = (unsigned char)(ts.tv_nsec & 0xFF);
-        rand_add(arg, &v, sizeof v, 1);
+        RAND_POOL_add(pool, arg, &v, sizeof(v) , 2);
     }
-    return 1;
+    return RAND_POOL_entropy_available(pool);
 }
 
 # else
@@ -127,27 +135,44 @@ int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
 #  endif
 
 /*
- * Try the various seeding methods in turn, exit when succesful.
+ * Try the various seeding methods in turn, exit when successful.
+ *
+ * TODO(DRBG): If more than one entropy source is available, is it
+ * preferable to stop as soon as enough entropy has been collected
+ * (as favored by @rsalz) or should one rather be defensive and add
+ * more entropy than requested and/or from different sources?
+ *
+ * Currently, the user can select multiple entropy sources in the
+ * configure step, yet in practice only the first available source
+ * will be used. A more flexible solution has been requested, but
+ * currently it is not clear how this can be achieved without
+ * overengineering the problem. There are many parameters which
+ * could be taken into account when selecting the order and amount
+ * of input from the different entropy sources (trust, quality,
+ * possibility of blocking).
  */
-int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
+size_t RAND_POOL_acquire_entropy(RAND_POOL *pool)
 {
 #  ifdef OPENSSL_RAND_SEED_NONE
-    return 0;
+    return RAND_POOL_entropy_available(pool);
 #  else
-    int ok = 1;
-    char temp[RANDOMNESS_NEEDED];
-#   define TEMPSIZE (int)sizeof(temp)
+    size_t bytes_needed;
+    size_t entropy_available = 0;
+    unsigned char *buffer;
 
 #   ifdef OPENSSL_RAND_SEED_GETRANDOM
-    {
-        int i = getrandom(temp, TEMPSIZE, 0);
+    bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
+    buffer = RAND_POOL_add_begin(pool, bytes_needed);
+    if (buffer != NULL) {
+        size_t bytes = 0;
 
-        if (i >= 0) {
-            rand_add(arg, temp, i, i);
-            if (i == TEMPSIZE)
-                goto done;
-        }
+        if (getrandom(buffer, bytes_needed, 0) == (int)bytes_needed)
+            bytes = bytes_needed;
+
+        entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
     }
+    if (entropy_available > 0)
+        return entropy_available;
 #   endif
 
 #   if defined(OPENSSL_RAND_SEED_LIBRANDOM)
@@ -157,7 +182,8 @@ int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
 #   endif
 
 #   ifdef OPENSSL_RAND_SEED_DEVRANDOM
-    {
+    bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
+    if (bytes_needed > 0) {
         static const char *paths[] = { DEVRANDOM, NULL };
         FILE *fp;
         int i;
@@ -166,44 +192,59 @@ int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
             if ((fp = fopen(paths[i], "rb")) == NULL)
                 continue;
             setbuf(fp, NULL);
-            if (fread(temp, 1, TEMPSIZE, fp) == TEMPSIZE) {
-                rand_add(arg, temp, TEMPSIZE, TEMPSIZE);
-                fclose(fp);
-                goto done;
+            buffer = RAND_POOL_add_begin(pool, bytes_needed);
+            if (buffer != NULL) {
+                size_t bytes = 0;
+                if (fread(buffer, 1, bytes_needed, fp) == bytes_needed)
+                    bytes = bytes_needed;
+
+                entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
             }
             fclose(fp);
+            if (entropy_available > 0)
+                return entropy_available;
+
+            bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
         }
     }
 #   endif
 
 #   ifdef OPENSSL_RAND_SEED_RDTSC
-    rand_read_tsc(rand_add, arg);
+    entropy_available = rand_acquire_entropy_from_tsc(pool);
+    if (entropy_available > 0)
+        return entropy_available;
 #   endif
 
 #   ifdef OPENSSL_RAND_SEED_RDCPU
-    if (rand_read_cpu(rand_add, arg))
-        goto done;
+    entropy_available = rand_acquire_entropy_from_cpu(pool);
+    if (entropy_available > 0)
+        return entropy_available;
 #   endif
 
 #   ifdef OPENSSL_RAND_SEED_EGD
-    {
+    bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
+    if (bytes_needed > 0) {
         static const char *paths[] = { DEVRANDOM_EGD, NULL };
         int i;
 
         for (i = 0; paths[i] != NULL; i++) {
-            if (RAND_query_egd_bytes(paths[i], temp, TEMPSIZE) == TEMPSIZE) {
-                rand_add(arg, temp, TEMPSIZE, TEMPSIZE);
-                goto done;
+            buffer = RAND_POOL_add_begin(pool, bytes_needed);
+            if (buffer != NULL) {
+                size_t bytes = 0;
+                int num = RAND_query_egd_bytes(paths[i],
+                                               buffer, (int)bytes_needed);
+                if (num == (int)bytes_needed)
+                    bytes = bytes_needed;
+
+                entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
             }
+            if (entropy_available > 0)
+                return entropy_available;
         }
     }
 #   endif
 
-    ok = 0;
-
-done:
-    OPENSSL_cleanse(temp, TEMPSIZE);
-    return ok;
+    return RAND_POOL_entropy_available(pool);
 #  endif
 }
 # endif
diff --git a/crypto/rand/rand_vms.c b/crypto/rand/rand_vms.c
index 773373d..4ec4b35 100644
--- a/crypto/rand/rand_vms.c
+++ b/crypto/rand/rand_vms.c
@@ -54,7 +54,7 @@ static struct items_data_st {
     {0, 0}
 };
 
-int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
+size_t RAND_POOL_acquire_entropy(RAND_POOL *pool)
 {
     /* determine the number of items in the JPI array */
     struct items_data_st item_entry;
@@ -112,9 +112,14 @@ int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
 
     total_length += (tmp_length - 1);
 
-    /* size of seed is total_length*4 bytes (64bytes) */
-    rand_add(arg, (PTR_T)data_buffer, total_length * 4, total_length * 2);
-    return 1;
+    /*
+     * Size of seed is total_length*4 bytes (64bytes). The original assumption
+     * was that it contains 4 bits of entropy per byte. This makes a total
+     * amount of total_length*16 bits (256bits).
+     */
+    return RAND_POOL_add(pool,
+                         (PTR_T)data_buffer, total_length * 4,
+                         total_length * 16);
 }
 
 #endif
diff --git a/crypto/rand/rand_win.c b/crypto/rand/rand_win.c
index 8637ca4..9eff319 100644
--- a/crypto/rand/rand_win.c
+++ b/crypto/rand/rand_win.c
@@ -10,7 +10,6 @@
 #include "internal/cryptlib.h"
 #include <openssl/rand.h>
 #include "rand_lcl.h"
-
 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
 
 # ifndef OPENSSL_RAND_SEED_OS
@@ -39,55 +38,80 @@
 #  define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
 # endif
 
-int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
+size_t RAND_POOL_acquire_entropy(RAND_POOL *pool)
 {
 # ifndef USE_BCRYPTGENRANDOM
     HCRYPTPROV hProvider;
-    int ok = 0;
 # endif
-    BYTE buf[RANDOMNESS_NEEDED];
+    unsigned char *buffer;
+    size_t bytes_needed;
+    size_t entropy_available = 0;
+
 
 # ifdef OPENSSL_RAND_SEED_RDTSC
-    rand_read_tsc(cb, arg);
+    entropy_available = rand_acquire_entropy_from_tsc(pool);
+    if (entropy_available > 0)
+        return entropy_available;
 # endif
+
 # ifdef OPENSSL_RAND_SEED_RDCPU
-    if (rand_read_cpu(cb, arg))
-        return 1;
+    entropy_available = rand_acquire_entropy_from_cpu(pool);
+    if (entropy_available > 0)
+        return entropy_available;
 # endif
 
 # ifdef USE_BCRYPTGENRANDOM
-    if (BCryptGenRandom(NULL, buf, (ULONG)sizeof(buf),
-                        BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) {
-        rand_add(arg, buf, sizeof(buf), sizeof(buf));
-        return 1;
+    bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
+    buffer = RAND_POOL_add_begin(pool, bytes_needed);
+    if (buffer != NULL) {
+        size_t bytes = 0;
+        if (BCryptGenRandom(NULL, buffer, bytes_needed,
+            BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS)
+            bytes = bytes_needed;
+
+        entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
     }
+    if (entropy_available > 0)
+        return entropy_available;
 # else
-    /* poll the CryptoAPI PRNG */
-    if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
-                             CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
-        if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
-            rand_add(arg, buf, sizeof(buf), sizeof(buf));
-            ok = 1;
+    bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
+    buffer = RAND_POOL_add_begin(pool, bytes_needed);
+    if (buffer != NULL) {
+        size_t bytes = 0;
+        /* poll the CryptoAPI PRNG */
+        if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
+            CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
+            if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
+                bytes = bytes_needed;
+
+            CryptReleaseContext(hProvider, 0);
         }
-        CryptReleaseContext(hProvider, 0);
-        if (ok)
-            return 1;
+
+        entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
     }
+    if (entropy_available > 0)
+        return entropy_available;
+
+    bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
+    buffer = RAND_POOL_add_begin(pool, bytes_needed);
+    if (buffer != NULL) {
+        size_t bytes = 0;
+        /* poll the Pentium PRG with CryptoAPI */
+        if (CryptAcquireContextW(&hProvider, NULL,
+                                 INTEL_DEF_PROV, PROV_INTEL_SEC,
+                                 CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
+            if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
+                bytes = bytes_needed;
 
-    /* poll the Pentium PRG with CryptoAPI */
-    if (CryptAcquireContextW(&hProvider, NULL, INTEL_DEF_PROV, PROV_INTEL_SEC,
-                             CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
-        if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
-            rand_add(arg, buf, sizeof(buf), sizeof(buf));
-            ok = 1;
+            CryptReleaseContext(hProvider, 0);
         }
-        CryptReleaseContext(hProvider, 0);
-        if (ok)
-            return 1;
+        entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
     }
+    if (entropy_available > 0)
+        return entropy_available;
 # endif
 
-    return 0;
+    return RAND_POOL_entropy_available(pool);
 }
 
 # if OPENSSL_API_COMPAT < 0x10100000L
diff --git a/doc/man3/RAND_add.pod b/doc/man3/RAND_add.pod
index ea81492..62048e6 100644
--- a/doc/man3/RAND_add.pod
+++ b/doc/man3/RAND_add.pod
@@ -2,8 +2,7 @@
 
 =head1 NAME
 
-RAND_add, RAND_poll, RAND_poll_ex, RAND_poll_cb,
-RAND_seed, RAND_status, RAND_event, RAND_screen
+RAND_add, RAND_poll, RAND_seed, RAND_status, RAND_event, RAND_screen
 - add randomness to the PRNG or get its status
 
 =head1 SYNOPSIS
@@ -11,10 +10,6 @@ RAND_seed, RAND_status, RAND_event, RAND_screen
  #include <openssl/rand.h>
 
  int RAND_status(void);
-
- typedef void (*RAND_poll_cb)(void *arg,
-                              const void *buf, int num, double randomness);
- int RAND_poll_ex(RAND_poll_cb cb, void *arg);
  int RAND_poll();
 
  void RAND_add(const void *buf, int num, double randomness);
@@ -40,16 +35,12 @@ and network packet timings, can be reasonable sources of seeding material.
 RAND_status() indicates whether or not the CSPRNG has been sufficiently
 seeded. If not, functions such as RAND_bytes(3) will fail.
 
-RAND_poll_ex() uses the system's capabilities to obtain a buffer
-containing random bits which can then be used to seed a CSPRNG. The
-exact features used depends on how OpenSSL was configured, and a summary
-can be displayed with the OpenSSL L<version(1)> command.  This function
-is normally called as needed by the CSPRNG.  The B<arg> parameter is an
-arbitrary pointer which will be passed as an argument to the callback.
-The B<cb> function is called each time there is data to add.
-
-RAND_poll() invokes RAND_poll_ex() with B<cb> and B<arg> set so that it
-will call RAND_add(), to add the randomness to the global CSPRNG.
+RAND_poll() uses the system's capabilities to seed the CSPRNG using
+random input obtained from polling various trusted entropy sources.
+The default choice of the entropy source can be modified at build time
+using the --with-rand-seed configure option, see also the B<NOTES> section.
+A summary of the configure options can be displayed with the OpenSSL
+L<version(1)> command.
 
 RAND_add() mixes the B<num> bytes at B<buf> into the PRNG state.
 The B<randomness> argument is an estimate of how much randomness is
@@ -78,6 +69,72 @@ RAND_event() returns RAND_status().
 
 The other functions do not return values.
 
+=head1 NOTES
+
+The new OpenSSL DRBG has some peculiarities which need to be taken
+into account when it is selected as the default OpenSSL CSPRNG, i.e.,
+when RAND_get_rand_method() == RAND_OpenSSL().
+This applies in particular to the way reseeding is done by the DRBG:
+
+=over 2
+
+=item *
+
+The DRBG seeds itself automatically, pulling random input from trusted
+entropy sources.
+Automatic reseeding occurs after a predefined number of generate requests.
+The selection of the trusted entropy sources is configured at build
+time using the --with-rand-seed option.
+
+=item *
+
+The DRBG distinguishes two different types of random input:
+'entropy', which comes from a trusted source, and 'additional input',
+which can optionally be added by the user and is considered untrusted.
+
+=back
+
+Automatic seeding can be disabled using the --with-rand-seed=none option.
+
+=head2 DRBG with automatic seeding enabled
+
+Calling RAND_poll() or RAND_add() is not necessary, because the DRBG
+polls the entropy source automatically.
+However, both calls are permitted, and do reseed the RNG.
+
+RAND_add() can be used to add both kinds of random input, depending on the
+value of the B<randomness> argument:
+
+=over 4
+
+=item randomness == 0:
+
+The random bytes are mixed as additional input into the current state of
+the DRBG.
+Mixing in additional input is not considered a full reseeding, hence the
+reseed counter is not reset.
+
+
+=item randomness > 0:
+
+The random bytes are used as entropy input for a full reseeding
+(resp. reinstantiation) if the DRBG is instantiated
+(resp. uninstantiated or in an error state).
+A reseeding requires 16 bytes (128 bits) of randomness.
+It is possible to provide less randomness than required.
+In this case the missing randomness will be obtained by pulling random input
+from the trusted entropy sources.
+
+=back
+
+=head2 DRBG with automatic seeding disabled (--with-rand-seed=none)
+
+Calling RAND_poll() will always fail.
+
+RAND_add() needs to be called for initial seeding and periodic reseeding.
+At least 16 bytes (128 bits) of randomness have to be provided, otherwise
+the (re-)seeding of the DRBG will fail.
+
 =head1 HISTORY
 
 RAND_event() and RAND_screen() were deprecated in OpenSSL 1.1.0 and should
diff --git a/include/internal/rand.h b/include/internal/rand.h
index 07f141d..feda9be 100644
--- a/include/internal/rand.h
+++ b/include/internal/rand.h
@@ -14,6 +14,17 @@
 #define RAND_DRBG_FLAG_CTR_USE_DF            0x2
 
 /*
+ * Default security strength (in the sense of [NIST SP 800-90Ar1])
+ * of the default OpenSSL DRBG, and the corresponding NID.
+ *
+ * Currently supported values: 128, 192, 256
+ *
+ * TODO(DRBG): would be nice to have the strength configurable
+ */
+# define RAND_DRBG_STRENGTH             128
+# define RAND_DRBG_NID                  NID_aes_128_ctr
+
+/*
  * Object lifetime functions.
  */
 RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent);
@@ -64,4 +75,38 @@ int RAND_DRBG_set_callbacks(RAND_DRBG *dctx,
                             RAND_DRBG_get_nonce_fn get_nonce,
                             RAND_DRBG_cleanup_nonce_fn cleanup_nonce);
 
+/*
+ * RAND_POOL functions
+ */
+RAND_POOL *RAND_POOL_new(int entropy_requested, size_t min_len, size_t max_len);
+void RAND_POOL_free(RAND_POOL *pool);
+
+const unsigned char *RAND_POOL_buffer(RAND_POOL *pool);
+unsigned char *RAND_POOL_detach(RAND_POOL *pool);
+
+size_t RAND_POOL_entropy(RAND_POOL *pool);
+size_t RAND_POOL_length(RAND_POOL *pool);
+
+size_t RAND_POOL_entropy_available(RAND_POOL *pool);
+size_t RAND_POOL_entropy_needed(RAND_POOL *pool);
+size_t RAND_POOL_bytes_needed(RAND_POOL *pool, unsigned int entropy_per_byte);
+size_t RAND_POOL_bytes_remaining(RAND_POOL *pool);
+
+size_t RAND_POOL_add(RAND_POOL *pool,
+                     const unsigned char *buffer, size_t len, size_t entropy);
+unsigned char *RAND_POOL_add_begin(RAND_POOL *pool, size_t len);
+size_t RAND_POOL_add_end(RAND_POOL *pool, size_t len, size_t entropy);
+
+
+/*
+ * Add random bytes to the pool to acquire requested amount of entropy
+ *
+ * This function is platform specific and tries to acquire the requested
+ * amount of entropy by polling platform specific entropy sources.
+ *
+ * If the function succeeds in acquiring at least |entropy_requested| bits
+ * of entropy, the total entropy count is returned. If it fails, it returns
+ * an entropy count of 0.
+ */
+size_t RAND_POOL_acquire_entropy(RAND_POOL *pool);
 #endif
diff --git a/include/openssl/ossl_typ.h b/include/openssl/ossl_typ.h
index b007776..f5214ab 100644
--- a/include/openssl/ossl_typ.h
+++ b/include/openssl/ossl_typ.h
@@ -115,6 +115,7 @@ typedef struct ec_key_method_st EC_KEY_METHOD;
 
 typedef struct rand_meth_st RAND_METHOD;
 typedef struct rand_drbg_st RAND_DRBG;
+typedef struct rand_pool_st RAND_POOL;
 
 typedef struct ssl_dane_st SSL_DANE;
 typedef struct x509_st X509;
diff --git a/include/openssl/rand.h b/include/openssl/rand.h
index 82e3762..2dec35e 100644
--- a/include/openssl/rand.h
+++ b/include/openssl/rand.h
@@ -64,7 +64,6 @@ int RAND_egd_bytes(const char *path, int bytes);
 typedef void (*RAND_poll_cb)(void *arg,
                              const void *buf, int num, double randomness);
 int RAND_poll(void);
-int RAND_poll_ex(RAND_poll_cb rand_add, void *arg);
 
 # if defined(_WIN32) && (defined(BASETYPES) || defined(_WINDEF_H))
 /* application has to include <windows.h> in order to use these */
diff --git a/include/openssl/randerr.h b/include/openssl/randerr.h
index 79c652f..b07ea23 100644
--- a/include/openssl/randerr.h
+++ b/include/openssl/randerr.h
@@ -24,14 +24,21 @@ int ERR_load_RAND_strings(void);
  */
 # define RAND_F_DRBG_BYTES                                101
 # define RAND_F_DRBG_GET_ENTROPY                          105
+# define RAND_F_DRBG_SETUP                                117
 # define RAND_F_GET_ENTROPY                               106
 # define RAND_F_RAND_BYTES                                100
 # define RAND_F_RAND_DRBG_GENERATE                        107
 # define RAND_F_RAND_DRBG_INSTANTIATE                     108
 # define RAND_F_RAND_DRBG_NEW                             109
 # define RAND_F_RAND_DRBG_RESEED                          110
+# define RAND_F_RAND_DRBG_RESTART                         102
 # define RAND_F_RAND_DRBG_SET                             104
 # define RAND_F_RAND_LOAD_FILE                            111
+# define RAND_F_RAND_POOL_ADD                             103
+# define RAND_F_RAND_POOL_ADD_BEGIN                       113
+# define RAND_F_RAND_POOL_ADD_END                         114
+# define RAND_F_RAND_POOL_BYTES_NEEDED                    115
+# define RAND_F_RAND_POOL_NEW                             116
 # define RAND_F_RAND_WRITE_FILE                           112
 
 /*
@@ -39,13 +46,18 @@ int ERR_load_RAND_strings(void);
  */
 # define RAND_R_ADDITIONAL_INPUT_TOO_LONG                 102
 # define RAND_R_ALREADY_INSTANTIATED                      103
+# define RAND_R_ARGUMENT_OUT_OF_RANGE                     105
 # define RAND_R_CANNOT_OPEN_FILE                          121
 # define RAND_R_DRBG_NOT_INITIALISED                      104
+# define RAND_R_ENTROPY_INPUT_TOO_LONG                    106
+# define RAND_R_ENTROPY_OUT_OF_RANGE                      124
+# define RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED            127
 # define RAND_R_ERROR_INITIALISING_DRBG                   107
 # define RAND_R_ERROR_INSTANTIATING_DRBG                  108
 # define RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT         109
 # define RAND_R_ERROR_RETRIEVING_ENTROPY                  110
 # define RAND_R_ERROR_RETRIEVING_NONCE                    111
+# define RAND_R_FAILED_TO_CREATE_LOCK                     126
 # define RAND_R_FUNC_NOT_IMPLEMENTED                      101
 # define RAND_R_FWRITE_ERROR                              123
 # define RAND_R_GENERATE_ERROR                            112
@@ -55,6 +67,7 @@ int ERR_load_RAND_strings(void);
 # define RAND_R_NOT_INSTANTIATED                          115
 # define RAND_R_PERSONALISATION_STRING_TOO_LONG           116
 # define RAND_R_PRNG_NOT_SEEDED                           100
+# define RAND_R_RANDOM_POOL_OVERFLOW                      125
 # define RAND_R_REQUEST_TOO_LARGE_FOR_DRBG                117
 # define RAND_R_RESEED_ERROR                              118
 # define RAND_R_SELFTEST_FAILURE                          119
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 9fec761..ce45a91 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -633,10 +633,13 @@ SSL *SSL_new(SSL_CTX *ctx)
      * chained DRBG.
      */
     if (RAND_get_rand_method() == RAND_OpenSSL()) {
-        s->drbg = RAND_DRBG_new(NID_aes_128_ctr, RAND_DRBG_FLAG_CTR_USE_DF,
-                                RAND_DRBG_get0_global());
+        s->drbg =
+            RAND_DRBG_new(RAND_DRBG_NID, RAND_DRBG_FLAG_CTR_USE_DF,
+                          RAND_DRBG_get0_global());
         if (s->drbg == NULL
-            || RAND_DRBG_instantiate(s->drbg, NULL, 0) == 0) {
+            || RAND_DRBG_instantiate(s->drbg,
+                                     (const unsigned char *) SSL_version_str,
+                                     sizeof(SSL_version_str) - 1) == 0) {
             CRYPTO_THREAD_lock_free(s->lock);
             goto err;
         }
@@ -5124,7 +5127,20 @@ uint32_t SSL_get_max_early_data(const SSL *s)
 
 int ssl_randbytes(SSL *s, unsigned char *rnd, size_t size)
 {
-    if (s->drbg != NULL)
-        return RAND_DRBG_generate(s->drbg, rnd, size, 0, NULL, 0);
+    if (s->drbg != NULL) {
+        /*
+         * Currently, it's the duty of the caller to serialize the generate
+         * requests to the DRBG. So formally we have to check whether
+         * s->drbg->lock != NULL and take the lock if this is the case.
+         * However, this DRBG is unique to a given SSL object, and we already
+         * require that SSL objects are only accessed by a single thread at
+         * a given time. Also, SSL DRBGs have no child DRBG, so there is
+         * no risk that this DRBG is accessed by a child DRBG in parallel
+         * for reseeding.  As such, we can rely on the application's
+         * serialization of SSL accesses for the needed concurrency protection
+         * here.
+         */
+         return RAND_DRBG_generate(s->drbg, rnd, size, 0, NULL, 0);
+    }
     return RAND_bytes(rnd, (int)size);
 }
diff --git a/test/drbgtest.c b/test/drbgtest.c
index 7d33c30..25920d6 100644
--- a/test/drbgtest.c
+++ b/test/drbgtest.c
@@ -481,7 +481,7 @@ static int test_rand_add(void)
 {
     char *p;
 
-    if (!TEST_ptr(p = malloc(RAND_ADD_SIZE)))
+    if (!TEST_ptr(p = calloc(RAND_ADD_SIZE, 1)))
         return 0;
     RAND_add(p, RAND_ADD_SIZE, RAND_ADD_SIZE);
     free(p);
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 0a29e8c..96990ed 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4371,7 +4371,6 @@ SCRYPT_PARAMS_it                        4314	1_1_1	EXIST:EXPORT_VAR_AS_FUNCTION:
 CRYPTO_secure_clear_free                4315	1_1_0g	EXIST::FUNCTION:
 EVP_PKEY_meth_get0                      4316	1_1_1	EXIST::FUNCTION:
 EVP_PKEY_meth_get_count                 4317	1_1_1	EXIST::FUNCTION:
-RAND_poll_ex                            4318	1_1_1	EXIST::FUNCTION:
 RAND_DRBG_get0_global                   4319	1_1_1	EXIST::FUNCTION:
 RAND_priv_bytes                         4320	1_1_1	EXIST::FUNCTION:
 BN_priv_rand                            4321	1_1_1	EXIST::FUNCTION:
@@ -4404,3 +4403,17 @@ EVP_PKEY_set1_engine                    4347	1_1_0g	EXIST::FUNCTION:ENGINE
 DH_new_by_nid                           4348	1_1_1	EXIST::FUNCTION:DH
 DH_get_nid                              4349	1_1_1	EXIST::FUNCTION:DH
 CRYPTO_get_alloc_counts                 4350	1_1_1	EXIST::FUNCTION:CRYPTO_MDEBUG
+RAND_POOL_new                           4351	1_1_1	EXIST::FUNCTION:
+RAND_POOL_free                          4352	1_1_1	EXIST::FUNCTION:
+RAND_POOL_buffer                        4353	1_1_1	EXIST::FUNCTION:
+RAND_POOL_detach                        4354	1_1_1	EXIST::FUNCTION:
+RAND_POOL_entropy                       4355	1_1_1	EXIST::FUNCTION:
+RAND_POOL_length                        4356	1_1_1	EXIST::FUNCTION:
+RAND_POOL_entropy_available             4357	1_1_1	EXIST::FUNCTION:
+RAND_POOL_entropy_needed                4358	1_1_1	EXIST::FUNCTION:
+RAND_POOL_bytes_needed                  4359	1_1_1	EXIST::FUNCTION:
+RAND_POOL_bytes_remaining               4360	1_1_1	EXIST::FUNCTION:
+RAND_POOL_add                           4361	1_1_1	EXIST::FUNCTION:
+RAND_POOL_add_begin                     4362	1_1_1	EXIST::FUNCTION:
+RAND_POOL_add_end                       4363	1_1_1	EXIST::FUNCTION:
+RAND_POOL_acquire_entropy               4364	1_1_1	EXIST::FUNCTION:


More information about the openssl-commits mailing list