2 * Copyright 2019-2020 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
);