From a2f27fd750b9ae62a571a9212c7154889100bdb0 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 24 May 2019 16:36:44 +0100 Subject: [PATCH] Move the rand_nonce_lock code into drbg_lib.c It was previously rand_lib but it makes more sense in drbg_lib.c since all the functions that use this lock are only ever called from drbg_lib.c We add some FIPS_MODE defines in preparation for later moving this code into the FIPS module. Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9039) --- crypto/init.c | 1 + crypto/rand/drbg_lib.c | 208 ++++++++++++++++++++++++++---------- crypto/rand/rand_lib.c | 125 +++++++--------------- include/internal/cryptlib.h | 5 +- 4 files changed, 195 insertions(+), 144 deletions(-) diff --git a/crypto/init.c b/crypto/init.c index 6a1f5eabe5..e73c9bafbd 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -852,5 +852,6 @@ void OPENSSL_fork_parent(void) void OPENSSL_fork_child(void) { rand_fork(); + /* TODO(3.0): Inform all providers about a fork event */ } #endif diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c index eece882916..26e2ccb152 100644 --- a/crypto/rand/drbg_lib.c +++ b/crypto/rand/drbg_lib.c @@ -69,6 +69,11 @@ typedef struct drbg_global_st { 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; @@ -142,6 +147,149 @@ static int is_digest(int type) } } +/* + * 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|. * @@ -989,62 +1137,10 @@ err: 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; @@ -1287,5 +1383,9 @@ RAND_METHOD rand_meth = { RAND_METHOD *RAND_OpenSSL(void) { +#ifndef FIPS_MODE return &rand_meth; +#else + return NULL; +#endif } diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index 2b77960529..45742f5123 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -17,21 +17,20 @@ #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 /* @@ -208,56 +207,6 @@ void rand_drbg_cleanup_entropy(RAND_DRBG *drbg, 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 @@ -292,39 +241,32 @@ void rand_fork(void) 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; } @@ -339,17 +281,16 @@ void rand_cleanup_int(void) 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. @@ -371,8 +312,6 @@ int RAND_poll(void) { int ret = 0; - RAND_POOL *pool = NULL; - const RAND_METHOD *meth = RAND_get_rand_method(); if (meth == RAND_OpenSSL()) { @@ -389,6 +328,8 @@ int RAND_poll(void) 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, @@ -406,12 +347,14 @@ int RAND_poll(void) 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 @@ -708,23 +651,28 @@ int rand_pool_add_end(RAND_POOL *pool, size_t len, size_t entropy) 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)) @@ -732,7 +680,7 @@ const RAND_METHOD *RAND_get_rand_method(void) 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. */ @@ -744,16 +692,17 @@ const RAND_METHOD *RAND_get_rand_method(void) 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; @@ -802,9 +751,9 @@ void RAND_add(const void *buf, int num, double randomness) */ 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); @@ -827,7 +776,7 @@ int RAND_bytes(unsigned char *buf, int 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(); diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 585263a173..d76f9e1704 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -147,8 +147,9 @@ typedef struct ossl_ex_data_global_st { # 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); -- 2.25.1