]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/store/store_lib.c
str[n]casecmp => OPENSSL_strncasecmp
[thirdparty/openssl.git] / crypto / store / store_lib.c
index fce2dbc2e221ec9686b8090a61505d772d3e3404..e748647a61216084984091014ef76486049b2ff6 100644 (file)
@@ -1,43 +1,78 @@
 /*
- * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
  *
- * Licensed under the OpenSSL license (the "License").  You may not use
+ * 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
  * in the file LICENSE in the source distribution or at
  * 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 "internal/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/store_int.h"
-#include "store_locl.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;
-
-    /* 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)
+#include "internal/cryptlib.h"
+#include "internal/provider.h"
+#include "internal/bio.h"
+#include "crypto/store.h"
+#include "store_local.h"
+
+static int ossl_store_close_it(OSSL_STORE_CTX *ctx);
+
+static int loader_set_params(OSSL_STORE_LOADER *loader,
+                             OSSL_STORE_LOADER_CTX *loader_ctx,
+                             const OSSL_PARAM params[], const char *propq)
+{
+   if (params != NULL) {
+       if (!loader->p_set_ctx_params(loader_ctx, params))
+           return 0;
+   }
+
+   if (propq != NULL) {
+       OSSL_PARAM propp[2];
+
+       if (OSSL_PARAM_locate_const(params,
+                                   OSSL_STORE_PARAM_PROPERTIES) != NULL)
+           /* use the propq from params */
+           return 1;
+
+       propp[0] = OSSL_PARAM_construct_utf8_string(OSSL_STORE_PARAM_PROPERTIES,
+                                                   (char *)propq, 0);
+       propp[1] = OSSL_PARAM_construct_end();
+
+       if (!loader->p_set_ctx_params(loader_ctx, propp))
+           return 0;
+    }
+    return 1;
+}
+
+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,
+                   const OSSL_PARAM params[],
+                   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 scheme_copy[256], *p, *schemes[2];
+    char *propq_copy = NULL;
+    int no_loader_found = 1;
+    char scheme_copy[256], *p, *schemes[2], *scheme = NULL;
     size_t schemes_n = 0;
     size_t i;
 
@@ -58,8 +93,8 @@ OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
     OPENSSL_strlcpy(scheme_copy, uri, sizeof(scheme_copy));
     if ((p = strchr(scheme_copy, ':')) != NULL) {
         *p++ = '\0';
-        if (strcasecmp(scheme_copy, "file") != 0) {
-            if (strncmp(p, "//", 2) == 0)
+        if (OPENSSL_strcasecmp(scheme_copy, "file") != 0) {
+            if (HAS_PREFIX(p, "//"))
                 schemes_n--;         /* Invalidate the file scheme */
             schemes[schemes_n++] = scheme_copy;
         }
@@ -67,23 +102,87 @@ 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++) {
-        if ((loader = ossl_store_get0_loader_int(schemes[i])) != NULL)
-            loader_ctx = loader->open(loader, uri, ui_method, ui_data);
+        scheme = schemes[i];
+        OSSL_TRACE1(STORE, "Looking up scheme %s\n", scheme);
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+        ERR_set_mark();
+        if ((loader = ossl_store_get0_loader_int(scheme)) != NULL) {
+            ERR_clear_last_mark();
+            no_loader_found = 0;
+            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);
+        } else {
+            ERR_pop_to_mark();
+        }
+#endif
+        if (loader == NULL
+            && (fetched_loader =
+                OSSL_STORE_LOADER_fetch(libctx, scheme, propq)) != NULL) {
+            const OSSL_PROVIDER *provider =
+                OSSL_STORE_LOADER_get0_provider(fetched_loader);
+            void *provctx = OSSL_PROVIDER_get0_provider_ctx(provider);
+
+            no_loader_found = 0;
+            loader_ctx = fetched_loader->p_open(provctx, uri);
+            if (loader_ctx == NULL) {
+                OSSL_STORE_LOADER_free(fetched_loader);
+                fetched_loader = NULL;
+            } else if (!loader_set_params(fetched_loader, loader_ctx,
+                                          params, propq)) {
+                (void)fetched_loader->p_close(loader_ctx);
+                OSSL_STORE_LOADER_free(fetched_loader);
+                fetched_loader = NULL;
+            }
+            loader = fetched_loader;
+        }
     }
