]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/encode_decode/encoder_lib.c
Rename OPENSSL_CTX prefix to OSSL_LIB_CTX
[thirdparty/openssl.git] / crypto / encode_decode / encoder_lib.c
CommitLineData
742496f1
RL
1/*
2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
3 *
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
8 */
9
b8975c68
RL
10#include "e_os.h" /* strcasecmp on Windows */
11#include <openssl/core_names.h>
742496f1 12#include <openssl/bio.h>
ece9304c 13#include <openssl/encoder.h>
b8975c68
RL
14#include <openssl/buffer.h>
15#include <openssl/params.h>
16#include <openssl/provider.h>
ece9304c 17#include "encoder_local.h"
742496f1 18
b8975c68
RL
19static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out);
20
ece9304c 21int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
742496f1 22{
b8975c68 23 return encoder_process(ctx, out);
742496f1
RL
24}
25
26#ifndef OPENSSL_NO_STDIO
27static BIO *bio_from_file(FILE *fp)
28{
29 BIO *b;
30
31 if ((b = BIO_new(BIO_s_file())) == NULL) {
ece9304c 32 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_BUF_LIB);
742496f1
RL
33 return NULL;
34 }
35 BIO_set_fp(b, fp, BIO_NOCLOSE);
36 return b;
37}
38
ece9304c 39int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp)
742496f1
RL
40{
41 BIO *b = bio_from_file(fp);
42 int ret = 0;
43
44 if (b != NULL)
ece9304c 45 ret = OSSL_ENCODER_to_bio(ctx, b);
742496f1
RL
46
47 BIO_free(b);
48 return ret;
49}
50#endif
b8975c68 51
25cf949f
RL
52int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata,
53 size_t *pdata_len)
54{
55 BIO *out = BIO_new(BIO_s_mem());
56 BUF_MEM *buf = NULL;
57 int ret = 0;
58
59 if (pdata_len == NULL) {
60 ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
61 return 0;
62 }
63
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 */
67
68 if (pdata != NULL && *pdata != NULL) {
69 if (*pdata_len < buf->length)
70 /*
71 * It's tempting to do |*pdata_len = (size_t)buf->length|
72 * However, it's believed to be confusing more than helpful,
73 * so we don't.
74 */
75 ret = 0;
76 else
77 *pdata_len -= buf->length;
78 } else {
79 /* The buffer with the right size is already allocated for us */
80 *pdata_len = (size_t)buf->length;
81 }
82
83 if (ret) {
84 if (pdata != NULL) {
85 if (*pdata != NULL) {
86 memcpy(*pdata, buf->data, buf->length);
87 *pdata += buf->length;
88 } else {
89 /* In this case, we steal the data from BIO_s_mem() */
90 *pdata = (unsigned char *)buf->data;
91 buf->data = NULL;
92 }
93 }
94 }
95 }
96 BIO_free(out);
97 return ret;
98}
99
b8975c68
RL
100int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
101 const char *output_type)
102{
103 if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
104 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
105 return 0;
106 }
107
108 ctx->output_type = output_type;
109 return 1;
110}
111
112int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
113{
114 if (!ossl_assert(ctx != NULL)) {
115 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
116 return 0;
117 }
118
119 if (!ossl_assert(selection != 0)) {
120 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
121 return 0;
122 }
123
124 ctx->selection = selection;
125 return 1;
126}
127
128static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
129 void *encoderctx)
130{
131 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
132 OSSL_PARAM params[3];
133
134 if (!ossl_assert(encoder != NULL)) {
135 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
136 return 0;
137 }
138
139 if (encoder->get_params == NULL) {
140 ERR_raise(ERR_LIB_OSSL_ENCODER,
141 OSSL_ENCODER_R_MISSING_GET_PARAMS);
142 return 0;
143 }
144
145 if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) {
146 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
147 return 0;
148 }
149
150 /*
151 * Cache the input and output types for this encoder. The output type
152 * is mandatory.
153 */
154 params[0] =
155 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
156 (char **)&encoder_inst->output_type, 0);
157 params[1] =
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();
161
162 if (!encoder->get_params(params)
163 || !OSSL_PARAM_modified(&params[1]))
164 goto err;
165
166 if (!OSSL_ENCODER_up_ref(encoder)) {
167 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
168 goto err;
169 }
170
171 encoder_inst->encoder = encoder;
172 encoder_inst->encoderctx = encoderctx;
173 return encoder_inst;
174 err:
175 ossl_encoder_instance_free(encoder_inst);
176 return NULL;
177}
178
179void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
180{
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);
188 }
189}
190
191static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
192 OSSL_ENCODER_INSTANCE *ei)
193{
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);
198 return 0;
199 }
200
201 return (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
202}
203
204int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
205{
206 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
207 const OSSL_PROVIDER *prov = NULL;
208 void *encoderctx = NULL;
209 void *provctx = NULL;
210
211 if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
212 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
213 return 0;
214 }
215
216 prov = OSSL_ENCODER_provider(encoder);
217 provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
218
219 if ((encoderctx = encoder->newctx(provctx)) == NULL
220 || (encoder_inst =
221 ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
222 goto err;
223 /* Avoid double free of encoderctx on further errors */
224 encoderctx = NULL;
225
226 if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
227 goto err;
228
229 return 1;
230 err:
231 ossl_encoder_instance_free(encoder_inst);
232 if (encoderctx != NULL)
233 encoder->freectx(encoderctx);
234 return 0;
235}
236
237int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
b4250010 238 OSSL_LIB_CTX *libctx, const char *propq)
b8975c68
RL
239{
240 return 1;
241}
242
243int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
244{
245 if (ctx == NULL || ctx->encoder_insts == NULL)
246 return 0;
247 return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
248}
249
250int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
251 OSSL_ENCODER_CONSTRUCT *construct)
252{
253 if (!ossl_assert(ctx != NULL)) {
254 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
255 return 0;
256 }
257 ctx->construct = construct;
258 return 1;
259}
260
261int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
262 void *construct_data)
263{
264 if (!ossl_assert(ctx != NULL)) {
265 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
266 return 0;
267 }
268 ctx->construct_data = construct_data;
269 return 1;
270}
271
272int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
273 OSSL_ENCODER_CLEANUP *cleanup)
274{
275 if (!ossl_assert(ctx != NULL)) {
276 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
277 return 0;
278 }
279 ctx->cleanup = cleanup;
280 return 1;
281}
282
283OSSL_ENCODER *
284OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
285{
286 if (encoder_inst == NULL)
287 return NULL;
288 return encoder_inst->encoder;
289}
290
291void *
292OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
293{
294 if (encoder_inst == NULL)
295 return NULL;
296 return encoder_inst->encoderctx;
297}
298
299const char *
300OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst)
301{
302 if (encoder_inst == NULL)
303 return NULL;
304 return encoder_inst->input_type;
305}
306
307const char *
308OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
309{
310 if (encoder_inst == NULL)
311 return NULL;
312 return encoder_inst->output_type;
313}
314
315static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
316{
317 size_t i, end;
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;
322 int ok = 0;
323
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);
334 BIO *current_out;
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;
340
341 if (latest_output_type == NULL) {
342 /*
343 * This is the first iteration, so we prepare the object to be
344 * encoded
345 */
346
347 current_data = ctx->construct(encoder_inst, ctx->construct_data);
348
349 /* Assume that the constructor recorded an error */
350 if (current_data == NULL)
351 goto loop_end;
352 } else {
353 /*
354 * Check that the latest output type matches the currently
355 * considered encoder
356 */
357 if (!OSSL_ENCODER_is_a(encoder, latest_output_type))
358 continue;
359
360 /*
361 * If there is a latest output type, there should be a latest output
362 */
363 if (!ossl_assert(latest_output != NULL)) {
364 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
365 goto loop_end;
366 }
367
368 /*
369 * Create an object abstraction from the latest output, which was
370 * stolen from the previous round.
371 */
372 abstract_p = abstract;
373 if (last_input_type != NULL)
374 *abstract_p++ =
375 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
376 (char *)last_input_type, 0);
377 *abstract_p++ =
378 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
379 latest_output,
380 latest_output_length);
381 *abstract_p = OSSL_PARAM_construct_end();
382 current_abstract = abstract;
383 }
384
385 /*
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.
389 */
390 if (strcasecmp(ctx->output_type, current_output_type) == 0)
391 current_out = out;
392 else if ((current_out = allocated_out = BIO_new(BIO_s_mem())) == NULL)
393 goto loop_end; /* Assume BIO_new() recorded an error */
394
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);
398
399 if (current_input_type != NULL)
400 last_input_type = current_input_type;
401
402 if (!ok)
403 goto loop_end;
404
405 OPENSSL_free(latest_output);
406
407 /*
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.
410 */
411 if (allocated_out != NULL) {
412 BUF_MEM *buf;
413
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);
419 }
420
421 loop_end:
422 if (current_data != NULL)
423 ctx->cleanup(ctx->construct_data);
424
425 if (ok)
426 break;
427 }
428
429 OPENSSL_free(latest_output);
430 return ok;
431}