CORE: Add OPENSSL_CTX_set0_default(), to set a default library context
[openssl.git] / crypto / context.c
index a2e19bac5442cb94f41347b7139f735a22e0c718..615c55c8c299a660c64fcd79166b66994691158c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2020 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
@@ -7,7 +7,8 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include "internal/cryptlib_int.h"
+#include "crypto/cryptlib.h"
+#include <openssl/conf.h>
 #include "internal/thread_once.h"
 #include "internal/property.h"
 
@@ -38,13 +39,6 @@ struct openssl_ctx_st {
     struct openssl_ctx_onfree_list_st *onfreelist;
 };
 
-#ifndef FIPS_MODE
-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;
@@ -118,19 +112,47 @@ static int context_deinit(OPENSSL_CTX *ctx)
     return 1;
 }
 
-#ifndef FIPS_MODE
+#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
 
@@ -145,25 +167,53 @@ OPENSSL_CTX *OPENSSL_CTX_new(void)
     return ctx;
 }
 
+#ifndef FIPS_MODULE
+int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file)
+{
+    return CONF_modules_load_file_with_libctx(ctx, config_file, NULL, 0) > 0;
+}
+#endif
+
 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_MODE
-    if (ctx == NULL) {
-        if (!RUN_ONCE(&default_context_init, do_default_context_init))
-            return 0;
-        return default_context;
-    }
+#ifndef FIPS_MODULE
+    if (ctx == NULL)
+        return get_default_context();
 #endif
     return ctx;
 }
 
+int openssl_ctx_is_default(OPENSSL_CTX *ctx)
+{
+#ifndef FIPS_MODULE
+    if (ctx == NULL || ctx == get_default_context())
+        return 1;
+#endif
+    return 0;
+}
+
 static void openssl_ctx_generic_new(void *parent_ign, void *ptr_ign,
                                     CRYPTO_EX_DATA *ad, int index,
                                     long argl_ign, void *argp)