]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/property/property.c
CORE: Encure that cached fetches can be done per provider
[thirdparty/openssl.git] / crypto / property / property.c
index b120dbe46057222b5062ab81eb9d70c4e7df8ef5..5df1bfc221d56ff04c6c794824f69a60ec98d236 100644 (file)
@@ -12,7 +12,9 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include <openssl/crypto.h>
+#include "internal/core.h"
 #include "internal/property.h"
+#include "internal/provider.h"
 #include "crypto/ctype.h"
 #include <openssl/lhash.h>
 #include <openssl/rand.h>
@@ -43,6 +45,7 @@ typedef struct {
 DEFINE_STACK_OF(IMPLEMENTATION)
 
 typedef struct {
+    const OSSL_PROVIDER *provider;
     const char *query;
     METHOD method;
     char body[1];
@@ -72,26 +75,33 @@ typedef struct {
 
 DEFINE_SPARSE_ARRAY_OF(ALGORITHM);
 
+typedef struct ossl_global_properties_st {
+    OSSL_PROPERTY_LIST *list;
+#ifndef FIPS_MODULE
+    unsigned int no_mirrored : 1;
+#endif
+} OSSL_GLOBAL_PROPERTIES;
+
 static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid);
 
 /* Global properties are stored per library context */
-static void ossl_ctx_global_properties_free(void *vstore)
+static void ossl_ctx_global_properties_free(void *vglobp)
 {
-    OSSL_PROPERTY_LIST **plp = vstore;
+    OSSL_GLOBAL_PROPERTIES *globp = vglobp;
 
-    if (plp != NULL) {
-        ossl_property_free(*plp);
-        OPENSSL_free(plp);
+    if (globp != NULL) {
+        ossl_property_free(globp->list);
+        OPENSSL_free(globp);
     }
 }
 
 static void *ossl_ctx_global_properties_new(OSSL_LIB_CTX *ctx)
 {
-    return OPENSSL_zalloc(sizeof(OSSL_PROPERTY_LIST **));
+    return OPENSSL_zalloc(sizeof(OSSL_GLOBAL_PROPERTIES));
 }
 
-
 static const OSSL_LIB_CTX_METHOD ossl_ctx_global_properties_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     ossl_ctx_global_properties_new,
     ossl_ctx_global_properties_free,
 };
@@ -99,14 +109,38 @@ static const OSSL_LIB_CTX_METHOD ossl_ctx_global_properties_method = {
 OSSL_PROPERTY_LIST **ossl_ctx_global_properties(OSSL_LIB_CTX *libctx,
                                                 int loadconfig)
 {
+    OSSL_GLOBAL_PROPERTIES *globp;
+
 #ifndef FIPS_MODULE
     if (loadconfig && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))
         return NULL;
 #endif
-    return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
-                                 &ossl_ctx_global_properties_method);
+    globp = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
+                                  &ossl_ctx_global_properties_method);
+
+    return &globp->list;
 }
 
+#ifndef FIPS_MODULE
+int ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx)
+{
+    OSSL_GLOBAL_PROPERTIES *globp
+        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
+                                &ossl_ctx_global_properties_method);
+
+    return globp->no_mirrored ? 1 : 0;
+}
+
+void ossl_global_properties_stop_mirroring(OSSL_LIB_CTX *libctx)
+{
+    OSSL_GLOBAL_PROPERTIES *globp
+        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
+                                &ossl_ctx_global_properties_method);
+
+    globp->no_mirrored = 1;
+}
+#endif
+
 static int ossl_method_up_ref(METHOD *method)
 {
     return (*method->up_ref)(method->method);
@@ -139,7 +173,13 @@ static unsigned long query_hash(const QUERY *a)
 
 static int query_cmp(const QUERY *a, const QUERY *b)
 {
-    return strcmp(a->query, b->query);
+    int res = strcmp(a->query, b->query);
+
+    if (res == 0 && a->provider != NULL && b->provider != NULL)
+        res = b->provider > a->provider ? 1
+            : b->provider < a->provider ? -1
+            : 0;
+    return res;
 }
 
 static void impl_free(IMPLEMENTATION *impl)
@@ -227,6 +267,9 @@ int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov,
     if (properties == NULL)
         properties = "";
 
+    if (!ossl_assert(prov != NULL))
+        return 0;
+
     /* Create new entry */
     impl = OPENSSL_malloc(sizeof(*impl));
     if (impl == NULL)
@@ -240,12 +283,7 @@ int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov,
     }
     impl->provider = prov;
 
