openssl/crypto/rand/drbg_lib.c

1017 lines
29 KiB
C
Raw Normal View History

/*
* Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (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
*/
/*
* RAND_DRBG_set is deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/core_names.h>
#include "rand_local.h"
#include "internal/thread_once.h"
#include "crypto/rand.h"
#include "crypto/cryptlib.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.)
*/
typedef struct drbg_global_st {
/*
* The three shared DRBG instances
*
* There are three shared DRBG instances: <primary>, <public>, and
* <private>. The <public> and <private> DRBGs are secondary ones.
* These are used for non-secret (e.g. nonces) and secret
* (e.g. private keys) data respectively.
*/
CRYPTO_RWLOCK *lock;
/*
* The <primary> 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 <primary> 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.
*/
RAND_DRBG *primary_drbg;
/*
* The <public> DRBG
*
* Used by default for generating random bytes using RAND_bytes().
*
* The <public> secondary DRBG is thread-local, i.e., there is one instance
* per thread.
*/
CRYPTO_THREAD_LOCAL public_drbg;
/*
* The <private> DRBG
*
* Used by default for generating private keys using RAND_priv_bytes()
*
* The <private> secondary DRBG is thread-local, i.e., there is one
* instance per thread.
*/
CRYPTO_THREAD_LOCAL private_drbg;
} DRBG_GLOBAL;
#define RAND_DRBG_TYPE_FLAGS ( \
RAND_DRBG_FLAG_PRIMARY | RAND_DRBG_FLAG_PUBLIC | RAND_DRBG_FLAG_PRIVATE )
#define RAND_DRBG_TYPE_PRIMARY 0
#define RAND_DRBG_TYPE_PUBLIC 1
#define RAND_DRBG_TYPE_PRIVATE 2
/* Defaults */
static int rand_drbg_type[3] = {
RAND_DRBG_TYPE, /* Primary */
RAND_DRBG_TYPE, /* Public */
RAND_DRBG_TYPE /* Private */
};
static unsigned int rand_drbg_flags[3] = {
RAND_DRBG_FLAGS | RAND_DRBG_FLAG_PRIMARY, /* Primary */
RAND_DRBG_FLAGS | RAND_DRBG_FLAG_PUBLIC, /* Public */
RAND_DRBG_FLAGS | RAND_DRBG_FLAG_PRIVATE /* Private */
};
static unsigned int primary_reseed_interval = PRIMARY_RESEED_INTERVAL;
static unsigned int secondary_reseed_interval = SECONDARY_RESEED_INTERVAL;
static time_t primary_reseed_time_interval = PRIMARY_RESEED_TIME_INTERVAL;
static time_t secondary_reseed_time_interval = SECONDARY_RESEED_TIME_INTERVAL;
/* A logical OR of all used DRBG flag bits (currently there is only one) */
static const unsigned int rand_drbg_used_flags =
RAND_DRBG_FLAG_CTR_NO_DF | RAND_DRBG_FLAG_HMAC | RAND_DRBG_TYPE_FLAGS;
static RAND_DRBG *drbg_setup(OPENSSL_CTX *ctx, RAND_DRBG *parent,
int drbg_type);
static int get_drbg_params(int type, unsigned int flags, const char **name,
OSSL_PARAM params[3])
{
OSSL_PARAM *p = params;
switch (type) {
case 0:
return 1;
default:
return 0;
#define CTR(v) \
*name = "CTR-DRBG"; \
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, v, 0)
case NID_aes_128_ctr:
CTR(SN_aes_128_ctr);
break;
case NID_aes_192_ctr:
CTR(SN_aes_192_ctr);
break;
case NID_aes_256_ctr:
CTR(SN_aes_256_ctr);
break;
#define DGST(v) \
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, v, 0); \
if ((flags & RAND_DRBG_FLAG_HMAC) == 0) { \
*name = "HASH-DRBG"; \
} else { \
*name = "HMAC-DRBG"; \
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_MAC, \
SN_hmac, 0); \
}
case NID_sha1:
DGST(SN_sha1);
break;
case NID_sha224:
DGST(SN_sha224);
break;
case NID_sha256:
DGST(SN_sha256);
break;
case NID_sha384:
DGST(SN_sha384);
break;
case NID_sha512:
DGST(SN_sha512);
break;
case NID_sha512_224:
DGST(SN_sha512_224);
break;
case NID_sha512_256:
DGST(SN_sha512_256);
break;
case NID_sha3_224:
DGST(SN_sha3_224);
break;
case NID_sha3_256:
DGST(SN_sha3_256);
break;
case NID_sha3_384:
DGST(SN_sha3_384);
break;
case NID_sha3_512:
DGST(SN_sha3_512);
}
*p = OSSL_PARAM_construct_end();
return 1;
}
/*
* Initialize the OPENSSL_CTX global DRBGs on first use.
* Returns the allocated global data on success or NULL on failure.
*/
static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
{
DRBG_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));
if (dgbl == NULL)
return NULL;
#ifndef FIPS_MODULE
/*
* We need to ensure that base libcrypto thread handling has been
* initialised.
*/
OPENSSL_init_crypto(0, NULL);
#endif
dgbl->lock = CRYPTO_THREAD_lock_new();
if (dgbl->lock == NULL)
goto err0;
if (!CRYPTO_THREAD_init_local(&dgbl->private_drbg, NULL))
goto err1;
if (!CRYPTO_THREAD_init_local(&dgbl->public_drbg, NULL))
goto err2;
return dgbl;
err2:
CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
err1:
CRYPTO_THREAD_lock_free(dgbl->lock);
err0:
OPENSSL_free(dgbl);
return NULL;
}
static void drbg_ossl_ctx_free(void *vdgbl)
{
DRBG_GLOBAL *dgbl = vdgbl;
if (dgbl == NULL)
return;
CRYPTO_THREAD_lock_free(dgbl->lock);
RAND_DRBG_free(dgbl->primary_drbg);
CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
OPENSSL_free(dgbl);
}
static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
drbg_ossl_ctx_new,
drbg_ossl_ctx_free,
};
static DRBG_GLOBAL *drbg_get_global(OPENSSL_CTX *libctx)
{
return openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_INDEX,
&drbg_ossl_ctx_method);
}
/*
* Set the |drbg|'s callback data pointer for the entropy and nonce callbacks
*
* The ownership of the context data remains with the caller,
* i.e., it is the caller's responsibility to keep it available as long
* as it is need by the callbacks and free it after use.
*
* Setting the callback data is allowed only if the drbg has not been
* initialized yet. Otherwise, the operation will fail.
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_set_callback_data(RAND_DRBG *drbg, void *data)
{
if (EVP_RAND_state(drbg->rand) != EVP_RAND_STATE_UNINITIALISED
|| drbg->parent != NULL)
return 0;
drbg->callback_data = data;
return 1;
}
/* Retrieve the callback data pointer */
void *RAND_DRBG_get_callback_data(RAND_DRBG *drbg)
{
return drbg->callback_data;
}
/*
* 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)
{
OSSL_PARAM params[6], *p = params;
unsigned int reseed_interval;
time_t reseed_time_interval;
const char *name = NULL;
EVP_RAND *rand;
EVP_RAND_CTX *pctx;
int use_df;
RAND_DRBG_get_entropy_fn get_entropy = drbg->get_entropy;
RAND_DRBG_cleanup_entropy_fn cleanup_entropy = drbg->cleanup_entropy;
RAND_DRBG_get_nonce_fn get_nonce = drbg->get_nonce;
RAND_DRBG_cleanup_nonce_fn cleanup_nonce = drbg->cleanup_nonce;
if (type == 0 && flags == 0) {
type = rand_drbg_type[RAND_DRBG_TYPE_PRIMARY];
flags = rand_drbg_flags[RAND_DRBG_TYPE_PRIMARY];
}
if (drbg->parent == NULL) {
reseed_interval = primary_reseed_interval;
reseed_time_interval = primary_reseed_time_interval;
} else {
reseed_interval = secondary_reseed_interval;
reseed_time_interval = secondary_reseed_time_interval;
}
*p++ = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS,
&reseed_interval);
*p++ = OSSL_PARAM_construct_time_t(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL,
&reseed_time_interval);
use_df = (flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0;
*p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_USE_DF, &use_df);
if (!get_drbg_params(type, flags, &name, p)) {
RANDerr(0, RAND_R_UNSUPPORTED_DRBG_TYPE);
return 0;
}
rand = EVP_RAND_fetch(drbg->libctx, name, NULL);
if (rand == NULL) {
RANDerr(0, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED);
return 0;
}
EVP_RAND_CTX_free(drbg->rand);
drbg->rand = NULL;
drbg->flags = flags;
drbg->type = type;
pctx = drbg->parent != NULL ? drbg->parent->rand : NULL;
drbg->rand = EVP_RAND_CTX_new(rand, pctx);
EVP_RAND_free(rand);
if (drbg->rand == NULL) {
RANDerr(0, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED);
goto err;
}
if (!EVP_RAND_set_ctx_params(drbg->rand, params)) {
RANDerr(0, RAND_R_ERROR_INITIALISING_DRBG);
goto err;
}
if (!RAND_DRBG_set_callbacks(drbg,
get_entropy, cleanup_entropy,
get_nonce, cleanup_nonce)) {
RANDerr(0, RAND_R_ERROR_INITIALISING_DRBG);
goto err;
}
return 1;
err:
EVP_RAND_CTX_free(drbg->rand);
drbg->rand = NULL;
drbg->type = 0;
drbg->flags = 0;
return 0;
}
/*
* Set/initialize default |type| and |flag| for new drbg instances.
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_set_defaults(int type, unsigned int flags)
{
int all;
const char *name;
OSSL_PARAM params[3];
if (!get_drbg_params(type, flags, &name, params)) {
RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_TYPE);
return 0;
}
if ((flags & ~rand_drbg_used_flags) != 0) {
RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_FLAGS);
return 0;
}
all = ((flags & RAND_DRBG_TYPE_FLAGS) == 0);
if (all || (flags & RAND_DRBG_FLAG_PRIMARY) != 0) {
rand_drbg_type[RAND_DRBG_TYPE_PRIMARY] = type;
rand_drbg_flags[RAND_DRBG_TYPE_PRIMARY] = flags
| RAND_DRBG_FLAG_PRIMARY;
}
if (all || (flags & RAND_DRBG_FLAG_PUBLIC) != 0) {
rand_drbg_type[RAND_DRBG_TYPE_PUBLIC] = type;
rand_drbg_flags[RAND_DRBG_TYPE_PUBLIC] = flags | RAND_DRBG_FLAG_PUBLIC;
}
if (all || (flags & RAND_DRBG_FLAG_PRIVATE) != 0) {
rand_drbg_type[RAND_DRBG_TYPE_PRIVATE] = type;
rand_drbg_flags[RAND_DRBG_TYPE_PRIVATE] = flags
| RAND_DRBG_FLAG_PRIVATE;
}
return 1;
}
/*
* Allocate memory and initialize a new DRBG.
* The |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(OPENSSL_CTX *ctx,
int type,
unsigned int flags,
RAND_DRBG *parent)
{
RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg));
if (drbg == NULL) {
RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
drbg->libctx = ctx;
drbg->parent = parent;
if (RAND_DRBG_set(drbg, type, flags) == 0)
goto err;
return drbg;
err:
RAND_DRBG_free(drbg);
return NULL;
}
RAND_DRBG *RAND_DRBG_new_ex(OPENSSL_CTX *ctx, int type, unsigned int flags,
RAND_DRBG *parent)
{
return rand_drbg_new(ctx, type, flags, parent);
}
RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent)
{
return RAND_DRBG_new_ex(NULL, 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-09-01 05:16:22 +08:00
if (drbg == NULL)
return;
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RAND_DRBG, drbg, &drbg->ex_data);
EVP_RAND_CTX_free(drbg->rand);
OPENSSL_free(drbg);
}
/*
* Instantiate |drbg|, after it has been initialized. Use |pers| and
* |perslen| as prediction-resistance input.
2017-10-12 01:25:26 +08: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)
{
return EVP_RAND_instantiate(drbg->rand, EVP_RAND_strength(drbg->rand), 0,
pers, perslen);
}
/*
* Uninstantiate |drbg|. Must be instantiated before it can be used.
2017-10-12 01:25:26 +08: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)
{
int index = -1, type, flags;
if (!EVP_RAND_uninstantiate(drbg->rand))
return 0;
/* The reset uses the default values for type and flags */
if (drbg->flags & RAND_DRBG_FLAG_PRIMARY)
index = RAND_DRBG_TYPE_PRIMARY;
else if (drbg->flags & RAND_DRBG_FLAG_PRIVATE)
index = RAND_DRBG_TYPE_PRIVATE;
else if (drbg->flags & RAND_DRBG_FLAG_PUBLIC)
index = RAND_DRBG_TYPE_PUBLIC;
if (index != -1) {
flags = rand_drbg_flags[index];
type = rand_drbg_type[index];
} else {
flags = drbg->flags;
type = drbg->type;
}
return RAND_DRBG_set(drbg, type, flags);
}
/*
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-09-01 05:16:22 +08:00
* Reseed |drbg|, mixing in the specified data
2017-10-12 01:25:26 +08: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)
{
return EVP_RAND_reseed(drbg->rand, prediction_resistance, NULL, 0,
adin, 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-09-01 05:16:22 +08:00
/*
* 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-09-01 05:16:22 +08: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-09-01 05:16:22 +08:00
*
* 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-09-01 05:16:22 +08:00
*
*/
int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
int prediction_resistance,
const unsigned char *adin, size_t adinlen)
{
return EVP_RAND_generate(drbg->rand, out, outlen, 0,
prediction_resistance, adin, adinlen);
}
/*
* Generates |outlen| random bytes and stores them in |out|. It will
* using the given |drbg| to generate the bytes.
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-09-01 05:16:22 +08: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-09-01 05:16:22 +08:00
*
* 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-09-01 05:16:22 +08:00
*/
int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen)
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-09-01 05:16:22 +08:00
{
return EVP_RAND_generate(drbg->rand, out, outlen, 0, 0, NULL, 0);
}
/* DRBG call back shims */
static int rand_drbg_get_entroy_cb(const OSSL_PARAM *params, OSSL_PARAM *out,
void *vdrbg)
{
RAND_DRBG *drbg = (RAND_DRBG *)vdrbg;
int entropy = 0, prediction_resistance = 0;
size_t min_len = 0, max_len = 2048;
const OSSL_PARAM *p;
OSSL_PARAM *q;
if (drbg->get_entropy == NULL)
DRBG: fix reseeding via RAND_add()/RAND_seed() with large input In pull request #4328 the seeding of the DRBG via RAND_add()/RAND_seed() was implemented by buffering the data in a random pool where it is picked up later by the rand_drbg_get_entropy() callback. This buffer was limited to the size of 4096 bytes. When a larger input was added via RAND_add() or RAND_seed() to the DRBG, the reseeding failed, but the error returned by the DRBG was ignored by the two calling functions, which both don't return an error code. As a consequence, the data provided by the application was effectively ignored. This commit fixes the problem by a more efficient implementation which does not copy the data in memory and by raising the buffer the size limit to INT32_MAX (2 gigabytes). This is less than the NIST limit of 2^35 bits but it was chosen intentionally to avoid platform dependent problems like integer sizes and/or signed/unsigned conversion. Additionally, the DRBG is now less permissive on errors: In addition to pushing a message to the openssl error stack, it enters the error state, which forces a reinstantiation on next call. Thanks go to Dr. Falko Strenzke for reporting this issue to the openssl-security mailing list. After internal discussion the issue has been categorized as not being security relevant, because the DRBG reseeds automatically and is fully functional even without additional randomness provided by the application. Fixes #7381 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/7382)
2018-10-10 07:53:29 +08:00
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-09-01 05:16:22 +08:00
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_ENTROPY_REQUIRED);
if (p == NULL || !OSSL_PARAM_get_int(p, &entropy))
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-09-01 05:16:22 +08:00
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_PREDICTION_RESISTANCE);
if (p == NULL || !OSSL_PARAM_get_int(p, &prediction_resistance))
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-09-01 05:16:22 +08:00
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MAX_LENGTH);
if (p == NULL || !OSSL_PARAM_get_size_t(p, &max_len))
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-09-01 05:16:22 +08:00
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MIN_LENGTH);
if (p == NULL || !OSSL_PARAM_get_size_t(p, &min_len))
return 0;
q = OSSL_PARAM_locate(out, OSSL_DRBG_PARAM_RANDOM_DATA);
if (q == NULL || q->data_type != OSSL_PARAM_OCTET_PTR || q->data == 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-09-01 05:16:22 +08:00
q->return_size = drbg->get_entropy(drbg, (unsigned char **)q->data, entropy,
min_len, max_len, prediction_resistance);
return 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-09-01 05:16:22 +08:00
}
static int rand_drbg_cleanup_entropy_cb(const OSSL_PARAM *params, void *vdrbg)
{
RAND_DRBG *drbg = (RAND_DRBG *)vdrbg;
const OSSL_PARAM *p;
size_t sz;
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-09-01 05:16:22 +08:00
if (drbg->cleanup_entropy == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_SIZE);
if (p == NULL || !OSSL_PARAM_get_size_t(p, &sz))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RANDOM_DATA);
if (p == NULL || p->data_type != OSSL_PARAM_OCTET_PTR)
return 0;
drbg->cleanup_entropy(drbg, p->data, sz);
return 1;
}
static int rand_drbg_get_nonce_cb(const OSSL_PARAM *params, OSSL_PARAM *out,
void *vdrbg)
{
RAND_DRBG *drbg = (RAND_DRBG *)vdrbg;
int entropy = 0;
size_t min_len = 0, max_len = 10240;
const OSSL_PARAM *p;
OSSL_PARAM *q;
if (drbg->get_nonce == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_ENTROPY_REQUIRED);
if (p == NULL || !OSSL_PARAM_get_int(p, &entropy))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MAX_LENGTH);
if (p == NULL || !OSSL_PARAM_get_size_t(p, &max_len))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MIN_LENGTH);
if (p == NULL || !OSSL_PARAM_get_size_t(p, &min_len))
return 0;
q = OSSL_PARAM_locate(out, OSSL_DRBG_PARAM_RANDOM_DATA);
if (q == NULL || q->data_type != OSSL_PARAM_OCTET_PTR || q->data == NULL)
return 0;
q->return_size = drbg->get_nonce(drbg, (unsigned char **)q->data, entropy,
min_len, max_len);
return 1;
}
static int rand_drbg_cleanup_nonce_cb(const OSSL_PARAM *params, void *vdrbg)
{
RAND_DRBG *drbg = (RAND_DRBG *)vdrbg;
const OSSL_PARAM *p;
size_t sz;
if (drbg->cleanup_nonce == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_SIZE);
if (p == NULL || !OSSL_PARAM_get_size_t(p, &sz))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RANDOM_DATA);
if (p == NULL || p->data_type != OSSL_PARAM_OCTET_PTR)
return 0;
drbg->cleanup_nonce(drbg, p->data, sz);
return 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-09-01 05:16:22 +08: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-09-01 05:16:22 +08: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-09-01 05:16:22 +08: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)
{
EVP_RAND_CTX *rand = drbg->rand;
OSSL_INOUT_CALLBACK *g_ent = NULL, *g_nonce = NULL;
OSSL_CALLBACK *c_ent = NULL, *c_nonce = NULL;
if (get_entropy != NULL) {
g_ent = &rand_drbg_get_entroy_cb;
c_ent = &rand_drbg_cleanup_entropy_cb;
}
if (get_nonce != NULL) {
g_nonce = rand_drbg_get_nonce_cb;
c_nonce = rand_drbg_cleanup_nonce_cb;
}
if (!EVP_RAND_set_callbacks(rand, g_ent, c_ent, g_nonce, c_nonce, drbg))
return 0;
drbg->get_entropy = g_ent != NULL ? get_entropy : NULL;
drbg->cleanup_entropy = c_ent != NULL ? cleanup_entropy : NULL;
drbg->get_nonce = g_nonce != NULL ? get_nonce : NULL;
drbg->cleanup_nonce = c_nonce != NULL ? cleanup_nonce : NULL;
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)
{
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
if (interval > MAX_RESEED_INTERVAL)
return 0;
params[0] = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS,
&interval);
return EVP_RAND_set_ctx_params(drbg->rand, params);
}
/*
* 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)
{
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
if (interval > MAX_RESEED_TIME_INTERVAL)
return 0;
params[0] =
OSSL_PARAM_construct_time_t(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL,
&interval);
return EVP_RAND_set_ctx_params(drbg->rand, params);
}
/*
* Set the default values for reseed (time) intervals of new DRBG instances
*
* The default values can be set independently for primary DRBG instances
* (without a parent) and secondary DRBG instances (with parent).
*
* Returns 1 on success, 0 on failure.
*/
int RAND_DRBG_set_reseed_defaults(
unsigned int _primary_reseed_interval,
unsigned int _secondary_reseed_interval,
time_t _primary_reseed_time_interval,
time_t _secondary_reseed_time_interval
)
{
if (_primary_reseed_interval > MAX_RESEED_INTERVAL
|| _secondary_reseed_interval > MAX_RESEED_INTERVAL)
return 0;
if (_primary_reseed_time_interval > MAX_RESEED_TIME_INTERVAL
|| _secondary_reseed_time_interval > MAX_RESEED_TIME_INTERVAL)
return 0;
primary_reseed_interval = _primary_reseed_interval;
secondary_reseed_interval = _secondary_reseed_interval;
primary_reseed_time_interval = _primary_reseed_time_interval;
secondary_reseed_time_interval = _secondary_reseed_time_interval;
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.
*/
static RAND_DRBG *drbg_setup(OPENSSL_CTX *ctx, RAND_DRBG *parent, int drbg_type)
{
RAND_DRBG *drbg;
drbg = RAND_DRBG_new_ex(ctx, rand_drbg_type[drbg_type],
rand_drbg_flags[drbg_type], parent);
if (drbg == NULL)
return NULL;
/* Only the primary DRBG needs to have a lock */
if (parent == NULL && EVP_RAND_enable_locking(drbg->rand) == 0)
goto err;
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-09-01 05:16:22 +08:00
/*
* Ignore instantiation error to support just-in-time instantiation.
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-09-01 05:16:22 +08:00
*
* The state of the drbg will be checked in RAND_DRBG_generate() and
* an automatic recovery is attempted.
*/
(void)RAND_DRBG_instantiate(drbg, NULL, 0);
return drbg;
err:
RAND_DRBG_free(drbg);
return NULL;
}
static void drbg_delete_thread_state(void *arg)
{
OPENSSL_CTX *ctx = arg;
DRBG_GLOBAL *dgbl = drbg_get_global(ctx);
RAND_DRBG *drbg;
if (dgbl == NULL)
return;
drbg = CRYPTO_THREAD_get_local(&dgbl->public_drbg);
CRYPTO_THREAD_set_local(&dgbl->public_drbg, NULL);
RAND_DRBG_free(drbg);
drbg = CRYPTO_THREAD_get_local(&dgbl->private_drbg);
CRYPTO_THREAD_set_local(&dgbl->private_drbg, NULL);
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-09-01 05:16:22 +08: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-09-01 05:16:22 +08:00
/* Implements the default OpenSSL RAND_add() method */
static int drbg_add(const void *buf, int num, double randomness)
{
RAND_DRBG *drbg = RAND_DRBG_get0_master();
if (drbg == NULL || num <= 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-09-01 05:16:22 +08:00
return 0;
return EVP_RAND_reseed(drbg->rand, 0, NULL, 0, buf, 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-09-01 05:16:22 +08: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-09-01 05:16:22 +08: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;
ret = EVP_RAND_state(drbg->rand) == EVP_RAND_STATE_READY ? 1 : 0;
return ret;
}
int RAND_DRBG_verify_zeroization(RAND_DRBG *drbg)
{
return EVP_RAND_verify_zeroization(drbg->rand);
}
/*
* Get the primary DRBG.
* Returns pointer to the DRBG on success, NULL on failure.
*
*/
RAND_DRBG *OPENSSL_CTX_get0_primary_drbg(OPENSSL_CTX *ctx)
{
DRBG_GLOBAL *dgbl = drbg_get_global(ctx);
if (dgbl == NULL)
return NULL;
if (dgbl->primary_drbg == NULL) {
if (!CRYPTO_THREAD_write_lock(dgbl->lock))
return NULL;
if (dgbl->primary_drbg == NULL)
dgbl->primary_drbg = drbg_setup(ctx, NULL, RAND_DRBG_TYPE_PRIMARY);
CRYPTO_THREAD_unlock(dgbl->lock);
}
return dgbl->primary_drbg;
}
RAND_DRBG *RAND_DRBG_get0_master(void)
{
return OPENSSL_CTX_get0_primary_drbg(NULL);
}
/*
* Get the public DRBG.
* Returns pointer to the DRBG on success, NULL on failure.
*/
RAND_DRBG *OPENSSL_CTX_get0_public_drbg(OPENSSL_CTX *ctx)
{
DRBG_GLOBAL *dgbl = drbg_get_global(ctx);
RAND_DRBG *drbg, *primary;
if (dgbl == NULL)
return NULL;
drbg = CRYPTO_THREAD_get_local(&dgbl->public_drbg);
if (drbg == NULL) {
primary = OPENSSL_CTX_get0_primary_drbg(ctx);
if (primary == NULL)
return NULL;
ctx = openssl_ctx_get_concrete(ctx);
/*
* If the private_drbg is also NULL then this is the first time we've
* used this thread.
*/
if (CRYPTO_THREAD_get_local(&dgbl->private_drbg) == NULL
&& !ossl_init_thread_start(NULL, ctx, drbg_delete_thread_state))
return NULL;
drbg = drbg_setup(ctx, primary, RAND_DRBG_TYPE_PUBLIC);
CRYPTO_THREAD_set_local(&dgbl->public_drbg, drbg);
}
return drbg;
}
RAND_DRBG *RAND_DRBG_get0_public(void)
{
return OPENSSL_CTX_get0_public_drbg(NULL);
}
/*
* Get the private DRBG.
* Returns pointer to the DRBG on success, NULL on failure.
*/
RAND_DRBG *OPENSSL_CTX_get0_private_drbg(OPENSSL_CTX *ctx)
{
DRBG_GLOBAL *dgbl = drbg_get_global(ctx);
RAND_DRBG *drbg, *primary;
if (dgbl == NULL)
return NULL;
drbg = CRYPTO_THREAD_get_local(&dgbl->private_drbg);
if (drbg == NULL) {
primary = OPENSSL_CTX_get0_primary_drbg(ctx);
if (primary == NULL)
return NULL;
ctx = openssl_ctx_get_concrete(ctx);
/*
* If the public_drbg is also NULL then this is the first time we've
* used this thread.
*/
if (CRYPTO_THREAD_get_local(&dgbl->public_drbg) == NULL
&& !ossl_init_thread_start(NULL, ctx, drbg_delete_thread_state))
return NULL;
drbg = drbg_setup(ctx, primary, RAND_DRBG_TYPE_PRIVATE);
CRYPTO_THREAD_set_local(&dgbl->private_drbg, drbg);
}
return drbg;
}
RAND_DRBG *RAND_DRBG_get0_private(void)
{
return OPENSSL_CTX_get0_private_drbg(NULL);
}
RAND_METHOD rand_meth = {
drbg_seed,
drbg_bytes,
NULL,
drbg_add,
drbg_bytes,
drbg_status
};
RAND_METHOD *RAND_OpenSSL(void)
{
#ifndef FIPS_MODULE
return &rand_meth;
#else
return NULL;
#endif
}