Fix OSSL_PARAM creation in OSSL_STORE_open_ex
[openssl.git] / crypto / store / store_lib.c
index 5bcd17b13b77affd2982de895796ce57e54a8ef4..5d0b3e739740df2443fbbca36e74ff845dbf3230 100644 (file)
@@ -7,42 +7,41 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include "e_os.h"
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 
+/* We need to use some STORE deprecated APIs */
+#define OPENSSL_SUPPRESS_DEPRECATED
+
 #include "e_os.h"
 
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/trace.h>
+#include <openssl/core_names.h>
+#include <openssl/provider.h>
+#include <openssl/param_build.h>
 #include <openssl/store.h>
 #include "internal/thread_once.h"
+#include "internal/cryptlib.h"
+#include "internal/provider.h"
 #include "crypto/store.h"
 #include "store_local.h"
 
-struct ossl_store_ctx_st {
-    const OSSL_STORE_LOADER *loader;
-    OSSL_STORE_LOADER_CTX *loader_ctx;
-    const UI_METHOD *ui_method;
-    void *ui_data;
-    OSSL_STORE_post_process_info_fn post_process;
-    void *post_process_data;
-    int expected_type;
-
-    /* 0 before the first STORE_load(), 1 otherwise */
-    int loading;
-};
-
-OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
-                                void *ui_data,
-                                OSSL_STORE_post_process_info_fn post_process,
-                                void *post_process_data)
+static int ossl_store_close_it(OSSL_STORE_CTX *ctx);
+
+OSSL_STORE_CTX *
+OSSL_STORE_open_ex(const char *uri, OSSL_LIB_CTX *libctx, const char *propq,
+                   const UI_METHOD *ui_method, void *ui_data,
+                   OSSL_STORE_post_process_info_fn post_process,
+                   void *post_process_data)
 {
     const OSSL_STORE_LOADER *loader = NULL;
+    OSSL_STORE_LOADER *fetched_loader = NULL;
     OSSL_STORE_LOADER_CTX *loader_ctx = NULL;
     OSSL_STORE_CTX *ctx = NULL;
+    char *propq_copy = NULL;
     char scheme_copy[256], *p, *schemes[2];
     size_t schemes_n = 0;
     size_t i;
@@ -73,28 +72,76 @@ OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
 
     ERR_set_mark();
 
-    /* Try each scheme until we find one that could open the URI */
+    /*
+     * Try each scheme until we find one that could open the URI.
+     *
+     * For each scheme, we look for the engine implementation first, and
+     * failing that, we then try to fetch a provided implementation.
+     * This is consistent with how we handle legacy / engine implementations
+     * elsewhere.
+     */
     for (i = 0; loader_ctx == NULL && i < schemes_n; i++) {
         OSSL_TRACE1(STORE, "Looking up scheme %s\n", schemes[i]);
+#ifndef OPENSSL_NO_DEPRECATED_3_0
         if ((loader = ossl_store_get0_loader_int(schemes[i])) != NULL) {
-            OSSL_TRACE1(STORE, "Found loader for scheme %s\n", schemes[i]);
-            loader_ctx = loader->open(loader, uri, ui_method, ui_data);
-            OSSL_TRACE2(STORE, "Opened %s => %p\n", uri, (void *)loader_ctx);
+            if (loader->open_ex != NULL)
+                loader_ctx = loader->open_ex(loader, uri, libctx, propq,
+                                             ui_method, ui_data);
+            else
+                loader_ctx = loader->open(loader, uri, ui_method, ui_data);
+        }
+#endif
+        if (loader == NULL
+            && (fetched_loader =
+                OSSL_STORE_LOADER_fetch(schemes[i], libctx, propq)) != NULL) {
+            const OSSL_PROVIDER *provider =
+                OSSL_STORE_LOADER_provider(fetched_loader);
+            void *provctx = OSSL_PROVIDER_get0_provider_ctx(provider);
+
+            loader_ctx = fetched_loader->p_open(provctx, uri);
+            if (loader_ctx == NULL) {
+                OSSL_STORE_LOADER_free(fetched_loader);
+                fetched_loader = NULL;
+            } else if (propq != NULL) {
+                OSSL_PARAM params[2];
+
+                params[0] = OSSL_PARAM_construct_utf8_string(
+                                OSSL_STORE_PARAM_PROPERTIES, (char *)propq, 0);
+                params[1] = OSSL_PARAM_construct_end();
+
+                if (!fetched_loader->p_set_ctx_params(loader_ctx, params)) {
+                    (void)fetched_loader->p_close(loader_ctx);
+                    OSSL_STORE_LOADER_free(fetched_loader);
+                    fetched_loader = NULL;
+                }
+            }
+            loader = fetched_loader;
         }
     }
 
+    if (loader != NULL)
+        OSSL_TRACE1(STORE, "Found loader for scheme %s\n", schemes[i]);
+
     if (loader_ctx == NULL)
         goto err;
 
-    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_OPEN, ERR_R_MALLOC_FAILURE);
+    OSSL_TRACE2(STORE, "Opened %s => %p\n", uri, (void *)loader_ctx);
+
+    if ((propq != NULL && (propq_copy = OPENSSL_strdup(propq)) == NULL)
+        || (ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
+    if (ui_method != NULL
+        && !ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data)) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_CRYPTO_LIB);
+        goto err;
+    }
+    ctx->properties = propq_copy;
+    ctx->fetched_loader = fetched_loader;
     ctx->loader = loader;
     ctx->loader_ctx = loader_ctx;
