From: Richard Levitte Date: Mon, 5 Dec 2016 22:15:58 +0000 (+0100) Subject: STORE 'file' scheme loader: add support for containers X-Git-Tag: OpenSSL_1_1_1-pre1~1172 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=e61ec2d9babf30da3a4d94554e576bf10c1fc92c;ds=sidebyside 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 (Merged from https://github.com/openssl/openssl/pull/3542) --- diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 79f08f4657..a00def173d 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -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 diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c index f8fc3ba4e4..3a566c3289 100644 --- a/crypto/store/loader_file.c +++ b/crypto/store/loader_file.c @@ -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); - - if (tmp_result != NULL) { - if (matching_functions) - matching_functions[matchcount] = handler->try_decode; - - if (++matchcount == 1) { - result = tmp_result; - tmp_result = NULL; + + { + size_t i = 0; + void *handler_ctx = NULL; + const FILE_HANDLER **matching_handlers = + OPENSSL_zalloc(sizeof(*matching_handlers) + * OSSL_NELEM(file_handlers)); + + if (matching_handlers == NULL) { + OSSL_STOREerr(OSSL_STORE_F_FILE_LOAD, ERR_R_MALLOC_FAILURE); + goto err; + } + + 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; diff --git a/crypto/store/store_err.c b/crypto/store/store_err.c index 20f19fcd26..d3dd382aef 100644 --- a/crypto/store/store_err.c +++ b/crypto/store/store_err.c @@ -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"}, diff --git a/include/openssl/storeerr.h b/include/openssl/storeerr.h index 28d11a274c..7782a6f717 100644 --- a/include/openssl/storeerr.h +++ b/include/openssl/storeerr.h @@ -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