diff options
Diffstat (limited to 'crypto/rand/drbg_lib.c')
-rw-r--r-- | crypto/rand/drbg_lib.c | 124 |
1 files changed, 96 insertions, 28 deletions
diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c index d1f419dddf..3690976051 100644 --- a/crypto/rand/drbg_lib.c +++ b/crypto/rand/drbg_lib.c @@ -12,6 +12,8 @@ #include <openssl/err.h> #include <openssl/rand.h> #include "rand_lcl.h" +#include "internal/thread_once.h" +#include "internal/rand_int.h" /* * Support framework for NIST SP 800-90A DRBG, AES-CTR mode. @@ -25,6 +27,8 @@ * a much bigger deal than just re-setting an allocated resource.) */ +static CRYPTO_ONCE rand_init_drbg = CRYPTO_ONCE_STATIC_INIT; + /* * Set/initialize |drbg| to be of type |nid|, with optional |flags|. * Return -2 if the type is not supported, 1 on success and -1 on @@ -76,18 +80,9 @@ RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent) goto err; if (parent != NULL) { - if (parent->state == DRBG_UNINITIALISED - && RAND_DRBG_instantiate(parent, NULL, 0) == 0) - goto err; if (!RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_parent, drbg_release_entropy, - NULL, NULL) - /* - * Add in our address. Note we are adding the pointer - * itself, not its contents! - */ - || !RAND_DRBG_instantiate(drbg, - (unsigned char*)&drbg, sizeof(drbg))) + NULL, NULL)) goto err; } @@ -98,17 +93,12 @@ err: return NULL; } -RAND_DRBG *RAND_DRBG_get0_global(void) -{ - return &rand_drbg; -} - /* * Uninstantiate |drbg| and free all memory. */ void RAND_DRBG_free(RAND_DRBG *drbg) { - /* The global DRBG is free'd by rand_cleanup_int() */ + /* The global DRBG is free'd by rand_cleanup_drbg_int() */ if (drbg == NULL || drbg == &rand_drbg) return; @@ -340,28 +330,80 @@ void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx) * global DRBG. They lock. */ +/* + * Creates a global DRBG with default settings. + * Returns 1 on success, 0 on failure + */ +static int setup_drbg(RAND_DRBG *drbg) +{ + int ret = 1; + + drbg->lock = CRYPTO_THREAD_lock_new(); + ret &= drbg->lock != NULL; + drbg->size = RANDOMNESS_NEEDED; + drbg->secure = CRYPTO_secure_malloc_initialized(); + /* If you change these parameters, see RANDOMNESS_NEEDED */ + 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; + return ret; +} + +/* + * Initialize the global DRBGs on first use. + * Returns 1 on success, 0 on failure. + */ +DEFINE_RUN_ONCE_STATIC(do_rand_init_drbg) +{ + int ret = 1; + + ret &= setup_drbg(&rand_drbg); + ret &= setup_drbg(&priv_drbg); + + return ret; +} + +/* Clean up a DRBG and free it */ +static void free_drbg(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) +{ + free_drbg(&rand_drbg); + free_drbg(&priv_drbg); +} + static int drbg_bytes(unsigned char *out, int count) { int ret = 0; size_t chunk; + RAND_DRBG *drbg = RAND_DRBG_get0_global(); - CRYPTO_THREAD_write_lock(rand_drbg.lock); - if (rand_drbg.state == DRBG_UNINITIALISED - && RAND_DRBG_instantiate(&rand_drbg, NULL, 0) == 0) + if (drbg == NULL) + return 0; + + CRYPTO_THREAD_write_lock(drbg->lock); + if (drbg->state == DRBG_UNINITIALISED) goto err; for ( ; count > 0; count -= chunk, out += chunk) { chunk = count; - if (chunk > rand_drbg.max_request) - chunk = rand_drbg.max_request; - ret = RAND_DRBG_generate(&rand_drbg, out, chunk, 0, NULL, 0); + if (chunk > drbg->max_request) + chunk = drbg->max_request; + ret = RAND_DRBG_generate(drbg, out, chunk, 0, NULL, 0); if (!ret) goto err; } ret = 1; err: - CRYPTO_THREAD_unlock(rand_drbg.lock); + CRYPTO_THREAD_unlock(drbg->lock); return ret; } @@ -396,15 +438,41 @@ static int drbg_seed(const void *buf, int num) static int drbg_status(void) { int ret; + RAND_DRBG *drbg = RAND_DRBG_get0_global(); + + if (drbg == NULL) + return 0; - CRYPTO_THREAD_write_lock(rand_drbg.lock); - if (rand_drbg.state == DRBG_UNINITIALISED) - RAND_DRBG_instantiate(&rand_drbg, NULL, 0); - ret = rand_drbg.state == DRBG_READY ? 1 : 0; - CRYPTO_THREAD_unlock(rand_drbg.lock); + CRYPTO_THREAD_write_lock(drbg->lock); + ret = drbg->state == DRBG_READY ? 1 : 0; + CRYPTO_THREAD_unlock(drbg->lock); return ret; } +/* + * Get the global public DRBG. + * Returns pointer to the DRBG on success, NULL on failure. + */ +RAND_DRBG *RAND_DRBG_get0_global(void) +{ + if (!RUN_ONCE(&rand_init_drbg, do_rand_init_drbg)) + return NULL; + + return &rand_drbg; +} + +/* + * Get the global private DRBG. + * Returns pointer to the DRBG on success, NULL on failure. + */ +RAND_DRBG *RAND_DRBG_get0_priv_global(void) +{ + if (!RUN_ONCE(&rand_init_drbg, do_rand_init_drbg)) + return NULL; + + return &priv_drbg; +} + RAND_DRBG rand_drbg; /* The default global DRBG. */ RAND_DRBG priv_drbg; /* The global private-key DRBG. */ |