-    /*
-     * Insert into the hash table if required.
-     *
-     * A write lock is used unconditionally because we wend our way down to the
-     * property string code which isn't locking friendly.
-     */
+    /* Insert into the hash table if required */
     if (!ossl_property_write_lock(store)) {
         OPENSSL_free(impl);
         return 0;
@@ -329,30 +367,63 @@ int ossl_method_store_remove(OSSL_METHOD_STORE *store, int nid,
     return 0;
 }
 
-int ossl_method_store_fetch(OSSL_METHOD_STORE *store, int nid,
-                            const char *prop_query,
-                            void **method)
+static void alg_do_one(ALGORITHM *alg, IMPLEMENTATION *impl,
+                       void (*fn)(int id, void *method, void *fnarg),
+                       void *fnarg)
+{
+    fn(alg->nid, impl->method.method, fnarg);
+}
+
+struct alg_do_each_data_st {
+    void (*fn)(int id, void *method, void *fnarg);
+    void *fnarg;
+};
+
+static void alg_do_each(ossl_uintmax_t idx, ALGORITHM *alg, void *arg)
+{
+    struct alg_do_each_data_st *data = arg;
+    int i, end = sk_IMPLEMENTATION_num(alg->impls);
+
+    for (i = 0; i < end; i++) {
+        IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i);
+
+        alg_do_one(alg, impl, data->fn, data->fnarg);
+    }
+}
+
+void ossl_method_store_do_all(OSSL_METHOD_STORE *store,
+                              void (*fn)(int id, void *method, void *fnarg),
+                              void *fnarg)
+{
+    struct alg_do_each_data_st data;
+
+    data.fn = fn;
+    data.fnarg = fnarg;
+    if (store != NULL)
+        ossl_sa_ALGORITHM_doall_arg(store->algs, alg_do_each, &data);
+}
+
+int ossl_method_store_fetch(OSSL_METHOD_STORE *store,
+                            int nid, const char *prop_query,
+                            const OSSL_PROVIDER **prov_rw, void **method)
 {
     OSSL_PROPERTY_LIST **plp;
     ALGORITHM *alg;
-    IMPLEMENTATION *impl;
+    IMPLEMENTATION *impl, *best_impl = NULL;
     OSSL_PROPERTY_LIST *pq = NULL, *p2 = NULL;
-    METHOD *best_method = NULL;
+    const OSSL_PROVIDER *prov = prov_rw != NULL ? *prov_rw : NULL;
     int ret = 0;
     int j, best = -1, score, optional;
 
 #ifndef FIPS_MODULE
     if (!OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))
-       return 0;
+        return 0;
 #endif
 
     if (nid <= 0 || method == NULL || store == NULL)
         return 0;
 
-    /*
-     * This only needs to be a read lock, because queries never create property
-     * names or value and thus don't modify any of the property string layer.
-     */
+    /* This only needs to be a read lock, because the query won't create anything */
     if (!ossl_property_read_lock(store))
         return 0;
     alg = ossl_method_store_retrieve(store, nid);