-    ctx->ui_method = ui_method;
-    ctx->ui_data = ui_data;
     ctx->post_process = post_process;
     ctx->post_process_data = post_process_data;
 
@@ -110,16 +157,39 @@ OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
  err:
     ERR_clear_last_mark();
     if (loader_ctx != NULL) {
+        /*
+         * Temporary structure so OSSL_STORE_close() can work even when
+         * |ctx| couldn't be allocated properly
+         */
+        OSSL_STORE_CTX tmpctx = { NULL, };
+
+        tmpctx.fetched_loader = fetched_loader;
+        tmpctx.loader = loader;
+        tmpctx.loader_ctx = loader_ctx;
+
         /*
          * We ignore a returned error because we will return NULL anyway in
          * this case, so if something goes wrong when closing, that'll simply
          * just add another entry on the error stack.
          */
-        (void)loader->close(loader_ctx);
+        (void)ossl_store_close_it(&tmpctx);
     }
+    OSSL_STORE_LOADER_free(fetched_loader);
+    OPENSSL_free(propq_copy);
+    OPENSSL_free(ctx);
     return NULL;
 }
 
+OSSL_STORE_CTX *OSSL_STORE_open(const char *uri,
+                                const UI_METHOD *ui_method, void *ui_data,
+                                OSSL_STORE_post_process_info_fn post_process,
+                                void *post_process_data)
+{
+    return OSSL_STORE_open_ex(uri, NULL, NULL, ui_method, ui_data, post_process,
+                              post_process_data);
+}
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
 int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ...)
 {
     va_list args;
@@ -134,39 +204,155 @@ int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ...)
 
 int OSSL_STORE_vctrl(OSSL_STORE_CTX *ctx, int cmd, va_list args)
 {
-    if (ctx->loader->ctrl != NULL)
+    if (ctx->fetched_loader != NULL) {
+        if (ctx->fetched_loader->p_set_ctx_params != NULL) {
+            OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+            switch (cmd) {
+            case OSSL_STORE_C_USE_SECMEM:
+                {
+                    int on = *(va_arg(args, int *));
+
+                    params[0] = OSSL_PARAM_construct_int("use_secmem", &on);
+                }
+                break;
+            default:
+                break;
+            }
+
+            return ctx->fetched_loader->p_set_ctx_params(ctx->loader_ctx,
+                                                         params);
+        }
+    } else if (ctx->loader->ctrl != NULL) {
         return ctx->loader->ctrl(ctx->loader_ctx, cmd, args);
-    return 0;
+    }
+
+    /*
+     * If the fetched loader doesn't have a set_ctx_params or a ctrl, it's as
+     * if there was one that ignored our params, which usually returns 1.
+     */
+    return 1;
 }
+#endif
 
 int OSSL_STORE_expect(OSSL_STORE_CTX *ctx, int expected_type)
 {
+    int ret = 1;
+
     if (ctx->loading) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_EXPECT,
-                      OSSL_STORE_R_LOADING_STARTED);
+        ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED);
         return 0;
     }
 
     ctx->expected_type = expected_type;
