2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #include "e_os.h" /* strcasecmp on Windows */
11 #include <openssl/core_names.h>
12 #include <openssl/bio.h>
13 #include <openssl/encoder.h>
14 #include <openssl/buffer.h>
15 #include <openssl/params.h>
16 #include <openssl/provider.h>
17 #include "encoder_local.h"
19 static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out);
21 int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
23 return encoder_process(ctx, out);
26 #ifndef OPENSSL_NO_STDIO
27 static BIO *bio_from_file(FILE *fp)
31 if ((b = BIO_new(BIO_s_file())) == NULL) {
32 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_BUF_LIB);
35 BIO_set_fp(b, fp, BIO_NOCLOSE);
39 int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp)
41 BIO *b = bio_from_file(fp);
45 ret = OSSL_ENCODER_to_bio(ctx, b);
52 int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
53 const char *output_type)
55 if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
56 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
60 ctx->output_type = output_type;
64 int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
66 if (!ossl_assert(ctx != NULL)) {
67 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
71 if (!ossl_assert(selection != 0)) {
72 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
76 ctx->selection = selection;
80 static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
83 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
86 if (!ossl_assert(encoder != NULL)) {
87 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
91 if (encoder->get_params == NULL) {
92 ERR_raise(ERR_LIB_OSSL_ENCODER,
93 OSSL_ENCODER_R_MISSING_GET_PARAMS);
97 if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) {
98 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
103 * Cache the input and output types for this encoder. The output type
107 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
108 (char **)&encoder_inst->output_type, 0);
110 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_INPUT_TYPE,
111 (char **)&encoder_inst->input_type, 0);
112 params[2] = OSSL_PARAM_construct_end();
114 if (!encoder->get_params(params)
115 || !OSSL_PARAM_modified(¶ms[1]))
118 if (!OSSL_ENCODER_up_ref(encoder)) {
119 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
123 encoder_inst->encoder = encoder;
124 encoder_inst->encoderctx = encoderctx;
127 ossl_encoder_instance_free(encoder_inst);
131 void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
133 if (encoder_inst != NULL) {
134 if (encoder_inst->encoder != NULL)
135 encoder_inst->encoder->freectx(encoder_inst->encoderctx);
136 encoder_inst->encoderctx = NULL;
137 OSSL_ENCODER_free(encoder_inst->encoder);
138 encoder_inst->encoder = NULL;
139 OPENSSL_free(encoder_inst);
143 static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
144 OSSL_ENCODER_INSTANCE *ei)
146 if (ctx->encoder_insts == NULL
147 && (ctx->encoder_insts =
148 sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) {
149 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
153 return (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
156 int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
158 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
159 const OSSL_PROVIDER *prov = NULL;
160 void *encoderctx = NULL;
161 void *provctx = NULL;
163 if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
164 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
168 prov = OSSL_ENCODER_provider(encoder);
169 provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
171 if ((encoderctx = encoder->newctx(provctx)) == NULL
173 ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
175 /* Avoid double free of encoderctx on further errors */
178 if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
183 ossl_encoder_instance_free(encoder_inst);
184 if (encoderctx != NULL)
185 encoder->freectx(encoderctx);
189 int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
190 OPENSSL_CTX *libctx, const char *propq)
195 int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
197 if (ctx == NULL || ctx->encoder_insts == NULL)
199 return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
202 int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
203 OSSL_ENCODER_CONSTRUCT *construct)
205 if (!ossl_assert(ctx != NULL)) {
206 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
209 ctx->construct = construct;
213 int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
214 void *construct_data)
216 if (!ossl_assert(ctx != NULL)) {
217 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
220 ctx->construct_data = construct_data;
224 int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
225 OSSL_ENCODER_CLEANUP *cleanup)
227 if (!ossl_assert(ctx != NULL)) {
228 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
231 ctx->cleanup = cleanup;
236 OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
238 if (encoder_inst == NULL)
240 return encoder_inst->encoder;
244 OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
246 if (encoder_inst == NULL)
248 return encoder_inst->encoderctx;
252 OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst)
254 if (encoder_inst == NULL)
256 return encoder_inst->input_type;
260 OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
262 if (encoder_inst == NULL)
264 return encoder_inst->output_type;
267 static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
270 void *latest_output = NULL;
271 size_t latest_output_length = 0;
272 const char *latest_output_type = NULL;
273 const char *last_input_type = NULL;
276 end = OSSL_ENCODER_CTX_get_num_encoders(ctx);
277 for (i = 0; i < end; i++) {
278 OSSL_ENCODER_INSTANCE *encoder_inst =
279 sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
280 OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
281 void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
282 const char *current_input_type =
283 OSSL_ENCODER_INSTANCE_get_input_type(encoder_inst);
284 const char *current_output_type =
285 OSSL_ENCODER_INSTANCE_get_output_type(encoder_inst);
287 BIO *allocated_out = NULL;
288 const void *current_data = NULL;
289 OSSL_PARAM abstract[3];
290 OSSL_PARAM *abstract_p;
291 const OSSL_PARAM *current_abstract = NULL;
293 if (latest_output_type == NULL) {
295 * This is the first iteration, so we prepare the object to be
299 current_data = ctx->construct(encoder_inst, ctx->construct_data);
301 /* Assume that the constructor recorded an error */
302 if (current_data == NULL)
306 * Check that the latest output type matches the currently
309 if (!OSSL_ENCODER_is_a(encoder, latest_output_type))
313 * If there is a latest output type, there should be a latest output
315 if (!ossl_assert(latest_output != NULL)) {
316 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
321 * Create an object abstraction from the latest output, which was
322 * stolen from the previous round.
324 abstract_p = abstract;
325 if (last_input_type != NULL)
327 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
328 (char *)last_input_type, 0);
330 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
332 latest_output_length);
333 *abstract_p = OSSL_PARAM_construct_end();
334 current_abstract = abstract;
338 * If the desired output type matches the output type of the currently
339 * considered encoder, we're setting up final output. Otherwise, set
340 * up an intermediary memory output.
342 if (strcasecmp(ctx->output_type, current_output_type) == 0)
344 else if ((current_out = allocated_out = BIO_new(BIO_s_mem())) == NULL)
345 goto loop_end; /* Assume BIO_new() recorded an error */
347 ok = encoder->encode(encoderctx, (OSSL_CORE_BIO *)current_out,
348 current_data, current_abstract, ctx->selection,
349 ossl_pw_passphrase_callback_enc, &ctx->pwdata);
351 if (current_input_type != NULL)
352 last_input_type = current_input_type;
357 OPENSSL_free(latest_output);
360 * Steal the output from the BIO_s_mem, if we did allocate one.
361 * That'll be the data for an object abstraction in the next round.
363 if (allocated_out != NULL) {
366 BIO_get_mem_ptr(allocated_out, &buf);
367 latest_output = buf->data;
368 latest_output_length = buf->length;
369 memset(buf, 0, sizeof(*buf));
370 BIO_free(allocated_out);
374 if (current_data != NULL)
375 ctx->cleanup(ctx->construct_data);
381 OPENSSL_free(latest_output);