mirror of
https://github.com/openssl/openssl.git
synced 2024-12-27 06:21:43 +08:00
e982e04f5d
The OSSL_ENCODER library used to ask each encoder implementation for certain data in form of parameters to place them correctly in the encoder chain, if at all. These parameters were duplicates of properties of those same implementations, and therefore unnecessarily redundant. Now that we have functionality to query property definition values, those duplicates are no longer needed, and are therefore not looked at any more. Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/15570)
673 lines
22 KiB
C
673 lines
22 KiB
C
/*
|
|
* Copyright 2019-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 "e_os.h" /* strcasecmp on Windows */
|
|
#include <openssl/core_names.h>
|
|
#include <openssl/bio.h>
|
|
#include <openssl/encoder.h>
|
|
#include <openssl/buffer.h>
|
|
#include <openssl/params.h>
|
|
#include <openssl/provider.h>
|
|
#include <openssl/trace.h>
|
|
#include "internal/bio.h"
|
|
#include "internal/provider.h"
|
|
#include "encoder_local.h"
|
|
|
|
struct encoder_process_data_st {
|
|
OSSL_ENCODER_CTX *ctx;
|
|
|
|
/* Current BIO */
|
|
BIO *bio;
|
|
|
|
/* Index of the current encoder instance to be processed */
|
|
int current_encoder_inst_index;
|
|
|
|
/* Processing data passed down through recursion */
|
|
int level; /* Recursion level */
|
|
OSSL_ENCODER_INSTANCE *next_encoder_inst;
|
|
int count_output_structure;
|
|
|
|
/* Processing data passed up through recursion */
|
|
OSSL_ENCODER_INSTANCE *prev_encoder_inst;
|
|
unsigned char *running_output;
|
|
size_t running_output_length;
|
|
/* Data type = the name of the first succeeding encoder implementation */
|
|
const char *data_type;
|
|
};
|
|
|
|
static int encoder_process(struct encoder_process_data_st *data);
|
|
|
|
int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
|
|
{
|
|
struct encoder_process_data_st data;
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
data.ctx = ctx;
|
|
data.bio = out;
|
|
data.current_encoder_inst_index = OSSL_ENCODER_CTX_get_num_encoders(ctx);
|
|
|
|
if (data.current_encoder_inst_index == 0) {
|
|
ERR_raise_data(ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_ENCODER_NOT_FOUND,
|
|
"No encoders were found. For standard encoders you need "
|
|
"at least one of the default or base providers "
|
|
"available. Did you forget to load them?");
|
|
return 0;
|
|
}
|
|
|
|
return encoder_process(&data) > 0;
|
|
}
|
|
|
|
#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_ENCODER, ERR_R_BUF_LIB);
|
|
return NULL;
|
|
}
|
|
BIO_set_fp(b, fp, BIO_NOCLOSE);
|
|
return b;
|
|
}
|
|
|
|
int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp)
|
|
{
|
|
BIO *b = bio_from_file(fp);
|
|
int ret = 0;
|
|
|
|
if (b != NULL)
|
|
ret = OSSL_ENCODER_to_bio(ctx, b);
|
|
|
|
BIO_free(b);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata,
|
|
size_t *pdata_len)
|
|
{
|
|
BIO *out = BIO_new(BIO_s_mem());
|
|
BUF_MEM *buf = NULL;
|
|
int ret = 0;
|
|
|
|
if (pdata_len == NULL) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (OSSL_ENCODER_to_bio(ctx, out)
|
|
&& BIO_get_mem_ptr(out, &buf) > 0) {
|
|
ret = 1; /* Hope for the best. A too small buffer will clear this */
|
|
|
|
if (pdata != NULL && *pdata != NULL) {
|
|
if (*pdata_len < buf->length)
|
|
/*
|
|
* It's tempting to do |*pdata_len = (size_t)buf->length|
|
|
* However, it's believed to be confusing more than helpful,
|
|
* so we don't.
|
|
*/
|
|
ret = 0;
|
|
else
|
|
*pdata_len -= buf->length;
|
|
} else {
|
|
/* The buffer with the right size is already allocated for us */
|
|
*pdata_len = (size_t)buf->length;
|
|
}
|
|
|
|
if (ret) {
|
|
if (pdata != NULL) {
|
|
if (*pdata != NULL) {
|
|
memcpy(*pdata, buf->data, buf->length);
|
|
*pdata += buf->length;
|
|
} else {
|
|
/* In this case, we steal the data from BIO_s_mem() */
|
|
*pdata = (unsigned char *)buf->data;
|
|
buf->data = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
BIO_free(out);
|
|
return ret;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
|
|
{
|
|
if (!ossl_assert(ctx != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (!ossl_assert(selection != 0)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
|
|
return 0;
|
|
}
|
|
|
|
ctx->selection = selection;
|
|
return 1;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
|
|
const char *output_type)
|
|
{
|
|
if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
ctx->output_type = output_type;
|
|
return 1;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
|
|
const char *output_structure)
|
|
{
|
|
if (!ossl_assert(ctx != NULL) || !ossl_assert(output_structure != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
ctx->output_structure = output_structure;
|
|
return 1;
|
|
}
|
|
|
|
static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
|
|
void *encoderctx)
|
|
{
|
|
OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
|
|
const OSSL_PROVIDER *prov;
|
|
OSSL_LIB_CTX *libctx;
|
|
const OSSL_PROPERTY_LIST *props;
|
|
const OSSL_PROPERTY_DEFINITION *prop;
|
|
|
|
if (!ossl_assert(encoder != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
if (!OSSL_ENCODER_up_ref(encoder)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
|
|
goto err;
|
|
}
|
|
|
|
prov = OSSL_ENCODER_get0_provider(encoder);
|
|
libctx = ossl_provider_libctx(prov);
|
|
props = ossl_encoder_parsed_properties(encoder);
|
|
if (props == NULL) {
|
|
ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION,
|
|
"there are no property definitions with encoder %s",
|
|
OSSL_ENCODER_get0_name(encoder));
|
|
goto err;
|
|
}
|
|
|
|
/* The "output" property is mandatory */
|
|
prop = ossl_property_find_property(props, libctx, "output");
|
|
encoder_inst->output_type = ossl_property_get_string_value(libctx, prop);
|
|
if (encoder_inst->output_type == NULL) {
|
|
ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION,
|
|
"the mandatory 'output' property is missing "
|
|
"for encoder %s (properties: %s)",
|
|
OSSL_ENCODER_get0_name(encoder),
|
|
OSSL_ENCODER_get0_properties(encoder));
|
|
goto err;
|
|
}
|
|
|
|
/* The "structure" property is optional */
|
|
prop = ossl_property_find_property(props, libctx, "structure");
|
|
if (prop != NULL)
|
|
encoder_inst->output_structure
|
|
= ossl_property_get_string_value(libctx, prop);
|
|
|
|
encoder_inst->encoder = encoder;
|
|
encoder_inst->encoderctx = encoderctx;
|
|
return encoder_inst;
|
|
err:
|
|
ossl_encoder_instance_free(encoder_inst);
|
|
return NULL;
|
|
}
|
|
|
|
void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
|
|
{
|
|
if (encoder_inst != NULL) {
|
|
if (encoder_inst->encoder != NULL)
|
|
encoder_inst->encoder->freectx(encoder_inst->encoderctx);
|
|
encoder_inst->encoderctx = NULL;
|
|
OSSL_ENCODER_free(encoder_inst->encoder);
|
|
encoder_inst->encoder = NULL;
|
|
OPENSSL_free(encoder_inst);
|
|
}
|
|
}
|
|
|
|
static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
|
|
OSSL_ENCODER_INSTANCE *ei)
|
|
{
|
|
int ok;
|
|
|
|
if (ctx->encoder_insts == NULL
|
|
&& (ctx->encoder_insts =
|
|
sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
ok = (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
|
|
if (ok) {
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"(ctx %p) Added encoder instance %p (encoder %p) with:\n",
|
|
(void *)ctx, (void *)ei, (void *)ei->encoder);
|
|
BIO_printf(trc_out,
|
|
" output type: %s, output structure: %s\n",
|
|
ei->output_type, ei->output_structure);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
|
|
{
|
|
OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
|
|
const OSSL_PROVIDER *prov = NULL;
|
|
void *encoderctx = NULL;
|
|
void *provctx = NULL;
|
|
|
|
if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
prov = OSSL_ENCODER_get0_provider(encoder);
|
|
provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
|
|
|
|
if ((encoderctx = encoder->newctx(provctx)) == NULL
|
|
|| (encoder_inst =
|
|
ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
|
|
goto err;
|
|
/* Avoid double free of encoderctx on further errors */
|
|
encoderctx = NULL;
|
|
|
|
if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
|
|
goto err;
|
|
|
|
return 1;
|
|
err:
|
|
ossl_encoder_instance_free(encoder_inst);
|
|
if (encoderctx != NULL)
|
|
encoder->freectx(encoderctx);
|
|
return 0;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
|
|
OSSL_LIB_CTX *libctx, const char *propq)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
|
|
{
|
|
if (ctx == NULL || ctx->encoder_insts == NULL)
|
|
return 0;
|
|
return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
|
|
OSSL_ENCODER_CONSTRUCT *construct)
|
|
{
|
|
if (!ossl_assert(ctx != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
ctx->construct = construct;
|
|
return 1;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
|
|
void *construct_data)
|
|
{
|
|
if (!ossl_assert(ctx != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
ctx->construct_data = construct_data;
|
|
return 1;
|
|
}
|
|
|
|
int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
|
|
OSSL_ENCODER_CLEANUP *cleanup)
|
|
{
|
|
if (!ossl_assert(ctx != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
ctx->cleanup = cleanup;
|
|
return 1;
|
|
}
|
|
|
|
OSSL_ENCODER *
|
|
OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
|
|
{
|
|
if (encoder_inst == NULL)
|
|
return NULL;
|
|
return encoder_inst->encoder;
|
|
}
|
|
|
|
void *
|
|
OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
|
|
{
|
|
if (encoder_inst == NULL)
|
|
return NULL;
|
|
return encoder_inst->encoderctx;
|
|
}
|
|
|
|
const char *
|
|
OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
|
|
{
|
|
if (encoder_inst == NULL)
|
|
return NULL;
|
|
return encoder_inst->output_type;
|
|
}
|
|
|
|
const char *
|
|
OSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE *encoder_inst)
|
|
{
|
|
if (encoder_inst == NULL)
|
|
return NULL;
|
|
return encoder_inst->output_structure;
|
|
}
|
|
|
|
static int encoder_process(struct encoder_process_data_st *data)
|
|
{
|
|
OSSL_ENCODER_INSTANCE *current_encoder_inst = NULL;
|
|
OSSL_ENCODER *current_encoder = NULL;
|
|
OSSL_ENCODER_CTX *current_encoder_ctx = NULL;
|
|
BIO *allocated_out = NULL;
|
|
const void *original_data = NULL;
|
|
OSSL_PARAM abstract[10];
|
|
const OSSL_PARAM *current_abstract = NULL;
|
|
int i;
|
|
int ok = -1; /* -1 signifies that the lookup loop gave nothing */
|
|
int top = 0;
|
|
|
|
if (data->next_encoder_inst == NULL) {
|
|
/* First iteration, where we prepare for what is to come */
|
|
|
|
data->count_output_structure =
|
|
data->ctx->output_structure == NULL ? -1 : 0;
|
|
top = 1;
|
|
}
|
|
|
|
for (i = data->current_encoder_inst_index; i-- > 0;) {
|
|
OSSL_ENCODER *next_encoder = NULL;
|
|
const char *current_output_type;
|
|
const char *current_output_structure;
|
|
struct encoder_process_data_st new_data;
|
|
|
|
if (!top)
|
|
next_encoder =
|
|
OSSL_ENCODER_INSTANCE_get_encoder(data->next_encoder_inst);
|
|
|
|
current_encoder_inst =
|
|
sk_OSSL_ENCODER_INSTANCE_value(data->ctx->encoder_insts, i);
|
|
current_encoder =
|
|
OSSL_ENCODER_INSTANCE_get_encoder(current_encoder_inst);
|
|
current_encoder_ctx =
|
|
OSSL_ENCODER_INSTANCE_get_encoder_ctx(current_encoder_inst);
|
|
current_output_type =
|
|
OSSL_ENCODER_INSTANCE_get_output_type(current_encoder_inst);
|
|
current_output_structure =
|
|
OSSL_ENCODER_INSTANCE_get_output_structure(current_encoder_inst);
|
|
memset(&new_data, 0, sizeof(new_data));
|
|
new_data.ctx = data->ctx;
|
|
new_data.current_encoder_inst_index = i;
|
|
new_data.next_encoder_inst = current_encoder_inst;
|
|
new_data.count_output_structure = data->count_output_structure;
|
|
new_data.level = data->level + 1;
|
|
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"[%d] (ctx %p) Considering encoder instance %p (encoder %p)\n",
|
|
data->level, (void *)data->ctx,
|
|
(void *)current_encoder_inst, (void *)current_encoder);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
|
|
/*
|
|
* If this is the top call, we check if the output type of the current
|
|
* encoder matches the desired output type.
|
|
* If this isn't the top call, i.e. this is deeper in the recursion,
|
|
* we instead check if the output type of the current encoder matches
|
|
* the name of the next encoder (the one found by the parent call).
|
|
*/
|
|
if (top) {
|
|
if (data->ctx->output_type != NULL
|
|
&& strcasecmp(current_output_type,
|
|
data->ctx->output_type) != 0) {
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"[%d] Skipping because current encoder output type (%s) != desired output type (%s)\n",
|
|
data->level,
|
|
current_output_type, data->ctx->output_type);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
continue;
|
|
}
|
|
} else {
|
|
if (!OSSL_ENCODER_is_a(next_encoder, current_output_type)) {
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"[%d] Skipping because current encoder output type (%s) != name of encoder %p\n",
|
|
data->level,
|
|
current_output_type, (void *)next_encoder);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the caller and the current encoder specify an output structure,
|
|
* Check if they match. If they do, count the match, otherwise skip
|
|
* the current encoder.
|
|
*/
|
|
if (data->ctx->output_structure != NULL
|
|
&& current_output_structure != NULL) {
|
|
if (strcasecmp(data->ctx->output_structure,
|
|
current_output_structure) != 0) {
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"[%d] Skipping because current encoder output structure (%s) != ctx output structure (%s)\n",
|
|
data->level,
|
|
current_output_structure,
|
|
data->ctx->output_structure);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
continue;
|
|
}
|
|
|
|
data->count_output_structure++;
|
|
}
|
|
|
|
/*
|
|
* Recurse to process the encoder implementations before the current
|
|
* one.
|
|
*/
|
|
ok = encoder_process(&new_data);
|
|
|
|
data->prev_encoder_inst = new_data.prev_encoder_inst;
|
|
data->running_output = new_data.running_output;
|
|
data->running_output_length = new_data.running_output_length;
|
|
|
|
/*
|
|
* ok == -1 means that the recursion call above gave no further
|
|
* encoders, and that the one we're currently at should
|
|
* be tried.
|
|
* ok == 0 means that something failed in the recursion call
|
|
* above, making the result unsuitable for a chain.
|
|
* In this case, we simply continue to try finding a
|
|
* suitable encoder at this recursion level.
|
|
* ok == 1 means that the recursion call was successful, and we
|
|
* try to use the result at this recursion level.
|
|
*/
|
|
if (ok != 0)
|
|
break;
|
|
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"[%d] Skipping because recusion level %d failed\n",
|
|
data->level, new_data.level);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
}
|
|
|
|
/*
|
|
* If |i < 0|, we didn't find any useful encoder in this recursion, so
|
|
* we do the rest of the process only if |i >= 0|.
|
|
*/
|
|
if (i < 0) {
|
|
ok = -1;
|
|
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"[%d] (ctx %p) No suitable encoder found\n",
|
|
data->level, (void *)data->ctx);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
} else {
|
|
/* Preparations */
|
|
|
|
switch (ok) {
|
|
case 0:
|
|
break;
|
|
case -1:
|
|
/*
|
|
* We have reached the beginning of the encoder instance sequence,
|
|
* so we prepare the object to be encoded.
|
|
*/
|
|
|
|
/*
|
|
* |data->count_output_structure| is one of these values:
|
|
*
|
|
* -1 There is no desired output structure
|
|
* 0 There is a desired output structure, and it wasn't
|
|
* matched by any of the encoder instances that were
|
|
* considered
|
|
* >0 There is a desired output structure, and at least one
|
|
* of the encoder instances matched it
|
|
*/
|
|
if (data->count_output_structure == 0)
|
|
return 0;
|
|
|
|
original_data =
|
|
data->ctx->construct(current_encoder_inst,
|
|
data->ctx->construct_data);
|
|
|
|
/* Also set the data type, using the encoder implementation name */
|
|
data->data_type = OSSL_ENCODER_get0_name(current_encoder);
|
|
|
|
/* Assume that the constructor recorded an error */
|
|
if (original_data != NULL)
|
|
ok = 1;
|
|
else
|
|
ok = 0;
|
|
break;
|
|
case 1:
|
|
if (!ossl_assert(data->running_output != NULL)) {
|
|
ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
|
|
ok = 0;
|
|
break;
|
|
}
|
|
|
|
{
|
|
/*
|
|
* Create an object abstraction from the latest output, which
|
|
* was stolen from the previous round.
|
|
*/
|
|
|
|
OSSL_PARAM *abstract_p = abstract;
|
|
const char *prev_output_structure =
|
|
OSSL_ENCODER_INSTANCE_get_output_structure(data->prev_encoder_inst);
|
|
|
|
*abstract_p++ =
|
|
OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
|
|
(char *)data->data_type, 0);
|
|
if (prev_output_structure != NULL)
|
|
*abstract_p++ =
|
|
OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
|
|
(char *)prev_output_structure,
|
|
0);
|
|
*abstract_p++ =
|
|
OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
|
|
data->running_output,
|
|
data->running_output_length);
|
|
*abstract_p = OSSL_PARAM_construct_end();
|
|
current_abstract = abstract;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Calling the encoder implementation */
|
|
|
|
if (ok) {
|
|
OSSL_CORE_BIO *cbio = NULL;
|
|
BIO *current_out = NULL;
|
|
|
|
/*
|
|
* If we're at the last encoder instance to use, we're setting up
|
|
* final output. Otherwise, set up an intermediary memory output.
|
|
*/
|
|
if (top)
|
|
current_out = data->bio;
|
|
else if ((current_out = allocated_out = BIO_new(BIO_s_mem()))
|
|
== NULL)
|
|
ok = 0; /* Assume BIO_new() recorded an error */
|
|
|
|
if (ok)
|
|
ok = (cbio = ossl_core_bio_new_from_bio(current_out)) != NULL;
|
|
if (ok) {
|
|
ok = current_encoder->encode(current_encoder_ctx, cbio,
|
|
original_data, current_abstract,
|
|
data->ctx->selection,
|
|
ossl_pw_passphrase_callback_enc,
|
|
&data->ctx->pwdata);
|
|
OSSL_TRACE_BEGIN(ENCODER) {
|
|
BIO_printf(trc_out,
|
|
"[%d] (ctx %p) Running encoder instance %p => %d\n",
|
|
data->level, (void *)data->ctx,
|
|
(void *)current_encoder_inst, ok);
|
|
} OSSL_TRACE_END(ENCODER);
|
|
}
|
|
|
|
ossl_core_bio_free(cbio);
|
|
data->prev_encoder_inst = current_encoder_inst;
|
|
}
|
|
}
|
|
|
|
/* Cleanup and collecting the result */
|
|
|
|
OPENSSL_free(data->running_output);
|
|
data->running_output = NULL;
|
|
|
|
/*
|
|
* Steal the output from the BIO_s_mem, if we did allocate one.
|
|
* That'll be the data for an object abstraction in the next round.
|
|
*/
|
|
if (allocated_out != NULL) {
|
|
BUF_MEM *buf;
|
|
|
|
BIO_get_mem_ptr(allocated_out, &buf);
|
|
data->running_output = (unsigned char *)buf->data;
|
|
data->running_output_length = buf->length;
|
|
memset(buf, 0, sizeof(*buf));
|
|
}
|
|
|
|
BIO_free(allocated_out);
|
|
if (original_data != NULL)
|
|
data->ctx->cleanup(data->ctx->construct_data);
|
|
return ok;
|
|
}
|