+#include "internal/cryptlib.h"
+#include <openssl/opensslconf.h>
+#include "internal/rand_int.h"
+#include <openssl/engine.h>
+#include "internal/thread_once.h"
+#include "rand_lcl.h"
+#include "e_os.h"
+
+#ifndef OPENSSL_NO_ENGINE
+/* non-NULL if default_RAND_meth is ENGINE-provided */
+static ENGINE *funct_ref;
+static CRYPTO_RWLOCK *rand_engine_lock;
+#endif
+static CRYPTO_RWLOCK *rand_meth_lock;
+static const RAND_METHOD *default_RAND_meth;
+static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;
+
+int rand_fork_count;
+
+static CRYPTO_RWLOCK *rand_nonce_lock;
+static int rand_nonce_count;
+
+static int rand_cleaning_up = 0;
+
+#ifdef OPENSSL_RAND_SEED_RDTSC
+/*
+ * IMPORTANT NOTE: It is not currently possible to use this code
+ * because we are not sure about the amount of randomness it provides.
+ * Some SP900 tests have been run, but there is internal skepticism.
+ * So for now this code is not used.
+ */
+# 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-speed clock, it can help.
+ *
+ * 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_tsc(RAND_POOL *pool)
+{
+ unsigned char c;
+ int i;
+
+ if ((OPENSSL_ia32cap_P[0] & (1 << 4)) != 0) {
+ for (i = 0; i < TSC_READ_COUNT; i++) {
+ c = (unsigned char)(OPENSSL_rdtsc() & 0xFF);
+ 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(unsigned char *buf, size_t len);
+size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len);
+
+extern unsigned int OPENSSL_ia32cap_P[];
+
+/*
+ * 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)
+{
+ size_t bytes_needed;
+ unsigned char *buffer;
+
+ bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
+ if (bytes_needed > 0) {
+ buffer = rand_pool_add_begin(pool, bytes_needed);
+
+ if (buffer != NULL) {
+ /* Whichever comes first, use RDSEED, RDRAND or nothing */
+ if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) {
+ if (OPENSSL_ia32_rdseed_bytes(buffer, bytes_needed)
+ == bytes_needed) {
+ rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);
+ }
+ } else if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) {
+ if (OPENSSL_ia32_rdrand_bytes(buffer, bytes_needed)
+ == bytes_needed) {
+ rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);
+ }
+ } else {
+ rand_pool_add_end(pool, 0, 0);
+ }
+ }
+ }
+
+ return rand_pool_entropy_available(pool);
+}
+#endif
+
+
+/*
+ * 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().
+ *
+ * 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 rand_drbg_get_entropy(RAND_DRBG *drbg,
+ unsigned char **pout,
+ int entropy, size_t min_len, size_t max_len,
+ int prediction_resistance)
+{
+ size_t ret = 0;
+ size_t entropy_available = 0;
+ RAND_POOL *pool;
+
+ if (drbg->parent && drbg->strength > drbg->parent->strength) {
+ /*
+ * We currently don't support the algorithm from NIST SP 800-90C
+ * 10.1.2 to use a weaker DRBG as source
+ */
+ RANDerr(RAND_F_RAND_DRBG_GET_ENTROPY, RAND_R_PARENT_STRENGTH_TOO_WEAK);
+ return 0;
+ }
+
+ if (drbg->pool != NULL) {
+ pool = drbg->pool;
+ pool->entropy_requested = entropy;
+ } else {
+ pool = rand_pool_new(entropy, min_len, max_len);
+ if (pool == NULL)
+ return 0;
+ }
+
+ if (drbg->parent) {
+ size_t bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
+ 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. (Note: taking the lock will be a no-op
+ * if locking if drbg->parent->lock == NULL.)
+ */
+ rand_drbg_lock(drbg->parent);
+ if (RAND_DRBG_generate(drbg->parent,
+ buffer, bytes_needed,
+ prediction_resistance,
+ NULL, 0) != 0)
+ bytes = bytes_needed;
+ drbg->reseed_next_counter
+ = tsan_load(&drbg->parent->reseed_prop_counter);
+ rand_drbg_unlock(drbg->parent);
+
+ rand_pool_add_end(pool, bytes, 8 * bytes);
+ entropy_available = rand_pool_entropy_available(pool);
+ }
+
+ } else {
+ if (prediction_resistance) {
+ /*
+ * We don't have any entropy sources that comply with the NIST
+ * standard to provide prediction resistance (see NIST SP 800-90C,
+ * Section 5.4).
+ */
+ RANDerr(RAND_F_RAND_DRBG_GET_ENTROPY,
+ RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED);
+ goto err;
+ }
+
+ /* Get entropy by polling system entropy sources. */
+ entropy_available = rand_pool_acquire_entropy(pool);
+ }
+
+ if (entropy_available > 0) {
+ ret = rand_pool_length(pool);
+ *pout = rand_pool_detach(pool);
+ }
+
+ err:
+ /* we need to reset drbg->pool in the error case */
+ if (ret == 0 && drbg->pool != NULL)
+ drbg->pool = NULL;
+
+ rand_pool_free(pool);
+ return ret;
+}
+
+/*
+ * 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->pool == NULL)
+ OPENSSL_secure_clear_free(out, outlen);
+ else
+ drbg->pool = NULL;
+}
+
+
+/*
+ * Implements the get_nonce() callback (see RAND_DRBG_set_callbacks())
+ *
+ */
+size_t rand_drbg_get_nonce(RAND_DRBG *drbg,
+ unsigned char **pout,
+ int entropy, size_t min_len, size_t max_len)
+{
+ size_t ret = 0;
+ RAND_POOL *pool;
+
+ struct {
+ void * instance;
+ int count;
+ } data = { 0 };
+
+ pool = rand_pool_new(0, min_len, max_len);
+ if (pool == NULL)
+ return 0;
+
+ if (rand_pool_add_nonce_data(pool) == 0)
+ goto err;
+
+ data.instance = drbg;
+ CRYPTO_atomic_add(&rand_nonce_count, 1, &data.count, rand_nonce_lock);
+
+ if (rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0) == 0)
+ goto err;
+
+ ret = rand_pool_length(pool);
+ *pout = rand_pool_detach(pool);
+
+ err:
+ rand_pool_free(pool);
+
+ return ret;
+}
+
+/*
+ * Implements the cleanup_nonce() callback (see RAND_DRBG_set_callbacks())
+ *
+ */
+void rand_drbg_cleanup_nonce(RAND_DRBG *drbg,
+ unsigned char *out, size_t outlen)
+{
+ OPENSSL_secure_clear_free(out, outlen);
+}
+
+/*
+ * Generate additional data that can be used for the drbg. The data does
+ * not need to contain entropy, but it's useful if it contains at least
+ * some bits that are unpredictable.
+ *
+ * Returns 0 on failure.
+ *
+ * On success it allocates a buffer at |*pout| and returns the length of
+ * the data. The buffer should get freed using OPENSSL_secure_clear_free().
+ */
+size_t rand_drbg_get_additional_data(unsigned char **pout, size_t max_len)
+{
+ size_t ret = 0;
+ RAND_POOL *pool;
+
+ pool = rand_pool_new(0, 0, max_len);
+ if (pool == NULL)
+ return 0;
+
+ if (rand_pool_add_additional_data(pool) == 0)
+ goto err;
+
+ ret = rand_pool_length(pool);
+ *pout = rand_pool_detach(pool);
+
+ err:
+ rand_pool_free(pool);
+
+ return ret;
+}
+
+void rand_drbg_cleanup_additional_data(unsigned char *out, size_t outlen)
+{
+ OPENSSL_secure_clear_free(out, outlen);
+}
+
+void rand_fork(void)
+{
+ rand_fork_count++;
+}
+
+DEFINE_RUN_ONCE_STATIC(do_rand_init)
+{
+#ifndef OPENSSL_NO_ENGINE
+ rand_engine_lock = CRYPTO_THREAD_lock_new();
+ if (rand_engine_lock == NULL)
+ return 0;
+#endif
+
+ rand_meth_lock = CRYPTO_THREAD_lock_new();
+ if (rand_meth_lock == NULL)
+ goto err1;
+
+ rand_nonce_lock = CRYPTO_THREAD_lock_new();
+ if (rand_nonce_lock == NULL)
+ goto err2;
+
+ if (!rand_cleaning_up && !rand_pool_init())
+ goto err3;
+
+ return 1;
+
+err3:
+ rand_pool_cleanup();
+err2:
+ CRYPTO_THREAD_lock_free(rand_meth_lock);
+ rand_meth_lock = NULL;
+err1:
+#ifndef OPENSSL_NO_ENGINE
+ CRYPTO_THREAD_lock_free(rand_engine_lock);
+ rand_engine_lock = NULL;
+#endif
+ return 0;
+}
+
+void rand_cleanup_int(void)
+{
+ const RAND_METHOD *meth = default_RAND_meth;
+
+ rand_cleaning_up = 1;
+
+ if (meth != NULL && meth->cleanup != NULL)
+ meth->cleanup();
+ RAND_set_rand_method(NULL);
+ rand_pool_cleanup();
+#ifndef OPENSSL_NO_ENGINE
+ CRYPTO_THREAD_lock_free(rand_engine_lock);
+ rand_engine_lock = NULL;
+#endif
+ CRYPTO_THREAD_lock_free(rand_meth_lock);
+ rand_meth_lock = NULL;
+ CRYPTO_THREAD_lock_free(rand_nonce_lock);
+ rand_nonce_lock = NULL;
+}
+
+/*
+ * RAND_close_seed_files() ensures that any seed file decriptors are
+ * closed after use.
+ */
+void RAND_keep_random_devices_open(int keep)
+{
+ rand_pool_keep_random_devices_open(keep);
+}
+
+/*
+ * 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 master DRBG */
+ RAND_DRBG *drbg = RAND_DRBG_get0_master();
+
+ if (drbg == NULL)
+ return 0;
+
+ rand_drbg_lock(drbg);
+ ret = rand_drbg_restart(drbg, NULL, 0, 0);
+ rand_drbg_unlock(drbg);