OSSL_STORE: Treat URIs as files first (with exceptions), then as full URIs
To handle paths that contain devices (for example, C:/foo/bar.pem on Windows), try to "open" the URI using the file scheme loader first, and failing that, check if the device is really a scheme we know. The "file" scheme does the same kind of thing to pick out the path part of the URI. An exception to this special treatment is if the URI has an authority part (something that starts with "//" directly after what looks like a scheme). Such URIs will never be treated as plain file paths. Reviewed-by: Andy Polyakov <appro@openssl.org> (Merged from https://github.com/openssl/openssl/pull/3907)
This commit is contained in:
parent
ba476aa32c
commit
ae9c39d83a
2 changed files with 75 additions and 27 deletions
|
@ -744,26 +744,41 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
|
|||
{
|
||||
OSSL_STORE_LOADER_CTX *ctx = NULL;
|
||||
struct stat st;
|
||||
const char *path = NULL;
|
||||
const char *paths[2], *path;
|
||||
size_t paths_n = 0, i;
|
||||
|
||||
/*
|
||||
* First step, just take the URI as is.
|
||||
*/
|
||||
paths[paths_n++] = uri;
|
||||
|
||||
/*
|
||||
* Second step, if the URI appears to start with the 'file' scheme,
|
||||
* extract the path and make that the second path to check.
|
||||
* There's a special case if the URI also contains an authority, then
|
||||
* the full URI shouldn't be used as a path anywhere.
|
||||
*/
|
||||
if (strncasecmp(uri, "file:", 5) == 0) {
|
||||
if (strncasecmp(&uri[5], "//localhost/", 12) == 0) {
|
||||
path = &uri[16];
|
||||
} else if (strncmp(&uri[5], "///", 3) == 0) {
|
||||
path = &uri[7];
|
||||
} else if (strncmp(&uri[5], "//", 2) != 0) {
|
||||
path = &uri[5];
|
||||
} else {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN,
|
||||
OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED);
|
||||
return NULL;
|
||||
const char *p = &uri[5];
|
||||
|
||||
if (strncmp(&uri[5], "//", 2) == 0) {
|
||||
paths_n--; /* Invalidate using the full URI */
|
||||
if (strncasecmp(&uri[7], "localhost/", 10) == 0) {
|
||||
p = &uri[16];
|
||||
} else if (uri[7] == '/') {
|
||||
p = &uri[7];
|
||||
} else {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN,
|
||||
OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the scheme "file" was an explicit part of the URI, the path must
|
||||
* be absolute. So says RFC 8089
|
||||
*/
|
||||
if (path[0] != '/') {
|
||||
if (p[0] != '/') {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN,
|
||||
OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE);
|
||||
return NULL;
|
||||
|
@ -771,20 +786,28 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
|
|||
|
||||
#ifdef _WIN32
|
||||
/* Windows file: URIs with a drive letter start with a / */
|
||||
if (path[0] == '/' && path[2] == ':' && path[3] == '/')
|
||||
path++;
|
||||
if (p[0] == '/' && p[2] == ':' && p[3] == '/')
|
||||
p++;
|
||||
#endif
|
||||
} else {
|
||||
path = uri;
|
||||
paths[paths_n++] = p;
|
||||
}
|
||||
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
SYSerr(SYS_F_STAT, errno);
|
||||
ERR_add_error_data(1, path);
|
||||
for (i = 0, path = NULL; path == NULL && i < paths_n; i++) {
|
||||
if (stat(paths[i], &st) < 0) {
|
||||
SYSerr(SYS_F_STAT, errno);
|
||||
ERR_add_error_data(1, paths[i]);
|
||||
} else {
|
||||
path = paths[i];
|
||||
}
|
||||
}
|
||||
if (path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Successfully found a working path, clear possible collected errors */
|
||||
ERR_clear_error();
|
||||
|
||||
ctx = OPENSSL_zalloc(sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "e_os.h"
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/store.h>
|
||||
|
@ -31,22 +33,45 @@ OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, const UI_METHOD *ui_method,
|
|||
OSSL_STORE_post_process_info_fn post_process,
|
||||
void *post_process_data)
|
||||
{
|
||||
const OSSL_STORE_LOADER *loader;
|
||||
const OSSL_STORE_LOADER *loader = NULL;
|
||||
OSSL_STORE_LOADER_CTX *loader_ctx = NULL;
|
||||
OSSL_STORE_CTX *ctx = NULL;
|
||||
char scheme_copy[256], *p;
|
||||
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';
|
||||
p = scheme_copy;
|
||||
} else {
|
||||
p = "file";
|
||||
*p++ = '\0';
|
||||
if (strcasecmp(scheme_copy, "file") != 0) {
|
||||
if (strncmp(p, "//", 2) == 0)
|
||||
schemes_n--; /* Invalidate the file scheme */
|
||||
schemes[schemes_n++] = scheme_copy;
|
||||
}
|
||||
}
|
||||
|
||||
if ((loader = ossl_store_get0_loader_int(p)) == NULL
|
||||
|| (loader_ctx = loader->open(loader, uri, ui_method, ui_data)) == NULL)
|
||||
/* Try each scheme until we find one that could open the URI */
|
||||
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);
|
||||
}
|
||||
if (loader_ctx == NULL)
|
||||
goto done;
|
||||
|
||||
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
|
||||
OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_OPEN, ERR_R_MALLOC_FAILURE);
|
||||
goto done;
|
||||
|
|
Loading…
Reference in a new issue