CORE: Add OPENSSL_CTX_set0_default(), to set a default library context
authorRichard Levitte <levitte@openssl.org>
Mon, 22 Jun 2020 11:12:53 +0000 (13:12 +0200)
committerRichard Levitte <levitte@openssl.org>
Sun, 28 Jun 2020 08:55:51 +0000 (10:55 +0200)
Applications may want to set their own default library context,
possibly per-thread.  OPENSSL_CTX_set0_default() does that.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/12228)

crypto/context.c
doc/man3/OPENSSL_CTX.pod
include/openssl/crypto.h
util/libcrypto.num

index 1c95298..615c55c 100644 (file)
@@ -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;
index 3301250..0a98451 100644 (file)
@@ -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<OPENSSL_CTX> is an internal OpenSSL library context type.
-Applications may allocate their own, but may also use C<NULL> to use
-the internal default context with functions that take a C<OPENSSL_CTX>
+B<OPENSSL_CTX> 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<OPENSSL_CTX>
 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<OPENSSL_thread_stop_ex(3)> for more information.
 
+OPENSSL_CTX_new() creates a new OpenSSL library context.
+
 OPENSSL_CTX_load_config() loads a configuration file using the given C<ctx>.
-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<ctx>, unless it happens to be the
+default OpenSSL library context.
 
-OPENSSL_CTX_free() frees the given C<ctx>.
+OPENSSL_CTX_set0_default() sets the default OpenSSL library context to be
+I<ctx> 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<NULL> 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
 
index 58965de..33296b6 100644 (file)
@@ -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
 }
index ee3aa6d..22c7cdc 100644 (file)
@@ -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: