]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/core_algorithm.c
Stop raising ERR_R_MALLOC_FAILURE in most places
[thirdparty/openssl.git] / crypto / core_algorithm.c
index 50344fbe2dc7f22529b03b9314237acf6c918b7b..16055bad30224cc18453e0bfb2ce9bccc751d328 100644 (file)
 struct algorithm_data_st {
     OSSL_LIB_CTX *libctx;
     int operation_id;            /* May be zero for finding them all */
-    int (*pre)(OSSL_PROVIDER *, int operation_id, void *data, int *result);
+    int (*pre)(OSSL_PROVIDER *, int operation_id, int no_store, void *data,
+               int *result);
+    int (*reserve_store)(int no_store, void *data);
     void (*fn)(OSSL_PROVIDER *, const OSSL_ALGORITHM *, int no_store,
                void *data);
+    int (*unreserve_store)(void *data);
     int (*post)(OSSL_PROVIDER *, int operation_id, int no_store, void *data,
                 int *result);
     void *data;
 };
 
+/*
+ * Process one OSSL_ALGORITHM array, for the operation |cur_operation|,
+ * by constructing methods for all its implementations and adding those
+ * to the appropriate method store.
+ * Which method store is appropriate is given by |no_store| ("permanent"
+ * if 0, temporary if 1) and other data in |data->data|.
+ *
+ * Returns:
+ * -1 to quit adding algorithm implementations immediately
+ * 0 if not successful, but adding should continue
+ * 1 if successful so far, and adding should continue
+ */
+static int algorithm_do_map(OSSL_PROVIDER *provider, const OSSL_ALGORITHM *map,
+                            int cur_operation, int no_store, void *cbdata)
+{
+    struct algorithm_data_st *data = cbdata;
+    int ret = 0;
+
+    if (!data->reserve_store(no_store, data->data))
+        /* Error, bail out! */
+        return -1;
+
+    /* Do we fulfill pre-conditions? */
+    if (data->pre == NULL) {
+        /* If there is no pre-condition function, assume "yes" */
+        ret = 1;
+    } else if (!data->pre(provider, cur_operation, no_store, data->data,
+                          &ret)) {
+        /* Error, bail out! */
+        ret = -1;
+        goto end;
+    }
+
+    /*
+     * If pre-condition not fulfilled don't add this set of implementations,
+     * but do continue with the next.  This simply means that another thread
+     * got to it first.
+     */
+    if (ret == 0) {
+        ret = 1;
+        goto end;
+    }
+
+    if (map != NULL) {
+        const OSSL_ALGORITHM *thismap;
+
+        for (thismap = map; thismap->algorithm_names != NULL; thismap++)
+            data->fn(provider, thismap, no_store, data->data);
+    }
+
+    /* Do we fulfill post-conditions? */
+    if (data->post == NULL) {
+        /* If there is no post-condition function, assume "yes" */
+        ret = 1;
+    } else if (!data->post(provider, cur_operation, no_store, data->data,
+                           &ret)) {
+        /* Error, bail out! */
+        ret = -1;
+    }
+
+ end:
+    data->unreserve_store(data->data);
+
+    return ret;
+}
+
+/*
+ * Given a provider, process one operation given by |data->operation_id|, or
+ * if that's zero, process all known operations.
+ * For each such operation, query the associated OSSL_ALGORITHM array from
+ * the provider, then process that array with |algorithm_do_map()|.
+ */
 static int algorithm_do_this(OSSL_PROVIDER *provider, void *cbdata)
 {
     struct algorithm_data_st *data = cbdata;
-    int no_store = 0;    /* Assume caching is ok */
     int first_operation = 1;
     int last_operation = OSSL_OP__HIGHEST;
     int cur_operation;
@@ -39,44 +113,18 @@ static int algorithm_do_this(OSSL_PROVIDER *provider, void *cbdata)
     for (cur_operation = first_operation;
          cur_operation <= last_operation;
          cur_operation++) {
+        int no_store = 0;        /* Assume caching is ok */
         const OSSL_ALGORITHM *map = NULL;
-        int ret;
-
-        /* Do we fulfill pre-conditions? */
-        if (data->pre == NULL) {
-            /* If there is no pre-condition function, assume "yes" */
-            ret = 1;
-        } else {
-            if (!data->pre(provider, cur_operation, data->data, &ret))
-                /* Error, bail out! */
-                return 0;
-        }
-
-        /* If pre-condition not fulfilled, go to the next operation */
-        if (!ret)
-            continue;
+        int ret = 0;
 
         map = ossl_provider_query_operation(provider, cur_operation,
                                             &no_store);
-        if (map != NULL) {
-            while (map->algorithm_names != NULL) {
-                const OSSL_ALGORITHM *thismap = map++;
-
-                data->fn(provider, thismap, no_store, data->data);
-            }
-        }
+        ret = algorithm_do_map(provider, map, cur_operation, no_store, data);
         ossl_provider_unquery_operation(provider, cur_operation, map);
 
-        /* Do we fulfill post-conditions? */
-        if (data->post == NULL) {
-            /* If there is no post-condition function, assume "yes" */
-            ret = 1;
-        } else {
-            if (!data->post(provider, cur_operation, no_store, data->data,
-                            &ret))
-                /* Error, bail out! */
-                return 0;
-        }
+        if (ret < 0)
+            /* Hard error, bail out immediately! */
+            return 0;
 
         /* If post-condition not fulfilled, set general failure */
         if (!ret)
@@ -89,10 +137,12 @@ static int algorithm_do_this(OSSL_PROVIDER *provider, void *cbdata)
 void ossl_algorithm_do_all(OSSL_LIB_CTX *libctx, int operation_id,
                            OSSL_PROVIDER *provider,
                            int (*pre)(OSSL_PROVIDER *, int operation_id,
-                                      void *data, int *result),
+                                      int no_store, void *data, int *result),
+                           int (*reserve_store)(int no_store, void *data),
                            void (*fn)(OSSL_PROVIDER *provider,
                                       const OSSL_ALGORITHM *algo,
                                       int no_store, void *data),
+                           int (*unreserve_store)(void *data),
                            int (*post)(OSSL_PROVIDER *, int operation_id,
                                        int no_store, void *data, int *result),
                            void *data)
@@ -102,14 +152,29 @@ void ossl_algorithm_do_all(OSSL_LIB_CTX *libctx, int operation_id,
     cbdata.libctx = libctx;
     cbdata.operation_id = operation_id;
     cbdata.pre = pre;
+    cbdata.reserve_store = reserve_store;
     cbdata.fn = fn;
+    cbdata.unreserve_store = unreserve_store;
     cbdata.post = post;
     cbdata.data = data;
 
-    if (provider == NULL)
+    if (provider == NULL) {
         ossl_provider_doall_activated(libctx, algorithm_do_this, &cbdata);
-    else
+    } else {
+        OSSL_LIB_CTX *libctx2 = ossl_provider_libctx(provider);
+
+        /*
+         * If a provider is given, its library context MUST match the library
+         * context we're passed.  If this turns out not to be true, there is
+         * a programming error in the functions up the call stack.
+         */
+        if (!ossl_assert(ossl_lib_ctx_get_concrete(libctx)
+                         == ossl_lib_ctx_get_concrete(libctx2)))
+            return;
+
+        cbdata.libctx = libctx2;
         algorithm_do_this(provider, &cbdata);
+    }
 }
 
 char *ossl_algorithm_get1_first_name(const OSSL_ALGORITHM *algo)
@@ -128,7 +193,5 @@ char *ossl_algorithm_get1_first_name(const OSSL_ALGORITHM *algo)
         first_name_len = first_name_end - algo->algorithm_names;
 
     ret = OPENSSL_strndup(algo->algorithm_names, first_name_len);
-    if (ret == NULL)
-        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
     return ret;
 }