+int RAND_DRBG_set_ex_data(RAND_DRBG *drbg, int idx, void *arg)
+{
+ return CRYPTO_set_ex_data(&drbg->ex_data, idx, arg);
+}
+
+void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx)
+{
+ return CRYPTO_get_ex_data(&drbg->ex_data, idx);
+}
+
+
+/*
+ * The following functions provide a RAND_METHOD that works on the
+ * global DRBG. They lock.
+ */
+
+/*
+ * Allocates a new global DRBG on the secure heap (if enabled) and
+ * initializes it with default settings.
+ *
+ * Returns a pointer to the new DRBG instance on success, NULL on failure.
+ */
+static RAND_DRBG *drbg_setup(RAND_DRBG *parent)
+{
+ RAND_DRBG *drbg;
+
+ drbg = RAND_DRBG_secure_new(RAND_DRBG_NID, 0, parent);
+ if (drbg == NULL)
+ return NULL;
+
+ if (rand_drbg_enable_locking(drbg) == 0)
+ goto err;
+
+ if (parent == NULL) {
+ drbg->reseed_interval = MASTER_RESEED_INTERVAL;
+ drbg->reseed_time_interval = MASTER_RESEED_TIME_INTERVAL;
+ } else {
+ drbg->reseed_interval = SLAVE_RESEED_INTERVAL;
+ drbg->reseed_time_interval = SLAVE_RESEED_TIME_INTERVAL;
+ }
+
+ /* enable seed propagation */
+ drbg->reseed_counter = 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 drbg;
+
+err:
+ RAND_DRBG_free(drbg);
+ return NULL;
+}
+
+/*
+ * Initialize the global DRBGs on first use.
+ * Returns 1 on success, 0 on failure.
+ */
+DEFINE_RUN_ONCE_STATIC(do_rand_drbg_init)
+{
+ /*
+ * ensure that libcrypto is initialized, otherwise the
+ * DRBG locks are not cleaned up properly
+ */
+ if (!OPENSSL_init_crypto(0, NULL))
+ return 0;
+
+ drbg_master = drbg_setup(NULL);
+ drbg_public = drbg_setup(drbg_master);
+ drbg_private = drbg_setup(drbg_master);
+
+ if (drbg_master == NULL || drbg_public == NULL || drbg_private == NULL)
+ return 0;
+
+ return 1;
+}
+
+/* Clean up the global DRBGs before exit */
+void rand_drbg_cleanup_int(void)
+{
+ RAND_DRBG_free(drbg_private);
+ RAND_DRBG_free(drbg_public);
+ RAND_DRBG_free(drbg_master);
+
+ drbg_private = drbg_public = drbg_master = NULL;
+}
+
+/* Implements the default OpenSSL RAND_bytes() method */
+static int drbg_bytes(unsigned char *out, int count)
+{
+ int ret;
+ RAND_DRBG *drbg = RAND_DRBG_get0_public();
+
+ if (drbg == NULL)
+ return 0;
+
+ rand_drbg_lock(drbg);
+ ret = RAND_DRBG_bytes(drbg, out, count);
+ rand_drbg_unlock(drbg);
+
+ return ret;
+}
+
+/* Implements the default OpenSSL RAND_add() method */
+static int drbg_add(const void *buf, int num, double randomness)
+{
+ int ret = 0;
+ RAND_DRBG *drbg = RAND_DRBG_get0_master();
+
+ if (drbg == NULL)
+ return 0;
+
+ if (num < 0 || randomness < 0.0)
+ return 0;
+
+ 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;
+ }
+
+ rand_drbg_lock(drbg);
+ ret = rand_drbg_restart(drbg, buf,
+ (size_t)(unsigned int)num,
+ (size_t)(8*randomness));
+ rand_drbg_unlock(drbg);
+
+ 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;
+ RAND_DRBG *drbg = RAND_DRBG_get0_master();
+
+ if (drbg == NULL)
+ return 0;
+
+ rand_drbg_lock(drbg);
+ ret = drbg->state == DRBG_READY ? 1 : 0;
+ rand_drbg_unlock(drbg);
+ return ret;
+}
+
+/*
+ * Get the master DRBG.
+ * Returns pointer to the DRBG on success, NULL on failure.
+ *
+ */
+RAND_DRBG *RAND_DRBG_get0_master(void)
+{
+ if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))
+ return NULL;
+
+ return drbg_master;
+}
+
+/*
+ * Get the public DRBG.
+ * Returns pointer to the DRBG on success, NULL on failure.
+ */
+RAND_DRBG *RAND_DRBG_get0_public(void)
+{
+ if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))
+ return NULL;
+
+ return drbg_public;
+}
+
+/*
+ * Get the private DRBG.
+ * Returns pointer to the DRBG on success, NULL on failure.
+ */
+RAND_DRBG *RAND_DRBG_get0_private(void)