-    if (ctx->loader->expect != NULL)
-        return ctx->loader->expect(ctx->loader_ctx, expected_type);
-    return 1;
+    if (ctx->fetched_loader != NULL
+        && ctx->fetched_loader->p_set_ctx_params != NULL) {
+        OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+        params[0] =
+            OSSL_PARAM_construct_int(OSSL_STORE_PARAM_EXPECT, &expected_type);
+        ret = ctx->fetched_loader->p_set_ctx_params(ctx->loader_ctx, params);
+    }
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+    if (ctx->fetched_loader == NULL
+        && ctx->loader->expect != NULL) {
+        ret = ctx->loader->expect(ctx->loader_ctx, expected_type);
+    }
+#endif
+    return ret;
 }
 
 int OSSL_STORE_find(OSSL_STORE_CTX *ctx, const OSSL_STORE_SEARCH *search)
 {
+    int ret = 1;
+
     if (ctx->loading) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_FIND,
-                      OSSL_STORE_R_LOADING_STARTED);
+        ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED);
         return 0;
     }
-    if (ctx->loader->find == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_FIND,
-                      OSSL_STORE_R_UNSUPPORTED_OPERATION);
+    if (search == NULL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
 
-    return ctx->loader->find(ctx->loader_ctx, search);
+    if (ctx->fetched_loader != NULL) {
+        OSSL_PARAM_BLD *bld;
+        OSSL_PARAM *params;
+        /* OSSL_STORE_SEARCH_BY_NAME, OSSL_STORE_SEARCH_BY_ISSUER_SERIAL*/
+        void *name_der = NULL;
+        int name_der_sz;
+        /* OSSL_STORE_SEARCH_BY_ISSUER_SERIAL */
+        BIGNUM *number = NULL;
+
+        if (ctx->fetched_loader->p_set_ctx_params == NULL) {
+            ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_OPERATION);
+            return 0;
+        }
+
+        if ((bld = OSSL_PARAM_BLD_new()) == NULL) {
+            ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+
+        ret = 0;                 /* Assume the worst */
+
+        switch (search->search_type) {
+        case OSSL_STORE_SEARCH_BY_NAME:
+            if ((name_der_sz = i2d_X509_NAME(search->name,
+                                             (unsigned char **)&name_der)) > 0
+                && OSSL_PARAM_BLD_push_octet_string(bld,
+                                                    OSSL_STORE_PARAM_SUBJECT,
+                                                    name_der, name_der_sz))
+                ret = 1;
+            break;
+        case OSSL_STORE_SEARCH_BY_ISSUER_SERIAL:
+            if ((name_der_sz = i2d_X509_NAME(search->name,
+                                             (unsigned char **)&name_der)) > 0
+                && (number = ASN1_INTEGER_to_BN(search->serial, NULL)) != NULL
+                && OSSL_PARAM_BLD_push_octet_string(bld,
+                                                    OSSL_STORE_PARAM_ISSUER,
+                                                    name_der, name_der_sz)
+                && OSSL_PARAM_BLD_push_BN(bld, OSSL_STORE_PARAM_SERIAL,
+                                          number))
+                ret = 1;
+            break;
+        case OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT:
+            if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_STORE_PARAM_DIGEST,
+                                                EVP_MD_name(search->digest), 0)
+                && OSSL_PARAM_BLD_push_octet_string(bld,
+                                                    OSSL_STORE_PARAM_FINGERPRINT,
+                                                    search->string,
+                                                    search->stringlength))
+                ret = 1;
+            break;
+        case OSSL_STORE_SEARCH_BY_ALIAS:
+            if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_STORE_PARAM_ALIAS,
+                                                (char *)search->string,
+                                                search->stringlength))
+                ret = 1;
+            break;
+        }
+        if (ret) {
+            params = OSSL_PARAM_BLD_to_param(bld);
+            ret = ctx->fetched_loader->p_set_ctx_params(ctx->loader_ctx,
+                                                        params);
+            OSSL_PARAM_BLD_free_params(params);
+        }
+        OSSL_PARAM_BLD_free(bld);
+        OPENSSL_free(name_der);
+        BN_free(number);
+    } else {
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+        /* legacy loader section */
+        if (ctx->loader->find == NULL) {
+            ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_OPERATION);
+            return 0;
+        }
+        ret = ctx->loader->find(ctx->loader_ctx, search);
+#endif
+    }
+
+    return ret;
 }
 
 OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
