void OPENSSL_fork_child(void)
{
rand_fork();
+ /* TODO(3.0): Inform all providers about a fork event */
}
#endif
CRYPTO_THREAD_LOCAL private_drbg;
} DRBG_GLOBAL;
+typedef struct drbg_nonce_global_st {
+ CRYPTO_RWLOCK *rand_nonce_lock;
+ int rand_nonce_count;
+} DRBG_NONCE_GLOBAL;
+
/* NIST SP 800-90A DRBG recommends the use of a personalization string. */
static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING;
}
}
+/*
+ * Initialize the OPENSSL_CTX global DRBGs on first use.
+ * Returns the allocated global data on success or NULL on failure.
+ */
+static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
+{
+ DRBG_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));
+
+ if (dgbl == NULL)
+ return NULL;
+
+ if (!CRYPTO_THREAD_init_local(&dgbl->private_drbg, NULL))
+ goto err1;
+
+ if (!CRYPTO_THREAD_init_local(&dgbl->public_drbg, NULL))
+ goto err2;
+
+ dgbl->master_drbg = drbg_setup(libctx, NULL, RAND_DRBG_TYPE_MASTER);
+ if (dgbl->master_drbg == NULL)
+ goto err3;
+
+ return dgbl;
+
+ err3:
+ CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
+ err2:
+ CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
+ err1:
+ OPENSSL_free(dgbl);
+ return NULL;
+}
+
+static void drbg_ossl_ctx_free(void *vdgbl)
+{
+ DRBG_GLOBAL *dgbl = vdgbl;
+
+ RAND_DRBG_free(dgbl->master_drbg);
+ CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
+ CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
+
+ OPENSSL_free(dgbl);
+}
+
+static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
+ drbg_ossl_ctx_new,
+ drbg_ossl_ctx_free,
+};
+
+/*
+ * drbg_ossl_ctx_new() calls drgb_setup() which calls rand_drbg_get_nonce()
+ * which needs to get the rand_nonce_lock out of the OPENSSL_CTX...but since
+ * drbg_ossl_ctx_new() hasn't finished running yet we need the rand_nonce_lock
+ * to be in a different global data object. Otherwise we will go into an
+ * infinite recursion loop.
+ */
+static void *drbg_nonce_ossl_ctx_new(OPENSSL_CTX *libctx)
+{
+ DRBG_NONCE_GLOBAL *dngbl = OPENSSL_zalloc(sizeof(*dngbl));
+
+ if (dngbl == NULL)
+ return NULL;
+
+ dngbl->rand_nonce_lock = CRYPTO_THREAD_lock_new();
+ if (dngbl->rand_nonce_lock == NULL) {
+ OPENSSL_free(dngbl);
+ return NULL;
+ }
+
+ return dngbl;
+}
+
+static void drbg_nonce_ossl_ctx_free(void *vdngbl)
+{
+ DRBG_NONCE_GLOBAL *dngbl = vdngbl;
+
+ CRYPTO_THREAD_lock_free(dngbl->rand_nonce_lock);
+
+ OPENSSL_free(dngbl);
+}
+
+static const OPENSSL_CTX_METHOD drbg_nonce_ossl_ctx_method = {
+ drbg_nonce_ossl_ctx_new,
+ drbg_nonce_ossl_ctx_free,
+};
+
+static DRBG_GLOBAL *drbg_get_global(OPENSSL_CTX *libctx)
+{
+ return openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_INDEX,
+ &drbg_ossl_ctx_method);
+}
+
+/* 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;
+ DRBG_NONCE_GLOBAL *dngbl
+ = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_DRBG_NONCE_INDEX,
+ &drbg_nonce_ossl_ctx_method);
+ struct {
+ void *instance;
+ int count;
+ } data;
+
+ if (dngbl == NULL)
+ return 0;
+
+ memset(&data, 0, sizeof(data));
+ 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(&dngbl->rand_nonce_count, 1, &data.count,
+ dngbl->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);
+}
+
/*
* Set/initialize |drbg| to be of type |type|, with optional |flags|.
*
return NULL;
}
-/*
- * Initialize the OPENSSL_CTX global DRBGs on first use.
- * Returns the allocated global data on success or NULL on failure.
- */
-static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
-{
- DRBG_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));
-
- if (dgbl == NULL)
- return NULL;
-
- if (!CRYPTO_THREAD_init_local(&dgbl->private_drbg, NULL))
- goto err1;
-
- if (!CRYPTO_THREAD_init_local(&dgbl->public_drbg, NULL))
- goto err2;
-
- dgbl->master_drbg = drbg_setup(libctx, NULL, RAND_DRBG_TYPE_MASTER);
- if (dgbl->master_drbg == NULL)
- goto err3;
-
- return dgbl;
-
- err3:
- CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
- err2:
- CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
- err1:
- OPENSSL_free(dgbl);
- return NULL;
-}
-
-static void drbg_ossl_ctx_free(void *vdgbl)
-{
- DRBG_GLOBAL *dgbl = vdgbl;
-
- RAND_DRBG_free(dgbl->master_drbg);
- CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
- CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
-
- OPENSSL_free(dgbl);
-}
-
-static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
- drbg_ossl_ctx_new,
- drbg_ossl_ctx_free,
-};
-
-static DRBG_GLOBAL *drbg_get_global(OPENSSL_CTX *libctx)
-{
- return openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_INDEX,
- &drbg_ossl_ctx_method);
-}
-
void drbg_delete_thread_state(void)
{
+ /* TODO(3.0): Other PRs will pass the ctx as a param to this function */
+ OPENSSL_CTX *ctx = NULL;
DRBG_GLOBAL *dgbl = drbg_get_global(ctx);
RAND_DRBG *drbg;
RAND_METHOD *RAND_OpenSSL(void)
{
+#ifndef FIPS_MODE
return &rand_meth;
+#else
+ return NULL;
+#endif
}
#include "rand_lcl.h"
#include "e_os.h"
-#ifndef OPENSSL_NO_ENGINE
+#ifndef FIPS_MODE
+# ifndef OPENSSL_NO_ENGINE
/* non-NULL if default_RAND_meth is ENGINE-provided */
static ENGINE *funct_ref;
static CRYPTO_RWLOCK *rand_engine_lock;
-#endif
+# 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_inited = 0;
+#endif /* FIPS_MODE */
+
+int rand_fork_count;
#ifdef OPENSSL_RAND_SEED_RDTSC
/*
OPENSSL_secure_clear_free(out, outlen);
}
-
-/*
- * 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;
-
- memset(&data, 0, sizeof(data));
- 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
rand_fork_count++;
}
+#ifndef FIPS_MODE
DEFINE_RUN_ONCE_STATIC(do_rand_init)
{
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
rand_engine_lock = CRYPTO_THREAD_lock_new();
if (rand_engine_lock == NULL)
return 0;
-#endif
+# 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;
+ goto err;
if (!rand_pool_init())
- goto err3;
+ goto err;
rand_inited = 1;
return 1;
-err3:
- CRYPTO_THREAD_lock_free(rand_nonce_lock);
- rand_nonce_lock = NULL;
-err2:
+ err:
CRYPTO_THREAD_lock_free(rand_meth_lock);
rand_meth_lock = NULL;
-err1:
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
CRYPTO_THREAD_lock_free(rand_engine_lock);
rand_engine_lock = NULL;
-#endif
+# endif
return 0;
}
meth->cleanup();
RAND_set_rand_method(NULL);
rand_pool_cleanup();
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
CRYPTO_THREAD_lock_free(rand_engine_lock);
rand_engine_lock = NULL;
-#endif
+# endif
CRYPTO_THREAD_lock_free(rand_meth_lock);
rand_meth_lock = NULL;
- CRYPTO_THREAD_lock_free(rand_nonce_lock);
- rand_nonce_lock = NULL;
rand_inited = 0;
}
+/* TODO(3.0): Do we need to handle this somehow in the FIPS module? */
/*
* RAND_close_seed_files() ensures that any seed file decriptors are
* closed after use.
{
int ret = 0;
- RAND_POOL *pool = NULL;
-
const RAND_METHOD *meth = RAND_get_rand_method();
if (meth == RAND_OpenSSL()) {
return ret;
} else {
+ RAND_POOL *pool = NULL;
+
/* fill random pool and seed the current legacy RNG */
pool = rand_pool_new(RAND_DRBG_STRENGTH,
(RAND_DRBG_STRENGTH + 7) / 8,
goto err;
ret = 1;
+
+ err:
+ rand_pool_free(pool);
}
-err:
- rand_pool_free(pool);
return ret;
}
+#endif /* FIPS_MODE */
/*
* Allocate memory and initialize a new random pool
return 1;
}
+#ifndef FIPS_MODE
int RAND_set_rand_method(const RAND_METHOD *meth)
{
if (!RUN_ONCE(&rand_init, do_rand_init))
return 0;
CRYPTO_THREAD_write_lock(rand_meth_lock);
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
ENGINE_finish(funct_ref);
funct_ref = NULL;
-#endif
+# endif
default_RAND_meth = meth;
CRYPTO_THREAD_unlock(rand_meth_lock);
return 1;
}
+#endif
const RAND_METHOD *RAND_get_rand_method(void)
{
+#ifdef FIPS_MODE
+ return NULL;
+#else
const RAND_METHOD *tmp_meth = NULL;
if (!RUN_ONCE(&rand_init, do_rand_init))
CRYPTO_THREAD_write_lock(rand_meth_lock);
if (default_RAND_meth == NULL) {
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
ENGINE *e;
/* If we have an engine that can do RAND, use it. */
ENGINE_finish(e);
default_RAND_meth = &rand_meth;
}
-#else
+# else
default_RAND_meth = &rand_meth;
-#endif
+# endif
}
tmp_meth = default_RAND_meth;
CRYPTO_THREAD_unlock(rand_meth_lock);
return tmp_meth;
+#endif
}
-#ifndef OPENSSL_NO_ENGINE
+#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE)
int RAND_set_rand_engine(ENGINE *engine)
{
const RAND_METHOD *tmp_meth = NULL;
*/
int RAND_priv_bytes(unsigned char *buf, int num)
{
- const RAND_METHOD *meth = RAND_get_rand_method();
RAND_DRBG *drbg;
int ret;
+ const RAND_METHOD *meth = RAND_get_rand_method();
if (meth != RAND_OpenSSL())
return RAND_bytes(buf, num);
return -1;
}
-#if !OPENSSL_API_1_1_0
+#if !OPENSSL_API_1_1_0 && !defined(FIPS_MODE)
int RAND_pseudo_bytes(unsigned char *buf, int num)
{
const RAND_METHOD *meth = RAND_get_rand_method();
# define OPENSSL_CTX_PROPERTY_STRING_INDEX 3
# define OPENSSL_CTX_NAMEMAP_INDEX 4
# define OPENSSL_CTX_DRBG_INDEX 5
-# define OPENSSL_CTX_RAND_CRNGT_INDEX 6
-# define OPENSSL_CTX_MAX_INDEXES 7
+# define OPENSSL_CTX_DRBG_NONCE_INDEX 6
+# define OPENSSL_CTX_RAND_CRNGT_INDEX 7
+# define OPENSSL_CTX_MAX_INDEXES 8
typedef struct openssl_ctx_method {
void *(*new_func)(OPENSSL_CTX *ctx);