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