diff options
-rw-r--r-- | crypto/store/store_result.c | 2 | ||||
-rw-r--r-- | providers/implementations/storemgmt/build.info | 2 | ||||
-rw-r--r-- | providers/implementations/storemgmt/file_store.c | 52 | ||||
-rw-r--r-- | providers/implementations/storemgmt/file_store_any2obj.c | 261 | ||||
-rw-r--r-- | providers/implementations/storemgmt/file_store_der2obj.c | 109 | ||||
-rw-r--r-- | providers/implementations/storemgmt/file_store_local.h | 2 |
6 files changed, 289 insertions, 139 deletions
diff --git a/crypto/store/store_result.c b/crypto/store/store_result.c index 91c679718c..3a0dc9dfba 100644 --- a/crypto/store/store_result.c +++ b/crypto/store/store_result.c @@ -268,7 +268,7 @@ static EVP_PKEY *try_key_value(struct extracted_param_data_st *data, } decoderctx = - OSSL_DECODER_CTX_new_for_pkey(&pk, "DER", data->data_structure, + OSSL_DECODER_CTX_new_for_pkey(&pk, NULL, data->data_structure, data->data_type, selection, libctx, propq); (void)OSSL_DECODER_CTX_set_passphrase_cb(decoderctx, cb, cbarg); diff --git a/providers/implementations/storemgmt/build.info b/providers/implementations/storemgmt/build.info index ad47fb1fe8..8e6445a4e7 100644 --- a/providers/implementations/storemgmt/build.info +++ b/providers/implementations/storemgmt/build.info @@ -3,4 +3,4 @@ $STORE_GOAL=../../libdefault.a -SOURCE[$STORE_GOAL]=file_store.c file_store_der2obj.c +SOURCE[$STORE_GOAL]=file_store.c file_store_any2obj.c diff --git a/providers/implementations/storemgmt/file_store.c b/providers/implementations/storemgmt/file_store.c index 02d0e29502..6ccda2b33f 100644 --- a/providers/implementations/storemgmt/file_store.c +++ b/providers/implementations/storemgmt/file_store.c @@ -420,8 +420,7 @@ void file_load_cleanup(void *construct_data) static int file_setup_decoders(struct file_ctx_st *ctx) { OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx); - OSSL_DECODER *to_obj = NULL; /* Last resort decoder */ - OSSL_DECODER_INSTANCE *to_obj_inst = NULL; + const OSSL_ALGORITHM *to_algo = NULL; int ok = 0; /* Setup for this session, so only if not already done */ @@ -438,32 +437,32 @@ static int file_setup_decoders(struct file_ctx_st *ctx) goto err; } - /* - * Create the internal last resort decoder implementation together - * with a "decoder instance". - * The decoder doesn't need any identification or to be attached to - * any provider, since it's only used locally. - */ - to_obj = ossl_decoder_from_algorithm(0, &ossl_der_to_obj_algorithm, - NULL); - if (to_obj == NULL) - goto err; - to_obj_inst = ossl_decoder_instance_new(to_obj, ctx->provctx); - if (to_obj_inst == NULL) - goto err; + for (to_algo = ossl_any_to_obj_algorithm; + to_algo->algorithm_names != NULL; + to_algo++) { + OSSL_DECODER *to_obj = NULL; + OSSL_DECODER_INSTANCE *to_obj_inst = NULL; - if (!ossl_decoder_ctx_add_decoder_inst(ctx->_.file.decoderctx, - to_obj_inst)) { - ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); - goto err; + /* + * Create the internal last resort decoder implementation + * together with a "decoder instance". + * The decoder doesn't need any identification or to be + * attached to any provider, since it's only used locally. + */ + to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL); + if (to_obj != NULL) + to_obj_inst = ossl_decoder_instance_new(to_obj, ctx->provctx); + OSSL_DECODER_free(to_obj); + if (to_obj_inst == NULL) + goto err; + + if (!ossl_decoder_ctx_add_decoder_inst(ctx->_.file.decoderctx, + to_obj_inst)) { + ossl_decoder_instance_free(to_obj_inst); + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } } - - /* - * OSSL_DECODER_INSTANCE shouldn't be freed from this point on. - * That's going to happen whenever the OSSL_DECODER_CTX is freed. - */ - to_obj_inst = NULL; - /* Add on the usual extra decoders */ if (!OSSL_DECODER_CTX_add_extra(ctx->_.file.decoderctx, libctx, ctx->_.file.propq)) { @@ -486,7 +485,6 @@ static int file_setup_decoders(struct file_ctx_st *ctx) ok = 1; err: - OSSL_DECODER_free(to_obj); return ok; } diff --git a/providers/implementations/storemgmt/file_store_any2obj.c b/providers/implementations/storemgmt/file_store_any2obj.c new file mode 100644 index 0000000000..28601683bf --- /dev/null +++ b/providers/implementations/storemgmt/file_store_any2obj.c @@ -0,0 +1,261 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This is a decoder that's completely internal to the 'file:' store + * implementation. Only code in file_store.c know about this one. Because + * of this close relationship, we can cut certain corners, such as making + * assumptions about the "provider context", which is currently simply the + * provider context that the file_store.c code operates within. + * + * All this does is to read known binary encodings (currently: DER, MSBLOB, + * PVK) from the input if it can, and passes it on to the data callback as + * an object abstraction, leaving it to the callback to figure out what it + * actually is. + * + * This MUST be made the last decoder in a chain, leaving it to other more + * specialized decoders to recognise and process their stuff first. + */ + +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/bio.h> +#include <openssl/buffer.h> +#include <openssl/err.h> +#include <openssl/asn1err.h> +#include <openssl/params.h> +#include "internal/asn1.h" +#include "crypto/pem.h" /* For internal PVK and "blob" headers */ +#include "prov/bio.h" +#include "file_store_local.h" + +/* + * newctx and freectx are not strictly necessary. However, the method creator, + * ossl_decoder_from_algorithm(), demands that they exist, so we make sure to + * oblige. + */ + +static OSSL_FUNC_decoder_newctx_fn any2obj_newctx; +static OSSL_FUNC_decoder_freectx_fn any2obj_freectx; + +static void *any2obj_newctx(void *provctx) +{ + return provctx; +} + +static void any2obj_freectx(void *vctx) +{ +} + +static int any2obj_decode_final(void *provctx, int objtype, BUF_MEM *mem, + OSSL_CALLBACK *data_cb, void *data_cbarg) +{ + /* + * 1 indicates that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + int ok = 1; + + if (mem != NULL) { + OSSL_PARAM params[3]; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); + params[1] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + mem->data, mem->length); + params[2] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + BUF_MEM_free(mem); + } + return ok; +} + +static OSSL_FUNC_decoder_decode_fn der2obj_decode; +static int der2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + BUF_MEM *mem = NULL; + int ok; + + if (in == NULL) + return 0; + + ERR_set_mark(); + ok = (asn1_d2i_read_bio(in, &mem) >= 0); + ERR_pop_to_mark(); + if (!ok && mem != NULL) { + BUF_MEM_free(mem); + mem = NULL; + } + BIO_free(in); + + /* any2obj_decode_final() frees |mem| for us */ + return any2obj_decode_final(provctx, OSSL_OBJECT_UNKNOWN, mem, + data_cb, data_cbarg); +} + +static OSSL_FUNC_decoder_decode_fn msblob2obj_decode; +static int msblob2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + BUF_MEM *mem = NULL; + size_t mem_len = 0, mem_want; + const unsigned char *p; + unsigned int bitlen, magic; + int isdss = -1; + int ispub = -1; + int ok = 0; + + if (in == NULL) + goto err; + + mem_want = 16; /* The size of the MSBLOB header */ + if ((mem = BUF_MEM_new()) == NULL + || !BUF_MEM_grow(mem, mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[0], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + if (!ok) + goto next; + + + ERR_set_mark(); + p = (unsigned char *)&mem->data[0]; + ok = ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) > 0; + ERR_pop_to_mark(); + if (!ok) + goto next; + + ok = 0; + mem_want = ossl_blob_length(bitlen, isdss, ispub); + if (!BUF_MEM_grow(mem, mem_len + mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[mem_len], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + + next: + /* Free resources we no longer need. */ + BIO_free(in); + if (!ok && mem != NULL) { + BUF_MEM_free(mem); + mem = NULL; + } + + /* any2obj_decode_final() frees |mem| for us */ + return any2obj_decode_final(provctx, OSSL_OBJECT_PKEY, mem, + data_cb, data_cbarg); + + err: + BIO_free(in); + BUF_MEM_free(mem); + return 0; +} + +static OSSL_FUNC_decoder_decode_fn pvk2obj_decode; +static int pvk2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + BIO *in = ossl_bio_new_from_core_bio(provctx, cin); + BUF_MEM *mem = NULL; + size_t mem_len = 0, mem_want; + const unsigned char *p; + unsigned int saltlen, keylen; + int ok = 0; + + if (in == NULL) + goto err; + + mem_want = 24; /* The size of the PVK header */ + if ((mem = BUF_MEM_new()) == NULL + || !BUF_MEM_grow(mem, mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[0], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + if (!ok) + goto next; + + + ERR_set_mark(); + p = (unsigned char *)&mem->data[0]; + ok = ossl_do_PVK_header(&p, 24, 0, &saltlen, &keylen) > 0; + ERR_pop_to_mark(); + if (!ok) + goto next; + + ok = 0; + mem_want = saltlen + keylen; + if (!BUF_MEM_grow(mem, mem_len + mem_want)) { + ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + + ERR_set_mark(); + ok = BIO_read(in, &mem->data[mem_len], mem_want) == (int)mem_want; + mem_len += mem_want; + ERR_pop_to_mark(); + + next: + /* Free resources we no longer need. */ + BIO_free(in); + if (!ok && mem != NULL) { + BUF_MEM_free(mem); + mem = NULL; + } + + /* any2obj_decode_final() frees |mem| for us */ + return any2obj_decode_final(provctx, OSSL_OBJECT_PKEY, mem, + data_cb, data_cbarg); + + err: + BIO_free(in); + BUF_MEM_free(mem); + return 0; +} + +#define MAKE_DECODER(fromtype, objtype) \ + static const OSSL_DISPATCH fromtype##_to_obj_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))any2obj_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))any2obj_freectx }, \ + { OSSL_FUNC_DECODER_DECODE, (void (*)(void))fromtype##2obj_decode }, \ + { 0, NULL } \ + } + +MAKE_DECODER(der, OSSL_OBJECT_UNKNOWN); +MAKE_DECODER(msblob, OSSL_OBJECT_PKEY); +MAKE_DECODER(pvk, OSSL_OBJECT_PKEY); + +const OSSL_ALGORITHM ossl_any_to_obj_algorithm[] = { + { "obj", "input=DER", der_to_obj_decoder_functions }, + { "obj", "input=MSBLOB", msblob_to_obj_decoder_functions }, + { "obj", "input=PVK", pvk_to_obj_decoder_functions }, + { NULL, } +}; diff --git a/providers/implementations/storemgmt/file_store_der2obj.c b/providers/implementations/storemgmt/file_store_der2obj.c deleted file mode 100644 index 5f71ea500d..0000000000 --- a/providers/implementations/storemgmt/file_store_der2obj.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -/* - * This is a decoder that's completely internal to the 'file:' store - * implementation. Only code in file_store.c know about this one. Because - * of this close relationship, we can cut certain corners, such as making - * assumptions about the "provider context", which is currently simply the - * provider context that the file_store.c code operates within. - * - * All this does is to read DER from the input if it can, and passes it on - * to the data callback as an object abstraction, leaving it to the callback - * to figure out what it actually is. - * - * This MUST be made the last decoder in a chain, leaving it to other more - * specialized decoders to recognise and process their stuff first. - */ - -#include <openssl/core_dispatch.h> -#include <openssl/core_names.h> -#include <openssl/core_object.h> -#include <openssl/bio.h> -#include <openssl/buffer.h> -#include <openssl/err.h> -#include <openssl/asn1err.h> -#include <openssl/params.h> -#include "internal/asn1.h" -#include "prov/bio.h" -#include "file_store_local.h" - -/* - * newctx and freectx are not strictly necessary. However, the method creator, - * ossl_decoder_from_algorithm(), demands that they exist, so we make sure to - * oblige. - */ - -static OSSL_FUNC_decoder_newctx_fn der2obj_newctx; -static OSSL_FUNC_decoder_freectx_fn der2obj_freectx; - -static void *der2obj_newctx(void *provctx) -{ - return provctx; -} - -static void der2obj_freectx(void *vctx) -{ -} - -static OSSL_FUNC_decoder_decode_fn der2obj_decode; - -static int der2obj_decode(void *provctx, OSSL_CORE_BIO *cin, int selection, - OSSL_CALLBACK *data_cb, void *data_cbarg, - OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) -{ - /* - * We're called from file_store.c, so we know that OSSL_CORE_BIO is a - * BIO in this case. - */ - BIO *in = ossl_bio_new_from_core_bio(provctx, cin); - BUF_MEM *mem = NULL; - int ok; - - if (in == NULL) - return 0; - - ERR_set_mark(); - ok = (asn1_d2i_read_bio(in, &mem) >= 0); - ERR_pop_to_mark(); - if (!ok && mem != NULL) { - OPENSSL_free(mem->data); - OPENSSL_free(mem); - mem = NULL; - } - - ok = 1; - if (mem != NULL) { - OSSL_PARAM params[3]; - int object_type = OSSL_OBJECT_UNKNOWN; - - params[0] = - OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); - params[1] = - OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, - mem->data, mem->length); - params[2] = OSSL_PARAM_construct_end(); - - ok = data_cb(params, data_cbarg); - OPENSSL_free(mem->data); - OPENSSL_free(mem); - } - BIO_free(in); - return ok; -} - -static const OSSL_DISPATCH der_to_obj_decoder_functions[] = { - { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))der2obj_newctx }, - { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))der2obj_freectx }, - { OSSL_FUNC_DECODER_DECODE, (void (*)(void))der2obj_decode }, - { 0, NULL } -}; - -const OSSL_ALGORITHM ossl_der_to_obj_algorithm = - { "obj", "input=DER", der_to_obj_decoder_functions }; diff --git a/providers/implementations/storemgmt/file_store_local.h b/providers/implementations/storemgmt/file_store_local.h index b25dacc18b..3459315948 100644 --- a/providers/implementations/storemgmt/file_store_local.h +++ b/providers/implementations/storemgmt/file_store_local.h @@ -7,5 +7,5 @@ * https://www.openssl.org/source/license.html */ -extern const OSSL_ALGORITHM ossl_der_to_obj_algorithm; +extern const OSSL_ALGORITHM ossl_any_to_obj_algorithm[]; |