openssl/crypto/rand/drbg_lib.c

1063 lines
30 KiB
C
Raw Normal View History

/*
* Copyright 2011-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#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
*
* 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
* instantiation and un-instantiate, and re-use within a new/free
* lifecycle. (No doubt this comes from the desire to support hardware
* DRBG, where allocation of resources on something like an HSM is
* a much bigger deal than just re-setting an allocated resource.)
*/
/*
* The three shared DRBG instances
*
* There are three shared DRBG instances: <master>, <public>, and <private>.
*/
/*
* The <master> 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 randomness which was added by RAND_add().
*
* The <master> 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 *master_drbg;
/*
* The <public> DRBG
*
* Used by default for generating random bytes using RAND_bytes().
*
* The <public> DRBG is thread-local, i.e., there is one instance per thread.
*/
static CRYPTO_THREAD_LOCAL public_drbg;
/*
* The <private> DRBG
*
* Used by default for generating private keys using RAND_priv_bytes()
*
* The <private> DRBG is thread-local, i.e., there is one instance per thread.
*/
static CRYPTO_THREAD_LOCAL private_drbg;
/* NIST SP 800-90A DRBG recommends the use of a personalization string. */
static const char ossl_pers_string[] = "OpenSSL NIST SP 800-90A DRBG";
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
static CRYPTO_ONCE rand_drbg_init = CRYPTO_ONCE_STATIC_INIT;
static int rand_drbg_type = RAND_DRBG_TYPE;
static unsigned int rand_drbg_flags = RAND_DRBG_FLAGS;
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;
Revert the crypto "global lock" implementation Conceptually, this is a squashed version of: Revert "Address feedback" This reverts commit 75551e07bd2339dfea06ef1d31d69929e13a4495. and Revert "Add CRYPTO_thread_glock_new" This reverts commit ed6b2c7938ec6f07b15745d4183afc276e74c6dd. But there were some intervening commits that made neither revert apply cleanly, so instead do it all as one shot. The crypto global locks were an attempt to cope with the awkward POSIX semantics for pthread_atfork(); its documentation (the "RATIONALE" section) indicates that the expected usage is to have the prefork handler lock all "global" locks, and the parent and child handlers release those locks, to ensure that forking happens with a consistent (lock) state. However, the set of functions available in the child process is limited to async-signal-safe functions, and pthread_mutex_unlock() is not on the list of async-signal-safe functions! The only synchronization primitives that are async-signal-safe are the semaphore primitives, which are not really appropriate for general-purpose usage. However, the state consistency problem that the global locks were attempting to solve is not actually a serious problem, particularly for OpenSSL. That is, we can consider four cases of forking application that might use OpenSSL: (1) Single-threaded, does not call into OpenSSL in the child (e.g., the child calls exec() immediately) For this class of process, no locking is needed at all, since there is only ever a single thread of execution and the only reentrancy is due to signal handlers (which are themselves limited to async-signal-safe operation and should not be doing much work at all). (2) Single-threaded, calls into OpenSSL after fork() The application must ensure that it does not fork() with an unexpected lock held (that is, one that would get unlocked in the parent but accidentally remain locked in the child and cause deadlock). Since OpenSSL does not expose any of its internal locks to the application and the application is single-threaded, the OpenSSL internal locks will be unlocked for the fork(), and the state will be consistent. (OpenSSL will need to reseed its PRNG in the child, but that is an orthogonal issue.) If the application makes use of locks from libcrypto, proper handling for those locks is the responsibility of the application, as for any other locking primitive that is available for application programming. (3) Multi-threaded, does not call into OpenSSL after fork() As for (1), the OpenSSL state is only relevant in the parent, so no particular fork()-related handling is needed. The internal locks are relevant, but there is no interaction with the child to consider. (4) Multi-threaded, calls into OpenSSL after fork() This is the case where the pthread_atfork() hooks to ensure that all global locks are in a known state across fork() would come into play, per the above discussion. However, these "calls into OpenSSL after fork()" are still subject to the restriction to async-signal-safe functions. Since OpenSSL uses all sorts of locking and libc functions that are not on the list of safe functions (e.g., malloc()), this case is not currently usable and is unlikely to ever be usable, independently of the locking situation. So, there is no need to go through contortions to attempt to support this case in the one small area of locking interaction with fork(). In light of the above analysis (thanks @davidben and @achernya), go back to the simpler implementation that does not need to distinguish "library-global" locks or to have complicated atfork handling for locks. Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com> (Merged from https://github.com/openssl/openssl/pull/5089)
2018-01-16 15:49:54 +00:00
static RAND_DRBG *drbg_setup(RAND_DRBG *parent);
static RAND_DRBG *rand_drbg_new(int secure,
int type,
unsigned int flags,
RAND_DRBG *parent);
/*
* 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 type, unsigned int flags)
{
int ret = 1;
if (type == 0 && flags == 0) {
type = rand_drbg_type;
flags = rand_drbg_flags;
}
drbg->state = DRBG_UNINITIALISED;
drbg->flags = flags;
drbg->type = type;
switch (type) {
default:
RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE);
return 0;
case 0:
/* Uninitialized; that's okay. */
return 1;
case NID_aes_128_ctr:
case NID_aes_192_ctr:
case NID_aes_256_ctr:
ret = drbg_ctr_init(drbg);
break;
}
if (ret == 0)
RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_ERROR_INITIALISING_DRBG);
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 ret = 1;
switch (type) {
default:
RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_TYPE);
return 0;
case NID_aes_128_ctr:
case NID_aes_192_ctr:
case NID_aes_256_ctr:
break;
}
if ((flags & ~RAND_DRBG_USED_FLAGS) != 0) {
RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_FLAGS);
return 0;
}
rand_drbg_type = type;
rand_drbg_flags = flags;
return ret;
}
/*
* 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.
* The |parent|, if not NULL, will be used as random source for reseeding.
*
* Returns a pointer to the new DRBG instance on success, NULL on failure.
*/
static RAND_DRBG *rand_drbg_new(int secure,
int type,
unsigned int flags,
RAND_DRBG *parent)
{
RAND_DRBG *drbg = secure ?
OPENSSL_secure_zalloc(sizeof(*drbg)) : OPENSSL_zalloc(sizeof(*drbg));
if (drbg == NULL) {
RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
drbg->secure = secure && CRYPTO_secure_allocated(drbg);
drbg->fork_count = rand_fork_count;
drbg->parent = parent;
if (parent == NULL) {
DRBG: implement a get_nonce() callback Fixes #5849 In pull request #5503 a fallback was added which adds a random nonce of security_strength/2 bits if no nonce callback is provided. This change raised the entropy requirements form 256 to 384 bit, which can cause problems on some platforms (e.g. VMS, see issue #5849). The requirements for the nonce are given in section 8.6.7 of NIST SP 800-90Ar1: A nonce may be required in the construction of a seed during instantiation in order to provide a security cushion to block certain attacks. The nonce shall be either: a) A value with at least (security_strength/2) bits of entropy, or b) A value that is expected to repeat no more often than a (security_strength/2)-bit random string would be expected to repeat. Each nonce shall be unique to the cryptographic module in which instantiation is performed, but need not be secret. When used, the nonce shall be considered to be a critical security parameter. This commit implements a nonce of type b) in order to lower the entropy requirements during instantiation back to 256 bits. The formulation "shall be unique to the cryptographic module" above implies that the nonce needs to be unique among (with high probability) among all DRBG instances in "space" and "time". We try to achieve this goal by creating a nonce of the following form nonce = app-specific-data || high-resolution-utc-timestamp || counter Where || denotes concatenation. The application specific data can be something like the process or group id of the application. A utc timestamp is used because it increases monotonically, provided the system time is synchronized. This approach may not be perfect yet for a FIPS evaluation, but it should be good enough for the moment. This commit also harmonizes the implementation of the get_nonce() and the get_additional_data() callbacks and moves the platform specific parts from rand_lib.c into rand_unix.c, rand_win.c, and rand_vms.c. Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5920)
2018-04-10 08:22:52 +00:00
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: implement a get_nonce() callback Fixes #5849 In pull request #5503 a fallback was added which adds a random nonce of security_strength/2 bits if no nonce callback is provided. This change raised the entropy requirements form 256 to 384 bit, which can cause problems on some platforms (e.g. VMS, see issue #5849). The requirements for the nonce are given in section 8.6.7 of NIST SP 800-90Ar1: A nonce may be required in the construction of a seed during instantiation in order to provide a security cushion to block certain attacks. The nonce shall be either: a) A value with at least (security_strength/2) bits of entropy, or b) A value that is expected to repeat no more often than a (security_strength/2)-bit random string would be expected to repeat. Each nonce shall be unique to the cryptographic module in which instantiation is performed, but need not be secret. When used, the nonce shall be considered to be a critical security parameter. This commit implements a nonce of type b) in order to lower the entropy requirements during instantiation back to 256 bits. The formulation "shall be unique to the cryptographic module" above implies that the nonce needs to be unique among (with high probability) among all DRBG instances in "space" and "time". We try to achieve this goal by creating a nonce of the following form nonce = app-specific-data || high-resolution-utc-timestamp || counter Where || denotes concatenation. The application specific data can be something like the process or group id of the application. A utc timestamp is used because it increases monotonically, provided the system time is synchronized. This approach may not be perfect yet for a FIPS evaluation, but it should be good enough for the moment. This commit also harmonizes the implementation of the get_nonce() and the get_additional_data() callbacks and moves the platform specific parts from rand_lib.c into rand_unix.c, rand_win.c, and rand_vms.c. Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5920)
2018-04-10 08:22:52 +00:00
drbg->get_entropy = rand_drbg_get_entropy;
drbg->cleanup_entropy = rand_drbg_cleanup_entropy;
/*
* Do not provide nonce callbacks, the child DRBGs will
* obtain their nonce using random bits from the parent.
*/
drbg->reseed_interval = slave_reseed_interval;
drbg->reseed_time_interval = slave_reseed_time_interval;
}
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:
if (drbg->secure)
OPENSSL_secure_free(drbg);
else
OPENSSL_free(drbg);
return NULL;
}
RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent)
{
return rand_drbg_new(0, type, flags, parent);
}
RAND_DRBG *RAND_DRBG_secure_new(int type, unsigned int flags, RAND_DRBG *parent)
{
return rand_drbg_new(1, type, flags, parent);
}
/*
* Uninstantiate |drbg| and free all memory.
*/
void RAND_DRBG_free(RAND_DRBG *drbg)
{
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (drbg == NULL)
return;
if (drbg->meth != NULL)
drbg->meth->uninstantiate(drbg);
CRYPTO_THREAD_lock_free(drbg->lock);
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data);
if (drbg->secure)
OPENSSL_secure_clear_free(drbg, sizeof(*drbg));
else
OPENSSL_clear_free(drbg, sizeof(*drbg));
}
/*
* Instantiate |drbg|, after it has been initialized. Use |pers| and
* |perslen| as prediction-resistance input.
2017-10-11 17:25:26 +00:00
*
* Requires that drbg->lock is already locked for write, if non-null.
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_instantiate(RAND_DRBG *drbg,
const unsigned char *pers, size_t perslen)
{
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,
RAND_R_PERSONALISATION_STRING_TOO_LONG);
goto end;
}
if (drbg->meth == NULL)
{
RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED);
goto end;
}
if (drbg->state != DRBG_UNINITIALISED) {
RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE
: RAND_R_ALREADY_INSTANTIATED);
goto end;
}
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, 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->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);
goto end;
}
}
if (!drbg->meth->instantiate(drbg, entropy, entropylen,
nonce, noncelen, pers, perslen)) {
RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG);
goto end;
}
drbg->state = DRBG_READY;
drbg->generate_counter = 0;
drbg->reseed_time = time(NULL);
if (drbg->reseed_counter > 0) {
if (drbg->parent == NULL)
drbg->reseed_counter++;
else
drbg->reseed_counter = drbg->parent->reseed_counter;
}
end:
if (entropy != NULL && drbg->cleanup_entropy != NULL)
drbg->cleanup_entropy(drbg, entropy, entropylen);
if (nonce != NULL && drbg->cleanup_nonce!= NULL )
drbg->cleanup_nonce(drbg, nonce, noncelen);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (drbg->pool != NULL) {
if (drbg->state == DRBG_READY) {
RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED);
drbg->state = DRBG_ERROR;
}
rand_pool_free(drbg->pool);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
drbg->pool = NULL;
}
if (drbg->state == DRBG_READY)
return 1;
return 0;
}
/*
* Uninstantiate |drbg|. Must be instantiated before it can be used.
2017-10-11 17:25:26 +00:00
*
* Requires that drbg->lock is already locked for write, if non-null.
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_uninstantiate(RAND_DRBG *drbg)
{
if (drbg->meth == NULL)
{
RANDerr(RAND_F_RAND_DRBG_UNINSTANTIATE,
RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED);
return 0;
}
/* Clear the entire drbg->ctr struct, then reset some important
* members of the drbg->ctr struct (e.g. keysize, df_ks) to their
* initial values.
*/
drbg->meth->uninstantiate(drbg);
return RAND_DRBG_set(drbg, drbg->type, drbg->flags);
}
/*
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
* Reseed |drbg|, mixing in the specified data
2017-10-11 17:25:26 +00:00
*
* Requires that drbg->lock is already locked for write, if non-null.
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_reseed(RAND_DRBG *drbg,
const unsigned char *adin, size_t adinlen,
int prediction_resistance)
{
unsigned char *entropy = NULL;
size_t entropylen = 0;
if (drbg->state == DRBG_ERROR) {
RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_IN_ERROR_STATE);
return 0;
}
if (drbg->state == DRBG_UNINITIALISED) {
RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_NOT_INSTANTIATED);
return 0;
}
if (adin == NULL)
adinlen = 0;
else if (adinlen > drbg->max_adinlen) {
RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG);
return 0;
}
drbg->state = DRBG_ERROR;
if (drbg->get_entropy != NULL)
entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
drbg->min_entropylen,
drbg->max_entropylen,
prediction_resistance);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (entropylen < drbg->min_entropylen
|| entropylen > drbg->max_entropylen) {
RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY);
goto end;
}
if (!drbg->meth->reseed(drbg, entropy, entropylen, adin, adinlen))
goto end;
drbg->state = DRBG_READY;
drbg->generate_counter = 0;
drbg->reseed_time = time(NULL);
if (drbg->reseed_counter > 0) {
if (drbg->parent == NULL)
drbg->reseed_counter++;
else
drbg->reseed_counter = drbg->parent->reseed_counter;
}
end:
if (entropy != NULL && drbg->cleanup_entropy != NULL)
drbg->cleanup_entropy(drbg, entropy, entropylen);
if (drbg->state == DRBG_READY)
return 1;
return 0;
}
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
/*
* Restart |drbg|, using the specified entropy or additional input
*
* Tries its best to get the drbg instantiated by all means,
* regardless of its current state.
*
* Optionally, a |buffer| of |len| random bytes can be passed,
* which is assumed to contain at least |entropy| bits of entropy.
*
* If |entropy| > 0, the buffer content is used as entropy input.
*
* If |entropy| == 0, the buffer content is used as additional input
*
* Returns 1 on success, 0 on failure.
*
* This function is used internally only.
*/
int rand_drbg_restart(RAND_DRBG *drbg,
const unsigned char *buffer, size_t len, size_t entropy)
{
int reseeded = 0;
const unsigned char *adin = NULL;
size_t adinlen = 0;
if (drbg->pool != NULL) {
RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR);
rand_pool_free(drbg->pool);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
drbg->pool = NULL;
}
if (buffer != NULL) {
if (entropy > 0) {
if (drbg->max_entropylen < len) {
RANDerr(RAND_F_RAND_DRBG_RESTART,
RAND_R_ENTROPY_INPUT_TOO_LONG);
return 0;
}
if (entropy > 8 * len) {
RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE);
return 0;
}
/* will be picked up by the rand_drbg_get_entropy() callback */
drbg->pool = rand_pool_new(entropy, len, len);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (drbg->pool == NULL)
return 0;
rand_pool_add(drbg->pool, buffer, len, entropy);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
} else {
if (drbg->max_adinlen < len) {
RANDerr(RAND_F_RAND_DRBG_RESTART,
RAND_R_ADDITIONAL_INPUT_TOO_LONG);
return 0;
}
adin = buffer;
adinlen = len;
}
}
/* repair error state */
if (drbg->state == DRBG_ERROR)
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
RAND_DRBG_uninstantiate(drbg);
/* repair uninitialized state */
if (drbg->state == DRBG_UNINITIALISED) {
/* reinstantiate drbg */
RAND_DRBG_instantiate(drbg,
(const unsigned char *) ossl_pers_string,
sizeof(ossl_pers_string) - 1);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
/* already reseeded. prevent second reseeding below */
reseeded = (drbg->state == DRBG_READY);
}
/* refresh current state if entropy or additional input has been provided */
if (drbg->state == DRBG_READY) {
if (adin != NULL) {
/*
* mix in additional input without reseeding
*
* Similar to RAND_DRBG_reseed(), but the provided additional
* data |adin| is mixed into the current state without pulling
* entropy from the trusted entropy source using get_entropy().
* This is not a reseeding in the strict sense of NIST SP 800-90A.
*/
drbg->meth->reseed(drbg, adin, adinlen, NULL, 0);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
} else if (reseeded == 0) {
/* do a full reseeding if it has not been done yet above */
RAND_DRBG_reseed(drbg, NULL, 0, 0);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
}
}
/* check whether a given entropy pool was cleared properly during reseed */
if (drbg->pool != NULL) {
drbg->state = DRBG_ERROR;
RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR);
rand_pool_free(drbg->pool);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
drbg->pool = NULL;
return 0;
}
return drbg->state == DRBG_READY;
}
/*
* Generate |outlen| bytes into the buffer at |out|. Reseed if we need
* to or if |prediction_resistance| is set. Additional input can be
* sent in |adin| and |adinlen|.
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
*
2017-10-11 17:25:26 +00:00
* Requires that drbg->lock is already locked for write, if non-null.
*
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
* Returns 1 on success, 0 on failure.
*
*/
int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
int prediction_resistance,
const unsigned char *adin, size_t adinlen)
{
int reseed_required = 0;
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (drbg->state != DRBG_READY) {
/* try to recover from previous errors */
rand_drbg_restart(drbg, NULL, 0, 0);
if (drbg->state == DRBG_ERROR) {
RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE);
return 0;
}
if (drbg->state == DRBG_UNINITIALISED) {
RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED);
return 0;
}
}
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (outlen > drbg->max_request) {
RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG);
return 0;
}
if (adinlen > drbg->max_adinlen) {
RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG);
return 0;
}
if (drbg->fork_count != rand_fork_count) {
drbg->fork_count = rand_fork_count;
reseed_required = 1;
}
if (drbg->reseed_interval > 0) {
if (drbg->generate_counter >= drbg->reseed_interval)
reseed_required = 1;
}
if (drbg->reseed_time_interval > 0) {
time_t now = time(NULL);
if (now < drbg->reseed_time
|| 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)
reseed_required = 1;
}
if (reseed_required || prediction_resistance) {
if (!RAND_DRBG_reseed(drbg, adin, adinlen, prediction_resistance)) {
RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_RESEED_ERROR);
return 0;
}
adin = NULL;
adinlen = 0;
}
if (!drbg->meth->generate(drbg, out, outlen, adin, adinlen)) {
drbg->state = DRBG_ERROR;
RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_GENERATE_ERROR);
return 0;
}
drbg->generate_counter++;
return 1;
}
/*
* Generates |outlen| random bytes and stores them in |out|. It will
* using the given |drbg| to generate the bytes.
*
* Requires that drbg->lock is already locked for write, if non-null.
*
* Returns 1 on success 0 on failure.
*/
int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen)
{
unsigned char *additional = NULL;
size_t additional_len;
size_t chunk;
size_t ret;
additional_len = rand_drbg_get_additional_data(&additional, drbg->max_adinlen);
for ( ; outlen > 0; outlen -= chunk, out += chunk) {
chunk = outlen;
if (chunk > drbg->max_request)
chunk = drbg->max_request;
ret = RAND_DRBG_generate(drbg, out, chunk, 0, additional, additional_len);
if (!ret)
goto err;
}
ret = 1;
err:
if (additional_len != 0)
OPENSSL_secure_clear_free(additional, additional_len);
return ret;
}
/*
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
* Set the RAND_DRBG callbacks for obtaining entropy and nonce.
*
* Setting the callbacks is allowed only if the drbg has not been
* initialized yet. Otherwise, the operation will fail.
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_set_callbacks(RAND_DRBG *drbg,
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
RAND_DRBG_get_entropy_fn get_entropy,
RAND_DRBG_cleanup_entropy_fn cleanup_entropy,
RAND_DRBG_get_nonce_fn get_nonce,
RAND_DRBG_cleanup_nonce_fn cleanup_nonce)
{
if (drbg->state != DRBG_UNINITIALISED)
return 0;
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
drbg->get_entropy = get_entropy;
drbg->cleanup_entropy = cleanup_entropy;
drbg->get_nonce = get_nonce;
drbg->cleanup_nonce = cleanup_nonce;
return 1;
}
/*
* Set the reseed interval.
*
* The drbg will reseed automatically whenever the number of generate
* requests exceeds the given reseed interval. If the reseed interval
* is 0, then this feature is disabled.
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval)
{
if (interval > MAX_RESEED_INTERVAL)
return 0;
drbg->reseed_interval = interval;
return 1;
}
/*
* Set the reseed time interval.
*
* The drbg will reseed automatically whenever the time elapsed since
* the last reseeding exceeds the given reseed time interval. For safety,
* a reseeding will also occur if the clock has been reset to a smaller
* value.
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval)
{
if (interval > MAX_RESEED_TIME_INTERVAL)
return 0;
drbg->reseed_time_interval = 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
* enabled is considered a successful no-op.
*
* Returns 1 on success, 0 on failure.
*/
int rand_drbg_lock(RAND_DRBG *drbg)
{
if (drbg->lock != NULL)
return CRYPTO_THREAD_write_lock(drbg->lock);
return 1;
}
/*
* Unlocks the given drbg. Unlocking a drbg which does not have locking
* enabled is considered a successful no-op.
*
* Returns 1 on success, 0 on failure.
*/
int rand_drbg_unlock(RAND_DRBG *drbg)
{
if (drbg->lock != NULL)
return CRYPTO_THREAD_unlock(drbg->lock);
return 1;
}
/*
* Enables locking for the given drbg
*
* Locking can only be enabled if the random generator
* is in the uninitialized state.
*
* Returns 1 on success, 0 on failure.
*/
int rand_drbg_enable_locking(RAND_DRBG *drbg)
{
if (drbg->state != DRBG_UNINITIALISED) {
RANDerr(RAND_F_RAND_DRBG_ENABLE_LOCKING,
RAND_R_DRBG_ALREADY_INITIALIZED);
return 0;
}
if (drbg->lock == NULL) {
if (drbg->parent != NULL && drbg->parent->lock == NULL) {
RANDerr(RAND_F_RAND_DRBG_ENABLE_LOCKING,
RAND_R_PARENT_LOCKING_NOT_ENABLED);
return 0;
}
drbg->lock = CRYPTO_THREAD_lock_new();
if (drbg->lock == NULL) {
RANDerr(RAND_F_RAND_DRBG_ENABLE_LOCKING,
RAND_R_FAILED_TO_CREATE_LOCK);
return 0;
}
}
return 1;
}
/*
* Get and set the EXDATA
*/
int RAND_DRBG_set_ex_data(RAND_DRBG *drbg, int idx, void *arg)
{
return CRYPTO_set_ex_data(&drbg->ex_data, idx, arg);
}
void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx)
{
return CRYPTO_get_ex_data(&drbg->ex_data, idx);
}
/*
* The following functions provide a RAND_METHOD that works on the
* global DRBG. They lock.
*/
/*
* Allocates a new global DRBG on the secure heap (if enabled) and
* initializes it with default settings.
*
* Returns a pointer to the new DRBG instance on success, NULL on failure.
*/
Revert the crypto "global lock" implementation Conceptually, this is a squashed version of: Revert "Address feedback" This reverts commit 75551e07bd2339dfea06ef1d31d69929e13a4495. and Revert "Add CRYPTO_thread_glock_new" This reverts commit ed6b2c7938ec6f07b15745d4183afc276e74c6dd. But there were some intervening commits that made neither revert apply cleanly, so instead do it all as one shot. The crypto global locks were an attempt to cope with the awkward POSIX semantics for pthread_atfork(); its documentation (the "RATIONALE" section) indicates that the expected usage is to have the prefork handler lock all "global" locks, and the parent and child handlers release those locks, to ensure that forking happens with a consistent (lock) state. However, the set of functions available in the child process is limited to async-signal-safe functions, and pthread_mutex_unlock() is not on the list of async-signal-safe functions! The only synchronization primitives that are async-signal-safe are the semaphore primitives, which are not really appropriate for general-purpose usage. However, the state consistency problem that the global locks were attempting to solve is not actually a serious problem, particularly for OpenSSL. That is, we can consider four cases of forking application that might use OpenSSL: (1) Single-threaded, does not call into OpenSSL in the child (e.g., the child calls exec() immediately) For this class of process, no locking is needed at all, since there is only ever a single thread of execution and the only reentrancy is due to signal handlers (which are themselves limited to async-signal-safe operation and should not be doing much work at all). (2) Single-threaded, calls into OpenSSL after fork() The application must ensure that it does not fork() with an unexpected lock held (that is, one that would get unlocked in the parent but accidentally remain locked in the child and cause deadlock). Since OpenSSL does not expose any of its internal locks to the application and the application is single-threaded, the OpenSSL internal locks will be unlocked for the fork(), and the state will be consistent. (OpenSSL will need to reseed its PRNG in the child, but that is an orthogonal issue.) If the application makes use of locks from libcrypto, proper handling for those locks is the responsibility of the application, as for any other locking primitive that is available for application programming. (3) Multi-threaded, does not call into OpenSSL after fork() As for (1), the OpenSSL state is only relevant in the parent, so no particular fork()-related handling is needed. The internal locks are relevant, but there is no interaction with the child to consider. (4) Multi-threaded, calls into OpenSSL after fork() This is the case where the pthread_atfork() hooks to ensure that all global locks are in a known state across fork() would come into play, per the above discussion. However, these "calls into OpenSSL after fork()" are still subject to the restriction to async-signal-safe functions. Since OpenSSL uses all sorts of locking and libc functions that are not on the list of safe functions (e.g., malloc()), this case is not currently usable and is unlikely to ever be usable, independently of the locking situation. So, there is no need to go through contortions to attempt to support this case in the one small area of locking interaction with fork(). In light of the above analysis (thanks @davidben and @achernya), go back to the simpler implementation that does not need to distinguish "library-global" locks or to have complicated atfork handling for locks. Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com> (Merged from https://github.com/openssl/openssl/pull/5089)
2018-01-16 15:49:54 +00:00
static RAND_DRBG *drbg_setup(RAND_DRBG *parent)
{
RAND_DRBG *drbg;
drbg = RAND_DRBG_secure_new(rand_drbg_type, rand_drbg_flags, parent);
if (drbg == NULL)
return NULL;
/* Only the master DRBG needs to have a lock */
if (parent == NULL && rand_drbg_enable_locking(drbg) == 0)
goto err;
/* enable seed propagation */
drbg->reseed_counter = 1;
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
/*
* Ignore instantiation error so 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);
return drbg;
err:
RAND_DRBG_free(drbg);
return NULL;
}
/*
* Initialize the global DRBGs on first use.
* Returns 1 on success, 0 on failure.
*/
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
DEFINE_RUN_ONCE_STATIC(do_rand_drbg_init)
{
int ret = 1;
/*
* ensure that libcrypto is initialized, otherwise the
* DRBG locks are not cleaned up properly
*/
if (!OPENSSL_init_crypto(0, NULL))
return 0;
ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND);
master_drbg = drbg_setup(NULL);
ret &= CRYPTO_THREAD_init_local(&private_drbg, NULL);
ret &= CRYPTO_THREAD_init_local(&public_drbg, NULL);
if (master_drbg == NULL || ret == 0)
return 0;
return 1;
}
/* Clean up the global DRBGs before exit */
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
void rand_drbg_cleanup_int(void)
{
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()
{
RAND_DRBG *drbg;
drbg = CRYPTO_THREAD_get_local(&public_drbg);
RAND_DRBG_free(drbg);
drbg = CRYPTO_THREAD_get_local(&private_drbg);
RAND_DRBG_free(drbg);
}
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
/* Implements the default OpenSSL RAND_bytes() method */
static int drbg_bytes(unsigned char *out, int count)
{
int ret;
RAND_DRBG *drbg = RAND_DRBG_get0_public();
if (drbg == NULL)
return 0;
ret = RAND_DRBG_bytes(drbg, out, count);
return ret;
}
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
/* Implements the default OpenSSL RAND_add() method */
static int drbg_add(const void *buf, int num, double randomness)
{
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
int ret = 0;
RAND_DRBG *drbg = RAND_DRBG_get0_master();
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (drbg == NULL)
return 0;
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (num < 0 || randomness < 0.0)
return 0;
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (randomness > (double)drbg->max_entropylen) {
/*
* The purpose of this check is to bound |randomness| by a
* relatively small value in order to prevent an integer
* overflow when multiplying by 8 in the rand_drbg_restart()
* call below.
*/
return 0;
}
rand_drbg_lock(drbg);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
ret = rand_drbg_restart(drbg, buf,
(size_t)(unsigned int)num,
(size_t)(8*randomness));
rand_drbg_unlock(drbg);
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
return ret;
}
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
/* Implements the default OpenSSL RAND_seed() method */
static int drbg_seed(const void *buf, int num)
{
return drbg_add(buf, num, num);
}
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
/* Implements the default OpenSSL RAND_status() method */
static int drbg_status(void)
{
int ret;
RAND_DRBG *drbg = RAND_DRBG_get0_master();
if (drbg == NULL)
return 0;
rand_drbg_lock(drbg);
ret = drbg->state == DRBG_READY ? 1 : 0;
rand_drbg_unlock(drbg);
return ret;
}
/*
* Get the master DRBG.
* Returns pointer to the DRBG on success, NULL on failure.
*
*/
RAND_DRBG *RAND_DRBG_get0_master(void)
{
if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))
return NULL;
return master_drbg;
}
/*
* Get the public DRBG.
* Returns pointer to the DRBG on success, NULL on failure.
*/
RAND_DRBG *RAND_DRBG_get0_public(void)
{
RAND_DRBG *drbg;
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))
return NULL;
drbg = CRYPTO_THREAD_get_local(&public_drbg);
if (drbg == NULL) {
ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND);
drbg = drbg_setup(master_drbg);
CRYPTO_THREAD_set_local(&public_drbg, drbg);
}
return drbg;
}
/*
* Get the private DRBG.
* Returns pointer to the DRBG on success, NULL on failure.
*/
RAND_DRBG *RAND_DRBG_get0_private(void)
{
RAND_DRBG *drbg;
Fix reseeding issues of the public RAND_DRBG Reseeding is handled very differently by the classic RAND_METHOD API and the new RAND_DRBG api. These differences led to some problems when the new RAND_DRBG was made the default OpenSSL RNG. In particular, RAND_add() did not work as expected anymore. These issues are discussed on the thread '[openssl-dev] Plea for a new public OpenSSL RNG API' and in Pull Request #4328. This commit fixes the mentioned issues, introducing the following changes: - Replace the fixed size RAND_BYTES_BUFFER by a new RAND_POOL API which facilitates collecting entropy by the get_entropy() callback. - Don't use RAND_poll()/RAND_add() for collecting entropy from the get_entropy() callback anymore. Instead, replace RAND_poll() by RAND_POOL_acquire_entropy(). - Add a new function rand_drbg_restart() which tries to get the DRBG in an instantiated state by all means, regardless of the current state (uninstantiated, error, ...) the DRBG is in. If the caller provides entropy or additional input, it will be used for reseeding. - Restore the original documented behaviour of RAND_add() and RAND_poll() (namely to reseed the DRBG immediately) by a new implementation based on rand_drbg_restart(). - Add automatic error recovery from temporary failures of the entropy source to RAND_DRBG_generate() using the rand_drbg_restart() function. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Kurt Roeckx <kurt@roeckx.be> Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4328)
2017-08-31 21:16:22 +00:00
if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))
return NULL;
drbg = CRYPTO_THREAD_get_local(&private_drbg);
if (drbg == NULL) {
ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND);
drbg = drbg_setup(master_drbg);
CRYPTO_THREAD_set_local(&private_drbg, drbg);
}
return drbg;
}
RAND_METHOD rand_meth = {
drbg_seed,
drbg_bytes,
NULL,
drbg_add,
drbg_bytes,
drbg_status
};
RAND_METHOD *RAND_OpenSSL(void)
{
return &rand_meth;
}