@@ -178,8 +364,42 @@ OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
     if (OSSL_STORE_eof(ctx))
         return NULL;
 
-    OSSL_TRACE(STORE, "Loading next object\n");
-    v = ctx->loader->load(ctx->loader_ctx, ctx->ui_method, ctx->ui_data);
+    if (ctx->loader != NULL)
+        OSSL_TRACE(STORE, "Loading next object\n");
+
+    if (ctx->cached_info != NULL
+        && sk_OSSL_STORE_INFO_num(ctx->cached_info) == 0) {
+        sk_OSSL_STORE_INFO_free(ctx->cached_info);
+        ctx->cached_info = NULL;
+    }
+
+    if (ctx->cached_info != NULL) {
+        v = sk_OSSL_STORE_INFO_shift(ctx->cached_info);
+    } else {
+        if (ctx->fetched_loader != NULL) {
+            struct ossl_load_result_data_st load_data;
+
+            load_data.v = NULL;
+            load_data.ctx = ctx;
+
+            if (!ctx->fetched_loader->p_load(ctx->loader_ctx,
+                                             ossl_store_handle_load_result,
+                                             &load_data,
+                                             ossl_pw_passphrase_callback_dec,
+                                             &ctx->pwdata)) {
+                if (!OSSL_STORE_eof(ctx))
+                    ctx->error_flag = 1;
+                return NULL;
+            }
+            v = load_data.v;
+        }
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+        if (ctx->fetched_loader == NULL)
+            v = ctx->loader->load(ctx->loader_ctx,
+                                  ctx->pwdata._.ui_method.ui_method,
+                                  ctx->pwdata._.ui_method.ui_method_data);
+#endif
+    }
 
     if (ctx->post_process != NULL && v != NULL) {
         v = ctx->post_process(v, ctx->post_process_data);
@@ -196,13 +416,6 @@ OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
         int returned_type = OSSL_STORE_INFO_get_type(v);
 
         if (returned_type != OSSL_STORE_INFO_NAME && returned_type != 0) {
-            /*
-             * Soft assert here so those who want to harsly weed out faulty
-             * loaders can do so using a debugging version of libcrypto.
-             */
-            if (ctx->loader->expect != NULL)
-                assert(ctx->expected_type == returned_type);
-
             if (ctx->expected_type != returned_type) {
                 OSSL_STORE_INFO_free(v);
                 goto again;
@@ -219,23 +432,58 @@ OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
 
 int OSSL_STORE_error(OSSL_STORE_CTX *ctx)
 {
-    return ctx->loader->error(ctx->loader_ctx);
+    int ret = 1;
+
+    if (ctx->fetched_loader != NULL)
+        ret = ctx->error_flag;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+    if (ctx->fetched_loader == NULL)
+        ret = ctx->loader->error(ctx->loader_ctx);
+#endif
+    return ret;
 }
 
 int OSSL_STORE_eof(OSSL_STORE_CTX *ctx)
 {
-    return ctx->loader->eof(ctx->loader_ctx);
+    int ret = 1;
+
+    if (ctx->fetched_loader != NULL)
+        ret = ctx->loader->p_eof(ctx->loader_ctx);
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+    if (ctx->fetched_loader == NULL)
+        ret = ctx->loader->eof(ctx->loader_ctx);
+#endif
+    return ret;
 }
 
-int OSSL_STORE_close(OSSL_STORE_CTX *ctx)
+static int ossl_store_close_it(OSSL_STORE_CTX *ctx)
 {
-    int loader_ret;
+    int ret = 0;
 
+    if (ctx == NULL)
+        return 1;
     OSSL_TRACE1(STORE, "Closing %p\n", (void *)ctx->loader_ctx);
-    loader_ret = ctx->loader->close(ctx->loader_ctx);
+
+    if (ctx->fetched_loader != NULL)
+        ret = ctx->loader->p_close(ctx->loader_ctx);
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+    if (ctx->fetched_loader == NULL)
+        ret = ctx->loader->close(ctx->loader_ctx);
+#endif
+
+    sk_OSSL_STORE_INFO_pop_free(ctx->cached_info, OSSL_STORE_INFO_free);
+    OSSL_STORE_LOADER_free(ctx->fetched_loader);
+    OPENSSL_free(ctx->properties);
+    ossl_pw_clear_passphrase_data(&ctx->pwdata);
+    return ret;
+}
+
+int OSSL_STORE_close(OSSL_STORE_CTX *ctx)
+{
+    int ret = ossl_store_close_it(ctx);
 
     OPENSSL_free(ctx);
-    return loader_ret;
+    return ret;
 }
 
 /*
@@ -245,7 +493,7 @@ int OSSL_STORE_close(OSSL_STORE_CTX *ctx)
  * In all cases, ownership of the object is transferred to the OSSL_STORE_INFO
  * and will therefore be freed when the OSSL_STORE_INFO is freed.
  */
-static OSSL_STORE_INFO *store_info_new(int type, void *data)
+OSSL_STORE_INFO *OSSL_STORE_INFO_new(int type, void *data)
 {
     OSSL_STORE_INFO *info = OPENSSL_zalloc(sizeof(*info));
 
@@ -259,11 +507,10 @@ static OSSL_STORE_INFO *store_info_new(int type, void *data)
 
 OSSL_STORE_INFO *OSSL_STORE_INFO_new_NAME(char *name)
 {
-    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_NAME, NULL);
+    OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_NAME, NULL);
 
     if (info == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_NAME,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
 
@@ -276,8 +523,7 @@ OSSL_STORE_INFO *OSSL_STORE_INFO_new_NAME(char *name)
 int OSSL_STORE_INFO_set0_NAME_description(OSSL_STORE_INFO *info, char *desc)
 {
     if (info->type != OSSL_STORE_INFO_NAME) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_SET0_NAME_DESCRIPTION,
-                      ERR_R_PASSED_INVALID_ARGUMENT);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT);
         return 0;
     }
 
@@ -287,41 +533,46 @@ int OSSL_STORE_INFO_set0_NAME_description(OSSL_STORE_INFO *info, char *desc)
 }
 OSSL_STORE_INFO *OSSL_STORE_INFO_new_PARAMS(EVP_PKEY *params)
 {
-    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_PARAMS, params);
+    OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_PARAMS, params);
 
     if (info == NULL)
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_PARAMS,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
+    return info;
+}
+
+OSSL_STORE_INFO *OSSL_STORE_INFO_new_PUBKEY(EVP_PKEY *pkey)
+{
+    OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_PUBKEY, pkey);
+
+    if (info == NULL)
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
     return info;
 }
 
 OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey)
 {
-    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_PKEY, pkey);
+    OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_PKEY, pkey);
 
     if (info == NULL)
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_PKEY,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
     return info;
 }
 
 OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509)
 {
-    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_CERT, x509);
+    OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_CERT, x509);
 
     if (info == NULL)
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_CERT,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
     return info;
 }
 
 OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl)
 {
-    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_CRL, crl);
+    OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_CRL, crl);
 
     if (info == NULL)
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_CRL,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
     return info;
 }
 
