/*
* 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
*/
#include <openssl/core_names.h>
#include <openssl/bio.h>
#include <openssl/params.h>
#include <openssl/provider.h>
#include <openssl/evperr.h>
#include <openssl/ecerr.h>
#include <openssl/pkcs12err.h>
#include <openssl/x509err.h>
#include <openssl/trace.h>
#include "internal/passphrase.h"
#include "internal/bio.h"
#include "crypto/decoder.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_decoder_inst_index;
/* For tracing, count recursion level */
size_t recursion;
/*-
* Flags
*/
unsigned int flag_next_level_called : 1;
unsigned int flag_construct_called : 1;
};
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;
BIO *new_bio = NULL;
if (BIO_tell(in) < 0) {
new_bio = BIO_new(BIO_f_readbuffer());
if (new_bio == NULL)
return 0;
in = BIO_push(new_bio, in);
}
memset(&data, 0, sizeof(data));
data.ctx = ctx;
data.bio = in;
/* Enable passphrase caching */
(void)ossl_pw_enable_passphrase_caching(&ctx->pwdata);
ok = decoder_process(NULL, &data);
if (!data.flag_construct_called) {
const char *spaces
= ctx->start_input_type != NULL && ctx->input_structure != NULL
? " " : "";
const char *input_type_label
= ctx->start_input_type != NULL ? "Input type: " : "";
const char *input_structure_label
= ctx->input_structure != NULL ? "Input structure: " : "";
const char *comma
= ctx->start_input_type != NULL && ctx->input_structure != NULL
? ", " : "";
const char *input_type
= ctx->start_input_type != NULL ? ctx->start_input_type : "";
const char *input_structure
= ctx->input_structure != NULL ? ctx->input_structure : "";
if (BIO_eof(in) == 0 /* Prevent spurious decoding error */)
ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_UNSUPPORTED,
"Not supported for the data to decode.%s%s%s%s%s%s",
spaces, input_type_label, input_type, comma,
input_structure_label, input_structure);
ok = 0;
}
/* Clear any internally cached passphrase */
(void)ossl_pw_clear_passphrase_cache(&ctx->pwdata);
if (new_bio != NULL) {
BIO_pop(new_bio);
BIO_free(new_bio);
}
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_from_data(OSSL_DECODER_CTX *ctx, const unsigned char **pdata,
size_t *pdata_len)
{
BIO *membio;
int ret = 0;
if (pdata == NULL || *pdata == NULL || pdata_len == NULL) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
membio = BIO_new_mem_buf(*pdata, (int)*pdata_len);
if (OSSL_DECODER_from_bio(ctx, membio)) {
*pdata_len = (size_t)BIO_get_mem_data(membio, pdata);
ret = 1;
}
BIO_free(membio);
return ret;
}
int OSSL_DECODER_CTX_set_selection(OSSL_DECODER_CTX *ctx, int selection)
{
if (!ossl_assert(ctx != NULL)) {
ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
/*
* 0 is a valid selection, and means that the caller leaves
* it to code to discover what the selection is.
*/
ctx->selection = selection;
return 1;
}
int OSSL_DECODER_CTX_set_input_type(OSSL_DECODER_CTX *ctx,
const char