mirror of
https://github.com/openssl/openssl.git
synced 2025-02-23 14:42:15 +08:00
Add support for random provider
Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/24498)
This commit is contained in:
parent
5b5c24d99e
commit
b1cca25999
@ -175,7 +175,7 @@ struct ossl_provider_st {
|
||||
OSSL_FUNC_provider_get_params_fn *get_params;
|
||||
OSSL_FUNC_provider_get_capabilities_fn *get_capabilities;
|
||||
OSSL_FUNC_provider_self_test_fn *self_test;
|
||||
OSSL_FUNC_provider_random_fn *random;
|
||||
OSSL_FUNC_provider_random_bytes_fn *random_bytes;
|
||||
OSSL_FUNC_provider_query_operation_fn *query_operation;
|
||||
OSSL_FUNC_provider_unquery_operation_fn *unquery_operation;
|
||||
|
||||
@ -1068,8 +1068,9 @@ static int provider_init(OSSL_PROVIDER *prov)
|
||||
prov->self_test =
|
||||
OSSL_FUNC_provider_self_test(provider_dispatch);
|
||||
break;
|
||||
case OSSL_FUNC_PROVIDER_RANDOM:
|
||||
prov->random = OSSL_FUNC_provider_random(provider_dispatch);
|
||||
case OSSL_FUNC_PROVIDER_RANDOM_BYTES:
|
||||
prov->random_bytes =
|
||||
OSSL_FUNC_provider_random_bytes(provider_dispatch);
|
||||
break;
|
||||
case OSSL_FUNC_PROVIDER_GET_CAPABILITIES:
|
||||
prov->get_capabilities =
|
||||
@ -1168,6 +1169,12 @@ static int provider_deactivate(OSSL_PROVIDER *prov, int upcalls,
|
||||
if (!ossl_assert(prov != NULL))
|
||||
return -1;
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
if (prov->random_bytes != NULL
|
||||
&& !ossl_rand_check_random_provider_on_unload(prov->libctx, prov))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* No need to lock if we've got no store because we've not been shared with
|
||||
* other threads.
|
||||
@ -1264,6 +1271,10 @@ static int provider_activate(OSSL_PROVIDER *prov, int lock, int upcalls)
|
||||
}
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
if (prov->random_bytes != NULL
|
||||
&& !ossl_rand_check_random_provider_on_load(prov->libctx, prov))
|
||||
return -1;
|
||||
|
||||
if (prov->ischild && upcalls && !ossl_provider_up_ref_parent(prov, 1))
|
||||
return -1;
|
||||
#endif
|
||||
@ -1864,11 +1875,12 @@ int ossl_provider_self_test(const OSSL_PROVIDER *prov)
|
||||
* If tracing is enabled, a message is printed indicating the requested
|
||||
* capabilities.
|
||||
*/
|
||||
int ossl_provider_random(const OSSL_PROVIDER *prov, int which, void *buf, size_t n,
|
||||
unsigned int strength)
|
||||
int ossl_provider_random_bytes(const OSSL_PROVIDER *prov, int which,
|
||||
void *buf, size_t n, unsigned int strength)
|
||||
{
|
||||
return prov->random == NULL ? 0 : prov->random(prov->provctx, which, buf, n,
|
||||
strength);
|
||||
return prov->random_bytes == NULL ? 0
|
||||
: prov->random_bytes(prov->provctx, which,
|
||||
buf, n, strength);
|
||||
}
|
||||
|
||||
int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov,
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "rand_local.h"
|
||||
#include "crypto/context.h"
|
||||
|
||||
|
||||
#ifndef OPENSSL_DEFAULT_SEED_SRC
|
||||
# define OPENSSL_DEFAULT_SEED_SRC SEED-SRC
|
||||
#endif
|
||||
@ -58,6 +57,7 @@ typedef struct rand_global_st {
|
||||
*/
|
||||
#ifndef FIPS_MODULE
|
||||
OSSL_PROVIDER *random_provider;
|
||||
char *random_provider_name;
|
||||
#endif /* !FIPS_MODULE */
|
||||
|
||||
/*
|
||||
@ -91,6 +91,7 @@ typedef struct rand_global_st {
|
||||
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);
|
||||
|
||||
@ -111,6 +112,24 @@ static RAND_GLOBAL *rand_get_global(OSSL_LIB_CTX *libctx)
|
||||
# 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 = 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;
|
||||
@ -431,9 +450,9 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
|
||||
return 0;
|
||||
#ifndef FIPS_MODULE
|
||||
if (dgbl->random_provider != NULL)
|
||||
return ossl_provider_random(dgbl->random_provider,
|
||||
OSSL_PROV_RANDOM_PRIVATE,
|
||||
buf, num, strength);
|
||||
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)
|
||||
@ -470,9 +489,9 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
|
||||
return 0;
|
||||
#ifndef FIPS_MODULE
|
||||
if (dgbl->random_provider != NULL)
|
||||
return ossl_provider_random(dgbl->random_provider,
|
||||
OSSL_PROV_RANDOM_PRIVATE,
|
||||
buf, num, strength);
|
||||
return ossl_provider_random_bytes(dgbl->random_provider,
|
||||
OSSL_PROV_RANDOM_PUBLIC,
|
||||
buf, num, strength);
|
||||
#endif /* !FIPS_MODULE */
|
||||
|
||||
rand = rand_get0_public(ctx, dgbl);
|
||||
@ -505,7 +524,12 @@ void *ossl_rand_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 = strdup(random_provider_fips_name);
|
||||
if (dgbl->random_provider_name == NULL)
|
||||
goto err0;
|
||||
#endif
|
||||
|
||||
dgbl->lock = CRYPTO_THREAD_lock_new();
|
||||
@ -524,6 +548,10 @@ void *ossl_rand_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;
|
||||
}
|
||||
@ -541,7 +569,7 @@ void ossl_rand_ctx_free(void *vdgbl)
|
||||
EVP_RAND_CTX_free(dgbl->primary);
|
||||
EVP_RAND_CTX_free(dgbl->seed);
|
||||
#ifndef FIPS_MODULE
|
||||
OSSL_PROVIDER_unload(dgbl->random_provider);
|
||||
OPENSSL_free(dgbl->random_provider_name);
|
||||
#endif /* !FIPS_MODULE */
|
||||
OPENSSL_free(dgbl->rng_name);
|
||||
OPENSSL_free(dgbl->rng_cipher);
|
||||
@ -778,9 +806,8 @@ static EVP_RAND_CTX *rand_new_crngt(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent)
|
||||
* 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)
|
||||
@ -836,6 +863,18 @@ EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
@ -845,7 +884,7 @@ static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
|
||||
|
||||
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;
|
||||
|
||||
@ -884,7 +923,7 @@ static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl)
|
||||
|
||||
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;
|
||||
|
||||
@ -979,7 +1018,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",
|
||||
@ -1015,6 +1055,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,
|
||||
@ -1069,16 +1134,69 @@ int RAND_set_seed_source_type(OSSL_LIB_CTX *ctx, const char *seed,
|
||||
&& random_set_string(&dgbl->seed_propq, propq);
|
||||
}
|
||||
|
||||
int RAND_set0_random_provider(OSSL_LIB_CTX *ctx, OSSL_PROVIDER *p)
|
||||
int RAND_set1_random_provider(OSSL_LIB_CTX *ctx, OSSL_PROVIDER *prov)
|
||||
{
|
||||
RAND_GLOBAL *dgbl = rand_get_global(ctx);
|
||||
OSSL_PROVIDER *old;
|
||||
|
||||
if (dgbl == NULL)
|
||||
return 0;
|
||||
old = dgbl->random_provider;
|
||||
dgbl->random_provider = p;
|
||||
OSSL_PROVIDER_unload(old);
|
||||
|
||||
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 */
|
||||
|
@ -151,4 +151,15 @@ uint32_t ossl_rand_uniform_uint32(OSSL_LIB_CTX *ctx, uint32_t upper, int *err);
|
||||
uint32_t ossl_rand_range_uint32(OSSL_LIB_CTX *ctx, uint32_t lower, uint32_t upper,
|
||||
int *err);
|
||||
|
||||
/*
|
||||
* Check if the named provider is the nominated entropy/random provider.
|
||||
* If it is, use it.
|
||||
*/
|
||||
# ifndef FIPS_MODULE
|
||||
int ossl_rand_check_random_provider_on_load(OSSL_LIB_CTX *ctx,
|
||||
OSSL_PROVIDER *prov);
|
||||
int ossl_rand_check_random_provider_on_unload(OSSL_LIB_CTX *ctx,
|
||||
OSSL_PROVIDER *prov);
|
||||
# endif /* FIPS_MODULE */
|
||||
|
||||
#endif
|
||||
|
@ -84,8 +84,8 @@ int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov,
|
||||
OSSL_CALLBACK *cb,
|
||||
void *arg);
|
||||
int ossl_provider_self_test(const OSSL_PROVIDER *prov);
|
||||
int ossl_provider_random(const OSSL_PROVIDER *prov, int which, void *buf, size_t n,
|
||||
unsigned int strength);
|
||||
int ossl_provider_random_bytes(const OSSL_PROVIDER *prov, int which,
|
||||
void *buf, size_t n, unsigned int strength);
|
||||
const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov,
|
||||
int operation_id,
|
||||
int *no_cache);
|
||||
|
@ -269,10 +269,10 @@ OSSL_CORE_MAKE_FUNC(int, provider_get_capabilities, (void *provctx,
|
||||
const char *capability, OSSL_CALLBACK *cb, void *arg))
|
||||
# define OSSL_FUNC_PROVIDER_SELF_TEST 1031
|
||||
OSSL_CORE_MAKE_FUNC(int, provider_self_test, (void *provctx))
|
||||
# define OSSL_FUNC_PROVIDER_RANDOM 1032
|
||||
OSSL_CORE_MAKE_FUNC(int, provider_random, (void *provctx, int which,
|
||||
void *buf, size_t n,
|
||||
unsigned int strength))
|
||||
# define OSSL_FUNC_PROVIDER_RANDOM_BYTES 1032
|
||||
OSSL_CORE_MAKE_FUNC(int, provider_random_bytes, (void *provctx, int which,
|
||||
void *buf, size_t n,
|
||||
unsigned int strength))
|
||||
|
||||
/* Operations */
|
||||
|
||||
|
@ -41,7 +41,7 @@ static OSSL_FUNC_provider_gettable_params_fn fips_gettable_params;
|
||||
static OSSL_FUNC_provider_get_params_fn fips_get_params;
|
||||
static OSSL_FUNC_provider_query_operation_fn fips_query;
|
||||
static OSSL_FUNC_provider_query_operation_fn fips_query_internal;
|
||||
static OSSL_FUNC_provider_random_fn fips_random;
|
||||
static OSSL_FUNC_provider_random_bytes_fn fips_random_bytes;
|
||||
|
||||
#define ALGC(NAMES, FUNC, CHECK) \
|
||||
{ { NAMES, FIPS_DEFAULT_PROPERTIES, FUNC }, CHECK }
|
||||
@ -122,8 +122,8 @@ void ossl_fips_prov_ossl_ctx_free(void *fgbl)
|
||||
OPENSSL_free(fgbl);
|
||||
}
|
||||
|
||||
static int fips_random(ossl_unused void *vprov, int which, void *buf, size_t n,
|
||||
unsigned int strength)
|
||||
static int fips_random_bytes(ossl_unused void *vprov, int which,
|
||||
void *buf, size_t n, unsigned int strength)
|
||||
{
|
||||
OSSL_LIB_CTX *libctx;
|
||||
PROV_CTX *prov = (PROV_CTX *)vprov;
|
||||
@ -619,7 +619,7 @@ static const OSSL_DISPATCH fips_dispatch_table[] = {
|
||||
{ OSSL_FUNC_PROVIDER_GET_CAPABILITIES,
|
||||
(void (*)(void))ossl_prov_get_capabilities },
|
||||
{ OSSL_FUNC_PROVIDER_SELF_TEST, (void (*)(void))fips_self_test },
|
||||
{ OSSL_FUNC_PROVIDER_RANDOM, (void (*)(void))fips_random },
|
||||
{ OSSL_FUNC_PROVIDER_RANDOM_BYTES, (void (*)(void))fips_random_bytes },
|
||||
OSSL_DISPATCH_END
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user