diff options
author | Pauli <paul.dale@oracle.com> | 2020-05-08 10:25:19 +1000 |
---|---|---|
committer | Pauli <paul.dale@oracle.com> | 2020-06-24 20:05:42 +1000 |
commit | f000e82898af251442ca52e81fc1ee45996090dc (patch) | |
tree | b378db85b032065a595ce8d7b0422981f09e0d58 /providers | |
parent | a998b85a4f0e706fa6a07b7feab557d9e570d372 (diff) |
CTR, HASH and HMAC DRBGs in provider
Move the three different DRBGs to the provider.
As part of the move, the DRBG specific data was pulled out of a common
structure and into their own structures. Only these smaller structures are
securely allocated. This saves quite a bit of secure memory:
+-------------------------------+
| DRBG | Bytes | Secure |
+--------------+-------+--------+
| HASH | 376 | 512 |
| HMAC | 168 | 256 |
| CTR | 176 | 256 |
| Common (new) | 320 | 0 |
| Common (old) | 592 | 1024 |
+--------------+-------+--------+
Bytes is the structure size on the X86/64.
Secure is the number of bytes of secure memory used (power of two allocator).
Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>
(Merged from https://github.com/openssl/openssl/pull/11682)
Diffstat (limited to 'providers')
-rw-r--r-- | providers/defltprov.c | 7 | ||||
-rw-r--r-- | providers/fips/fipsprov.c | 11 | ||||
-rw-r--r-- | providers/implementations/rands/build.info | 8 | ||||
-rw-r--r-- | providers/implementations/rands/crngt.c | 2 | ||||
-rw-r--r-- | providers/implementations/rands/drbg.c | 720 | ||||
-rw-r--r-- | providers/implementations/rands/drbg_ctr.c | 470 | ||||
-rw-r--r-- | providers/implementations/rands/drbg_hash.c | 302 | ||||
-rw-r--r-- | providers/implementations/rands/drbg_hmac.c | 319 | ||||
-rw-r--r-- | providers/implementations/rands/drbg_local.h | 196 | ||||
-rw-r--r-- | providers/implementations/rands/test_rng.c | 30 |
10 files changed, 1369 insertions, 696 deletions
diff --git a/providers/defltprov.c b/providers/defltprov.c index c68e34770e..7c1ffc7763 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -338,13 +338,10 @@ static const OSSL_ALGORITHM deflt_keyexch[] = { }; static const OSSL_ALGORITHM deflt_rands[] = { - { "TEST-RAND", "provider=default", test_rng_functions }, + { "CTR-DRBG", "provider=default", drbg_ctr_functions }, { "HASH-DRBG", "provider=default", drbg_hash_functions }, -/* { "HMAC-DRBG", "provider=default", drbg_hmac_functions }, - { "CTR-DRBG", "provider=default", drbg_ctr_functions }, -*/ - { "CRNGT:continuous-rng-test", "provider=default", crngt_functions }, + { "TEST-RAND", "provider=default", test_rng_functions }, { NULL, NULL, NULL } }; diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 5927c9fedc..6a1b56eeae 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -470,17 +470,10 @@ static const OSSL_ALGORITHM fips_kdfs[] = { }; static const OSSL_ALGORITHM fips_rands[] = { - /* - * The TEST RNG must be first, so it can be suppressed after the power up - * tests are completed. - */ - { "TEST-RAND", "provider=fips", test_rng_functions }, + { "CTR-DRBG", "provider=fips", drbg_ctr_functions }, { "HASH-DRBG", "provider=fips", drbg_hash_functions }, -/* { "HMAC-DRBG", "provider=fips", drbg_hmac_functions }, - { "CTR-DRBG", "provider=fips", drbg_ctr_functions }, -*/ - { "CRNGT:continuous-rng-test", "provider=fips", crngt_functions }, + { "TEST-RAND", "provider=fips", test_rng_functions }, { NULL, NULL, NULL } }; diff --git a/providers/implementations/rands/build.info b/providers/implementations/rands/build.info index 5d55c27fe4..1e710bb510 100644 --- a/providers/implementations/rands/build.info +++ b/providers/implementations/rands/build.info @@ -1,8 +1,6 @@ SUBDIRS=seeding -# Missing: drbg_ctr.c -SOURCE[../../libfips.a]=drbg.c -SOURCE[../../libnonfips.a]=drbg.c +$COMMON=drbg.c test_rng.c drbg_ctr.c drbg_hash.c drbg_hmac.c crngt.c rand_pool.c -# Missing: drbg_hmac.c -SOURCE[../../libimplementations.a]=test_rng.c drbg_hash.c crngt.c +SOURCE[../../libfips.a]=$COMMON +SOURCE[../../libnonfips.a]=$COMMON diff --git a/providers/implementations/rands/crngt.c b/providers/implementations/rands/crngt.c index 2680f7b644..1777b33489 100644 --- a/providers/implementations/rands/crngt.c +++ b/providers/implementations/rands/crngt.c @@ -21,7 +21,7 @@ #include "internal/cryptlib.h" #include "prov/rand_pool.h" #include "drbg_local.h" -#include "seeding/seeding.h" +#include "prov/seeding.h" typedef struct crng_test_global_st { unsigned char crngt_prev[EVP_MAX_MD_SIZE]; diff --git a/providers/implementations/rands/drbg.c b/providers/implementations/rands/drbg.c index c9e4cd4b60..db8fce877a 100644 --- a/providers/implementations/rands/drbg.c +++ b/providers/implementations/rands/drbg.c @@ -11,12 +11,15 @@ #include <openssl/crypto.h> #include <openssl/err.h> #include <openssl/rand.h> +#include <openssl/evp.h> #include "crypto/rand.h" #include "drbg_local.h" #include "internal/thread_once.h" #include "crypto/cryptlib.h" -#include "seeding/seeding.h" -#include "crypto/rand_pool.h" +#include "prov/seeding.h" +#include "prov/rand_pool.h" +#include "prov/provider_ctx.h" +#include "prov/providercommonerr.h" /* * Support framework for NIST SP 800-90A DRBG @@ -31,26 +34,14 @@ * a much bigger deal than just re-setting an allocated resource.) */ -#ifdef FIPS_MODULE -# define get_entropy prov_crngt_get_entropy -# define cleanup_entropy prov_crngt_cleanup_entropy -#else -# define get_entropy prov_drbg_get_entropy -# define cleanup_entropy prov_drbg_cleanup_entropy -#endif - /* NIST SP 800-90A DRBG recommends the use of a personalization string. */ static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING; -static unsigned int master_reseed_interval = MASTER_RESEED_INTERVAL; -static unsigned int slave_reseed_interval = SLAVE_RESEED_INTERVAL; - -static time_t master_reseed_time_interval = MASTER_RESEED_TIME_INTERVAL; -static time_t slave_reseed_time_interval = SLAVE_RESEED_TIME_INTERVAL; - static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, int function); +static int rand_drbg_restart(PROV_DRBG *drbg); + int drbg_lock(void *vctx) { PROV_DRBG *drbg = vctx; @@ -71,14 +62,12 @@ void drbg_unlock(void *vctx) static int drbg_lock_parent(PROV_DRBG *drbg) { void *parent = drbg->parent; - const OSSL_DISPATCH *pfunc; - if (parent != NULL) { - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_LOCK); - if (pfunc != NULL && !OSSL_get_OP_rand_lock(pfunc)(parent)) { - ERR_raise(ERR_LIB_PROV, RAND_R_PARENT_LOCKING_NOT_ENABLED); - return 0; - } + if (parent != NULL + && drbg->parent_lock != NULL + && !drbg->parent_lock(parent)) { + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); + return 0; } return 1; } @@ -86,74 +75,62 @@ static int drbg_lock_parent(PROV_DRBG *drbg) static void drbg_unlock_parent(PROV_DRBG *drbg) { void *parent = drbg->parent; - const OSSL_DISPATCH *pfunc; - if (parent != NULL) { - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_UNLOCK); - if (pfunc != NULL) - OSSL_get_OP_rand_unlock(pfunc)(parent); - } + if (parent != NULL && drbg->parent_unlock != NULL) + drbg->parent_unlock(parent); } -static int get_parent_strength(PROV_DRBG *drbg, int *str) +static int get_parent_strength(PROV_DRBG *drbg, unsigned int *str) { OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; - const OSSL_DISPATCH *pfunc; void *parent = drbg->parent; + int res; - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS); - if (pfunc == NULL) { - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH); + if (drbg->parent_get_ctx_params == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); return 0; } - *params = OSSL_PARAM_construct_int(OSSL_RAND_PARAM_STRENGTH, str); + + *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, str); if (!drbg_lock_parent(drbg)) { - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_LOCK_PARENT); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); return 0; } - if (!OSSL_get_OP_rand_get_ctx_params(pfunc)(parent, params)) { - drbg_unlock_parent(drbg); - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH); + res = drbg->parent_get_ctx_params(parent, params); + drbg_unlock_parent(drbg); + if (!res) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); return 0; } - drbg_unlock_parent(drbg); return 1; } static unsigned int get_parent_reseed_count(PROV_DRBG *drbg) { OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; - const OSSL_DISPATCH *pfunc; void *parent = drbg->parent; unsigned int r; - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS); - if (pfunc == NULL) { - ERR_raise(ERR_LIB_PROV, - RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER); - goto err; - } - *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_RESEED_PROP_CTR, &r); + *params = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_CTR, &r); if (!drbg_lock_parent(drbg)) { - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_LOCK_PARENT); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); goto err; } - if (!OSSL_get_OP_rand_get_ctx_params(pfunc)(parent, params)) { + if (!drbg->parent_get_ctx_params(parent, params)) { drbg_unlock_parent(drbg); - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_RESEED_PROP_CTR); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_RESEED_PROP_CTR); goto err; } drbg_unlock_parent(drbg); return r; err: - r = tsan_load(&drbg->reseed_prop_counter) - 2; + r = tsan_load(&drbg->reseed_counter) - 2; if (r == 0) r = UINT_MAX; return r; } -#ifndef FIPS_MODULE /* * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks()) * @@ -161,20 +138,19 @@ static unsigned int get_parent_reseed_count(PROV_DRBG *drbg) * is fetched using the parent's RAND_DRBG_generate(). * * Otherwise, the entropy is polled from the system entropy sources - * using rand_pool_acquire_entropy(). + * using prov_pool_acquire_entropy(). * * If a random pool has been added to the DRBG using RAND_add(), then * its entropy will be used up first. */ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, - int entropy, size_t min_len, size_t max_len, - int prediction_resistance) + 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; - int p_str; - const OSSL_DISPATCH *pfunc; + unsigned int p_str; if (drbg->parent != NULL) { if (!get_parent_strength(drbg, &p_str)) @@ -184,7 +160,7 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, * We currently don't support the algorithm from NIST SP 800-90C * 10.1.2 to use a weaker DRBG as source */ - RANDerr(0, RAND_R_PARENT_STRENGTH_TOO_WEAK); + RANDerr(0, PROV_R_PARENT_STRENGTH_TOO_WEAK); return 0; } } @@ -193,9 +169,11 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, pool = drbg->seed_pool; pool->entropy_requested = entropy; } else { - pool = rand_pool_new(entropy, drbg->secure, min_len, max_len); - if (pool == NULL) + pool = rand_pool_new(entropy, 1, min_len, max_len); + if (pool == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return 0; + } } if (drbg->parent != NULL) { @@ -213,25 +191,23 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, * generating bits from it. (Note: taking the lock will be a no-op * if locking if drbg->parent->lock == NULL.) */ - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GENERATE); - if (pfunc == NULL) - return 0; + if (drbg->parent_generate == NULL) + goto err; drbg_lock_parent(drbg); - if (OSSL_get_OP_rand_generate(pfunc)(drbg->parent, buffer, bytes_needed, - drbg->strength, - prediction_resistance, - (unsigned char *)&drbg, - sizeof(drbg)) != 0) + if (drbg->parent_generate(drbg->parent, buffer, bytes_needed, + drbg->strength, prediction_resistance, + (unsigned char *)&drbg, + sizeof(drbg)) != 0) bytes = bytes_needed; - drbg->reseed_next_counter = get_parent_reseed_count(drbg); drbg_unlock_parent(drbg); + drbg->parent_reseed_counter = get_parent_reseed_count(drbg); rand_pool_add_end(pool, bytes, 8 * bytes); entropy_available = rand_pool_entropy_available(pool); } } else { /* Get entropy by polling system entropy sources. */ - entropy_available = rand_pool_acquire_entropy(pool); + entropy_available = prov_pool_acquire_entropy(pool); } if (entropy_available > 0) { @@ -239,6 +215,7 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, *pout = rand_pool_detach(pool); } +err: if (drbg->seed_pool == NULL) rand_pool_free(pool); return ret; @@ -251,14 +228,68 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, static void prov_drbg_cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen) { - if (drbg->seed_pool == NULL) { - if (drbg->secure) - OPENSSL_secure_clear_free(out, outlen); - else - OPENSSL_clear_free(out, outlen); + OSSL_PARAM params[3], *p = params; + + if (drbg->get_entropy_fn != NULL) { + if (drbg->cleanup_entropy_fn != NULL) { + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE, + &outlen); + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)&out, 0); + *p = OSSL_PARAM_construct_end(); + + drbg->cleanup_entropy_fn(params, drbg->callback_arg); + } + } else if (drbg->seed_pool == NULL) { + OPENSSL_secure_clear_free(out, outlen); } } + +static size_t get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy, + size_t min_len, size_t max_len, + int prediction_resistance) +{ + if (drbg->get_entropy_fn != NULL) { + OSSL_PARAM params[6], *p = params; + OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED, + &entropy); + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_PREDICTION_RESISTANCE, + &prediction_resistance); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH, + &min_len); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH, + &max_len); + *p = OSSL_PARAM_construct_end(); + *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)pout, 0); + + if (drbg->get_entropy_fn(params, out, drbg->callback_arg)) + return out->return_size; + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_ENTROPY); + return 0; + } + +#ifdef FIPS_MODULE + if (drbg->parent == NULL) + return prov_crngt_get_entropy(drbg, pout, entropy, min_len, max_len, + prediction_resistance); +#endif + + return prov_drbg_get_entropy(drbg, pout, entropy, min_len, max_len, + prediction_resistance); +} + +static void cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen) +{ +#ifdef FIPS_MODULE + if (drbg->parent == NULL) + prov_crngt_cleanup_entropy(drbg, out, outlen); + else #endif + prov_drbg_cleanup_entropy(drbg, out, outlen); +} #ifndef PROV_RAND_GET_RANDOM_NONCE typedef struct prov_drbg_nonce_global_st { @@ -311,26 +342,63 @@ static size_t prov_drbg_get_nonce(PROV_DRBG *drbg, unsigned char **pout, int entropy, size_t min_len, size_t max_len) { - size_t ret = 0; + size_t ret = 0, n; RAND_POOL *pool; + unsigned char *buf = NULL; + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(drbg->provctx); PROV_DRBG_NONCE_GLOBAL *dngbl - = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_DRBG_NONCE_INDEX, + = openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_NONCE_INDEX, &drbg_nonce_ossl_ctx_method); + OSSL_PARAM params[5], *p = params; + OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; struct { void *instance; int count; } data; - if (dngbl == NULL) return 0; + if (drbg->get_nonce_fn != NULL) { + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED, + &entropy); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH, + &min_len); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH, + &max_len); + *p = OSSL_PARAM_construct_end(); + *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)pout, 0); + + if (drbg->get_nonce_fn(params, out, drbg->callback_arg)) + return out->return_size; + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_NONCE); + return 0; + } + if (drbg->parent != NULL) { + if (drbg->parent_nonce != NULL) { + n = drbg->parent_nonce(drbg->parent, NULL, 0, drbg->min_noncelen, + drbg->max_noncelen); + if (n > 0 && (buf = OPENSSL_malloc(n)) != NULL) { + ret = drbg->parent_nonce(drbg->parent, buf, 0, + drbg->min_noncelen, + drbg->max_noncelen); + if (ret == n) { + *pout = buf; + return ret; + } + OPENSSL_free(buf); + } + } + } + + /* Use the built in nonce source */ memset(&data, 0, sizeof(data)); pool = rand_pool_new(0, 0, min_len, max_len); if (pool == NULL) return 0; - if (rand_pool_add_nonce_data(pool) == 0) + if (prov_pool_add_nonce_data(pool) == 0) goto err; data.instance = drbg; @@ -348,17 +416,30 @@ static size_t prov_drbg_get_nonce(PROV_DRBG *drbg, return ret; } -#endif -/* - * Implements the cleanup_nonce() callback (see PROV_DRBG_set_callbacks()) - * - */ -static void prov_drbg_cleanup_nonce(PROV_DRBG *drbg, - unsigned char *out, size_t outlen) +static void prov_drbg_clear_nonce(PROV_DRBG *drbg, unsigned char *nonce, + size_t noncelen) { - OPENSSL_clear_free(out, outlen); + OSSL_PARAM params[3], *p = params; + + if (drbg->get_nonce_fn != NULL) { + if (drbg->cleanup_nonce_fn != NULL) { + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE, + &noncelen); + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)&nonce, 0); + *p = OSSL_PARAM_construct_end(); + + drbg->cleanup_nonce_fn(params, drbg->callback_arg); + } + } else { + OPENSSL_clear_free(nonce, noncelen); + } } +#else +# define prov_drbg_clear_nonce(drbg, nonce, len) \ + OPENSSL_clear_free((nonce), (len)) +#endif /* PROV_RAND_GET_RANDOM_NONCE */ /* * Instantiate |drbg|, after it has been initialized. Use |pers| and @@ -368,23 +449,16 @@ static void prov_drbg_cleanup_nonce(PROV_DRBG *drbg, * * Returns 1 on success, 0 on failure. */ -int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, +int PROV_DRBG_instantiate(PROV_DRBG *drbg, unsigned int strength, int prediction_resistance, - const unsigned char *pers, size_t perslen, - int (*ifnc)(PROV_DRBG *drbg, - const unsigned char *ent, size_t ent_len, - const unsigned char *nonce, - size_t nonce_len, - const unsigned char *pstr, - size_t pstr_len)) + const unsigned char *pers, size_t perslen) { unsigned char *nonce = NULL, *entropy = NULL; size_t noncelen = 0, entropylen = 0; size_t min_entropy, min_entropylen, max_entropylen; - const OSSL_DISPATCH *pnonce; if (strength > drbg->strength) { - PROVerr(0, RAND_R_INSUFFICIENT_DRBG_STRENGTH); + PROVerr(0, PROV_R_INSUFFICIENT_DRBG_STRENGTH); goto end; } min_entropy = drbg->strength; @@ -396,50 +470,54 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, perslen = sizeof(ossl_pers_string); } if (perslen > drbg->max_perslen) { - PROVerr(0, RAND_R_PERSONALISATION_STRING_TOO_LONG); + PROVerr(0, PROV_R_PERSONALISATION_STRING_TOO_LONG); goto end; } - if (drbg->state != DRBG_UNINITIALISED) { - if (drbg->state == DRBG_ERROR) - PROVerr(0, RAND_R_IN_ERROR_STATE); + if (drbg->state != EVP_RAND_STATE_UNINITIALISED) { + if (drbg->state == EVP_RAND_STATE_ERROR) + PROVerr(0, PROV_R_IN_ERROR_STATE); else - PROVerr(0, RAND_R_ALREADY_INSTANTIATED); + PROVerr(0, PROV_R_ALREADY_INSTANTIATED); goto end; } - drbg->state = DRBG_ERROR; + drbg->state = EVP_RAND_STATE_ERROR; if (drbg->min_noncelen > 0) { + if (drbg->parent_nonce != NULL) { + noncelen = drbg->parent_nonce(drbg->parent, NULL, drbg->strength, + drbg->min_noncelen, + drbg->max_noncelen); + if (noncelen == 0) { + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } + nonce = OPENSSL_malloc(noncelen); + if (nonce == NULL) { + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } + if (noncelen != drbg->parent_nonce(drbg->parent, nonce, + drbg->strength, + drbg->min_noncelen, + drbg->max_noncelen)) { + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); + OPENSSL_free(nonce); + } #ifndef PROV_RAND_GET_RANDOM_NONCE - if (drbg->parent != NULL) + } else if (drbg->parent != NULL) { #endif - { - pnonce = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_NONCE); - if (pnonce == NULL) { - /* - * NIST SP800-90Ar1 section 9.1 says you can combine getting - * the entropy and nonce in 1 call by increasing the entropy - * with 50% and increasing the minimum length to accommodate - * the length of the nonce. We do this in case a nonce is - * required and there is no parental nonce capability. - */ - min_entropy += drbg->strength / 2; - min_entropylen += drbg->min_noncelen; - max_entropylen += drbg->max_noncelen; - } else { - drbg_lock_parent(drbg); - noncelen = OSSL_get_OP_rand_nonce(pnonce)(drbg->parent, &nonce, - drbg->strength / 2, - drbg->min_noncelen, - drbg->max_noncelen); - drbg_unlock_parent(drbg); - if (noncelen < drbg->min_noncelen - || noncelen > drbg->max_noncelen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_NONCE); - goto end; - } - } + /* + * NIST SP800-90Ar1 section 9.1 says you can combine getting + * the entropy and nonce in 1 call by increasing the entropy + * with 50% and increasing the minimum length to accommodate + * the length of the nonce. We do this in case a nonce is + * required and there is no parental nonce capability. + */ + min_entropy += drbg->strength / 2; + min_entropylen += drbg->min_noncelen; + max_entropylen += drbg->max_noncelen; } #ifndef PROV_RAND_GET_RANDOM_NONCE else { /* parent == NULL */ @@ -448,17 +526,17 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, drbg->max_noncelen); if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_NONCE); + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); goto end; } } #endif } - drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); + drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); if (drbg->reseed_next_counter) { drbg->reseed_next_counter++; - if(!drbg->reseed_next_counter) + if (!drbg->reseed_next_counter) drbg->reseed_next_counter = 1; } @@ -467,31 +545,44 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, prediction_resistance); if (entropylen < min_entropylen || entropylen > max_entropylen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_ENTROPY); + PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY); goto end; } - if (!ifnc(drbg, entropy, entropylen, nonce, noncelen, pers, perslen)) { - PROVerr(0, RAND_R_ERROR_INSTANTIATING_DRBG); + if (!drbg->instantiate(drbg, entropy, entropylen, nonce, noncelen, + pers, perslen)) { + PROVerr(0, PROV_R_ERROR_INSTANTIATING_DRBG); goto end; } - drbg->state = DRBG_READY; + drbg->state = EVP_RAND_STATE_READY; drbg->reseed_gen_counter = 1; drbg->reseed_time = time(NULL); - tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); + tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); end: if (entropy != NULL) cleanup_entropy(drbg, entropy, entropylen); - if (nonce != NULL) - prov_drbg_cleanup_nonce(drbg, nonce, noncelen); - if (drbg->state == DRBG_READY) + prov_drbg_clear_nonce(drbg, nonce, noncelen); + if (drbg->state == EVP_RAND_STATE_READY) return 1; return 0; } /* + * Uninstantiate |drbg|. Must be instantiated before it can be used. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int PROV_DRBG_uninstantiate(PROV_DRBG *drbg) +{ + drbg->state = EVP_RAND_STATE_UNINITIALISED; + return 1; +} + +/* * Reseed |drbg|, mixing in the specified data * * Requires that drbg->lock is already locked for write, if non-null. @@ -500,60 +591,101 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, */ int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance, const unsigned char *ent, size_t ent_len, - const unsigned char *adin, size_t adinlen, - int (*reseed)(PROV_DRBG *drbg, - const unsigned char *ent, size_t ent_len, - const unsigned char *adin, size_t adin_len)) + const unsigned char *adin, size_t adinlen) { unsigned char *entropy = NULL; size_t entropylen = 0; - if (drbg->state == DRBG_ERROR) { - PROVerr(0, RAND_R_IN_ERROR_STATE); - return 0; + if (drbg->state != EVP_RAND_STATE_READY) { + /* try to recover from previous errors */ + rand_drbg_restart(drbg); + + if (drbg->state == EVP_RAND_STATE_ERROR) { + PROVerr(0, PROV_R_IN_ERROR_STATE); + return 0; + } + if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { + PROVerr(0, PROV_R_NOT_INSTANTIATED); + return 0; + } } - if (drbg->state == DRBG_UNINITIALISED) { - PROVerr(0, RAND_R_NOT_INSTANTIATED); - return 0; + + if (ent != NULL) { + if (ent_len < drbg->min_entropylen) { + RANDerr(0, RAND_R_ENTROPY_OUT_OF_RANGE); + drbg->state = EVP_RAND_STATE_ERROR; + return 0; + } + if (ent_len > drbg->max_entropylen) { + RANDerr(0, RAND_R_ENTROPY_INPUT_TOO_LONG); + drbg->state = EVP_RAND_STATE_ERROR; + return 0; + } } if (adin == NULL) { adinlen = 0; } else if (adinlen > drbg->max_adinlen) { - PROVerr(0, RAND_R_ADDITIONAL_INPUT_TOO_LONG); + PROVerr(0, PROV_R_ADDITIONAL_INPUT_TOO_LONG); return 0; } - drbg->state = DRBG_ERROR; + drbg->state = EVP_RAND_STATE_ERROR; - drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); + drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); if (drbg->reseed_next_counter) { drbg->reseed_next_counter++; - if(!drbg->reseed_next_counter) + if (!drbg->reseed_next_counter) drbg->reseed_next_counter = 1; } + if (ent != NULL) { +#ifdef FIP_MODULE + /* + * NIST SP-800-90A mandates that entropy *shall not* be provided + * by the consuming application. Instead the data is added as additional + * input. + * + * (NIST SP-800-90Ar1, Sections 9.1 and 9.2) + */ + if (!drbg->reseed(drbg, NULL, 0, ent, ent_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); + return 0; + } +#else + if (!drbg->reseed(drbg, ent, ent_len, adin, adinlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); + return 0; + } + /* There isn't much point adding the same additional input twice */ + adin = NULL; + adinlen = 0; +#endif + } + + /* Reseed using our sources in addition */ entropylen = get_entropy(drbg, &entropy, drbg->strength, drbg->min_entropylen, drbg->max_entropylen, prediction_resistance); if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_ENTROPY); + PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY); goto end; } - if (!reseed(drbg, entropy, entropylen, adin, adinlen)) + if (!drbg->reseed(drbg, entropy, entropylen, adin, adinlen)) goto end; - drbg->state = DRBG_READY; + drbg->state = EVP_RAND_STATE_READY; drbg->reseed_gen_counter = 1; drbg->reseed_time = time(NULL); - tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); + tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); + if (drbg->parent != NULL) + drbg->parent_reseed_counter = get_parent_reseed_count(drbg); end: - if (entropy != NULL) - OPENSSL_cleanse(entropy, entropylen); - if (drbg->state == DRBG_READY) + cleanup_entropy(drbg, entropy, entropylen); + if (drbg->state == EVP_RAND_STATE_READY) return 1; return 0; } @@ -569,35 +701,36 @@ int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance, * */ int PROV_DRBG_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, - int strength, int prediction_resistance, - const unsigned char *adin, size_t adinlen, - int (*generate)(PROV_DRBG *, unsigned char *out, - size_t outlen, const unsigned char *adin, - size_t adin_len), - int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, - size_t ent_len, const unsigned char *adin, |