@@ -333,6 +584,13 @@ int OSSL_STORE_INFO_get_type(const OSSL_STORE_INFO *info)
     return info->type;
 }
 
+void *OSSL_STORE_INFO_get0_data(int type, const OSSL_STORE_INFO *info)
+{
+    if (info->type == type)
+        return info->_.data;
+    return NULL;
+}
+
 const char *OSSL_STORE_INFO_get0_NAME(const OSSL_STORE_INFO *info)
 {
     if (info->type == OSSL_STORE_INFO_NAME)
@@ -346,12 +604,10 @@ char *OSSL_STORE_INFO_get1_NAME(const OSSL_STORE_INFO *info)
         char *ret = OPENSSL_strdup(info->_.name.name);
 
         if (ret == NULL)
-            OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME,
-                          ERR_R_MALLOC_FAILURE);
+            ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return ret;
     }
-    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME,
-                  OSSL_STORE_R_NOT_A_NAME);
+    ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_NAME);
     return NULL;
 }
 
@@ -369,12 +625,10 @@ char *OSSL_STORE_INFO_get1_NAME_description(const OSSL_STORE_INFO *info)
                                    ? info->_.name.desc : "");
 
         if (ret == NULL)
-            OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION,
-                     ERR_R_MALLOC_FAILURE);
+            ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return ret;
     }
