提交 970f467a 编写于 作者: R Richard Levitte

STORE 'file' scheme loader: Add directory listing capability

This has it recognised when the given path is a directory.  In that
case, the file loader will give back a series of names, all as URI
formatted as possible given the incoming URI.
Reviewed-by: NMatt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3542)
上级 7ad2ef36
...@@ -88,6 +88,7 @@ static ERR_STRING_DATA ERR_str_functs[] = { ...@@ -88,6 +88,7 @@ static ERR_STRING_DATA ERR_str_functs[] = {
{ERR_PACK(0, SYS_F_OPEN, 0), "open"}, {ERR_PACK(0, SYS_F_OPEN, 0), "open"},
{ERR_PACK(0, SYS_F_CLOSE, 0), "close"}, {ERR_PACK(0, SYS_F_CLOSE, 0), "close"},
{ERR_PACK(0, SYS_F_IOCTL, 0), "ioctl"}, {ERR_PACK(0, SYS_F_IOCTL, 0), "ioctl"},
{ERR_PACK(0, SYS_F_STAT, 0), "stat"},
{0, NULL}, {0, NULL},
}; };
......
...@@ -727,6 +727,7 @@ OCSP_F_PARSE_HTTP_LINE1:118:parse_http_line1 ...@@ -727,6 +727,7 @@ OCSP_F_PARSE_HTTP_LINE1:118:parse_http_line1
OSSL_STORE_F_FILE_GET_PASS:118:file_get_pass OSSL_STORE_F_FILE_GET_PASS:118:file_get_pass
OSSL_STORE_F_FILE_LOAD:119:file_load OSSL_STORE_F_FILE_LOAD:119:file_load
OSSL_STORE_F_FILE_LOAD_TRY_DECODE:124:file_load_try_decode OSSL_STORE_F_FILE_LOAD_TRY_DECODE:124:file_load_try_decode
OSSL_STORE_F_FILE_NAME_TO_URI:126:file_name_to_uri
OSSL_STORE_F_FILE_OPEN:120:file_open OSSL_STORE_F_FILE_OPEN:120:file_open
OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT:100:ossl_store_get0_loader_int OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT:100:ossl_store_get0_loader_int
OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT:101:OSSL_STORE_INFO_get1_CERT OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT:101:OSSL_STORE_INFO_get1_CERT
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
*/ */
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <assert.h>
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/dsa.h> /* For d2i_DSAPrivateKey */ #include <openssl/dsa.h> /* For d2i_DSAPrivateKey */
...@@ -21,6 +23,8 @@ ...@@ -21,6 +23,8 @@
#include <openssl/ui.h> #include <openssl/ui.h>
#include <openssl/x509.h> /* For the PKCS8 stuff o.O */ #include <openssl/x509.h> /* For the PKCS8 stuff o.O */
#include "internal/asn1_int.h" #include "internal/asn1_int.h"
#include "internal/o_dir.h"
#include "internal/cryptlib.h"
#include "store_locl.h" #include "store_locl.h"
#include "e_os.h" #include "e_os.h"
...@@ -555,23 +559,60 @@ static const FILE_HANDLER *file_handlers[] = { ...@@ -555,23 +559,60 @@ static const FILE_HANDLER *file_handlers[] = {
*/ */
struct ossl_store_loader_ctx_st { struct ossl_store_loader_ctx_st {
BIO *file; enum {
int is_pem; is_raw = 0,
is_pem,
is_dir
} type;
int errcnt; int errcnt;
union {
/* The following are used when the handler is marked as repeatable */ struct { /* Used with is_raw and is_pem */
const FILE_HANDLER *last_handler; BIO *file;
void *last_handler_ctx;
/*
* The following are used when the handler is marked as
* repeatable
*/
const FILE_HANDLER *last_handler;
void *last_handler_ctx;
} file;
struct { /* Used with is_dir */
OPENSSL_DIR_CTX *ctx;
int end_reached;
char *uri;
/*
* The directory reading utility we have combines opening with
* reading the first name. To make sure we can detect the end
* at the right time, we read early and cache the name.
*/
const char *last_entry;
int last_errno;
} dir;
} _;
}; };
static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)
{
if (ctx->type == is_dir) {
OPENSSL_free(ctx->_.dir.uri);
} else {
if (ctx->_.file.last_handler != NULL) {
ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);
ctx->_.file.last_handler_ctx = NULL;
ctx->_.file.last_handler = NULL;
}
}
OPENSSL_free(ctx);
}
static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
const char *uri, const char *uri,
const UI_METHOD *ui_method, const UI_METHOD *ui_method,
void *ui_data) void *ui_data)
{ {
BIO *buff = NULL;
char peekbuf[4096];
OSSL_STORE_LOADER_CTX *ctx = NULL; OSSL_STORE_LOADER_CTX *ctx = NULL;
struct stat st;
const char *path = NULL; const char *path = NULL;
if (strncasecmp(uri, "file:", 5) == 0) { if (strncasecmp(uri, "file:", 5) == 0) {
...@@ -607,29 +648,64 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, ...@@ -607,29 +648,64 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
} }
if (stat(path, &st) < 0) {
SYSerr(SYS_F_STAT, errno);
ERR_add_error_data(1, path);
return NULL;
}
ctx = OPENSSL_zalloc(sizeof(*ctx)); ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx == NULL) { if (ctx == NULL) {
OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE); OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_MALLOC_FAILURE);
return NULL; return NULL;
} }
if ((buff = BIO_new(BIO_f_buffer())) == NULL) if ((st.st_mode & S_IFDIR) == S_IFDIR) {
goto err; /*
if ((ctx->file = BIO_new_file(path, "rb")) == NULL) { * Try to copy everything, even if we know that some of them must be
goto err; * NULL for the moment. This prevents errors in the future, when more
} * components may be used.
ctx->file = BIO_push(buff, ctx->file); */
if (BIO_buffer_peek(ctx->file, peekbuf, sizeof(peekbuf)-1) > 0) { ctx->_.dir.uri = OPENSSL_strdup(uri);
peekbuf[sizeof(peekbuf)-1] = '\0'; ctx->type = is_dir;
if (strstr(peekbuf, "-----BEGIN ") != NULL)
ctx->is_pem = 1; if (ctx->_.dir.uri == NULL)
goto err;
ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path);
ctx->_.dir.last_errno = errno;
if (ctx->_.dir.last_entry == NULL) {
if (ctx->_.dir.last_errno != 0) {
char errbuf[256];
errno = ctx->_.dir.last_errno;
openssl_strerror_r(errno, errbuf, sizeof(errbuf));
OSSL_STOREerr(OSSL_STORE_F_FILE_OPEN, ERR_R_SYS_LIB);
ERR_add_error_data(1, errbuf);
goto err;
}
ctx->_.dir.end_reached = 1;
}
} else {
BIO *buff = NULL;
char peekbuf[4096];
if ((buff = BIO_new(BIO_f_buffer())) == NULL
|| (ctx->_.file.file = BIO_new_file(path, "rb")) == NULL) {
BIO_free_all(buff);
goto err;
}
ctx->_.file.file = BIO_push(buff, ctx->_.file.file);
if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf)-1) > 0) {
peekbuf[sizeof(peekbuf)-1] = '\0';
if (strstr(peekbuf, "-----BEGIN ") != NULL)
ctx->type = is_pem;
}
} }
return ctx; return ctx;
err: err:
if (buff != NULL) OSSL_STORE_LOADER_CTX_free(ctx);
BIO_free(buff);
OPENSSL_free(ctx);
return NULL; return NULL;
} }
...@@ -707,8 +783,8 @@ static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx, ...@@ -707,8 +783,8 @@ static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,
OSSL_STORE_INFO_free(result); OSSL_STORE_INFO_free(result);
result = NULL; result = NULL;
} else { } else {
ctx->last_handler = matching_handlers[0]; ctx->_.file.last_handler = matching_handlers[0];
ctx->last_handler_ctx = handler_ctx; ctx->_.file.last_handler_ctx = handler_ctx;
} }
} }
...@@ -743,15 +819,16 @@ static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx, ...@@ -743,15 +819,16 @@ static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx,
{ {
OSSL_STORE_INFO *result = NULL; OSSL_STORE_INFO *result = NULL;
if (ctx->last_handler != NULL) { if (ctx->_.file.last_handler != NULL) {
result = ctx->last_handler->try_decode(NULL, NULL, NULL, 0, result =
&ctx->last_handler_ctx, ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0,
ui_method, ui_data); &ctx->_.file.last_handler_ctx,
ui_method, ui_data);
if (result == NULL) { if (result == NULL) {
ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx); ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);
ctx->last_handler_ctx = NULL; ctx->_.file.last_handler_ctx = NULL;
ctx->last_handler = NULL; ctx->_.file.last_handler = NULL;
} }
} }
return result; return result;
...@@ -801,55 +878,135 @@ static int file_read_asn1(BIO *bp, unsigned char **data, long *len) ...@@ -801,55 +878,135 @@ static int file_read_asn1(BIO *bp, unsigned char **data, long *len)
return 1; return 1;
} }
static int ends_with_dirsep(const char *uri)
{
if (*uri != '\0')
uri += strlen(uri) - 1;
#if defined __VMS
if (*uri == ']' || *uri == '>' || *uri == ':')
return 1;
#elif defined _WIN32
if (*uri == '\\')
return 1;
#endif
return *uri == '/';
}
static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name,
char **data)
{
assert(name != NULL);
assert(data != NULL);
{
const char *pathsep = ends_with_dirsep(ctx->_.dir.uri) ? "" : "/";
long calculated_length = strlen(ctx->_.dir.uri) + strlen(pathsep)
+ strlen(name) + 1 /* \0 */;
*data = OPENSSL_zalloc(calculated_length);
if (*data == NULL) {
OSSL_STOREerr(OSSL_STORE_F_FILE_NAME_TO_URI, ERR_R_MALLOC_FAILURE);
return 0;
}
OPENSSL_strlcat(*data, ctx->_.dir.uri, calculated_length);
OPENSSL_strlcat(*data, pathsep, calculated_length);
OPENSSL_strlcat(*data, name, calculated_length);
}
return 1;
}
static int file_eof(OSSL_STORE_LOADER_CTX *ctx); static int file_eof(OSSL_STORE_LOADER_CTX *ctx);
static int file_error(OSSL_STORE_LOADER_CTX *ctx); static int file_error(OSSL_STORE_LOADER_CTX *ctx);
static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
const UI_METHOD *ui_method, void *ui_data) const UI_METHOD *ui_method, void *ui_data)
{ {
OSSL_STORE_INFO *result = NULL; OSSL_STORE_INFO *result = NULL;
int matchcount = -1;
result = file_load_try_repeat(ctx, ui_method, ui_data); if (ctx->type == is_dir) {
if (result != NULL) do {
return result; char *newname = NULL;
if (file_error(ctx)) if (ctx->_.dir.last_entry == NULL) {
return NULL; if (!ctx->_.dir.end_reached) {
char errbuf[256];
do { assert(ctx->_.dir.last_errno != 0);
char *pem_name = NULL; /* PEM record name */ errno = ctx->_.dir.last_errno;
char *pem_header = NULL; /* PEM record header */
unsigned char *data = NULL; /* DER encoded data */
long len = 0; /* DER encoded data length */
if (ctx->is_pem) {
if (!file_read_pem(ctx->file, &pem_name, &pem_header, &data, &len,
ui_method, ui_data)) {
if (!file_eof(ctx))
ctx->errcnt++; ctx->errcnt++;
goto err; openssl_strerror_r(errno, errbuf, sizeof(errbuf));
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_SYS_LIB);
ERR_add_error_data(1, errbuf);
}
return NULL;
} }
} else {
if (!file_read_asn1(ctx->file, &data, &len)) { if (ctx->_.dir.last_entry[0] != '.'
if (!file_eof(ctx)) && !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname))
ctx->errcnt++; return NULL;
goto err;
/*
* On the first call (with a NULL context), OPENSSL_DIR_read()
* cares about the second argument. On the following calls, it
* only cares that it isn't NULL. Therefore, we can safely give
* it our URI here.
*/
ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx,
ctx->_.dir.uri);
ctx->_.dir.last_errno = errno;
if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0)
ctx->_.dir.end_reached = 1;
if (newname != NULL
&& (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) {
OPENSSL_free(newname);
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_OSSL_STORE_LIB);
return NULL;
} }
} } while (result == NULL && !file_eof(ctx));
} else {
int matchcount = -1;
matchcount = -1; result = file_load_try_repeat(ctx, ui_method, ui_data);
result = file_load_try_decode(ctx, pem_name, pem_header, data, len, if (result != NULL)
ui_method, ui_data, &matchcount); return result;
err: if (file_error(ctx))
OPENSSL_free(pem_name); return NULL;
OPENSSL_free(pem_header);
OPENSSL_free(data);
} while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx));
/* We bail out on ambiguity */ do {
if (matchcount > 1) char *pem_name = NULL; /* PEM record name */
return NULL; char *pem_header = NULL; /* PEM record header */
unsigned char *data = NULL; /* DER encoded data */
long len = 0; /* DER encoded data length */
matchcount = -1;
if (ctx->type == is_pem) {
if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header,
&data, &len, ui_method, ui_data)) {
if (!file_eof(ctx))
ctx->errcnt++;
goto err;
}
} else {
if (!file_read_asn1(ctx->_.file.file, &data, &len)) {
if (!file_eof(ctx))
ctx->errcnt++;
goto err;
}
}
result = file_load_try_decode(ctx, pem_name, pem_header, data, len,
ui_method, ui_data, &matchcount);
err:
OPENSSL_free(pem_name);
OPENSSL_free(pem_header);
OPENSSL_free(data);
} while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx));
/* We bail out on ambiguity */
if (matchcount > 1)
return NULL;
}
return result; return result;
} }
...@@ -861,21 +1018,23 @@ static int file_error(OSSL_STORE_LOADER_CTX *ctx) ...@@ -861,21 +1018,23 @@ static int file_error(OSSL_STORE_LOADER_CTX *ctx)
static int file_eof(OSSL_STORE_LOADER_CTX *ctx) static int file_eof(OSSL_STORE_LOADER_CTX *ctx)
{ {
if (ctx->last_handler != NULL if (ctx->type == is_dir)
&& !ctx->last_handler->eof(ctx->last_handler_ctx)) return ctx->_.dir.end_reached;
if (ctx->_.file.last_handler != NULL
&& !ctx->_.file.last_handler->eof(ctx->_.file.last_handler_ctx))
return 0; return 0;
return BIO_eof(ctx->file); return BIO_eof(ctx->_.file.file);
} }
static int file_close(OSSL_STORE_LOADER_CTX *ctx) static int file_close(OSSL_STORE_LOADER_CTX *ctx)
{ {
if (ctx->last_handler != NULL) { if (ctx->type == is_dir) {
ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx); OPENSSL_DIR_end(&ctx->_.dir.ctx);
ctx->last_handler_ctx = NULL; } else {
ctx->last_handler = NULL; BIO_free_all(ctx->_.file.file);
} }
BIO_free_all(ctx->file); OSSL_STORE_LOADER_CTX_free(ctx);
OPENSSL_free(ctx);
return 1; return 1;
} }
......
...@@ -19,6 +19,8 @@ static const ERR_STRING_DATA OSSL_STORE_str_functs[] = { ...@@ -19,6 +19,8 @@ static const ERR_STRING_DATA OSSL_STORE_str_functs[] = {
{ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD, 0), "file_load"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD, 0), "file_load"},
{ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD_TRY_DECODE, 0), {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_LOAD_TRY_DECODE, 0),
"file_load_try_decode"}, "file_load_try_decode"},
{ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_NAME_TO_URI, 0),
"file_name_to_uri"},
{ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_OPEN, 0), "file_open"}, {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_FILE_OPEN, 0), "file_open"},
{ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT, 0), {ERR_PACK(ERR_LIB_OSSL_STORE, OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT, 0),
"ossl_store_get0_loader_int"}, "ossl_store_get0_loader_int"},
......
...@@ -164,6 +164,7 @@ typedef struct err_state_st { ...@@ -164,6 +164,7 @@ typedef struct err_state_st {
# define SYS_F_OPEN 19 # define SYS_F_OPEN 19
# define SYS_F_CLOSE 20 # define SYS_F_CLOSE 20
# define SYS_F_IOCTL 21 # define SYS_F_IOCTL 21
# define SYS_F_STAT 22
/* reasons */ /* reasons */
# define ERR_R_SYS_LIB ERR_LIB_SYS/* 2 */ # define ERR_R_SYS_LIB ERR_LIB_SYS/* 2 */
......
...@@ -25,6 +25,7 @@ int ERR_load_OSSL_STORE_strings(void); ...@@ -25,6 +25,7 @@ int ERR_load_OSSL_STORE_strings(void);
# define OSSL_STORE_F_FILE_GET_PASS 118 # define OSSL_STORE_F_FILE_GET_PASS 118
# define OSSL_STORE_F_FILE_LOAD 119 # define OSSL_STORE_F_FILE_LOAD 119
# define OSSL_STORE_F_FILE_LOAD_TRY_DECODE 124 # define OSSL_STORE_F_FILE_LOAD_TRY_DECODE 124
# define OSSL_STORE_F_FILE_NAME_TO_URI 126
# define OSSL_STORE_F_FILE_OPEN 120 # define OSSL_STORE_F_FILE_OPEN 120
# define OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT 100 # define OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT 100
# define OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT 101 # define OSSL_STORE_F_OSSL_STORE_INFO_GET1_CERT 101
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册