cmp_client_test.c: add tests for end_time being initialized for RR/GENM
[openssl.git] / crypto / provider_conf.c
index 7689301b757b4c202b06bed22eb2f7692b42fbaf..9751caac8e55d088fa0132dcc0ca2a1a46dac090 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2022 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
 #include "internal/provider.h"
 #include "internal/cryptlib.h"
 #include "provider_local.h"
+#include "crypto/context.h"
 
 DEFINE_STACK_OF(OSSL_PROVIDER)
 
 /* PROVIDER config module */
 
 typedef struct {
+    CRYPTO_RWLOCK *lock;
     STACK_OF(OSSL_PROVIDER) *activated_providers;
 } PROVIDER_CONF_GLOBAL;
 
-static void *prov_conf_ossl_ctx_new(OSSL_LIB_CTX *libctx)
+void *ossl_prov_conf_ctx_new(OSSL_LIB_CTX *libctx)
 {
     PROVIDER_CONF_GLOBAL *pcgbl = OPENSSL_zalloc(sizeof(*pcgbl));
 
     if (pcgbl == NULL)
         return NULL;
 
+    pcgbl->lock = CRYPTO_THREAD_lock_new();
+    if (pcgbl->lock == NULL) {
+        OPENSSL_free(pcgbl);
+        return NULL;
+    }
+
     return pcgbl;
 }
 
-static void prov_conf_ossl_ctx_free(void *vpcgbl)
+void ossl_prov_conf_ctx_free(void *vpcgbl)
 {
     PROVIDER_CONF_GLOBAL *pcgbl = vpcgbl;
 
@@ -43,16 +51,10 @@ static void prov_conf_ossl_ctx_free(void *vpcgbl)
                               ossl_provider_free);
 
     OSSL_TRACE(CONF, "Cleaned up providers\n");
+    CRYPTO_THREAD_lock_free(pcgbl->lock);
     OPENSSL_free(pcgbl);
 }
 