-    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_NAME_DESCRIPTION,
-                  OSSL_STORE_R_NOT_A_NAME);
+    ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_NAME);
     return NULL;
 }
 
@@ -391,8 +645,24 @@ EVP_PKEY *OSSL_STORE_INFO_get1_PARAMS(const OSSL_STORE_INFO *info)
         EVP_PKEY_up_ref(info->_.params);
         return info->_.params;
     }
-    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_PARAMS,
-                  OSSL_STORE_R_NOT_PARAMETERS);
+    ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_PARAMETERS);
+    return NULL;
+}
+
+EVP_PKEY *OSSL_STORE_INFO_get0_PUBKEY(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_PUBKEY)
+        return info->_.pubkey;
+    return NULL;
+}
+
+EVP_PKEY *OSSL_STORE_INFO_get1_PUBKEY(const OSSL_STORE_INFO *info)
+{
+    if (info->type == OSSL_STORE_INFO_PUBKEY) {
+        EVP_PKEY_up_ref(info->_.pubkey);
+        return info->_.pubkey;
+    }
+    ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PUBLIC_KEY);
     return NULL;
 }
 
@@ -409,8 +679,7 @@ EVP_PKEY *OSSL_STORE_INFO_get1_PKEY(const OSSL_STORE_INFO *info)
         EVP_PKEY_up_ref(info->_.pkey);
         return info->_.pkey;
     }
-    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_PKEY,
-                  OSSL_STORE_R_NOT_A_KEY);
+    ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PRIVATE_KEY);
     return NULL;
 }
 
@@ -427,8 +696,7 @@ X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *info)
         X509_up_ref(info->_.x509);
         return info->_.x509;
     }
-    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT,
-                  OSSL_STORE_R_NOT_A_CERTIFICATE);
+    ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CERTIFICATE);
     return NULL;
 }
 
@@ -445,8 +713,7 @@ X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *info)
         X509_CRL_up_ref(info->_.crl);
         return info->_.crl;
     }
-    OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_GET1_CRL,
-                  OSSL_STORE_R_NOT_A_CRL);
+    ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CRL);
     return NULL;
 }
 
@@ -457,10 +724,6 @@ void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info)
 {
     if (info != NULL) {
         switch (info->type) {
-        case OSSL_STORE_INFO_EMBEDDED:
-            BUF_MEM_free(info->_.embedded.blob);
-            OPENSSL_free(info->_.embedded.pem_name);
-            break;
         case OSSL_STORE_INFO_NAME:
             OPENSSL_free(info->_.name.name);
             OPENSSL_free(info->_.name.desc);
@@ -468,6 +731,9 @@ void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info)
         case OSSL_STORE_INFO_PARAMS:
             EVP_PKEY_free(info->_.params);
             break;
+        case OSSL_STORE_INFO_PUBKEY:
+            EVP_PKEY_free(info->_.pubkey);
+            break;
         case OSSL_STORE_INFO_PKEY:
             EVP_PKEY_free(info->_.pkey);
             break;
@@ -484,12 +750,55 @@ void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info)
 
 int OSSL_STORE_supports_search(OSSL_STORE_CTX *ctx, int search_type)
 {
-    OSSL_STORE_SEARCH tmp_search;
-
-    if (ctx->loader->find == NULL)
-        return 0;
-    tmp_search.search_type = search_type;
-    return ctx->loader->find(NULL, &tmp_search);
+    int ret = 0;
+
+    if (ctx->fetched_loader != NULL) {
+        void *provctx =
+            ossl_provider_ctx(OSSL_STORE_LOADER_provider(ctx->fetched_loader));
+        const OSSL_PARAM *params;
+        const OSSL_PARAM *p_subject = NULL;
+        const OSSL_PARAM *p_issuer = NULL;
+        const OSSL_PARAM *p_serial = NULL;
+        const OSSL_PARAM *p_fingerprint = NULL;
+        const OSSL_PARAM *p_alias = NULL;
+
+        if (ctx->fetched_loader->p_settable_ctx_params == NULL)
+            return 0;
+
+        params = ctx->fetched_loader->p_settable_ctx_params(provctx);
+        p_subject = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT);
+        p_issuer = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_ISSUER);
+        p_serial = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SERIAL);
+        p_fingerprint =
+            OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_FINGERPRINT);
+        p_alias = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_ALIAS);
+
+        switch (search_type) {
+        case OSSL_STORE_SEARCH_BY_NAME:
+            ret = (p_subject != NULL);
+            break;
+        case OSSL_STORE_SEARCH_BY_ISSUER_SERIAL:
+            ret = (p_issuer != NULL && p_serial != NULL);
+            break;
+        case OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT:
+            ret = (p_fingerprint != NULL);
+            break;
+        case OSSL_STORE_SEARCH_BY_ALIAS:
+            ret = (p_alias != NULL);
+            break;
+        }
+    }
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+    if (ctx->fetched_loader == NULL) {
+        OSSL_STORE_SEARCH tmp_search;
+
+        if (ctx->loader->find == NULL)
+            return 0;
+        tmp_search.search_type = search_type;
+        ret = ctx->loader->find(NULL, &tmp_search);
+    }
+#endif
+    return ret;
 }
 
 /* Search term constructors */