@@ -377,29 +448,38 @@ int ossl_method_store_fetch(OSSL_METHOD_STORE *store, int nid,
     }
 
     if (pq == NULL) {
-        if ((impl = sk_IMPLEMENTATION_value(alg->impls, 0)) != NULL) {
-            best_method = &impl->method;
-            ret = 1;
+        for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) {
+            if ((impl = sk_IMPLEMENTATION_value(alg->impls, j)) != NULL
+                && (prov == NULL || impl->provider == prov)) {
+                best_impl = impl;
+                ret = 1;
+                break;
+            }
         }
         goto fin;
     }
     optional = ossl_property_has_optional(pq);
     for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) {
-        impl = sk_IMPLEMENTATION_value(alg->impls, j);
-        score = ossl_property_match_count(pq, impl->properties);
-        if (score > best) {
-            best_method = &impl->method;
-            best = score;
-            ret = 1;
-            if (!optional)
-                goto fin;
+        if ((impl = sk_IMPLEMENTATION_value(alg->impls, j)) != NULL
+            && (prov == NULL || impl->provider == prov)) {
+            score = ossl_property_match_count(pq, impl->properties);
+            if (score > best) {
+                best_impl = impl;
+                best = score;
+                ret = 1;
+                if (!optional)
+                    goto fin;
+            }
         }
     }
 fin:
-    if (ret && ossl_method_up_ref(best_method))
-        *method = best_method->method;
-    else
+    if (ret && ossl_method_up_ref(&best_impl->method)) {
+        *method = best_impl->method.method;
+        if (prov_rw != NULL)
+            *prov_rw = best_impl->provider;
+    } else {
         ret = 0;
+    }
     ossl_property_unlock(store);
     ossl_property_free(p2);
     return ret;
@@ -425,6 +505,7 @@ static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid)
     ALGORITHM *alg = ossl_method_store_retrieve(store, nid);
 
     if (alg != NULL) {
+        ossl_provider_clear_all_operation_bits(store->ctx);
         store->nelem -= lh_QUERY_num_items(alg->cache);
         impl_cache_flush_alg(0, alg, NULL);
     }
@@ -436,6 +517,7 @@ int ossl_method_store_flush_cache(OSSL_METHOD_STORE *store, int all)
 
     if (!ossl_property_write_lock(store))
         return 0;
+    ossl_provider_clear_all_operation_bits(store->ctx);
     ossl_sa_ALGORITHM_doall_arg(store->algs, &impl_cache_flush_alg, arg);
     store->nelem = 0;
     ossl_property_unlock(store);
@@ -500,13 +582,14 @@ static void ossl_method_cache_flush_some(OSSL_METHOD_STORE *store)
     state.nelem = 0;
     if ((state.seed = OPENSSL_rdtsc()) == 0)
         state.seed = 1;
+    ossl_provider_clear_all_operation_bits(store->ctx);
     store->need_flush = 0;
     ossl_sa_ALGORITHM_doall_arg(store->algs, &impl_cache_flush_one_alg, &state);
     store->nelem = state.nelem;
 }
 
-int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, int nid,
-                                const char *prop_query, void **method)
+int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
+                                int nid, const char *prop_query, void **method)
 {
     ALGORITHM *alg;
     QUERY elem, *r;
@@ -522,6 +605,7 @@ int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, int nid,
         goto err;
 
     elem.query = prop_query != NULL ? prop_query : "";
+    elem.provider = prov;
     r = lh_QUERY_retrieve(alg->cache, &elem);
     if (r == NULL)
         goto err;
@@ -534,8 +618,8 @@ err:
     return res;
 }
 
-int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, int nid,
-                                const char *prop_query, void *method,
+int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
+                                int nid, const char *prop_query, void *method,
                                 int (*method_up_ref)(void *),
                                 void (*method_destruct)(void *))
 {
@@ -549,6 +633,9 @@ int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, int nid,
     if (prop_query == NULL)
         return 1;
 
+    if (!ossl_assert(prov != NULL))
+        return 0;
+
     if (!ossl_property_write_lock(store))
         return 0;
     if (store->need_flush)
@@ -559,6 +646,7 @@ int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, int nid,
 
     if (method == NULL) {
         elem.query = prop_query;
+        elem.provider = prov;
         if ((old = lh_QUERY_delete(alg->cache, &elem)) != NULL) {
             impl_cache_free(old);
             store->nelem--;
@@ -568,6 +656,7 @@ int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, int nid,
     p = OPENSSL_malloc(sizeof(*p) + (len = strlen(prop_query)));
     if (p != NULL) {
         p->query = p->body;
+        p->provider = prov;
         p->method.method = method;
         p->method.up_ref = method_up_ref;
         p->method.free = method_destruct;