+
+    if (no_loader_found)
+        /*
+         * It's assumed that ossl_store_get0_loader_int() and
+         * OSSL_STORE_LOADER_fetch() report their own errors
+         */
+        goto err;
+
+    OSSL_TRACE1(STORE, "Found loader for scheme %s\n", scheme);
+
     if (loader_ctx == NULL)
+        /*
+         * It's assumed that the loader's open() method reports its own
+         * errors
+         */
         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)
+            || !ossl_pw_enable_passphrase_caching(&ctx->pwdata))) {
+        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;
 
@@ -99,16 +198,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, NULL,
+                              post_process, post_process_data);
+}
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
 int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ...)
 {
     va_list args;
@@ -123,9 +245,161 @@ 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 == NULL
+            || expected_type < 0 || expected_type > OSSL_STORE_INFO_CRL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+    if (ctx->loading) {
+        ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED);
+        return 0;
+    }
+
+    ctx->expected_type = expected_type;
+    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) {
+        ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED);
+        return 0;
+    }
+    if (search == NULL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    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_get0_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_free(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)
@@ -137,7 +411,42 @@ OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
     if (OSSL_STORE_eof(ctx))
         return NULL;
 
-    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);
@@ -150,35 +459,91 @@ OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx)
             goto again;
     }
 
+    /* Clear any internally cached passphrase */
+    (void)ossl_pw_clear_passphrase_cache(&ctx->pwdata);
+
+    if (v != NULL && ctx->expected_type != 0) {
+        int returned_type = OSSL_STORE_INFO_get_type(v);
+
+        if (returned_type != OSSL_STORE_INFO_NAME && returned_type != 0) {
+            if (ctx->expected_type != returned_type) {
+                OSSL_STORE_INFO_free(v);
+                goto again;
+            }
+        }
+    }
+
+    if (v != NULL)
+        OSSL_TRACE1(STORE, "Got a %s\n",
+                    OSSL_STORE_INFO_type_string(OSSL_STORE_INFO_get_type(v)));
+
     return v;
 }
 
 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 != 0;
