Commit e61ec2d9 authored by Richard Levitte's avatar Richard Levitte
Browse files

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: default avatarMatt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3542)
parent e1613d9f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+111 −46
Original line number Diff line number Diff line
@@ -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,27 +512,40 @@ 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)

        {
            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, ui_method,
                                    ui_data);
                    handler->try_decode(pem_name, pem_header, data, len,
                                        &tmp_handler_ctx, ui_method, ui_data);

            if (tmp_result != NULL) {
                if (matching_functions)
                    matching_functions[matchcount] = handler->try_decode;
                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 {
                    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;
@@ -508,6 +554,9 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
                        /* 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;
                    }
                }
@@ -519,12 +568,20 @@ static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,
            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;
+1 −0
Original line number Diff line number Diff line
@@ -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"},
+1 −0
Original line number Diff line number Diff line
@@ -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