-static const OSSL_LIB_CTX_METHOD provider_conf_ossl_ctx_method = {
-    /* Must be freed before the provider store is freed */
-    OSSL_LIB_CTX_METHOD_PRIORITY_2,
-    prov_conf_ossl_ctx_new,
-    prov_conf_ossl_ctx_free,
-};
-
 static const char *skip_dot(const char *name)
 {
     const char *p = strchr(name, '.');
@@ -128,19 +130,88 @@ static int prov_already_activated(const char *name,
     return 0;
 }
 
+static int provider_conf_activate(OSSL_LIB_CTX *libctx, const char *name,
+                                  const char *value, const char *path,
+                                  int soft, const CONF *cnf)
+{
+    PROVIDER_CONF_GLOBAL *pcgbl
+        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_PROVIDER_CONF_INDEX);
+    OSSL_PROVIDER *prov = NULL, *actual = NULL;
+    int ok = 0;
+
+    if (pcgbl == NULL || !CRYPTO_THREAD_write_lock(pcgbl->lock)) {
+        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (!prov_already_activated(name, pcgbl->activated_providers)) {
+        /*
+        * There is an attempt to activate a provider, so we should disable
+        * loading of fallbacks. Otherwise a misconfiguration could mean the
+        * intended provider does not get loaded. Subsequent fetches could
+        * then fallback to the default provider - which may be the wrong
+        * thing.
+        */
+        if (!ossl_provider_disable_fallback_loading(libctx)) {
+            CRYPTO_THREAD_unlock(pcgbl->lock);
+            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        prov = ossl_provider_find(libctx, name, 1);
+        if (prov == NULL)
+            prov = ossl_provider_new(libctx, name, NULL, 1);
+        if (prov == NULL) {
+            CRYPTO_THREAD_unlock(pcgbl->lock);
+            if (soft)
+                ERR_clear_error();
+            return 0;
+        }
+
+        if (path != NULL)
+            ossl_provider_set_module_path(prov, path);
+
+        ok = provider_conf_params(prov, NULL, NULL, value, cnf);
+
+        if (ok) {
+            if (!ossl_provider_activate(prov, 1, 0)) {
+                ok = 0;
+            } else if (!ossl_provider_add_to_store(prov, &actual, 0)) {
+                ossl_provider_deactivate(prov, 1);
+                ok = 0;
+            } else if (actual != prov
+                       && !ossl_provider_activate(actual, 1, 0)) {
+                ossl_provider_free(actual);
+                ok = 0;
+            } else {
+                if (pcgbl->activated_providers == NULL)
+                    pcgbl->activated_providers = sk_OSSL_PROVIDER_new_null();
+                if (pcgbl->activated_providers == NULL
+                    || !sk_OSSL_PROVIDER_push(pcgbl->activated_providers,
+                                              actual)) {
+                    ossl_provider_deactivate(actual, 1);
+                    ossl_provider_free(actual);
+                    ok = 0;
+                } else {
+                    ok = 1;
+                }
+            }
+        }
+        if (!ok)
+            ossl_provider_free(prov);
+    }
+    CRYPTO_THREAD_unlock(pcgbl->lock);
+
+    return ok;
+}
+
 static int provider_conf_load(OSSL_LIB_CTX *libctx, const char *name,
                               const char *value, const CONF *cnf)
 {
     int i;
     STACK_OF(CONF_VALUE) *ecmds;
     int soft = 0;
-    OSSL_PROVIDER *prov = NULL, *actual = NULL;
     const char *path = NULL;
     long activate = 0;
     int ok = 0;
-    PROVIDER_CONF_GLOBAL *pcgbl
-        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_PROVIDER_CONF_INDEX,
-                                &provider_conf_ossl_ctx_method);
 
     name = skip_dot(name);
     OSSL_TRACE1(CONF, "Configuring provider %s\n", name);
@@ -176,65 +247,22 @@ static int provider_conf_load(OSSL_LIB_CTX *libctx, const char *name,
             activate = 1;
     }
 
-    if (activate && !prov_already_activated(name, pcgbl->activated_providers)) {
-        /*
-        * There is an attempt to activate a provider, so we should disable
-        * loading of fallbacks. Otherwise a misconfiguration could mean the
-        * intended provider does not get loaded. Subsequent fetches could then
-        * fallback to the default provider - which may be the wrong thing.
-        */
-        if (!ossl_provider_disable_fallback_loading(libctx)) {
-            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
-        prov = ossl_provider_find(libctx, name, 1);
-        if (prov == NULL)
-            prov = ossl_provider_new(libctx, name, NULL, 1);
-        if (prov == NULL) {
-            if (soft)
-                ERR_clear_error();
-            return 0;
-        }
-
-        if (path != NULL)
-            ossl_provider_set_module_path(prov, path);
-
-        ok = provider_conf_params(prov, NULL, NULL, value, cnf);
-
-        if (ok) {
-            if (!ossl_provider_activate(prov, 1, 0)) {
-                ok = 0;
-            } else if (!ossl_provider_add_to_store(prov, &actual, 0)) {
-                ossl_provider_deactivate(prov);
-                ok = 0;
-            } else {
-                if (pcgbl->activated_providers == NULL)
-                    pcgbl->activated_providers = sk_OSSL_PROVIDER_new_null();
-                sk_OSSL_PROVIDER_push(pcgbl->activated_providers, actual);
-                ok = 1;
-            }
-        }
-
-        if (!ok)
-            ossl_provider_free(prov);
-    } else if (!activate) {
+    if (activate) {
+        ok = provider_conf_activate(libctx, name, value, path, soft, cnf);
+    } else {
         OSSL_PROVIDER_INFO entry;
 
         memset(&entry, 0, sizeof(entry));
         ok = 1;
         if (name != NULL) {
             entry.name = OPENSSL_strdup(name);
-            if (entry.name == NULL) {
-                ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+            if (entry.name == NULL)
                 ok = 0;
-            }
         }
         if (ok && path != NULL) {
             entry.path = OPENSSL_strdup(path);
-            if (entry.path == NULL) {
-                ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+            if (entry.path == NULL)
                 ok = 0;
-            }
         }
         if (ok)
             ok = provider_conf_params(NULL, &entry, NULL, value, cnf);