STORE 'file' scheme loader: add support for containers
Containers are objects that are containers for a bunch of other objects with types we recognise but aren't readable in a stream. Such containers are read and parsed, and their content is cached, to be served one object at a time. This extends the FILE_HANDLER type to include a function to destroy the cache and a function to simulate the EOF check. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/3542)
This commit is contained in:
parent
e1613d9f25
commit
e61ec2d9ba
4 changed files with 111 additions and 43 deletions
|
@ -1978,6 +1978,7 @@ OCSP_R_UNKNOWN_NID:120:unknown nid
|
|||
OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE:129:unsupported requestorname type
|
||||
OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type
|
||||
OSSL_STORE_R_INVALID_SCHEME:106:invalid scheme
|
||||
OSSL_STORE_R_IS_NOT_A:112:is not a
|
||||
OSSL_STORE_R_NOT_A_CERTIFICATE:100:not a certificate
|
||||
OSSL_STORE_R_NOT_A_CRL:101:not a crl
|
||||
OSSL_STORE_R_NOT_A_KEY:102:not a key
|
||||
|
|
|
@ -116,6 +116,11 @@ static int file_get_pem_pass(char *buf, int num, int w, void *data)
|
|||
* blob: The blob of data to match with what this handler
|
||||
* can use.
|
||||
* len: The length of the blob.
|
||||
* handler_ctx: For a handler marked repeatable, this pointer can
|
||||
* be used to create a context for the handler. IT IS
|
||||
* THE HANDLER'S RESPONSIBILITY TO CREATE AND DESTROY
|
||||
* THIS CONTEXT APPROPRIATELY, i.e. create on first call
|
||||
* and destroy when about to return NULL.
|
||||
* ui_method: Application UI method for getting a password, pin
|
||||
* or any other interactive data.
|
||||
* ui_data: Application data to be passed to ui_method when
|
||||
|
@ -126,20 +131,37 @@ static int file_get_pem_pass(char *buf, int num, int w, void *data)
|
|||
typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name,
|
||||
const char *pem_header,
|
||||
const unsigned char *blob,
|
||||
size_t len,
|
||||
size_t len, void **handler_ctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data);
|
||||
/*
|
||||
* The eof function should return 1 if there's no more data to be found
|
||||
* with the handler_ctx, otherwise 0. This is only used when the handler is
|
||||
* marked repeatable.
|
||||
*/
|
||||
typedef int (*file_eof_fn)(void *handler_ctx);
|
||||
/*
|
||||
* The destroy_ctx function is used to destroy the handler_ctx that was
|
||||
* intiated by a repeatable try_decode fuction. This is only used when
|
||||
* the handler is marked repeatable.
|
||||
*/
|
||||
typedef void (*file_destroy_ctx_fn)(void **handler_ctx);
|
||||
|
||||
typedef struct file_handler_st {
|
||||
const char *name;
|
||||
file_try_decode_fn try_decode;
|
||||
file_eof_fn eof;
|
||||
file_destroy_ctx_fn destroy_ctx;
|
||||
|
||||
/* flags */
|
||||
int repeatable;
|
||||
} FILE_HANDLER;
|
||||
|
||||
int pem_check_suffix(const char *pem_str, const char *suffix);
|
||||
static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name,
|
||||
const char *pem_header,
|
||||
const unsigned char *blob,
|
||||
size_t len,
|
||||
size_t len, void **pctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data)
|
||||
{
|
||||
|
@ -183,7 +205,7 @@ static FILE_HANDLER PrivateKey_handler = {
|
|||
static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name,
|
||||
const char *pem_header,
|
||||
const unsigned char *blob,
|
||||
size_t len,
|
||||
size_t len, void **pctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data)
|
||||
{
|
||||
|
@ -207,7 +229,7 @@ static FILE_HANDLER PUBKEY_handler = {
|
|||
static OSSL_STORE_INFO *try_decode_params(const char *pem_name,
|
||||
const char *pem_header,
|
||||
const unsigned char *blob,
|
||||
size_t len,
|
||||
size_t len, void **pctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data)
|
||||
{
|
||||
|
@ -262,7 +284,7 @@ static FILE_HANDLER params_handler = {
|
|||
static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name,
|
||||
const char *pem_header,
|
||||
const unsigned char *blob,
|
||||
size_t len,
|
||||
size_t len, void **pctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data)
|
||||
{
|
||||
|
@ -304,7 +326,7 @@ static FILE_HANDLER X509Certificate_handler = {
|
|||
static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name,
|
||||
const char *pem_header,
|
||||
const unsigned char *blob,
|
||||
size_t len,
|
||||
size_t len, void **pctx,
|
||||
const UI_METHOD *ui_method,
|
||||
void *ui_data)
|
||||
{
|
||||
|
@ -346,6 +368,10 @@ struct ossl_store_loader_ctx_st {
|
|||
BIO *file;
|
||||
int is_pem;
|
||||
int errcnt;
|
||||
|
||||
/* The following are used when the handler is marked as repeatable */
|
||||
const FILE_HANDLER *last_handler;
|
||||
void *last_handler_ctx;
|
||||
};
|
||||
|
||||
static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
|
||||
|
@ -425,6 +451,19 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
|
|||
OSSL_STORE_INFO *result = NULL;
|
||||
int matchcount = -1;
|
||||
|
||||
if (ctx->last_handler != NULL) {
|
||||
result = ctx->last_handler->try_decode(NULL, NULL, NULL, 0,
|
||||
&ctx->last_handler_ctx,
|
||||
ui_method, ui_data);
|
||||
|
||||
if (result != NULL)
|
||||
return result;
|
||||
|
||||
ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx);
|
||||
ctx->last_handler_ctx = NULL;
|
||||
ctx->last_handler = NULL;
|
||||
}
|
||||
|
||||
if (file_error(ctx))
|
||||
return NULL;
|
||||
|
||||
|
@ -435,8 +474,6 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
|
|||
BUF_MEM *mem = NULL;
|
||||
long len = 0; /* DER encoded data length */
|
||||
int r = 0;
|
||||
size_t i = 0;
|
||||
file_try_decode_fn *matching_functions = NULL;
|
||||
|
||||
matchcount = -1;
|
||||
if (ctx->is_pem) {
|
||||
|
@ -467,10 +504,6 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
#if 0 /* PKCS12 not yet ready */
|
||||
PKCS12 *pkcs12 =NULL;
|
||||
#endif
|
||||
|
||||
if ((len = asn1_d2i_read_bio(ctx->file, &mem)) < 0) {
|
||||
if (!file_eof(ctx))
|
||||
ctx->errcnt++;
|
||||
|
@ -479,52 +512,76 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
|
|||
|
||||
data = (unsigned char *)mem->data;
|
||||
len = (long)mem->length;
|
||||
|
||||
#if 0 /* PKCS12 not yet ready */
|
||||
/* Try and see if we loaded a PKCS12 */
|
||||
pkcs12 = d2i_PKCS12(NULL, &data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
result = NULL;
|
||||
matchcount = 0;
|
||||
matching_functions = OPENSSL_zalloc(sizeof(*matching_functions)
|
||||
* OSSL_NELEM(file_handlers));
|
||||
|
||||
for (i = 0; i < OSSL_NELEM(file_handlers); i++) {
|
||||
const FILE_HANDLER *handler = file_handlers[i];
|
||||
OSSL_STORE_INFO *tmp_result =
|
||||
handler->try_decode(pem_name, pem_header, data, len, ui_method,
|
||||
ui_data);
|
||||
{
|
||||
size_t i = 0;
|
||||
void *handler_ctx = NULL;
|
||||
const FILE_HANDLER **matching_handlers =
|
||||
OPENSSL_zalloc(sizeof(*matching_handlers)
|
||||
* OSSL_NELEM(file_handlers));
|
||||
|
||||
if (tmp_result != NULL) {
|
||||
if (matching_functions)
|
||||
matching_functions[matchcount] = handler->try_decode;
|
||||
if (matching_handlers == NULL) {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (++matchcount == 1) {
|
||||
result = tmp_result;
|
||||
tmp_result = NULL;
|
||||
matchcount = 0;
|
||||
for (i = 0; i < OSSL_NELEM(file_handlers); i++) {
|
||||
const FILE_HANDLER *handler = file_handlers[i];
|
||||
void *tmp_handler_ctx = NULL;
|
||||
OSSL_STORE_INFO *tmp_result =
|
||||
handler->try_decode(pem_name, pem_header, data, len,
|
||||
&tmp_handler_ctx, ui_method, ui_data);
|
||||
|
||||
if (tmp_result == NULL) {
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, OSSL_STORE_R_IS_NOT_A);
|
||||
ERR_add_error_data(1, handler->name);
|
||||
} else {
|
||||
/* more than one match => ambiguous, kill any result */
|
||||
OSSL_STORE_INFO_free(result);
|
||||
OSSL_STORE_INFO_free(tmp_result);
|
||||
result = NULL;
|
||||
if (matching_handlers)
|
||||
matching_handlers[matchcount] = handler;
|
||||
|
||||
if (handler_ctx)
|
||||
handler->destroy_ctx(&handler_ctx);
|
||||
handler_ctx = tmp_handler_ctx;
|
||||
|
||||
if (++matchcount == 1) {
|
||||
result = tmp_result;
|
||||
tmp_result = NULL;
|
||||
} else {
|
||||
/* more than one match => ambiguous, kill any result */
|
||||
OSSL_STORE_INFO_free(result);
|
||||
OSSL_STORE_INFO_free(tmp_result);
|
||||
if (handler->destroy_ctx != NULL)
|
||||
handler->destroy_ctx(&handler_ctx);
|
||||
handler_ctx = NULL;
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchcount > 1)
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
|
||||
OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE);
|
||||
if (matchcount == 0)
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
|
||||
OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE);
|
||||
if (matchcount > 1)
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
|
||||
OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE);
|
||||
if (matchcount == 0)
|
||||
OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD,
|
||||
OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE);
|
||||
else if (matching_handlers[0]->repeatable) {
|
||||
ctx->last_handler = matching_handlers[0];
|
||||
ctx->last_handler_ctx = handler_ctx;
|
||||
mem = NULL;
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
OPENSSL_free(matching_handlers);
|
||||
}
|
||||
|
||||
if (result)
|
||||
ERR_clear_error();
|
||||
|
||||
err:
|
||||
OPENSSL_free(matching_functions);
|
||||
OPENSSL_free(pem_name);
|
||||
OPENSSL_free(pem_header);
|
||||
if (mem == NULL)
|
||||
|
@ -548,11 +605,19 @@ static int file_error(OSSL_STORE_LOADER_CTX *ctx)
|
|||
|
||||
static int file_eof(OSSL_STORE_LOADER_CTX *ctx)
|
||||
{
|
||||
if (ctx->last_handler != NULL
|
||||
&& !ctx->last_handler->eof(ctx->last_handler_ctx))
|
||||
return 0;
|
||||
return BIO_eof(ctx->file);
|
||||
}
|
||||
|
||||
static int file_close(OSSL_STORE_LOADER_CTX *ctx)
|
||||
{
|
||||
if (ctx->last_handler != NULL) {
|
||||
ctx->last_handler->destroy_ctx(&ctx->last_handler_ctx);
|
||||
ctx->last_handler_ctx = NULL;
|
||||
ctx->last_handler = NULL;
|
||||
}
|
||||
BIO_free_all(ctx->file);
|
||||
OPENSSL_free(ctx);
|
||||
return 1;
|
||||
|
|
|
@ -65,6 +65,7 @@ static const ERR_STRING_DATA OSSL_STORE_str_reasons[] = {
|
|||
"ambiguous content type"},
|
||||
{ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_INVALID_SCHEME),
|
||||
"invalid scheme"},
|
||||
{ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_IS_NOT_A), "is not a"},
|
||||
{ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_CERTIFICATE),
|
||||
"not a certificate"},
|
||||
{ERR_PACK(ERR_LIB_OSSL_STORE, 0, OSSL_STORE_R_NOT_A_CRL), "not a crl"},
|
||||
|
|
|
@ -51,6 +51,7 @@ int ERR_load_OSSL_STORE_strings(void);
|
|||
*/
|
||||
# define OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE 107
|
||||
# define OSSL_STORE_R_INVALID_SCHEME 106
|
||||
# define OSSL_STORE_R_IS_NOT_A 112
|
||||
# define OSSL_STORE_R_NOT_A_CERTIFICATE 100
|
||||
# define OSSL_STORE_R_NOT_A_CRL 101
|
||||
# define OSSL_STORE_R_NOT_A_KEY 102
|
||||
|
|
Loading…
Reference in a new issue