diff options
Diffstat (limited to 'crypto/rand/rand_lib.c')
| -rw-r--r-- | crypto/rand/rand_lib.c | 559 |
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 */ |
