summaryrefslogtreecommitdiff
path: root/crypto/rand/rand_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/rand/rand_lib.c')
-rw-r--r--crypto/rand/rand_lib.c559
1 files changed, 429 insertions, 130 deletions
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index 5fde214448f3..9233322b5ff5 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 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
@@ -13,11 +13,93 @@
#include <openssl/err.h>
#include <openssl/opensslconf.h>
#include <openssl/core_names.h>
+#include <openssl/provider.h>
#include "internal/cryptlib.h"
+#include "internal/provider.h"
#include "internal/thread_once.h"
#include "crypto/rand.h"
#include "crypto/cryptlib.h"
#include "rand_local.h"
+#include "crypto/context.h"
+#include "internal/provider.h"
+
+#ifndef OPENSSL_DEFAULT_SEED_SRC
+# define OPENSSL_DEFAULT_SEED_SRC SEED-SRC
+#endif
+
+typedef struct rand_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;
+
+ EVP_RAND_CTX *seed;
+
+ /*
+ * 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.
+ */
+ EVP_RAND_CTX *primary;
+
+ /*
+ * The provider which we'll use to generate randomness.
+ */
+#ifndef FIPS_MODULE
+ OSSL_PROVIDER *random_provider;
+ char *random_provider_name;
+#endif /* !FIPS_MODULE */
+
+ /*
+ * 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;
+
+ /*
+ * 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;
+
+ /* Which RNG is being used by default and it's configuration settings */
+ char *rng_name;
+ char *rng_cipher;
+ char *rng_digest;
+ char *rng_propq;
+
+ /* Allow the randomness source to be changed */
+ char *seed_name;
+ char *seed_propq;
+} RAND_GLOBAL;
+
+static EVP_RAND_CTX *rand_get0_primary(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl);
+static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl);
+static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl);
+
+static RAND_GLOBAL *rand_get_global(OSSL_LIB_CTX *libctx)
+{
+ return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_DRBG_INDEX);
+}
#ifndef FIPS_MODULE
# include <stdio.h>
@@ -28,17 +110,36 @@
# include <openssl/engine.h>
# include "crypto/rand_pool.h"
# include "prov/seeding.h"
-# include "e_os.h"
+# include "internal/e_os.h"
+# include "internal/property.h"
+
+/*
+ * The default name for the random provider.
+ * This ensures that the FIPS provider will supply libcrypto's random byte
+ * requirements.
+ */
+static const char random_provider_fips_name[] = "fips";
+
+static int set_random_provider_name(RAND_GLOBAL *dgbl, const char *name)
+{
+ if (dgbl->random_provider_name != NULL
+ && OPENSSL_strcasecmp(dgbl->random_provider_name, name) == 0)
+ return 1;
+
+ OPENSSL_free(dgbl->random_provider_name);
+ dgbl->random_provider_name = OPENSSL_strdup(name);
+ return dgbl->random_provider_name != NULL;
+}
# ifndef OPENSSL_NO_ENGINE
/* non-NULL if default_RAND_meth is ENGINE-provided */
static ENGINE *funct_ref;
static CRYPTO_RWLOCK *rand_engine_lock;
-# endif
+# endif /* !OPENSSL_NO_ENGINE */
# ifndef OPENSSL_NO_DEPRECATED_3_0
static CRYPTO_RWLOCK *rand_meth_lock;
static const RAND_METHOD *default_RAND_meth;
-# endif
+# endif /* !OPENSSL_NO_DEPRECATED_3_0 */
static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;
static int rand_inited = 0;
@@ -49,13 +150,13 @@ DEFINE_RUN_ONCE_STATIC(do_rand_init)
rand_engine_lock = CRYPTO_THREAD_lock_new();
if (rand_engine_lock == NULL)
return 0;
-# endif
+# endif /* !OPENSSL_NO_ENGINE */
# ifndef OPENSSL_NO_DEPRECATED_3_0
rand_meth_lock = CRYPTO_THREAD_lock_new();
if (rand_meth_lock == NULL)
goto err;
-# endif
+# endif /* !OPENSSL_NO_DEPRECATED_3_0 */
if (!ossl_rand_pool_init())
goto err;
@@ -67,11 +168,11 @@ DEFINE_RUN_ONCE_STATIC(do_rand_init)
# ifndef OPENSSL_NO_DEPRECATED_3_0
CRYPTO_THREAD_lock_free(rand_meth_lock);
rand_meth_lock = NULL;
-# endif
+# endif /* !OPENSSL_NO_DEPRECATED_3_0 */
# ifndef OPENSSL_NO_ENGINE
CRYPTO_THREAD_lock_free(rand_engine_lock);
rand_engine_lock = NULL;
-# endif
+# endif /* !OPENSSL_NO_ENGINE */
return 0;
}
@@ -86,16 +187,16 @@ void ossl_rand_cleanup_int(void)
if (meth != NULL && meth->cleanup != NULL)
meth->cleanup();
RAND_set_rand_method(NULL);
-# endif
+# endif /* !OPENSSL_NO_DEPRECATED_3_0 */
ossl_rand_pool_cleanup();
# ifndef OPENSSL_NO_ENGINE
CRYPTO_THREAD_lock_free(rand_engine_lock);
rand_engine_lock = NULL;
-# endif
+# endif /* !OPENSSL_NO_ENGINE */
# ifndef OPENSSL_NO_DEPRECATED_3_0
CRYPTO_THREAD_lock_free(rand_meth_lock);
rand_meth_lock = NULL;
-# endif
+# endif /* !OPENSSL_NO_DEPRECATED_3_0 */
ossl_release_default_drbg_ctx();
rand_inited = 0;
}
@@ -152,7 +253,7 @@ int RAND_poll(void)
ossl_rand_pool_free(pool);
return ret;
}
-# endif
+# endif /* !OPENSSL_NO_DEPRECATED_3_0 */
RAND_seed(salt, sizeof(salt));
return 1;
@@ -188,6 +289,13 @@ const RAND_METHOD *RAND_get_rand_method(void)
if (!RUN_ONCE(&rand_init, do_rand_init))
return NULL;
+ if (!CRYPTO_THREAD_read_lock(rand_meth_lock))
+ return NULL;
+ tmp_meth = default_RAND_meth;
+ CRYPTO_THREAD_unlock(rand_meth_lock);
+ if (tmp_meth != NULL)
+ return tmp_meth;
+
if (!CRYPTO_THREAD_write_lock(rand_meth_lock))
return NULL;
if (default_RAND_meth == NULL) {
@@ -325,6 +433,7 @@ const RAND_METHOD *RAND_get_rand_method(void)
int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
unsigned int strength)
{
+ RAND_GLOBAL *dgbl;
EVP_RAND_CTX *rand;
#if !defined(OPENSSL_NO_DEPRECATED_3_0) && !defined(FIPS_MODULE)
const RAND_METHOD *meth = RAND_get_rand_method();
@@ -337,7 +446,16 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
}
#endif
- rand = RAND_get0_private(ctx);
+ dgbl = rand_get_global(ctx);
+ if (dgbl == NULL)
+ return 0;
+#ifndef FIPS_MODULE
+ if (dgbl->random_provider != NULL)
+ return ossl_provider_random_bytes(dgbl->random_provider,
+ OSSL_PROV_RANDOM_PRIVATE,
+ buf, num, strength);
+#endif /* !FIPS_MODULE */
+ rand = rand_get0_private(ctx, dgbl);
if (rand != NULL)
return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0);
@@ -354,6 +472,7 @@ int RAND_priv_bytes(unsigned char *buf, int num)
int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
unsigned int strength)
{
+ RAND_GLOBAL *dgbl;
EVP_RAND_CTX *rand;
#if !defined(OPENSSL_NO_DEPRECATED_3_0) && !defined(FIPS_MODULE)
const RAND_METHOD *meth = RAND_get_rand_method();
@@ -366,7 +485,17 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
}
#endif
- rand = RAND_get0_public(ctx);
+ dgbl = rand_get_global(ctx);
+ if (dgbl == NULL)
+ return 0;
+#ifndef FIPS_MODULE
+ if (dgbl->random_provider != NULL)
+ return ossl_provider_random_bytes(dgbl->random_provider,
+ OSSL_PROV_RANDOM_PUBLIC,
+ buf, num, strength);
+#endif /* !FIPS_MODULE */
+
+ rand = rand_get0_public(ctx, dgbl);
if (rand != NULL)
return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0);
@@ -380,68 +509,11 @@ int RAND_bytes(unsigned char *buf, int num)
return RAND_bytes_ex(NULL, buf, (size_t)num, 0);
}
-typedef struct rand_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;
-
- EVP_RAND_CTX *seed;
-
- /*
- * 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.
- */
- EVP_RAND_CTX *primary;
-
- /*
- * 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;
-
- /*
- * 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;
-
- /* Which RNG is being used by default and it's configuration settings */
- char *rng_name;
- char *rng_cipher;
- char *rng_digest;
- char *rng_propq;
-
- /* Allow the randomness source to be changed */
- char *seed_name;
- char *seed_propq;
-} RAND_GLOBAL;
-
/*
* Initialize the OSSL_LIB_CTX global DRBGs on first use.
* Returns the allocated global data on success or NULL on failure.
*/
-static void *rand_ossl_ctx_new(OSSL_LIB_CTX *libctx)
+void *ossl_rand_ctx_new(OSSL_LIB_CTX *libctx)
{
RAND_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));
@@ -453,7 +525,12 @@ static void *rand_ossl_ctx_new(OSSL_LIB_CTX *libctx)
* We need to ensure that base libcrypto thread handling has been
* initialised.
*/
- OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL);
+ OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL);
+
+ /* Prepopulate the random provider name */
+ dgbl->random_provider_name = OPENSSL_strdup(random_provider_fips_name);
+ if (dgbl->random_provider_name == NULL)
+ goto err0;
#endif
dgbl->lock = CRYPTO_THREAD_lock_new();
@@ -472,6 +549,10 @@ static void *rand_ossl_ctx_new(OSSL_LIB_CTX *libctx)
CRYPTO_THREAD_cleanup_local(&dgbl->private);
err1:
CRYPTO_THREAD_lock_free(dgbl->lock);
+#ifndef FIPS_MODULE
+ err0:
+ OPENSSL_free(dgbl->random_provider_name);
+#endif
OPENSSL_free(dgbl);
return NULL;
}
@@ -488,6 +569,9 @@ void ossl_rand_ctx_free(void *vdgbl)
CRYPTO_THREAD_cleanup_local(&dgbl->public);
EVP_RAND_CTX_free(dgbl->primary);
EVP_RAND_CTX_free(dgbl->seed);
+#ifndef FIPS_MODULE
+ OPENSSL_free(dgbl->random_provider_name);
+#endif /* !FIPS_MODULE */
OPENSSL_free(dgbl->rng_name);
OPENSSL_free(dgbl->rng_cipher);
OPENSSL_free(dgbl->rng_digest);
@@ -498,18 +582,6 @@ void ossl_rand_ctx_free(void *vdgbl)
OPENSSL_free(dgbl);
}
-static const OSSL_LIB_CTX_METHOD rand_drbg_ossl_ctx_method = {
- OSSL_LIB_CTX_METHOD_PRIORITY_2,
- rand_ossl_ctx_new,
- ossl_rand_ctx_free,
-};
-
-static RAND_GLOBAL *rand_get_global(OSSL_LIB_CTX *libctx)
-{
- return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_DRBG_INDEX,
- &rand_drbg_ossl_ctx_method);
-}
-
static void rand_delete_thread_state(void *arg)
{
OSSL_LIB_CTX *ctx = arg;
@@ -528,36 +600,64 @@ static void rand_delete_thread_state(void *arg)
EVP_RAND_CTX_free(rand);
}
-#ifndef FIPS_MODULE
+#if !defined(FIPS_MODULE) || !defined(OPENSSL_NO_FIPS_JITTER)
static EVP_RAND_CTX *rand_new_seed(OSSL_LIB_CTX *libctx)
{
EVP_RAND *rand;
- RAND_GLOBAL *dgbl = rand_get_global(libctx);
- EVP_RAND_CTX *ctx;
+ const char *propq;
char *name;
+ EVP_RAND_CTX *ctx = NULL;
+# ifdef OPENSSL_NO_FIPS_JITTER
+ RAND_GLOBAL *dgbl = rand_get_global(libctx);
if (dgbl == NULL)
return NULL;
- name = dgbl->seed_name != NULL ? dgbl->seed_name : "SEED-SRC";
- rand = EVP_RAND_fetch(libctx, name, dgbl->seed_propq);
+ propq = dgbl->seed_propq;
+ name = dgbl->seed_name != NULL ? dgbl->seed_name
+ : OPENSSL_MSTR(OPENSSL_DEFAULT_SEED_SRC);
+# else /* !OPENSSL_NO_FIPS_JITTER */
+ name = "JITTER";
+ propq = "";
+# endif /* OPENSSL_NO_FIPS_JITTER */
+
+ rand = EVP_RAND_fetch(libctx, name, propq);
if (rand == NULL) {
ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG);
- return NULL;
+ goto err;
}
ctx = EVP_RAND_CTX_new(rand, NULL);
EVP_RAND_free(rand);
if (ctx == NULL) {
ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_CREATE_DRBG);
- return NULL;
+ goto err;
}
if (!EVP_RAND_instantiate(ctx, 0, 0, NULL, 0, NULL)) {
ERR_raise(ERR_LIB_RAND, RAND_R_ERROR_INSTANTIATING_DRBG);
- EVP_RAND_CTX_free(ctx);
- return NULL;
+ goto err;
}
return ctx;
+ err:
+ EVP_RAND_CTX_free(ctx);
+ return NULL;
}
-#endif
+#endif /* !FIPS_MODULE || !OPENSSL_NO_FIPS_JITTER */
+
+#ifndef FIPS_MODULE
+EVP_RAND_CTX *ossl_rand_get0_seed_noncreating(OSSL_LIB_CTX *ctx)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+ EVP_RAND_CTX *ret;
+
+ if (dgbl == NULL)
+ return NULL;
+
+ if (!CRYPTO_THREAD_read_lock(dgbl->lock))
+ return NULL;
+ ret = dgbl->seed;
+ CRYPTO_THREAD_unlock(dgbl->lock);
+ return ret;
+}
+#endif /* !FIPS_MODULE */
static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent,
unsigned int reseed_interval,
@@ -566,8 +666,11 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent,
EVP_RAND *rand;
RAND_GLOBAL *dgbl = rand_get_global(libctx);
EVP_RAND_CTX *ctx;
- OSSL_PARAM params[7], *p = params;
+ OSSL_PARAM params[9], *p = params;
+ const OSSL_PARAM *settables;
+ const char *prov_name;
char *name, *cipher;
+ int use_df = 1;
if (dgbl == NULL)
return NULL;
@@ -577,6 +680,7 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent,
ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG);
return NULL;
}
+ prov_name = ossl_provider_name(EVP_RAND_get0_provider(rand));
ctx = EVP_RAND_CTX_new(rand, parent);
EVP_RAND_free(rand);
if (ctx == NULL) {
@@ -584,20 +688,26 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent,
return NULL;
}
- /*
- * Rather than trying to decode the DRBG settings, just pass them through
- * and rely on the other end to ignore those it doesn't care about.
- */
- cipher = dgbl->rng_cipher != NULL ? dgbl->rng_cipher : "AES-256-CTR";
- *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER,
- cipher, 0);
- if (dgbl->rng_digest != NULL)
+ settables = EVP_RAND_CTX_settable_params(ctx);
+ if (OSSL_PARAM_locate_const(settables, OSSL_DRBG_PARAM_CIPHER)) {
+ cipher = dgbl->rng_cipher != NULL ? dgbl->rng_cipher : "AES-256-CTR";
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER,
+ cipher, 0);
+ }
+ if (dgbl->rng_digest != NULL
+ && OSSL_PARAM_locate_const(settables, OSSL_DRBG_PARAM_DIGEST))
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST,
dgbl->rng_digest, 0);
+ if (prov_name != NULL)
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_CORE_PROV_NAME,
+ (char *)prov_name, 0);
if (dgbl->rng_propq != NULL)
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_PROPERTIES,
dgbl->rng_propq, 0);
- *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_MAC, "HMAC", 0);
+ if (OSSL_PARAM_locate_const(settables, OSSL_ALG_PARAM_MAC))
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_MAC, "HMAC", 0);
+ if (OSSL_PARAM_locate_const(settables, OSSL_DRBG_PARAM_USE_DF))
+ *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_USE_DF, &use_df);
*p++ = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS,
&reseed_interval);
*p++ = OSSL_PARAM_construct_time_t(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL,
@@ -611,14 +721,40 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent,
return ctx;
}
+#if defined(FIPS_MODULE)
+static EVP_RAND_CTX *rand_new_crngt(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent)
+{
+ EVP_RAND *rand;
+ EVP_RAND_CTX *ctx;
+
+ rand = EVP_RAND_fetch(libctx, "CRNG-TEST", "-fips");
+ if (rand == NULL) {
+ ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG);
+ return NULL;
+ }
+ ctx = EVP_RAND_CTX_new(rand, parent);
+ EVP_RAND_free(rand);
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_CREATE_DRBG);
+ return NULL;
+ }
+
+ if (!EVP_RAND_instantiate(ctx, 0, 0, NULL, 0, NULL)) {
+ ERR_raise(ERR_LIB_RAND, RAND_R_ERROR_INSTANTIATING_DRBG);
+ EVP_RAND_CTX_free(ctx);
+ return NULL;
+ }
+ return ctx;
+}
+#endif /* FIPS_MODULE */
+
/*
* Get the primary random generator.
* Returns pointer to its EVP_RAND_CTX on success, NULL on failure.
*
*/
-EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
+static EVP_RAND_CTX *rand_get0_primary(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
{
- RAND_GLOBAL *dgbl = rand_get_global(ctx);
EVP_RAND_CTX *ret;
if (dgbl == NULL)
@@ -642,21 +778,28 @@ EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
return ret;
}
-#ifndef FIPS_MODULE
+#if !defined(FIPS_MODULE) || !defined(OPENSSL_NO_FIPS_JITTER)
+ /* Create a seed source for libcrypto or jitter enabled FIPS provider */
if (dgbl->seed == NULL) {
ERR_set_mark();
dgbl->seed = rand_new_seed(ctx);
ERR_pop_to_mark();
}
-#endif
+#endif /* !FIPS_MODULE || !OPENSSL_NO_FIPS_JITTER */
+
+#if defined(FIPS_MODULE)
+ /* The FIPS provider has entropy health tests instead of the primary */
+ ret = rand_new_crngt(ctx, dgbl->seed);
+#else /* FIPS_MODULE */
+ ret = rand_new_drbg(ctx, dgbl->seed, PRIMARY_RESEED_INTERVAL,
+ PRIMARY_RESEED_TIME_INTERVAL);
+#endif /* FIPS_MODULE */
- ret = dgbl->primary = rand_new_drbg(ctx, dgbl->seed,
- PRIMARY_RESEED_INTERVAL,
- PRIMARY_RESEED_TIME_INTERVAL);
/*
- * The primary DRBG may be shared between multiple threads so we must
- * enable locking.
- */
+ * The primary DRBG may be shared between multiple threads so we must
+ * enable locking.
+ */
+ dgbl->primary = ret;
if (ret != NULL && !EVP_RAND_enable_locking(ret)) {
ERR_raise(ERR_LIB_EVP, EVP_R_UNABLE_TO_ENABLE_LOCKING);
EVP_RAND_CTX_free(ret);
@@ -668,12 +811,19 @@ EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
}
/*
- * Get the public random generator.
+ * Get the primary random generator.
* Returns pointer to its EVP_RAND_CTX on success, NULL on failure.
+ *
*/
-EVP_RAND_CTX *RAND_get0_public(OSSL_LIB_CTX *ctx)
+EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
{
RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+ return dgbl == NULL ? NULL : rand_get0_primary(ctx, dgbl);
+}
+
+static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
+{
EVP_RAND_CTX *rand, *primary;
if (dgbl == NULL)
@@ -681,11 +831,14 @@ EVP_RAND_CTX *RAND_get0_public(OSSL_LIB_CTX *ctx)
rand = CRYPTO_THREAD_get_local(&dgbl->public);
if (rand == NULL) {
- primary = RAND_get0_primary(ctx);
+ primary = rand_get0_primary(ctx, dgbl);
if (primary == NULL)
return NULL;
ctx = ossl_lib_ctx_get_concrete(ctx);
+
+ if (ctx == NULL)
+ return NULL;
/*
* If the private is also NULL then this is the first time we've
* used this thread.
@@ -701,24 +854,30 @@ EVP_RAND_CTX *RAND_get0_public(OSSL_LIB_CTX *ctx)
}
/*
- * Get the private random generator.
+ * Get the public random generator.
* Returns pointer to its EVP_RAND_CTX on success, NULL on failure.
*/
-EVP_RAND_CTX *RAND_get0_private(OSSL_LIB_CTX *ctx)
+EVP_RAND_CTX *RAND_get0_public(OSSL_LIB_CTX *ctx)
{
RAND_GLOBAL *dgbl = rand_get_global(ctx);
- EVP_RAND_CTX *rand, *primary;
- if (dgbl == NULL)
- return NULL;
+ return dgbl == NULL ? NULL : rand_get0_public(ctx, dgbl);
+}
+
+static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
+{
+ EVP_RAND_CTX *rand, *primary;
rand = CRYPTO_THREAD_get_local(&dgbl->private);
if (rand == NULL) {
- primary = RAND_get0_primary(ctx);
+ primary = rand_get0_primary(ctx, dgbl);
if (primary == NULL)
return NULL;
ctx = ossl_lib_ctx_get_concrete(ctx);
+
+ if (ctx == NULL)
+ return NULL;
/*
* If the public is also NULL then this is the first time we've
* used this thread.
@@ -733,6 +892,57 @@ EVP_RAND_CTX *RAND_get0_private(OSSL_LIB_CTX *ctx)
return rand;
}
+/*
+ * Get the private random generator.
+ * Returns pointer to its EVP_RAND_CTX on success, NULL on failure.
+ */
+EVP_RAND_CTX *RAND_get0_private(OSSL_LIB_CTX *ctx)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+ return dgbl == NULL ? NULL : rand_get0_private(ctx, dgbl);
+}
+
+#ifdef FIPS_MODULE
+EVP_RAND_CTX *ossl_rand_get0_private_noncreating(OSSL_LIB_CTX *ctx)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+ if (dgbl == NULL)
+ return NULL;
+
+ return CRYPTO_THREAD_get_local(&dgbl->private);
+}
+#endif
+
+int RAND_set0_public(OSSL_LIB_CTX *ctx, EVP_RAND_CTX *rand)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+ EVP_RAND_CTX *old;
+ int r;
+
+ if (dgbl == NULL)
+ return 0;
+ old = CRYPTO_THREAD_get_local(&dgbl->public);
+ if ((r = CRYPTO_THREAD_set_local(&dgbl->public, rand)) > 0)
+ EVP_RAND_CTX_free(old);
+ return r;
+}
+
+int RAND_set0_private(OSSL_LIB_CTX *ctx, EVP_RAND_CTX *rand)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+ EVP_RAND_CTX *old;
+ int r;
+
+ if (dgbl == NULL)
+ return 0;
+ old = CRYPTO_THREAD_get_local(&dgbl->private);
+ if ((r = CRYPTO_THREAD_set_local(&dgbl->private, rand)) > 0)
+ EVP_RAND_CTX_free(old);
+ return r;
+}
+
#ifndef FIPS_MODULE
static int random_set_string(char **p, const char *s)
{
@@ -740,10 +950,8 @@ static int random_set_string(char **p, const char *s)
if (s != NULL) {
d = OPENSSL_strdup(s);
- if (d == NULL) {
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+ if (d == NULL)
return 0;
- }
}
OPENSSL_free(*p);
*p = d;
@@ -757,7 +965,8 @@ static int random_conf_init(CONF_IMODULE *md, const CONF *cnf)
{
STACK_OF(CONF_VALUE) *elist;
CONF_VALUE *cval;
- RAND_GLOBAL *dgbl = rand_get_global(NCONF_get0_libctx((CONF *)cnf));
+ OSSL_LIB_CTX *libctx = NCONF_get0_libctx((CONF *)cnf);
+ RAND_GLOBAL *dgbl = rand_get_global(libctx);
int i, r = 1;
OSSL_TRACE1(CONF, "Loading random module: section %s\n",
@@ -793,6 +1002,31 @@ static int random_conf_init(CONF_IMODULE *md, const CONF *cnf)
} else if (OPENSSL_strcasecmp(cval->name, "seed_properties") == 0) {
if (!random_set_string(&dgbl->seed_propq, cval->value))
return 0;
+ } else if (OPENSSL_strcasecmp(cval->name, "random_provider") == 0) {
+# ifndef FIPS_MODULE
+ OSSL_PROVIDER *prov = ossl_provider_find(libctx, cval->value, 0);
+
+ if (prov != NULL) {
+ if (!RAND_set1_random_provider(libctx, prov)) {
+ ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
+ OSSL_PROVIDER_unload(prov);
+ return 0;
+ }
+ /*
+ * We need to release the reference from ossl_provider_find because
+ * we don't want to keep a reference counted handle to the provider.
+ *
+ * The provider unload code checks for the random provider and,
+ * if present, our reference will be NULLed when it is fully freed.
+ * The provider load code, conversely, checks the provider name
+ * and re-hooks our reference if required. This means that a load,
+ * hook random provider, use, unload, reload, reuse sequence will
+ * work as expected.
+ */
+ OSSL_PROVIDER_unload(prov);
+ } else if (!set_random_provider_name(dgbl, cval->value))
+ return 0;
+# endif
} else {
ERR_raise_data(ERR_LIB_CRYPTO,
CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION,
@@ -839,7 +1073,7 @@ int RAND_set_seed_source_type(OSSL_LIB_CTX *ctx, const char *seed,
if (dgbl == NULL)
return 0;
- if (dgbl->primary != NULL) {
+ if (dgbl->seed != NULL) {
ERR_raise(ERR_LIB_CRYPTO, RAND_R_ALREADY_INSTANTIATED);
return 0;
}
@@ -847,4 +1081,69 @@ int RAND_set_seed_source_type(OSSL_LIB_CTX *ctx, const char *seed,
&& random_set_string(&dgbl->seed_propq, propq);
}
-#endif
+int RAND_set1_random_provider(OSSL_LIB_CTX *ctx, OSSL_PROVIDER *prov)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+ if (dgbl == NULL)
+ return 0;
+
+ if (prov == NULL) {
+ OPENSSL_free(dgbl->random_provider_name);
+ dgbl->random_provider_name = NULL;
+ dgbl->random_provider = NULL;
+ return 1;
+ }
+
+ if (dgbl->random_provider == prov)
+ return 1;
+
+ if (!set_random_provider_name(dgbl, OSSL_PROVIDER_get0_name(prov)))
+ return 0;
+
+ dgbl->random_provider = prov;
+ return 1;
+}
+
+/*
+ * When a new provider is loaded, we need to check to see if it is the
+ * designated randomness provider and register it if it is.
+ */
+int ossl_rand_check_random_provider_on_load(OSSL_LIB_CTX *ctx,
+ OSSL_PROVIDER *prov)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+ if (dgbl == NULL)
+ return 0;
+
+ /* No random provider name specified, or one is installed already */
+ if (dgbl->random_provider_name == NULL || dgbl->random_provider != NULL)
+ return 1;
+
+ /* Does this provider match the name we're using? */
+ if (strcmp(dgbl->random_provider_name, OSSL_PROVIDER_get0_name(prov)) != 0)
+ return 1;
+
+ dgbl->random_provider = prov;
+ return 1;
+}
+
+/*
+ * When a provider is being unloaded, if it is the randomness provider,
+ * we need to deregister it.
+ */
+int ossl_rand_check_random_provider_on_unload(OSSL_LIB_CTX *ctx,
+ OSSL_PROVIDER *prov)
+{
+ RAND_GLOBAL *dgbl = rand_get_global(ctx);
+
+ if (dgbl == NULL)
+ return 0;
+
+ if (dgbl->random_provider == prov)
+ dgbl->random_provider = NULL;
+ return 1;
+}
+
+#endif /* !FIPS_MODULE */