@@ -498,8 +807,7 @@ OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_name(X509_NAME *name)
     OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
 
     if (search == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_SEARCH_BY_NAME,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
 
@@ -514,8 +822,7 @@ OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_issuer_serial(X509_NAME *name,
     OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
 
     if (search == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_SEARCH_BY_ISSUER_SERIAL,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
 
@@ -532,20 +839,17 @@ OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_key_fingerprint(const EVP_MD *digest,
     OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
 
     if (search == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
 
     if (digest != NULL && len != (size_t)EVP_MD_size(digest)) {
-        char buf1[20], buf2[20];
-
-        BIO_snprintf(buf1, sizeof(buf1), "%d", EVP_MD_size(digest));
-        BIO_snprintf(buf2, sizeof(buf2), "%zu", len);
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT,
-                      OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST);
-        ERR_add_error_data(5, EVP_MD_name(digest), " size is ", buf1,
-                           ", fingerprint size is ", buf2);
+        ERR_raise_data(ERR_LIB_OSSL_STORE,
+                       OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST,
+                       "%s size is %d, fingerprint size is %zu",
+                       EVP_MD_name(digest), EVP_MD_size(digest), len);
+        OPENSSL_free(search);
+        return NULL;
     }
 
     search->search_type = OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT;
@@ -560,8 +864,7 @@ OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_alias(const char *alias)
     OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
 
     if (search == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_SEARCH_BY_ALIAS,
-                      ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
 
@@ -611,87 +914,85 @@ const EVP_MD *OSSL_STORE_SEARCH_get0_digest(const OSSL_STORE_SEARCH *criterion)
     return criterion->digest;
 }
 
-/* Internal functions */
-OSSL_STORE_INFO *ossl_store_info_new_EMBEDDED(const char *new_pem_name,
-                                              BUF_MEM *embedded)
+OSSL_STORE_CTX *OSSL_STORE_attach(BIO *bp, const char *scheme,
+                                  OSSL_LIB_CTX *libctx, const char *propq,
+                                  const UI_METHOD *ui_method, void *ui_data,
+                                  OSSL_STORE_post_process_info_fn post_process,
+                                  void *post_process_data)
 {
-    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_EMBEDDED, NULL);
-
-    if (info == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED,
-                      ERR_R_MALLOC_FAILURE);
-        return NULL;
-    }
+    const OSSL_STORE_LOADER *loader = NULL;
+    OSSL_STORE_LOADER *fetched_loader = NULL;
+    OSSL_STORE_LOADER_CTX *loader_ctx = NULL;
+    OSSL_STORE_CTX *ctx = NULL;
 
-    info->_.embedded.blob = embedded;
-    info->_.embedded.pem_name =
-        new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name);
+    if (scheme == NULL)
+        scheme = "file";
 
-    if (new_pem_name != NULL && info->_.embedded.pem_name == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED,
-                      ERR_R_MALLOC_FAILURE);
-        OSSL_STORE_INFO_free(info);
-        info = NULL;
+    OSSL_TRACE1(STORE, "Looking up scheme %s\n", scheme);
+    ERR_set_mark();
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+    if ((loader = ossl_store_get0_loader_int(scheme)) != NULL)
+        loader_ctx = loader->attach(loader, bp, libctx, propq,
+                                    ui_method, ui_data);
+#endif
+    if (loader == NULL
+        && (fetched_loader =
+            OSSL_STORE_LOADER_fetch(scheme, libctx, propq)) != NULL) {
+        const OSSL_PROVIDER *provider =
+            OSSL_STORE_LOADER_provider(fetched_loader);
+        void *provctx = OSSL_PROVIDER_get0_provider_ctx(provider);
+
+        if ((loader_ctx =
+             fetched_loader->p_attach(provctx, (OSSL_CORE_BIO *)bp)) == NULL) {
+            OSSL_STORE_LOADER_free(fetched_loader);
+            fetched_loader = NULL;
+        } else if (propq != NULL) {
+            OSSL_PARAM params[] = {
+                OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_PROPERTIES,
+                                       NULL, 0),
+                OSSL_PARAM_END
+            };
+
+            params[0].data = (void *)propq;
+            if (!fetched_loader->p_set_ctx_params(loader_ctx, params)) {
+                (void)fetched_loader->p_close(loader_ctx);
+                OSSL_STORE_LOADER_free(fetched_loader);
+                fetched_loader = NULL;
+            }
+        }
+        loader = fetched_loader;
     }
 
-    return info;
-}
-
-BUF_MEM *ossl_store_info_get0_EMBEDDED_buffer(OSSL_STORE_INFO *info)
-{
-    if (info->type == OSSL_STORE_INFO_EMBEDDED)
-        return info->_.embedded.blob;
-    return NULL;
-}
-
-char *ossl_store_info_get0_EMBEDDED_pem_name(OSSL_STORE_INFO *info)
-{
-    if (info->type == OSSL_STORE_INFO_EMBEDDED)
-        return info->_.embedded.pem_name;
-    return NULL;
-}
-
-OSSL_STORE_CTX *ossl_store_attach_pem_bio(BIO *bp, const UI_METHOD *ui_method,
-                                          void *ui_data, OPENSSL_CTX *libctx,
-                                          const char *propq)
-{
-    OSSL_STORE_CTX *ctx = NULL;
-    const OSSL_STORE_LOADER *loader = NULL;
-    OSSL_STORE_LOADER_CTX *loader_ctx = NULL;
+    if (loader_ctx == NULL) {
+        ERR_clear_last_mark();
+        return NULL;
+    }
 
-    if ((loader = ossl_store_get0_loader_int("file")) == NULL
-        || ((loader_ctx = ossl_store_file_attach_pem_bio_int(bp, libctx,
-                                                             propq)) == NULL))
-        goto done;
     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_ATTACH_PEM_BIO,
-                     ERR_R_MALLOC_FAILURE);
-        goto done;
+        ERR_clear_last_mark();
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
+        return NULL;
     }
 
