/*
* Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#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 "internal/bio.h"
#include "crypto/store.h"
#include "store_local.h"
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;
/*
* Put the file scheme first. If the uri does represent an existing file,
* possible device name and all, then it should be loaded. Only a failed
* attempt at loading a local file should have us try something else.
*/
schemes[schemes_n++] = "file";
/*
* Now, check if we have something that looks like a scheme, and add it
* as a second scheme. However, also check if there's an authority start
* (://), because that will invalidate the previous file scheme. Also,
* check that this isn't actually the file scheme, as there's no point
* going through that one twice!
*/
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)
schemes_n--; /* Invalidate the file scheme */
schemes[schemes_n++] = scheme_copy;
}
}
ERR_set_mark();
/*
* 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) {
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"