123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- /*
- * Copyright 2020 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
- */
- #include <openssl/core_names.h>
- #include <openssl/bio.h>
- #include <openssl/params.h>
- #include <openssl/provider.h>
- #include "encoder_local.h"
- #include "e_os.h"
- struct decoder_process_data_st {
- OSSL_DECODER_CTX *ctx;
- /* Current BIO */
- BIO *bio;
- /* Index of the current decoder instance to be processed */
- size_t current_deser_inst_index;
- };
- static int decoder_process(const OSSL_PARAM params[], void *arg);
- int OSSL_DECODER_from_bio(OSSL_DECODER_CTX *ctx, BIO *in)
- {
- struct decoder_process_data_st data;
- int ok = 0;
- memset(&data, 0, sizeof(data));
- data.ctx = ctx;
- data.bio = in;
- ok = decoder_process(NULL, &data);
- /* Clear any internally cached passphrase */
- if (!ctx->flag_user_passphrase) {
- OSSL_DECODER_CTX_set_passphrase(ctx, NULL, 0);
- ctx->flag_user_passphrase = 0;
- }
- return ok;
- }
- #ifndef OPENSSL_NO_STDIO
- static BIO *bio_from_file(FILE *fp)
- {
- BIO *b;
- if ((b = BIO_new(BIO_s_file())) == NULL) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_BIO_LIB);
- return NULL;
- }
- BIO_set_fp(b, fp, BIO_NOCLOSE);
- return b;
- }
- int OSSL_DECODER_from_fp(OSSL_DECODER_CTX *ctx, FILE *fp)
- {
- BIO *b = bio_from_file(fp);
- int ret = 0;
- if (b != NULL)
- ret = OSSL_DECODER_from_bio(ctx, b);
- BIO_free(b);
- return ret;
- }
- #endif
- int OSSL_DECODER_CTX_set_input_type(OSSL_DECODER_CTX *ctx,
- const char *input_type)
- {
- if (!ossl_assert(ctx != NULL)) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- /*
- * NULL is a valid starting input type, and means that the caller leaves
- * it to code to discover what the starting input type is.
- */
- ctx->start_input_type = input_type;
- return 1;
- }
- int OSSL_DECODER_CTX_add_decoder(OSSL_DECODER_CTX *ctx, OSSL_DECODER *decoder)
- {
- OSSL_DECODER_INSTANCE *decoder_inst = NULL;
- const OSSL_PROVIDER *prov = NULL;
- OSSL_PARAM params[2];
- void *provctx = NULL;
- if (!ossl_assert(ctx != NULL) || !ossl_assert(decoder != NULL)) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- if (decoder->get_params == NULL) {
- ERR_raise(ERR_LIB_OSSL_DECODER,
- OSSL_DECODER_R_MISSING_GET_PARAMS);
- return 0;
- }
- if (ctx->decoder_insts == NULL
- && (ctx->decoder_insts =
- sk_OSSL_DECODER_INSTANCE_new_null()) == NULL) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- if ((decoder_inst = OPENSSL_zalloc(sizeof(*decoder_inst))) == NULL) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- if (!OSSL_DECODER_up_ref(decoder)) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- decoder_inst->decoder = decoder;
- prov = OSSL_DECODER_provider(decoder_inst->decoder);
- provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
- /* Cache the input type for this encoder */
- params[0] =
- OSSL_PARAM_construct_utf8_ptr(OSSL_DECODER_PARAM_INPUT_TYPE,
- (char **)&decoder_inst->input_type, 0);
- params[1] = OSSL_PARAM_construct_end();
- if (!decoder_inst->decoder->get_params(params)
- || !OSSL_PARAM_modified(¶ms[0]))
- goto err;
- if ((decoder_inst->deserctx = decoder_inst->decoder->newctx(provctx))
- == NULL)
- goto err;
- if (sk_OSSL_DECODER_INSTANCE_push(ctx->decoder_insts, decoder_inst) <= 0)
- goto err;
- return 1;
- err:
- if (decoder_inst != NULL) {
- if (decoder_inst->decoder != NULL)
- decoder_inst->decoder->freectx(decoder_inst->deserctx);
- OSSL_DECODER_free(decoder_inst->decoder);
- OPENSSL_free(decoder_inst);
- }
- return 0;
- }
- int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx,
- OPENSSL_CTX *libctx, const char *propq)
- {
- /*
- * This function goes through existing decoder methods in
- * |ctx->decoder_insts|, and tries to fetch new decoders that produce
- * what the existing ones want as input, and push those newly fetched
- * decoders on top of the same stack.
- * Then it does the same again, but looping over the newly fetched
- * decoders, until there are no more encoders to be fetched, or
- * when we have done this 10 times.
- *
- * we do this with sliding windows on the stack by keeping track of indexes
- * and of the end.
- *
- * +----------------+
- * | DER to RSA | <--- w_prev_start
- * +----------------+
- * | DER to DSA |
- * +----------------+
- * | DER to DH |
- * +----------------+
- * | PEM to DER | <--- w_prev_end, w_new_start
- * +----------------+
- * <--- w_new_end
- */
- size_t w_prev_start, w_prev_end; /* "previous" decoders */
- size_t w_new_start, w_new_end; /* "new" decoders */
- size_t count = 0; /* Calculates how many were added in each iteration */
- size_t depth = 0; /* Counts the number of iterations */
- if (!ossl_assert(ctx != NULL)) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- /*
- * If there is no stack of OSSL_DECODER_INSTANCE, we have nothing
- * more to add. That's fine.
- */
- if (ctx->decoder_insts == NULL)
- return 1;
- w_prev_start = 0;
- w_prev_end = sk_OSSL_DECODER_INSTANCE_num(ctx->decoder_insts);
- do {
- size_t i;
- w_new_start = w_new_end = w_prev_end;
- for (i = w_prev_start; i < w_prev_end; i++) {
- OSSL_DECODER_INSTANCE *decoder_inst =
- sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts, i);
- const char *name = decoder_inst->input_type;
- OSSL_DECODER *decoder = NULL;
- /*
- * If the caller has specified what the initial input should be,
- * and the decoder implementation we're looking at has that
- * input type, there's no point adding on more implementations
- * on top of this one, so we don't.
- */
- if (ctx->start_input_type != NULL
- && strcasecmp(ctx->start_input_type,
- decoder_inst->input_type) != 0)
- continue;
- ERR_set_mark();
- decoder = OSSL_DECODER_fetch(libctx, name, propq);
- ERR_pop_to_mark();
- if (decoder != NULL) {
- size_t j;
- /*
- * Check that we don't already have this decoder in our
- * stack We only need to check among the newly added ones.
- */
- for (j = w_new_start; j < w_new_end; j++) {
- OSSL_DECODER_INSTANCE *check_inst =
- sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts, j);
- if (decoder == check_inst->decoder) {
- /* We found it, so drop the new fetch */
- OSSL_DECODER_free(decoder);
- decoder = NULL;
- break;
- }
- }
- }
- if (decoder == NULL)
- continue;
- /*
- * Apart from keeping w_new_end up to date, We don't care about
- * errors here. If it doesn't collect, then it doesn't...
- */
- if (OSSL_DECODER_CTX_add_decoder(ctx, decoder)) /* ref++ */
- w_new_end++;
- OSSL_DECODER_free(decoder); /* ref-- */
- }
- /* How many were added in this iteration */
- count = w_new_end - w_new_start;
- /* Slide the "previous decoder" windows */
- w_prev_start = w_new_start;
- w_prev_end = w_new_end;
- depth++;
- } while (count != 0 && depth <= 10);
- return 1;
- }
- int OSSL_DECODER_CTX_num_decoders(OSSL_DECODER_CTX *ctx)
- {
- if (ctx == NULL || ctx->decoder_insts == NULL)
- return 0;
- return sk_OSSL_DECODER_INSTANCE_num(ctx->decoder_insts);
- }
- int OSSL_DECODER_CTX_set_construct(OSSL_DECODER_CTX *ctx,
- OSSL_DECODER_CONSTRUCT *construct)
- {
- if (!ossl_assert(ctx != NULL)) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- ctx->construct = construct;
- return 1;
- }
- int OSSL_DECODER_CTX_set_construct_data(OSSL_DECODER_CTX *ctx,
- void *construct_data)
- {
- if (!ossl_assert(ctx != NULL)) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- ctx->construct_data = construct_data;
- return 1;
- }
- int OSSL_DECODER_CTX_set_cleanup(OSSL_DECODER_CTX *ctx,
- OSSL_DECODER_CLEANUP *cleanup)
- {
- if (!ossl_assert(ctx != NULL)) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- ctx->cleanup = cleanup;
- return 1;
- }
- OSSL_DECODER_CONSTRUCT *
- OSSL_DECODER_CTX_get_construct(OSSL_DECODER_CTX *ctx)
- {
- if (ctx == NULL)
- return NULL;
- return ctx->construct;
- }
- void *OSSL_DECODER_CTX_get_construct_data(OSSL_DECODER_CTX *ctx)
- {
- if (ctx == NULL)
- return NULL;
- return ctx->construct_data;
- }
- OSSL_DECODER_CLEANUP *
- OSSL_DECODER_CTX_get_cleanup(OSSL_DECODER_CTX *ctx)
- {
- if (ctx == NULL)
- return NULL;
- return ctx->cleanup;
- }
- int OSSL_DECODER_export(OSSL_DECODER_INSTANCE *decoder_inst,
- void *reference, size_t reference_sz,
- OSSL_CALLBACK *export_cb, void *export_cbarg)
- {
- if (!(ossl_assert(decoder_inst != NULL)
- && ossl_assert(reference != NULL)
- && ossl_assert(export_cb != NULL)
- && ossl_assert(export_cbarg != NULL))) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- return decoder_inst->decoder->export_object(decoder_inst->deserctx,
- reference, reference_sz,
- export_cb, export_cbarg);
- }
- OSSL_DECODER *OSSL_DECODER_INSTANCE_decoder(OSSL_DECODER_INSTANCE *decoder_inst)
- {
- if (decoder_inst == NULL)
- return NULL;
- return decoder_inst->decoder;
- }
- void *OSSL_DECODER_INSTANCE_decoder_ctx(OSSL_DECODER_INSTANCE *decoder_inst)
- {
- if (decoder_inst == NULL)
- return NULL;
- return decoder_inst->deserctx;
- }
- static int decoder_process(const OSSL_PARAM params[], void *arg)
- {
- struct decoder_process_data_st *data = arg;
- OSSL_DECODER_CTX *ctx = data->ctx;
- OSSL_DECODER_INSTANCE *decoder_inst = NULL;
- OSSL_DECODER *decoder = NULL;
- BIO *bio = data->bio;
- long loc;
- size_t i;
- int ok = 0;
- /* For recursions */
- struct decoder_process_data_st new_data;
- memset(&new_data, 0, sizeof(new_data));
- new_data.ctx = data->ctx;
- if (params == NULL) {
- /* First iteration, where we prepare for what is to come */
- data->current_deser_inst_index =
- OSSL_DECODER_CTX_num_decoders(ctx);
- bio = data->bio;
- } else {
- const OSSL_PARAM *p;
- decoder_inst =
- sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts,
- data->current_deser_inst_index);
- decoder = OSSL_DECODER_INSTANCE_decoder(decoder_inst);
- if (ctx->construct != NULL
- && ctx->construct(decoder_inst, params, ctx->construct_data)) {
- ok = 1;
- goto end;
- }
- /* The constructor didn't return success */
- /*
- * so we try to use the object we got and feed it to any next
- * decoder that will take it. Object references are not
- * allowed for this.
- * If this data isn't present, decoding has failed.
- */
- p = OSSL_PARAM_locate_const(params, OSSL_DECODER_PARAM_DATA);
- if (p == NULL || p->data_type != OSSL_PARAM_OCTET_STRING)
- goto end;
- new_data.bio = BIO_new_mem_buf(p->data, (int)p->data_size);
- if (new_data.bio == NULL)
- goto end;
- bio = new_data.bio;
- }
- /*
- * If we have no more decoders to look through at this point,
- * we failed
- */
- if (data->current_deser_inst_index == 0)
- goto end;
- if ((loc = BIO_tell(bio)) < 0) {
- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_BIO_LIB);
- goto end;
- }
- for (i = data->current_deser_inst_index; i-- > 0;) {
- OSSL_DECODER_INSTANCE *new_deser_inst =
- sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts, i);
- OSSL_DECODER *new_deser =
- OSSL_DECODER_INSTANCE_decoder(new_deser_inst);
- /*
- * If |decoder| is NULL, it means we've just started, and the caller
- * may have specified what it expects the initial input to be. If
- * that's the case, we do this extra check.
- */
- if (decoder == NULL && ctx->start_input_type != NULL
- && strcasecmp(ctx->start_input_type,
- new_deser_inst->input_type) != 0)
- continue;
- /*
- * If we have a previous decoder, we check that the input type
- * of the next to be used matches the type of this previous one.
- * decoder_inst->input_type is a cache of the parameter "input-type"
- * value for that decoder.
- */
- if (decoder != NULL
- && !OSSL_DECODER_is_a(decoder, new_deser_inst->input_type))
- continue;
- /*
- * Checking the return value of BIO_reset() or BIO_seek() is unsafe.
- * Furthermore, BIO_reset() is unsafe to use if the source BIO happens
- * to be a BIO_s_mem(), because the earlier BIO_tell() gives us zero
- * no matter where we are in the underlying buffer we're reading from.
- *
- * So, we simply do a BIO_seek(), and use BIO_tell() that we're back
- * at the same position. This is a best effort attempt, but BIO_seek()
- * and BIO_tell() should come as a pair...
- */
- (void)BIO_seek(bio, loc);
- if (BIO_tell(bio) != loc)
- goto end;
- /* Recurse */
- new_data.current_deser_inst_index = i;
- ok = new_deser->decode(new_deser_inst->deserctx, (OSSL_CORE_BIO *)bio,
- decoder_process, &new_data,
- ctx->passphrase_cb, new_data.ctx);
- if (ok)
- break;
- }
- end:
- BIO_free(new_data.bio);
- return ok;
- }
|