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_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata,
55 BIO *out = BIO_new(BIO_s_mem());
59 if (pdata_len == NULL) {
60 ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
64 if (OSSL_ENCODER_to_bio(ctx, out)
65 && BIO_get_mem_ptr(out, &buf) > 0) {
66 ret = 1; /* Hope for the best. A too small buffer will clear this */
68 if (pdata != NULL && *pdata != NULL) {
69 if (*pdata_len < buf->length)
71 * It's tempting to do |*pdata_len = (size_t)buf->length|
72 * However, it's believed to be confusing more than helpful,
77 *pdata_len -= buf->length;
79 /* The buffer with the right size is already allocated for us */
80 *pdata_len = (size_t)buf->length;
86 memcpy(*pdata, buf->data, buf->length);
87 *pdata += buf->length;
89 /* In this case, we steal the data from BIO_s_mem() */
90 *pdata = (unsigned char *)buf->data;
100 int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
101 const char *output_type)
103 if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
104 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
108 ctx->output_type = output_type;
112 int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
114 if (!ossl_assert(ctx != NULL)) {
115 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
119 if (!ossl_assert(selection != 0)) {
120 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
124 ctx->selection = selection;
128 static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
131 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
132 OSSL_PARAM params[3];
134 if (!ossl_assert(encoder != NULL)) {
135 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
139 if (encoder->get_params == NULL) {
140 ERR_raise(ERR_LIB_OSSL_ENCODER,
141 OSSL_ENCODER_R_MISSING_GET_PARAMS);
145 if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) {
146 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
151 * Cache the input and output types for this encoder. The output type
155 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
156 (char **)&encoder_inst->output_type, 0);
158 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_INPUT_TYPE,
159 (char **)&encoder_inst->input_type, 0);
160 params[2] = OSSL_PARAM_construct_end();
162 if (!encoder->get_params(params)
163 || !OSSL_PARAM_modified(¶ms[1]))
166 if (!OSSL_ENCODER_up_ref(encoder)) {
167 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
171 encoder_inst->encoder = encoder;
172 encoder_inst->encoderctx = encoderctx;
175 ossl_encoder_instance_free(encoder_inst);
179 void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
181 if (encoder_inst != NULL) {
182 if (encoder_inst->encoder != NULL)
183 encoder_inst->encoder->freectx(encoder_inst->encoderctx);
184 encoder_inst->encoderctx = NULL;
185 OSSL_ENCODER_free(encoder_inst->encoder);
186 encoder_inst->encoder = NULL;
187 OPENSSL_free(encoder_inst);
191 static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
192 OSSL_ENCODER_INSTANCE *ei)
194 if (ctx->encoder_insts == NULL
195 && (ctx->encoder_insts =
196 sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) {
197 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
201 return (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
204 int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
206 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
207 const OSSL_PROVIDER *prov = NULL;
208 void *encoderctx = NULL;
209 void *provctx = NULL;
211 if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
212 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
216 prov = OSSL_ENCODER_provider(encoder);
217 provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
219 if ((encoderctx = encoder->newctx(provctx)) == NULL
221 ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
223 /* Avoid double free of encoderctx on further errors */
226 if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
231 ossl_encoder_instance_free(encoder_inst);
232 if (encoderctx != NULL)
233 encoder->freectx(encoderctx);
237 int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
238 OSSL_LIB_CTX *libctx, const char *propq)
243 int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
245 if (ctx == NULL || ctx->encoder_insts == NULL)
247 return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
250 int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
251 OSSL_ENCODER_CONSTRUCT *construct)
253 if (!ossl_assert(ctx != NULL)) {
254 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
257 ctx->construct = construct;
261 int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
262 void *construct_data)
264 if (!ossl_assert(ctx != NULL)) {
265 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
268 ctx->construct_data = construct_data;
272 int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
273 OSSL_ENCODER_CLEANUP *cleanup)
275 if (!ossl_assert(ctx != NULL)) {
276 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
279 ctx->cleanup = cleanup;
284 OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
286 if (encoder_inst == NULL)
288 return encoder_inst->encoder;
292 OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
294 if (encoder_inst == NULL)
296 return encoder_inst->encoderctx;
300 OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst)
302 if (encoder_inst == NULL)
304 return encoder_inst->input_type;
308 OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
310 if (encoder_inst == NULL)
312 return encoder_inst->output_type;
315 static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
318 void *latest_output = NULL;
319 size_t latest_output_length = 0;
320 const char *latest_output_type = NULL;
321 const char *last_input_type = NULL;
324 end = OSSL_ENCODER_CTX_get_num_encoders(ctx);
325 for (i = 0; i < end; i++) {
326 OSSL_ENCODER_INSTANCE *encoder_inst =
327 sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
328 OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
329 void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
330 const char *current_input_type =
331 OSSL_ENCODER_INSTANCE_get_input_type(encoder_inst);
332 const char *current_output_type =
333 OSSL_ENCODER_INSTANCE_get_output_type(encoder_inst);
335 BIO *allocated_out = NULL;
336 const void *current_data = NULL;
337 OSSL_PARAM abstract[3];
338 OSSL_PARAM *abstract_p;
339 const OSSL_PARAM *current_abstract = NULL;
341 if (latest_output_type == NULL) {
343 * This is the first iteration, so we prepare the object to be
347 current_data = ctx->construct(encoder_inst, ctx->construct_data);
349 /* Assume that the constructor recorded an error */
350 if (current_data == NULL)
354 * Check that the latest output type matches the currently
357 if (!OSSL_ENCODER_is_a(encoder, latest_output_type))
361 * If there is a latest output type, there should be a latest output
363 if (!ossl_assert(latest_output != NULL)) {
364 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
369 * Create an object abstraction from the latest output, which was
370 * stolen from the previous round.
372 abstract_p = abstract;
373 if (last_input_type != NULL)
375 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
376 (char *)last_input_type, 0);
378 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
380 latest_output_length);
381 *abstract_p = OSSL_PARAM_construct_end();
382 current_abstract = abstract;
386 * If the desired output type matches the output type of the currently
387 * considered encoder, we're setting up final output. Otherwise, set
388 * up an intermediary memory output.
390 if (strcasecmp(ctx->output_type, current_output_type) == 0)
392 else if ((current_out = allocated_out = BIO_new(BIO_s_mem())) == NULL)
393 goto loop_end; /* Assume BIO_new() recorded an error */
395 ok = encoder->encode(encoderctx, (OSSL_CORE_BIO *)current_out,
396 current_data, current_abstract, ctx->selection,
397 ossl_pw_passphrase_callback_enc, &ctx->pwdata);
399 if (current_input_type != NULL)
400 last_input_type = current_input_type;
405 OPENSSL_free(latest_output);
408 * Steal the output from the BIO_s_mem, if we did allocate one.
409 * That'll be the data for an object abstraction in the next round.
411 if (allocated_out != NULL) {
414 BIO_get_mem_ptr(allocated_out, &buf);
415 latest_output = buf->data;
416 latest_output_length = buf->length;
417 memset(buf, 0, sizeof(*buf));
418 BIO_free(allocated_out);
422 if (current_data != NULL)
423 ctx->cleanup(ctx->construct_data);
429 OPENSSL_free(latest_output);