summaryrefslogtreecommitdiffstats
path: root/crypto/rand
diff options
context:
space:
mode:
authorPauli <paul.dale@oracle.com>2020-05-08 10:25:19 +1000
committerPauli <paul.dale@oracle.com>2020-06-24 20:05:42 +1000
commitf000e82898af251442ca52e81fc1ee45996090dc (patch)
treeb378db85b032065a595ce8d7b0422981f09e0d58 /crypto/rand
parenta998b85a4f0e706fa6a07b7feab557d9e570d372 (diff)
CTR, HASH and HMAC DRBGs in provider
Move the three different DRBGs to the provider. As part of the move, the DRBG specific data was pulled out of a common structure and into their own structures. Only these smaller structures are securely allocated. This saves quite a bit of secure memory: +-------------------------------+ | DRBG | Bytes | Secure | +--------------+-------+--------+ | HASH | 376 | 512 | | HMAC | 168 | 256 | | CTR | 176 | 256 | | Common (new) | 320 | 0 | | Common (old) | 592 | 1024 | +--------------+-------+--------+ Bytes is the structure size on the X86/64. Secure is the number of bytes of secure memory used (power of two allocator). Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com> (Merged from https://github.com/openssl/openssl/pull/11682)
Diffstat (limited to 'crypto/rand')
-rw-r--r--crypto/rand/build.info12
-rw-r--r--crypto/rand/drbg_lib.c1056
-rw-r--r--crypto/rand/rand_lib.c309
-rw-r--r--crypto/rand/rand_local.h72
4 files changed, 341 insertions, 1108 deletions
diff --git a/crypto/rand/build.info b/crypto/rand/build.info
index 7840428045..b7a4d598f1 100644
--- a/crypto/rand/build.info
+++ b/crypto/rand/build.info
@@ -1,16 +1,10 @@
LIBS=../../libcrypto
-$COMMON=rand_pool.c rand_lib.c drbg_lib.c drbg_ctr.c drbg_hash.c drbg_hmac.c
-$CRYPTO=rand_unix.c rand_win.c randfile.c rand_err.c
+$COMMON=drbg_lib.c rand_lib.c
+$CRYPTO=randfile.c rand_err.c
IF[{- !$disabled{'egd'} -}]
- $CYPTO=$CYPTO rand_egd.c
-ENDIF
-IF[{- $config{target} =~ /vxworks/i -}]
- $CYPTO=$CYPTO rand_vxworks.c
-ENDIF
-IF[{- $config{target} =~ /vms/i -}]
- $CYPTO=$CYPTO rand_vms.c
+ $CRYPTO=$CRYPTO rand_egd.c
ENDIF
diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c
index 94a4e98d73..80759cbfaf 100644
--- a/crypto/rand/drbg_lib.c
+++ b/crypto/rand/drbg_lib.c
@@ -11,10 +11,10 @@
#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/rand_pool.h"
#include "crypto/cryptlib.h"
/*
@@ -37,6 +37,7 @@ typedef struct drbg_global_st {
*
* There are three shared DRBG instances: <master>, <public>, and <private>.
*/
+ CRYPTO_RWLOCK *lock;
/*
* The <master> DRBG
@@ -70,14 +71,6 @@ typedef struct drbg_global_st {
CRYPTO_THREAD_LOCAL private_drbg;
} DRBG_GLOBAL;
-typedef struct drbg_nonce_global_st {
- CRYPTO_RWLOCK *rand_nonce_lock;
- int rand_nonce_count;
-} DRBG_NONCE_GLOBAL;
-
-/* NIST SP 800-90A DRBG recommends the use of a personalization string. */
-static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING;
-
#define RAND_DRBG_TYPE_FLAGS ( \
RAND_DRBG_FLAG_MASTER | RAND_DRBG_FLAG_PUBLIC | RAND_DRBG_FLAG_PRIVATE )
@@ -110,45 +103,76 @@ static const unsigned int rand_drbg_used_flags =
static RAND_DRBG *drbg_setup(OPENSSL_CTX *ctx, RAND_DRBG *parent, int drbg_type);
-static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx,
- int secure,
- int type,
- unsigned int flags,
- RAND_DRBG *parent);
-
-static int rand_drbg_set(RAND_DRBG *drbg, int type, unsigned int flags);
-static int rand_drbg_init_method(RAND_DRBG *drbg);
-
-static int is_ctr(int 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 NID_aes_128_ctr:
- case NID_aes_192_ctr:
- case NID_aes_256_ctr:
+ 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); \
}
-}
-static int is_digest(int type)
-{
- switch (type) {
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:
- return 1;
- default:
- return 0;
+ DGST(SN_sha3_512);
}
+ *p = OSSL_PARAM_construct_end();
+ return 1;
}
/*
@@ -170,23 +194,23 @@ static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
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;
- dgbl->master_drbg = drbg_setup(libctx, NULL, RAND_DRBG_TYPE_MASTER);
- if (dgbl->master_drbg == NULL)
- goto err3;
-
return dgbl;
- err3:
- CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
err2:
CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
err1:
+ CRYPTO_THREAD_lock_free(dgbl->lock);
+ err0:
OPENSSL_free(dgbl);
return NULL;
}
@@ -198,6 +222,7 @@ static void drbg_ossl_ctx_free(void *vdgbl)
if (dgbl == NULL)
return;
+ CRYPTO_THREAD_lock_free(dgbl->lock);
RAND_DRBG_free(dgbl->master_drbg);
CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
@@ -210,104 +235,12 @@ static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
drbg_ossl_ctx_free,
};
-/*
- * drbg_ossl_ctx_new() calls drgb_setup() which calls rand_drbg_get_nonce()
- * which needs to get the rand_nonce_lock out of the OPENSSL_CTX...but since
- * drbg_ossl_ctx_new() hasn't finished running yet we need the rand_nonce_lock
- * to be in a different global data object. Otherwise we will go into an
- * infinite recursion loop.
- */
-static void *drbg_nonce_ossl_ctx_new(OPENSSL_CTX *libctx)
-{
- DRBG_NONCE_GLOBAL *dngbl = OPENSSL_zalloc(sizeof(*dngbl));
-
- if (dngbl == NULL)
- return NULL;
-
- dngbl->rand_nonce_lock = CRYPTO_THREAD_lock_new();
- if (dngbl->rand_nonce_lock == NULL) {
- OPENSSL_free(dngbl);
- return NULL;
- }
-
- return dngbl;
-}
-
-static void drbg_nonce_ossl_ctx_free(void *vdngbl)
-{
- DRBG_NONCE_GLOBAL *dngbl = vdngbl;
-
- if (dngbl == NULL)
- return;
-
- CRYPTO_THREAD_lock_free(dngbl->rand_nonce_lock);
-
- OPENSSL_free(dngbl);
-}
-
-static const OPENSSL_CTX_METHOD drbg_nonce_ossl_ctx_method = {
- drbg_nonce_ossl_ctx_new,
- drbg_nonce_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);
}
-/* Implements the get_nonce() callback (see RAND_DRBG_set_callbacks()) */
-size_t rand_drbg_get_nonce(RAND_DRBG *drbg,
- unsigned char **pout,
- int entropy, size_t min_len, size_t max_len)
-{
- size_t ret = 0;
- RAND_POOL *pool;
- DRBG_NONCE_GLOBAL *dngbl
- = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_DRBG_NONCE_INDEX,
- &drbg_nonce_ossl_ctx_method);
- struct {
- void *instance;
- int count;
- } data;
-
- if (dngbl == NULL)
- return 0;
-
- memset(&data, 0, sizeof(data));
- pool = rand_pool_new(0, 0, min_len, max_len);
- if (pool == NULL)
- return 0;
-
- if (rand_pool_add_nonce_data(pool) == 0)
- goto err;
-
- data.instance = drbg;
- CRYPTO_atomic_add(&dngbl->rand_nonce_count, 1, &data.count,
- dngbl->rand_nonce_lock);
-
- if (rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0) == 0)
- goto err;
-
- ret = rand_pool_length(pool);
- *pout = rand_pool_detach(pool);
-
- err:
- rand_pool_free(pool);
-
- return ret;
-}
-
-/*
- * Implements the cleanup_nonce() callback (see RAND_DRBG_set_callbacks())
- *
- */
-void rand_drbg_cleanup_nonce(RAND_DRBG *drbg,
- unsigned char *out, size_t outlen)
-{
- OPENSSL_clear_free(out, outlen);
-}
-
/*
* Set the |drbg|'s callback data pointer for the entropy and nonce callbacks
*
@@ -322,8 +255,8 @@ void rand_drbg_cleanup_nonce(RAND_DRBG *drbg,
*/
int RAND_DRBG_set_callback_data(RAND_DRBG *drbg, void *data)
{
- if (drbg->state != DRBG_UNINITIALISED
- || drbg->parent != NULL)
+ if (EVP_RAND_state(drbg->rand) != EVP_RAND_STATE_UNINITIALISED
+ || drbg->parent != NULL)
return 0;
drbg->callback_data = data;
@@ -345,68 +278,71 @@ void *RAND_DRBG_get_callback_data(RAND_DRBG *drbg)
*/
int RAND_DRBG_set(RAND_DRBG *drbg, int type, unsigned int flags)
{
- return rand_drbg_set(drbg, type, flags) && rand_drbg_init_method(drbg);
-}
+ 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;
-static int rand_drbg_set(RAND_DRBG *drbg, int type, unsigned int flags)
-{
if (type == 0 && flags == 0) {
type = rand_drbg_type[RAND_DRBG_TYPE_MASTER];
flags = rand_drbg_flags[RAND_DRBG_TYPE_MASTER];
}
- /* If set is called multiple times - clear the old one */
- if (drbg->type != 0 && (type != drbg->type || flags != drbg->flags)) {
- if (drbg->meth != NULL)
- drbg->meth->uninstantiate(drbg);
- rand_pool_free(drbg->adin_pool);
- drbg->adin_pool = NULL;
+ if (drbg->parent == NULL) {
+ reseed_interval = master_reseed_interval;
+ reseed_time_interval = master_reseed_time_interval;
+ } else {
+ reseed_interval = slave_reseed_interval;
+ reseed_time_interval = slave_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;
}
- drbg->state = DRBG_UNINITIALISED;
+ 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;
- drbg->meth = NULL;
- if (type == 0 || is_ctr(type) || is_digest(type))
- return 1;
+ 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;
+ }
+ return 1;
+err:
+ EVP_RAND_CTX_free(drbg->rand);
+ drbg->rand = NULL;
drbg->type = 0;
drbg->flags = 0;
- RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE);
-
return 0;
}
-static int rand_drbg_init_method(RAND_DRBG *drbg)
-{
- int ret;
-
- if (drbg->meth != NULL)
- return 1;
-
- if (is_ctr(drbg->type)) {
- ret = drbg_ctr_init(drbg);
- } else if (is_digest(drbg->type)) {
- if (drbg->flags & RAND_DRBG_FLAG_HMAC)
- ret = drbg_hmac_init(drbg);
- else
- ret = drbg_hash_init(drbg);
- } else {
- /* other cases should already be excluded */
- RANDerr(RAND_F_RAND_DRBG_INIT_METHOD, ERR_R_INTERNAL_ERROR);
- drbg->type = 0;
- drbg->flags = 0;
- return 0;
- }
-
- if (ret == 0) {
- drbg->state = DRBG_ERROR;
- RANDerr(RAND_F_RAND_DRBG_INIT_METHOD, RAND_R_ERROR_INITIALISING_DRBG);
- }
- return ret;
-}
-
/*
* Set/initialize default |type| and |flag| for new drbg instances.
*
@@ -415,7 +351,10 @@ static int rand_drbg_init_method(RAND_DRBG *drbg)
int RAND_DRBG_set_defaults(int type, unsigned int flags)
{
int all;
- if (!(is_digest(type) || is_ctr(type))) {
+ 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;
}
@@ -443,20 +382,17 @@ int RAND_DRBG_set_defaults(int type, unsigned int flags)
/*
- * 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.
+ * 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 secure,
int type,
unsigned int flags,
RAND_DRBG *parent)
{
- RAND_DRBG *drbg = secure ? OPENSSL_secure_zalloc(sizeof(*drbg))
- : OPENSSL_zalloc(sizeof(*drbg));
+ RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg));
if (drbg == NULL) {
RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE);
@@ -464,49 +400,11 @@ static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx,
}
drbg->libctx = ctx;
- drbg->secure = secure && CRYPTO_secure_allocated(drbg);
- drbg->fork_id = openssl_get_fork_id();
drbg->parent = parent;
- if (parent == NULL) {
- drbg->get_entropy = rand_drbg_get_entropy;
- drbg->cleanup_entropy = rand_drbg_cleanup_entropy;
-#ifndef RAND_DRBG_GET_RANDOM_NONCE
- drbg->get_nonce = rand_drbg_get_nonce;
- drbg->cleanup_nonce = rand_drbg_cleanup_nonce;
-#endif
-
- drbg->reseed_interval = master_reseed_interval;
- drbg->reseed_time_interval = master_reseed_time_interval;
- } else {
- drbg->get_entropy = rand_drbg_get_entropy;
- drbg->cleanup_entropy = rand_drbg_cleanup_entropy;
- /*
- * 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:
@@ -518,7 +416,7 @@ static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx,
RAND_DRBG *RAND_DRBG_new_ex(OPENSSL_CTX *ctx, int type, unsigned int flags,
RAND_DRBG *parent)
{
- return rand_drbg_new(ctx, 0, type, flags, parent);
+ return rand_drbg_new(ctx, type, flags, parent);
}
RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent)
@@ -526,16 +424,6 @@ RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent)
return RAND_DRBG_new_ex(NULL, type, flags, parent);
}
-RAND_DRBG *RAND_DRBG_secure_new_ex(OPENSSL_CTX *ctx, int type,
- unsigned int flags, RAND_DRBG *parent)
-{
- return rand_drbg_new(ctx, 1, type, flags, parent);
-}
-
-RAND_DRBG *RAND_DRBG_secure_new(int type, unsigned int flags, RAND_DRBG *parent)
-{
- return RAND_DRBG_secure_new_ex(NULL, type, flags, parent);
-}
/*
* Uninstantiate |drbg| and free all memory.
*/
@@ -544,18 +432,8 @@ void RAND_DRBG_free(RAND_DRBG *drbg)
if (drbg == NULL)
return;
- if (drbg->meth != NULL)
- drbg->meth->uninstantiate(drbg);
- rand_pool_free(drbg->adin_pool);
- CRYPTO_THREAD_lock_free(drbg->lock);
-#ifndef FIPS_MODULE
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RAND_DRBG, drbg, &drbg->ex_data);
-#endif
-
- if (drbg->secure)
- OPENSSL_secure_clear_free(drbg, sizeof(*drbg));
- else
- OPENSSL_clear_free(drbg, sizeof(*drbg));
+ OPENSSL_free(drbg);
}
/*
@@ -569,92 +447,8 @@ void RAND_DRBG_free(RAND_DRBG *drbg)
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, min_entropylen, max_entropylen;
-
- if (drbg->meth == NULL && !rand_drbg_init_method(drbg)) {
- RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
- RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED);
- goto end;
- }
-
- min_entropy = drbg->strength;
- min_entropylen = drbg->min_entropylen;
- 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->state != DRBG_UNINITIALISED) {
- if (drbg->state == DRBG_ERROR)
- RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_IN_ERROR_STATE);
- else
- RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, 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 accommodate 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;
- }
-
- drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
- if (drbg->reseed_next_counter) {
- drbg->reseed_next_counter++;
- if(!drbg->reseed_next_counter)
- drbg->reseed_next_counter = 1;
- }
-
- 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->reseed_gen_counter = 1;
- drbg->reseed_time = time(NULL);
- tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_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);
- if (drbg->state == DRBG_READY)
- return 1;
- return 0;
+ return EVP_RAND_instantiate(drbg->rand, EVP_RAND_strength(drbg->rand), 0,
+ pers, perslen);
}
/*
@@ -667,10 +461,9 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg,
int RAND_DRBG_uninstantiate(RAND_DRBG *drbg)
{
int index = -1, type, flags;
- if (drbg->meth != NULL) {
- drbg->meth->uninstantiate(drbg);
- drbg->meth = NULL;
- }
+
+ if (!EVP_RAND_uninstantiate(drbg->rand))
+ return 0;
/* The reset uses the default values for type and flags */
if (drbg->flags & RAND_DRBG_FLAG_MASTER)
@@ -687,7 +480,7 @@ int RAND_DRBG_uninstantiate(RAND_DRBG *drbg)
flags = drbg->flags;
type = drbg->type;
}
- return rand_drbg_set(drbg, type, flags);
+ return RAND_DRBG_set(drbg, type, flags);
}
/*
@@ -701,288 +494,152 @@ 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;
-
- drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
- if (drbg->reseed_next_counter) {
- drbg->reseed_next_counter++;
- if(!drbg->reseed_next_counter)
- drbg->reseed_next_counter = 1;
- }
-
- if (drbg->get_entropy != NULL)
- entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
- drbg->min_entropylen,
- drbg->max_entropylen,
- prediction_resistance);
- if (entropylen < drbg->min_entropylen
- || entropylen > drbg->max_entropylen) {
- RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY);
- goto end;
- }
-
- if (!drbg->meth->reseed(drbg, entropy, entropylen, adin, adinlen))
- goto end;
-
- drbg->state = DRBG_READY;
- drbg->reseed_gen_counter = 1;
- drbg->reseed_time = time(NULL);
- tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter);
-
- end:
- if (entropy != NULL && drbg->cleanup_entropy != NULL)
- drbg->cleanup_entropy(drbg, entropy, entropylen);
- if (drbg->state == DRBG_READY)
- return 1;
- return 0;
+ return EVP_RAND_reseed(drbg->rand, prediction_resistance, NULL, 0,
+ adin, adinlen);
}
/*
- * 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.
+ * 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|.
*
- * Optionally, a |buffer| of |len| random bytes can be passed,
- * which is assumed to contain at least |entropy| bits of entropy.
+ * Requires that drbg->lock is already locked for write, if non-null.
*
- * If |entropy| > 0, the buffer content is used as entropy input.
+ * Returns 1 on success, 0 on failure.
*
- * If |entropy| == 0, the buffer content is used as additional input
+ */
+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.
*
- * Returns 1 on success, 0 on failure.
+ * Requires that drbg->lock is already locked for write, if non-null.
*
- * This function is used internally only.
+ * Returns 1 on success 0 on failure.
*/
-int rand_drbg_restart(RAND_DRBG *drbg,
- const unsigned char *buffer, size_t len, size_t entropy)
+int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen)
{
- int reseeded = 0;
- const unsigned char *adin = NULL;
- size_t adinlen = 0;
-
- if (drbg->seed_pool != NULL) {
- RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR);
- drbg->state = DRBG_ERROR;
- rand_pool_free(drbg->seed_pool);
- drbg->seed_pool = NULL;
+ 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)
return 0;
- }
- if (buffer != NULL) {
- if (entropy > 0) {
- if (drbg->max_entropylen < len) {
- RANDerr(RAND_F_RAND_DRBG_RESTART,
- RAND_R_ENTROPY_INPUT_TOO_LONG);
- drbg->state = DRBG_ERROR;
- return 0;
- }
-
- if (entropy > 8 * len) {
- RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE);
- drbg->state = DRBG_ERROR;
- return 0;
- }
-
- /* will be picked up by the rand_drbg_get_entropy() callback */
- drbg->seed_pool = rand_pool_attach(buffer, len, entropy);
- if (drbg->seed_pool == NULL)
- return 0;
- } else {
- if (drbg->max_adinlen < len) {
- RANDerr(RAND_F_RAND_DRBG_RESTART,
- RAND_R_ADDITIONAL_INPUT_TOO_LONG);
- drbg->state = DRBG_ERROR;
- return 0;
- }
- adin = buffer;
- adinlen = len;
- }
- }
+ p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_ENTROPY_REQUIRED);
+ if (p == NULL || !OSSL_PARAM_get_int(p, &entropy))
+ return 0;
- /* repair error state */
- if (drbg->state == DRBG_ERROR)
- 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);
- /* already reseeded. prevent second reseeding below */
- reseeded = (drbg->state == DRBG_READY);
- }
+ p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_PREDICTION_RESISTANCE);
+ if (p == NULL || !OSSL_PARAM_get_int(p, &prediction_resistance))
+ return 0;
- /* 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);
- } else if (reseeded == 0) {
- /* do a full reseeding if it has not been done yet above */
- RAND_DRBG_reseed(drbg, NULL, 0, 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;
- rand_pool_free(drbg->seed_pool);
- drbg->seed_pool = NULL;
+ 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;
- return drbg->state == DRBG_READY;
+ q->return_size = drbg->get_entropy(drbg, (unsigned char **)q->data, entropy,
+ min_len, max_len, prediction_resistance);
+ return 1;
}
-/*
- * 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|.
- *
- * Requires that drbg->lock is already locked for write, if non-null.
- *
- * 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)
+static int rand_drbg_cleanup_entropy_cb(const OSSL_PARAM *params, void *vdrbg)
{
- int fork_id;
- int reseed_required = 0;
-
- 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;
- }
- }
+ RAND_DRBG *drbg = (RAND_DRBG *)vdrbg;
+ const OSSL_PARAM *p;
+ size_t sz;
- if (outlen > drbg->max_request) {
- RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG);
+ if (drbg->cleanup_entropy == NULL)
return 0;
- }
- if (adinlen > drbg->max_adinlen) {
- RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG);
+
+ p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_SIZE);
+ if (p == NULL || !OSSL_PARAM_get_size_t(p, &sz))
return 0;
- }
- fork_id = openssl_get_fork_id();
+ p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RANDOM_DATA);
+ if (p == NULL || p->data_type != OSSL_PARAM_OCTET_PTR)
+ return 0;
- if (drbg->fork_id != fork_id) {
- drbg->fork_id = fork_id;
- reseed_required = 1;
- }
+ drbg->cleanup_entropy(drbg, p->data, sz);
+ return 1;
+}
- if (drbg->reseed_interval > 0) {
- if (drbg->reseed_gen_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->parent != NULL) {
- unsigned int reseed_counter = tsan_load(&drbg->reseed_prop_counter);
- if (reseed_counter > 0
- && tsan_load(&drbg->parent->reseed_prop_counter)
- != reseed_counter)
- reseed_required = 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;
+ co