summaryrefslogtreecommitdiff
path: root/crypto/encode_decode/encoder_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/encode_decode/encoder_lib.c')
-rw-r--r--crypto/encode_decode/encoder_lib.c674
1 files changed, 674 insertions, 0 deletions
diff --git a/crypto/encode_decode/encoder_lib.c b/crypto/encode_decode/encoder_lib.c
new file mode 100644
index 000000000000..7a55c7ab9a27
--- /dev/null
+++ b/crypto/encode_decode/encoder_lib.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright 2019-2022 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/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;
+ BUF_MEM *buf = NULL;
+ int ret = 0;
+
+ if (pdata_len == NULL) {
+ ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ out = BIO_new(BIO_s_mem());
+
+ if (out != NULL
+ && 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):\n"
+ " %s with %s\n",
+ (void *)ctx, (void *)ei, (void *)ei->encoder,
+ OSSL_ENCODER_get0_name(ei->encoder),
+ OSSL_ENCODER_get0_properties(ei->encoder));
+ } 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
+ && OPENSSL_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 (OPENSSL_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;
+}