X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Frand%2Fdrbg_lib.c;h=10a17a9a5f49f25006cc06a7e8e683e15ad0093d;hp=daac770d36096e7cda15add6b96768f7acdbe4bc;hb=8bf366519661e12fd894dc5420f5b64dccfd7ecd;hpb=35503b7cdc38b21739df1163d6d24b00dd386bef diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c index daac770d36..10a17a9a5f 100644 --- a/crypto/rand/drbg_lib.c +++ b/crypto/rand/drbg_lib.c @@ -14,10 +14,12 @@ #include "rand_lcl.h" #include "internal/thread_once.h" #include "internal/rand_int.h" +#include "internal/cryptlib_int.h" /* - * Support framework for NIST SP 800-90A DRBG, AES-CTR mode. - * The RAND_DRBG is OpenSSL's pointer to an instance of the DRBG. + * Support framework for NIST SP 800-90A DRBG + * + * See manual page RAND_DRBG(7) for a general overview. * * The OpenSSL model is to have new and free functions, and that new * does all initialization. That is not the NIST model, which has @@ -28,84 +30,40 @@ */ /* - * THE THREE SHARED DRBGs - * - * There are three shared DRBGs (master, public and private), which are - * accessed concurrently by all threads. + * The three shared DRBG instances * - * THE MASTER DRBG + * There are three shared DRBG instances: , , and . + */ + +/* + * The DRBG * * Not used directly by the application, only for reseeding the two other * DRBGs. It reseeds itself by pulling either randomness from os entropy - * sources or by consuming randomnes which was added by RAND_add() + * sources or by consuming randomness which was added by RAND_add(). + * + * The DRBG is a global instance which is accessed concurrently by + * all threads. The necessary locking is managed automatically by its child + * DRBG instances during reseeding. */ -static RAND_DRBG *drbg_master; +static RAND_DRBG *master_drbg; /* - * THE PUBLIC DRBG + * The DRBG * * Used by default for generating random bytes using RAND_bytes(). + * + * The DRBG is thread-local, i.e., there is one instance per thread. */ -static RAND_DRBG *drbg_public; +static CRYPTO_THREAD_LOCAL public_drbg; /* - * THE PRIVATE DRBG + * The DRBG * * Used by default for generating private keys using RAND_priv_bytes() + * + * The DRBG is thread-local, i.e., there is one instance per thread. */ -static RAND_DRBG *drbg_private; -/*+ - * DRBG HIERARCHY - * - * In addition there are DRBGs, which are not shared, but used only by a - * single thread at every time, for example the DRBGs which are owned by - * an SSL context. All DRBGs are organized in a hierarchical fashion - * with the DRBG as root. - * - * This gives the following overall picture: - * - * - * | - * RAND_add() ==> \ - * / \ | shared DRBGs (with locking) - * / - * | - * owned by an SSL context - * - * AUTOMATIC RESEEDING - * - * Before satisfying a generate request, a DRBG reseeds itself automatically, - * if one of the following two conditions holds: - * - * - the number of generate requests since the last reseeding exceeds a - * certain threshold, the so called |reseed_interval|. This behaviour - * can be disabled by setting the |reseed_interval| to 0. - * - * - the time elapsed since the last reseeding exceeds a certain time - * interval, the so called |reseed_time_interval|. This behaviour - * can be disabled by setting the |reseed_time_interval| to 0. - * - * MANUAL RESEEDING - * - * For the three shared DRBGs (and only for these) there is another way to - * reseed them manually by calling RAND_seed() (or RAND_add() with a positive - * |randomness| argument). This will immediately reseed the DRBG. - * The and DRBG will detect this on their next generate - * call and reseed, pulling randomness from . - * - * LOCKING - * - * The three shared DRBGs are intended to be used concurrently, so they - * support locking. The RAND methods take the locks automatically, so using - * the RAND api (in particular RAND_bytes() and RAND_priv_bytes()) is - * thread-safe. Note however that accessing the shared DRBGs directly via - * the RAND_DRBG interface is *not* thread-safe. - * - * All other DRBG instances don't support locking, because they are - * intendended to be used by a single thread. Instead of accessing a single - * DRBG instance concurrently from different threads, it is recommended to - * instantiate a separate DRBG instance per thread. Using the same shared - * DRBG (preferrably the public DRBG) as parent of DRBG instances on - * different threads is safe. - */ +static CRYPTO_THREAD_LOCAL private_drbg; + /* NIST SP 800-90A DRBG recommends the use of a personalization string. */ @@ -113,38 +71,114 @@ static const char ossl_pers_string[] = "OpenSSL NIST SP 800-90A DRBG"; static CRYPTO_ONCE rand_drbg_init = CRYPTO_ONCE_STATIC_INIT; -static RAND_DRBG *drbg_setup(RAND_DRBG *parent); + +#define RAND_DRBG_TYPE_FLAGS ( \ + RAND_DRBG_FLAG_MASTER | RAND_DRBG_FLAG_PUBLIC | RAND_DRBG_FLAG_PRIVATE ) + +#define RAND_DRBG_TYPE_MASTER 0 +#define RAND_DRBG_TYPE_PUBLIC 1 +#define RAND_DRBG_TYPE_PRIVATE 2 + +/* Defaults */ +static int rand_drbg_type[3] = { + RAND_DRBG_TYPE, /* Master */ + RAND_DRBG_TYPE, /* Public */ + RAND_DRBG_TYPE /* Private */ +}; +static unsigned int rand_drbg_flags[3] = { + RAND_DRBG_FLAGS | RAND_DRBG_FLAG_MASTER, /* Master */ + RAND_DRBG_FLAGS | RAND_DRBG_FLAG_PUBLIC, /* Public */ + RAND_DRBG_FLAGS | RAND_DRBG_FLAG_PRIVATE /* Private */ +}; + +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; + +/* A logical OR of all used DRBG flag bits (currently there is only one) */ +static const unsigned int rand_drbg_used_flags = + RAND_DRBG_FLAG_CTR_NO_DF | RAND_DRBG_FLAG_HMAC | RAND_DRBG_TYPE_FLAGS; + + +static RAND_DRBG *drbg_setup(RAND_DRBG *parent, int drbg_type); static RAND_DRBG *rand_drbg_new(int secure, int type, unsigned int flags, RAND_DRBG *parent); +static int is_ctr(int type) +{ + switch (type) { + case NID_aes_128_ctr: + case NID_aes_192_ctr: + case NID_aes_256_ctr: + return 1; + default: + return 0; + } +} + +static int is_digest(int type) +{ + switch (type) { + case NID_sha1: + case NID_sha224: + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_sha512_224: + case NID_sha512_256: + case NID_sha3_224: + case NID_sha3_256: + case NID_sha3_384: + case NID_sha3_512: + return 1; + default: + return 0; + } +} + /* - * Set/initialize |drbg| to be of type |nid|, with optional |flags|. + * Set/initialize |drbg| to be of type |type|, with optional |flags|. + * + * If |type| and |flags| are zero, use the defaults * * Returns 1 on success, 0 on failure. */ -int RAND_DRBG_set(RAND_DRBG *drbg, int nid, unsigned int flags) +int RAND_DRBG_set(RAND_DRBG *drbg, int type, unsigned int flags) { int ret = 1; + if (type == 0 && flags == 0) { + type = rand_drbg_type[RAND_DRBG_TYPE_MASTER]; + flags = rand_drbg_flags[RAND_DRBG_TYPE_MASTER]; + } + + /* If set is called multiple times - clear the old one */ + if (type != drbg->type && drbg->type != 0 && drbg->meth != NULL) { + drbg->meth->uninstantiate(drbg); + } + drbg->state = DRBG_UNINITIALISED; drbg->flags = flags; - drbg->nid = nid; + drbg->type = type; - switch (nid) { - default: - RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE); - return 0; - case 0: + if (type == 0) { /* Uninitialized; that's okay. */ return 1; - case NID_aes_128_ctr: - case NID_aes_192_ctr: - case NID_aes_256_ctr: + } else if (is_ctr(type)) { ret = drbg_ctr_init(drbg); - break; + } else if (is_digest(type)) { + if (flags & RAND_DRBG_FLAG_HMAC) + ret = drbg_hmac_init(drbg); + else + ret = drbg_hash_init(drbg); + } else { + RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE); + return 0; } if (ret == 0) @@ -152,6 +186,41 @@ int RAND_DRBG_set(RAND_DRBG *drbg, int nid, unsigned int flags) return ret; } +/* + * Set/initialize default |type| and |flag| for new drbg instances. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_set_defaults(int type, unsigned int flags) +{ + int all; + if (!(is_digest(type) || is_ctr(type))) { + RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_TYPE); + return 0; + } + + if ((flags & ~rand_drbg_used_flags) != 0) { + RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_FLAGS); + return 0; + } + + all = ((flags & RAND_DRBG_TYPE_FLAGS) == 0); + if (all || (flags & RAND_DRBG_FLAG_MASTER) != 0) { + rand_drbg_type[RAND_DRBG_TYPE_MASTER] = type; + rand_drbg_flags[RAND_DRBG_TYPE_MASTER] = flags | RAND_DRBG_FLAG_MASTER; + } + if (all || (flags & RAND_DRBG_FLAG_PUBLIC) != 0) { + rand_drbg_type[RAND_DRBG_TYPE_PUBLIC] = type; + rand_drbg_flags[RAND_DRBG_TYPE_PUBLIC] = flags | RAND_DRBG_FLAG_PUBLIC; + } + if (all || (flags & RAND_DRBG_FLAG_PRIVATE) != 0) { + rand_drbg_type[RAND_DRBG_TYPE_PRIVATE] = type; + rand_drbg_flags[RAND_DRBG_TYPE_PRIVATE] = flags | RAND_DRBG_FLAG_PRIVATE; + } + return 1; +} + + /* * Allocate memory and initialize a new DRBG. The DRBG is allocated on * the secure heap if |secure| is nonzero and the secure heap is enabled. @@ -169,29 +238,52 @@ static RAND_DRBG *rand_drbg_new(int secure, if (drbg == NULL) { RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); - goto err; + return NULL; } drbg->secure = secure && CRYPTO_secure_allocated(drbg); drbg->fork_count = rand_fork_count; drbg->parent = parent; - if (RAND_DRBG_set(drbg, type, flags) == 0) - goto err; - if (parent != NULL && drbg->strength > parent->strength) { + if (parent == NULL) { + drbg->get_entropy = rand_drbg_get_entropy; + drbg->cleanup_entropy = rand_drbg_cleanup_entropy; +#ifndef RAND_DRBG_GET_RANDOM_NONCE + drbg->get_nonce = rand_drbg_get_nonce; + drbg->cleanup_nonce = rand_drbg_cleanup_nonce; +#endif + + drbg->reseed_interval = master_reseed_interval; + drbg->reseed_time_interval = master_reseed_time_interval; + } else { + drbg->get_entropy = rand_drbg_get_entropy; + drbg->cleanup_entropy = rand_drbg_cleanup_entropy; /* - * We currently don't support the algorithm from NIST SP 800-90C - * 10.1.2 to use a weaker DRBG as source + * Do not provide nonce callbacks, the child DRBGs will + * obtain their nonce using random bits from the parent. */ - RANDerr(RAND_F_RAND_DRBG_NEW, RAND_R_PARENT_STRENGTH_TOO_WEAK); - goto err; + + drbg->reseed_interval = slave_reseed_interval; + drbg->reseed_time_interval = slave_reseed_time_interval; } - if (!RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy, - rand_drbg_cleanup_entropy, - NULL, NULL)) + if (RAND_DRBG_set(drbg, type, flags) == 0) goto err; + if (parent != NULL) { + rand_drbg_lock(parent); + if (drbg->strength > parent->strength) { + /* + * We currently don't support the algorithm from NIST SP 800-90C + * 10.1.2 to use a weaker DRBG as source + */ + rand_drbg_unlock(parent); + RANDerr(RAND_F_RAND_DRBG_NEW, RAND_R_PARENT_STRENGTH_TOO_WEAK); + goto err; + } + rand_drbg_unlock(parent); + } + return drbg; err: @@ -245,6 +337,9 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg, { unsigned char *nonce = NULL, *entropy = NULL; size_t noncelen = 0, entropylen = 0; + size_t min_entropy = drbg->strength; + size_t min_entropylen = drbg->min_entropylen; + size_t max_entropylen = drbg->max_entropylen; if (perslen > drbg->max_perslen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, @@ -252,8 +347,7 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg, goto end; } - if (drbg->meth == NULL) - { + if (drbg->meth == NULL) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); goto end; @@ -267,21 +361,33 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg, } drbg->state = DRBG_ERROR; + + /* + * 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 accomadate the length of the nonce. + * We do this in case a nonce is require and get_nonce is NULL. + */ + if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) { + min_entropy += drbg->strength / 2; + min_entropylen += drbg->min_noncelen; + max_entropylen += drbg->max_noncelen; + } + if (drbg->get_entropy != NULL) - entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, - drbg->min_entropylen, drbg->max_entropylen); - if (entropylen < drbg->min_entropylen - || entropylen > drbg->max_entropylen) { + entropylen = drbg->get_entropy(drbg, &entropy, min_entropy, + min_entropylen, max_entropylen, 0); + if (entropylen < min_entropylen + || entropylen > max_entropylen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY); goto end; } - if (drbg->max_noncelen > 0 && drbg->get_nonce != NULL) { + if (drbg->min_noncelen > 0 && drbg->get_nonce != NULL) { noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2, drbg->min_noncelen, drbg->max_noncelen); if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, - RAND_R_ERROR_RETRIEVING_NONCE); + RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE); goto end; } } @@ -293,13 +399,13 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg, } drbg->state = DRBG_READY; - drbg->generate_counter = 0; + drbg->reseed_gen_counter = 1; drbg->reseed_time = time(NULL); - if (drbg->reseed_counter > 0) { + if (drbg->reseed_prop_counter > 0) { if (drbg->parent == NULL) - drbg->reseed_counter++; + drbg->reseed_prop_counter++; else - drbg->reseed_counter = drbg->parent->reseed_counter; + drbg->reseed_prop_counter = drbg->parent->reseed_prop_counter; } end: @@ -313,7 +419,7 @@ end: RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED); drbg->state = DRBG_ERROR; } - RAND_POOL_free(drbg->pool); + rand_pool_free(drbg->pool); drbg->pool = NULL; } if (drbg->state == DRBG_READY) @@ -330,8 +436,8 @@ end: */ int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) { - if (drbg->meth == NULL) - { + int index = -1, type, flags; + if (drbg->meth == NULL) { RANDerr(RAND_F_RAND_DRBG_UNINSTANTIATE, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); return 0; @@ -342,7 +448,23 @@ int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) * initial values. */ drbg->meth->uninstantiate(drbg); - return RAND_DRBG_set(drbg, drbg->nid, drbg->flags); + + /* The reset uses the default values for type and flags */ + if (drbg->flags & RAND_DRBG_FLAG_MASTER) + index = RAND_DRBG_TYPE_MASTER; + else if (drbg->flags & RAND_DRBG_FLAG_PRIVATE) + index = RAND_DRBG_TYPE_PRIVATE; + else if (drbg->flags & RAND_DRBG_FLAG_PUBLIC) + index = RAND_DRBG_TYPE_PUBLIC; + + if (index != -1) { + flags = rand_drbg_flags[index]; + type = rand_drbg_type[index]; + } else { + flags = drbg->flags; + type = drbg->type; + } + return RAND_DRBG_set(drbg, type, flags); } /* @@ -353,7 +475,8 @@ int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) * Returns 1 on success, 0 on failure. */ int RAND_DRBG_reseed(RAND_DRBG *drbg, - const unsigned char *adin, size_t adinlen) + const unsigned char *adin, size_t adinlen, + int prediction_resistance) { unsigned char *entropy = NULL; size_t entropylen = 0; @@ -367,9 +490,9 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg, return 0; } - if (adin == NULL) + if (adin == NULL) { adinlen = 0; - else if (adinlen > drbg->max_adinlen) { + } else if (adinlen > drbg->max_adinlen) { RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG); return 0; } @@ -377,7 +500,9 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg, drbg->state = DRBG_ERROR; if (drbg->get_entropy != NULL) entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, - drbg->min_entropylen, drbg->max_entropylen); + drbg->min_entropylen, + drbg->max_entropylen, + prediction_resistance); if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) { RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY); @@ -388,13 +513,13 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg, goto end; drbg->state = DRBG_READY; - drbg->generate_counter = 0; + drbg->reseed_gen_counter = 1; drbg->reseed_time = time(NULL); - if (drbg->reseed_counter > 0) { + if (drbg->reseed_prop_counter > 0) { if (drbg->parent == NULL) - drbg->reseed_counter++; + drbg->reseed_prop_counter++; else - drbg->reseed_counter = drbg->parent->reseed_counter; + drbg->reseed_prop_counter = drbg->parent->reseed_prop_counter; } end: @@ -431,7 +556,7 @@ int rand_drbg_restart(RAND_DRBG *drbg, if (drbg->pool != NULL) { RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); - RAND_POOL_free(drbg->pool); + rand_pool_free(drbg->pool); drbg->pool = NULL; } @@ -449,11 +574,11 @@ int rand_drbg_restart(RAND_DRBG *drbg, } /* will be picked up by the rand_drbg_get_entropy() callback */ - drbg->pool = RAND_POOL_new(entropy, len, len); + drbg->pool = rand_pool_new(entropy, len, len); if (drbg->pool == NULL) return 0; - RAND_POOL_add(drbg->pool, buffer, len, entropy); + rand_pool_add(drbg->pool, buffer, len, entropy); } else { if (drbg->max_adinlen < len) { RANDerr(RAND_F_RAND_DRBG_RESTART, @@ -493,7 +618,7 @@ int rand_drbg_restart(RAND_DRBG *drbg, drbg->meth->reseed(drbg, adin, adinlen, NULL, 0); } else if (reseeded == 0) { /* do a full reseeding if it has not been done yet above */ - RAND_DRBG_reseed(drbg, NULL, 0); + RAND_DRBG_reseed(drbg, NULL, 0, 0); } } @@ -501,7 +626,7 @@ int rand_drbg_restart(RAND_DRBG *drbg, if (drbg->pool != NULL) { drbg->state = DRBG_ERROR; RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); - RAND_POOL_free(drbg->pool); + rand_pool_free(drbg->pool); drbg->pool = NULL; return 0; } @@ -554,7 +679,7 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, } if (drbg->reseed_interval > 0) { - if (drbg->generate_counter >= drbg->reseed_interval) + if (drbg->reseed_gen_counter > drbg->reseed_interval) reseed_required = 1; } if (drbg->reseed_time_interval > 0) { @@ -563,13 +688,13 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, || now - drbg->reseed_time >= drbg->reseed_time_interval) reseed_required = 1; } - if (drbg->reseed_counter > 0 && drbg->parent != NULL) { - if (drbg->reseed_counter != drbg->parent->reseed_counter) + if (drbg->reseed_prop_counter > 0 && drbg->parent != NULL) { + if (drbg->reseed_prop_counter != drbg->parent->reseed_prop_counter) reseed_required = 1; } if (reseed_required || prediction_resistance) { - if (!RAND_DRBG_reseed(drbg, adin, adinlen)) { + if (!RAND_DRBG_reseed(drbg, adin, adinlen, prediction_resistance)) { RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_RESEED_ERROR); return 0; } @@ -583,7 +708,7 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, return 0; } - drbg->generate_counter++; + drbg->reseed_gen_counter++; return 1; } @@ -625,40 +750,10 @@ err: /* * Set the RAND_DRBG callbacks for obtaining entropy and nonce. * - * In the following, the signature and the semantics of the - * get_entropy() and cleanup_entropy() callbacks are explained. - * - * GET_ENTROPY - * - * size_t get_entropy(RAND_DRBG *ctx, - * unsigned char **pout, - * int entropy, - * size_t min_len, size_t max_len); - * - * This is a request to allocate and fill a buffer of size - * |min_len| <= size <= |max_len| (in bytes) which contains - * at least |entropy| bits of randomness. The buffer's address is - * to be returned in |*pout| and the number of collected - * randomness bytes (which may be less than the allocated size - * of the buffer) as return value. - * - * If the callback fails to acquire at least |entropy| bits of - * randomness, it shall return a buffer length of 0. - * - * CLEANUP_ENTROPY - * - * void cleanup_entropy(RAND_DRBG *ctx, - * unsigned char *out, size_t outlen); - * - * A request to clear and free the buffer allocated by get_entropy(). - * The values |out| and |outlen| are expected to be the random buffer's - * address and length, as returned by the get_entropy() callback. + * Setting the callbacks is allowed only if the drbg has not been + * initialized yet. Otherwise, the operation will fail. * - * GET_NONCE, CLEANUP_NONCE - * - * Signature and semantics of the get_nonce() and cleanup_nonce() - * callbacks are analogous to get_entropy() and cleanup_entropy(). - * Currently, the nonce is used only for the known answer tests. + * Returns 1 on success, 0 on failure. */ int RAND_DRBG_set_callbacks(RAND_DRBG *drbg, RAND_DRBG_get_entropy_fn get_entropy, @@ -710,6 +805,38 @@ int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval) return 1; } +/* + * Set the default values for reseed (time) intervals of new DRBG instances + * + * The default values can be set independently for master DRBG instances + * (without a parent) and slave DRBG instances (with parent). + * + * Returns 1 on success, 0 on failure. + */ + +int RAND_DRBG_set_reseed_defaults( + unsigned int _master_reseed_interval, + unsigned int _slave_reseed_interval, + time_t _master_reseed_time_interval, + time_t _slave_reseed_time_interval + ) +{ + if (_master_reseed_interval > MAX_RESEED_INTERVAL + || _slave_reseed_interval > MAX_RESEED_INTERVAL) + return 0; + + if (_master_reseed_time_interval > MAX_RESEED_TIME_INTERVAL + || _slave_reseed_time_interval > MAX_RESEED_TIME_INTERVAL) + return 0; + + master_reseed_interval = _master_reseed_interval; + slave_reseed_interval = _slave_reseed_interval; + + master_reseed_time_interval = _master_reseed_time_interval; + slave_reseed_time_interval = _slave_reseed_time_interval; + + return 1; +} /* * Locks the given drbg. Locking a drbg which does not have locking @@ -798,37 +925,31 @@ void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx) * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ -static RAND_DRBG *drbg_setup(RAND_DRBG *parent) +static RAND_DRBG *drbg_setup(RAND_DRBG *parent, int drbg_type) { RAND_DRBG *drbg; - drbg = RAND_DRBG_secure_new(RAND_DRBG_NID, 0, parent); + drbg = RAND_DRBG_secure_new(rand_drbg_type[drbg_type], + rand_drbg_flags[drbg_type], parent); if (drbg == NULL) return NULL; - if (rand_drbg_enable_locking(drbg) == 0) + /* Only the master DRBG needs to have a lock */ + if (parent == NULL && 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; + drbg->reseed_prop_counter = 1; /* - * Ignore instantiation error so support just-in-time instantiation. + * Ignore instantiation error to 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); + (void)RAND_DRBG_instantiate(drbg, + (const unsigned char *) ossl_pers_string, + sizeof(ossl_pers_string) - 1); return drbg; err: @@ -849,24 +970,48 @@ DEFINE_RUN_ONCE_STATIC(do_rand_drbg_init) 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) + if (!CRYPTO_THREAD_init_local(&private_drbg, NULL)) return 0; + if (!CRYPTO_THREAD_init_local(&public_drbg, NULL)) + goto err1; + + master_drbg = drbg_setup(NULL, RAND_DRBG_TYPE_MASTER); + if (master_drbg == NULL) + goto err2; + return 1; + +err2: + CRYPTO_THREAD_cleanup_local(&public_drbg); +err1: + CRYPTO_THREAD_cleanup_local(&private_drbg); + return 0; } /* 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); + if (master_drbg != NULL) { + RAND_DRBG_free(master_drbg); + master_drbg = NULL; + + CRYPTO_THREAD_cleanup_local(&private_drbg); + CRYPTO_THREAD_cleanup_local(&public_drbg); + } +} + +void drbg_delete_thread_state(void) +{ + RAND_DRBG *drbg; + + drbg = CRYPTO_THREAD_get_local(&public_drbg); + CRYPTO_THREAD_set_local(&public_drbg, NULL); + RAND_DRBG_free(drbg); - drbg_private = drbg_public = drbg_master = NULL; + drbg = CRYPTO_THREAD_get_local(&private_drbg); + CRYPTO_THREAD_set_local(&private_drbg, NULL); + RAND_DRBG_free(drbg); } /* Implements the default OpenSSL RAND_bytes() method */ @@ -878,9 +1023,7 @@ static int drbg_bytes(unsigned char *out, int count) if (drbg == NULL) return 0; - rand_drbg_lock(drbg); ret = RAND_DRBG_bytes(drbg, out, count); - rand_drbg_unlock(drbg); return ret; } @@ -947,7 +1090,7 @@ RAND_DRBG *RAND_DRBG_get0_master(void) if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init)) return NULL; - return drbg_master; + return master_drbg; } /* @@ -956,10 +1099,19 @@ RAND_DRBG *RAND_DRBG_get0_master(void) */ RAND_DRBG *RAND_DRBG_get0_public(void) { + RAND_DRBG *drbg; + if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init)) return NULL; - return drbg_public; + drbg = CRYPTO_THREAD_get_local(&public_drbg); + if (drbg == NULL) { + if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND)) + return NULL; + drbg = drbg_setup(master_drbg, RAND_DRBG_TYPE_PUBLIC); + CRYPTO_THREAD_set_local(&public_drbg, drbg); + } + return drbg; } /* @@ -968,10 +1120,19 @@ RAND_DRBG *RAND_DRBG_get0_public(void) */ RAND_DRBG *RAND_DRBG_get0_private(void) { + RAND_DRBG *drbg; + if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init)) return NULL; - return drbg_private; + drbg = CRYPTO_THREAD_get_local(&private_drbg); + if (drbg == NULL) { + if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND)) + return NULL; + drbg = drbg_setup(master_drbg, RAND_DRBG_TYPE_PRIVATE); + CRYPTO_THREAD_set_local(&private_drbg, drbg); + } + return drbg; } RAND_METHOD rand_meth = {