From 5a9752756b68632320c5aed7b6eb38e63a8ebf31 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 22 Jun 2020 13:12:53 +0200 Subject: [PATCH] CORE: Add OPENSSL_CTX_set0_default(), to set a default library context Applications may want to set their own default library context, possibly per-thread. OPENSSL_CTX_set0_default() does that. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/12228) --- crypto/context.c | 75 +++++++++++++++++++++++++++++----------- doc/man3/OPENSSL_CTX.pod | 33 +++++++++++------- include/openssl/crypto.h | 1 + util/libcrypto.num | 1 + 4 files changed, 77 insertions(+), 33 deletions(-) diff --git a/crypto/context.c b/crypto/context.c index 1c95298ea2..615c55c8c2 100644 --- a/crypto/context.c +++ b/crypto/context.c @@ -39,13 +39,6 @@ struct openssl_ctx_st { struct openssl_ctx_onfree_list_st *onfreelist; }; -#ifndef FIPS_MODULE -static OPENSSL_CTX default_context_int; - -/* Always points at default_context_int if it has been initialised */ -static OPENSSL_CTX *default_context = NULL; -#endif - static int context_init(OPENSSL_CTX *ctx) { size_t i; @@ -120,18 +113,46 @@ static int context_deinit(OPENSSL_CTX *ctx) } #ifndef FIPS_MODULE +/* The default default context */ +static OPENSSL_CTX default_context_int; + +static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT; +static CRYPTO_THREAD_LOCAL default_context_thread_local; + +DEFINE_RUN_ONCE_STATIC(default_context_do_init) +{ + return CRYPTO_THREAD_init_local(&default_context_thread_local, NULL) + && context_init(&default_context_int); +} + void openssl_ctx_default_deinit(void) { - context_deinit(default_context); + context_deinit(&default_context_int); } -static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT; -DEFINE_RUN_ONCE_STATIC(do_default_context_init) +static OPENSSL_CTX *get_thread_default_context(void) { - if (context_init(&default_context_int)) - default_context = &default_context_int; + if (!RUN_ONCE(&default_context_init, default_context_do_init)) + return NULL; - return 1; + return CRYPTO_THREAD_get_local(&default_context_thread_local); +} + +static OPENSSL_CTX *get_default_context(void) +{ + OPENSSL_CTX *current_defctx = get_thread_default_context(); + + if (current_defctx == NULL) + current_defctx = &default_context_int; + return current_defctx; +} + +static int set_default_context(OPENSSL_CTX *defctx) +{ + if (defctx == &default_context_int) + defctx = NULL; + + return CRYPTO_THREAD_set_local(&default_context_thread_local, defctx); } #endif @@ -155,19 +176,31 @@ int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file) void OPENSSL_CTX_free(OPENSSL_CTX *ctx) { - if (ctx != NULL) - context_deinit(ctx); + if (openssl_ctx_is_default(ctx)) + return; + + context_deinit(ctx); OPENSSL_free(ctx); } +OPENSSL_CTX *OPENSSL_CTX_set0_default(OPENSSL_CTX *libctx) +{ +#ifndef FIPS_MODULE + OPENSSL_CTX *current_defctx; + + if ((current_defctx = get_default_context()) != NULL + && set_default_context(libctx)) + return current_defctx; +#endif + + return NULL; +} + OPENSSL_CTX *openssl_ctx_get_concrete(OPENSSL_CTX *ctx) { #ifndef FIPS_MODULE - if (ctx == NULL) { - if (!RUN_ONCE(&default_context_init, do_default_context_init)) - return 0; - return default_context; - } + if (ctx == NULL) + return get_default_context(); #endif return ctx; } @@ -175,7 +208,7 @@ OPENSSL_CTX *openssl_ctx_get_concrete(OPENSSL_CTX *ctx) int openssl_ctx_is_default(OPENSSL_CTX *ctx) { #ifndef FIPS_MODULE - if (ctx == NULL || ctx == default_context) + if (ctx == NULL || ctx == get_default_context()) return 1; #endif return 0; diff --git a/doc/man3/OPENSSL_CTX.pod b/doc/man3/OPENSSL_CTX.pod index 3301250756..0a98451f3d 100644 --- a/doc/man3/OPENSSL_CTX.pod +++ b/doc/man3/OPENSSL_CTX.pod @@ -2,7 +2,8 @@ =head1 NAME -OPENSSL_CTX, OPENSSL_CTX_new, OPENSSL_CTX_free, OPENSSL_CTX_load_config +OPENSSL_CTX, OPENSSL_CTX_new, OPENSSL_CTX_free, OPENSSL_CTX_load_config, +OPENSSL_CTX_set0_default - OpenSSL library context =head1 SYNOPSIS @@ -14,37 +15,45 @@ OPENSSL_CTX, OPENSSL_CTX_new, OPENSSL_CTX_free, OPENSSL_CTX_load_config OPENSSL_CTX *OPENSSL_CTX_new(void); int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file); void OPENSSL_CTX_free(OPENSSL_CTX *ctx); + OPENSSL_CTX *OPENSSL_CTX_set0_default(OPENSSL_CTX *ctx); =head1 DESCRIPTION -C is an internal OpenSSL library context type. -Applications may allocate their own, but may also use C to use -the internal default context with functions that take a C +B is an internal OpenSSL library context type. +Applications may allocate their own, but may also use NULL to use +a default context with functions that take an B argument. -OPENSSL_CTX_new() creates a new OpenSSL library context. When a non default library context is in use care should be taken with multi-threaded applications to properly clean up thread local resources before the OPENSSL_CTX is freed. See L for more information. +OPENSSL_CTX_new() creates a new OpenSSL library context. + OPENSSL_CTX_load_config() loads a configuration file using the given C. -This can be used to associate a libctx with providers that are loaded from -a configuration. +This can be used to associate a library context with providers that are loaded +from a configuration. + +OPENSSL_CTX_free() frees the given I, unless it happens to be the +default OpenSSL library context. -OPENSSL_CTX_free() frees the given C. +OPENSSL_CTX_set0_default() sets the default OpenSSL library context to be +I in the current thread. The previous default library context is +returned. Care should be taken by the caller to restore the previous +default library context with a subsequent call of this function. =head1 RETURN VALUES -OPENSSL_CTX_new() return a library context pointer on success, or -C on error. +OPENSSL_CTX_new() and OPENSSL_CTX_set0_default() return a library context +pointer on success, or NULL on error. OPENSSL_CTX_free() doesn't return any value. =head1 HISTORY -OPENSSL_CTX, OPENSSL_CTX_new(), OPENSSL_CTX_load_config() and OPENSSL_CTX_free() -were added in OpenSSL 3.0. +OPENSSL_CTX, OPENSSL_CTX_new(), OPENSSL_CTX_load_config(), OPENSSL_CTX_free() +and OPENSSL_CTX_set0_default() were added in OpenSSL 3.0. =head1 COPYRIGHT diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h index 58965de0e8..33296b6ada 100644 --- a/include/openssl/crypto.h +++ b/include/openssl/crypto.h @@ -494,6 +494,7 @@ int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b); OPENSSL_CTX *OPENSSL_CTX_new(void); int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file); void OPENSSL_CTX_free(OPENSSL_CTX *); +OPENSSL_CTX *OPENSSL_CTX_set0_default(OPENSSL_CTX *libctx); # ifdef __cplusplus } diff --git a/util/libcrypto.num b/util/libcrypto.num index ee3aa6d97c..22c7cdc709 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5134,3 +5134,4 @@ OSSL_PROVIDER_get_capabilities ? 3_0_0 EXIST::FUNCTION: EC_GROUP_new_by_curve_name_with_libctx ? 3_0_0 EXIST::FUNCTION:EC EC_KEY_new_with_libctx ? 3_0_0 EXIST::FUNCTION:EC EC_KEY_new_by_curve_name_with_libctx ? 3_0_0 EXIST::FUNCTION:EC +OPENSSL_CTX_set0_default ? 3_0_0 EXIST::FUNCTION: -- 2.34.1