+}
+
+static int ossl_store_close_it(OSSL_STORE_CTX *ctx)
+{
+    int ret = 0;
+
+    if (ctx == NULL)
+        return 1;
+    OSSL_TRACE1(STORE, "Closing %p\n", (void *)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->closefn(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 loader_ret = ctx->loader->close(ctx->loader_ctx);
+    int ret = ossl_store_close_it(ctx);
 
     OPENSSL_free(ctx);
-    return loader_ret;
+    return ret;
 }
 
 /*
  * Functions to generate OSSL_STORE_INFOs, one function for each type we
  * support having in them as well as a generic constructor.
  *
- * In all cases, ownership of the object is transfered to the OSSL_STORE_INFO
+ * 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));
 
@@ -192,11 +557,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;
     }
 
@@ -209,8 +573,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;
     }
 
@@ -220,41 +583,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;
 }
 
@@ -266,6 +634,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)
@@ -279,12 +654,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;
 }
 
@@ -302,12 +675,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;
 }
 
@@ -324,8 +695,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;
 }
 
@@ -342,8 +729,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;
 }
 
@@ -360,8 +746,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;
 }
 
@@ -378,8 +763,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;
 }
 
@@ -390,10 +774,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);
@@ -401,6 +781,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;
@@ -415,85 +798,246 @@ void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info)
     }
 }
 
-/* Internal functions */
-OSSL_STORE_INFO *ossl_store_info_new_EMBEDDED(const char *new_pem_name,
-                                              BUF_MEM *embedded)
+int OSSL_STORE_supports_search(OSSL_STORE_CTX *ctx, int search_type)
 {
-    OSSL_STORE_INFO *info = store_info_new(OSSL_STORE_INFO_EMBEDDED, NULL);
+    int ret = 0;
+
+    if (ctx->fetched_loader != NULL) {
+        void *provctx =
+            ossl_provider_ctx(OSSL_STORE_LOADER_get0_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;
+}
 
-    if (info == NULL) {
-        OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_INFO_NEW_EMBEDDED,
-                      ERR_R_MALLOC_FAILURE);
+/* Search term constructors */
+OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_name(X509_NAME *name)
+{
+    OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
+
+    if (search == NULL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
 
-    info->_.embedded.blob = embedded;
-    info->_.embedded.pem_name =
-        new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name);
+    search->search_type = OSSL_STORE_SEARCH_BY_NAME;
+    search->name = name;
+    return search;
+}
+
+OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_issuer_serial(X509_NAME *name,
+                                                      const ASN1_INTEGER *serial)
+{
+    OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
 
-    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;
+    if (search == NULL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
+        return NULL;
     }
 
-    return info;
+    search->search_type = OSSL_STORE_SEARCH_BY_ISSUER_SERIAL;
+    search->name = name;
+    search->serial = serial;
+    return search;
 }
 
-BUF_MEM *ossl_store_info_get0_EMBEDDED_buffer(OSSL_STORE_INFO *info)
+OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_key_fingerprint(const EVP_MD *digest,
+                                                        const unsigned char
+                                                        *bytes, size_t len)
 {
-    if (info->type == OSSL_STORE_INFO_EMBEDDED)
-        return info->_.embedded.blob;
-    return NULL;
+    OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
+
+    if (search == NULL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    if (digest != NULL && len != (size_t)EVP_MD_get_size(digest)) {
+        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_get0_name(digest), EVP_MD_get_size(digest), len);
+        OPENSSL_free(search);
+        return NULL;
+    }
+
+    search->search_type = OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT;
+    search->digest = digest;
+    search->string = bytes;
+    search->stringlength = len;
+    return search;
 }
 
-char *ossl_store_info_get0_EMBEDDED_pem_name(OSSL_STORE_INFO *info)
+OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_alias(const char *alias)
 {
-    if (info->type == OSSL_STORE_INFO_EMBEDDED)
-        return info->_.embedded.pem_name;
-    return NULL;
+    OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search));
+
+    if (search == NULL) {
+        ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    search->search_type = OSSL_STORE_SEARCH_BY_ALIAS;
+    search->string = (const unsigned char *)alias;
+    search->stringlength = strlen(alias);
+    return search;
 }
 
-OSSL_STORE_CTX *ossl_store_attach_pem_bio(BIO *bp, const UI_METHOD *ui_method,
-                                          void *ui_data)
+/* Search term destructor */
+void OSSL_STORE_SEARCH_free(OSSL_STORE_SEARCH *search)
+{
+    OPENSSL_free(search);
+}
+
+/* Search term accessors */
+int OSSL_STORE_SEARCH_get_type(const OSSL_STORE_SEARCH *criterion)
+{
+    return criterion->search_type;
+}
+
+X509_NAME *OSSL_STORE_SEARCH_get0_name(const OSSL_STORE_SEARCH *criterion)
+{
+    return criterion->name;
+}
+
+const ASN1_INTEGER *OSSL_STORE_SEARCH_get0_serial(const OSSL_STORE_SEARCH
+                                                  *criterion)
+{
+    return criterion->serial;
+}
+
+const unsigned char *OSSL_STORE_SEARCH_get0_bytes(const OSSL_STORE_SEARCH
+                                                  *criterion, size_t *length)
+{
+    *length = criterion->stringlength;
+    return criterion->string;
+}
+
+const char *OSSL_STORE_SEARCH_get0_string(const OSSL_STORE_SEARCH *criterion)
+{
+    return (const char *)criterion->string;
+}
+
+const EVP_MD *OSSL_STORE_SEARCH_get0_digest(const OSSL_STORE_SEARCH *criterion)
+{
+    return criterion->digest;
+}
+
+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,
+                                  const OSSL_PARAM params[],
+                                  OSSL_STORE_post_process_info_fn post_process,
+                                  void *post_process_data)
 {
-    OSSL_STORE_CTX *ctx = 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;
+
+    if (scheme == NULL)
+        scheme = "file";
+
+    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(libctx, scheme, propq)) != NULL) {
+        const OSSL_PROVIDER *provider =
+            OSSL_STORE_LOADER_get0_provider(fetched_loader);
+        void *provctx = OSSL_PROVIDER_get0_provider_ctx(provider);
+        OSSL_CORE_BIO *cbio = ossl_core_bio_new_from_bio(bp);
+
+        if (cbio == NULL
+            || (loader_ctx = fetched_loader->p_attach(provctx, cbio)) == NULL) {
+            OSSL_STORE_LOADER_free(fetched_loader);
+            fetched_loader = NULL;
+        } else if (!loader_set_params(fetched_loader, loader_ctx,
+                                      params, propq)) {
+            (void)fetched_loader->p_close(loader_ctx);
+            OSSL_STORE_LOADER_free(fetched_loader);
+            fetched_loader = NULL;
+        }
+        loader = fetched_loader;
+        ossl_core_bio_free(cbio);
+    }
+
+    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)) == 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;
 }