+    if (ui_method != NULL
+        && !ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data)) {
+        ERR_clear_last_mark();
+        OPENSSL_free(ctx);
+        return NULL;
+    }
+
+    ctx->fetched_loader = fetched_loader;
     ctx->loader = loader;
     ctx->loader_ctx = loader_ctx;
-    loader_ctx = NULL;
-    ctx->ui_method = ui_method;
-    ctx->ui_data = ui_data;
-    ctx->post_process = NULL;
-    ctx->post_process_data = NULL;
-
- done:
-    if (loader_ctx != NULL)
-        /*
-         * We ignore a returned error because we will return NULL anyway in
-         * this case, so if something goes wrong when closing, that'll simply
-         * just add another entry on the error stack.
-         */
-        (void)loader->close(loader_ctx);
-    return ctx;
-}
+    ctx->post_process = post_process;
+    ctx->post_process_data = post_process_data;
 
-int ossl_store_detach_pem_bio(OSSL_STORE_CTX *ctx)
-{
-    int loader_ret = ossl_store_file_detach_pem_bio_int(ctx->loader_ctx);
+    /*
+     * ossl_store_get0_loader_int will raise an error if the loader for the
+     * the scheme cannot be retrieved. But if a loader was successfully
+     * fetched then we remove this error from the error stack.
+     */
+    ERR_pop_to_mark();
 
-    OPENSSL_free(ctx);
-    return loader_ret;
+    return ctx;
 }