]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/encode_decode/encoder_lib.c
ENCODER: Add output structure support for EVP_PKEY encoding
[thirdparty/openssl.git] / crypto / encode_decode / encoder_lib.c
CommitLineData
742496f1 1/*
eec0ad10 2 * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
742496f1
RL
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
b9a2afdf
RL
19struct encoder_process_data_st {
20 OSSL_ENCODER_CTX *ctx;
21
22 /* Current BIO */
23 BIO *bio;
24
25 /* Index of the current encoder instance to be processed */
26 int current_encoder_inst_index;
27
28 /* Processing data passed down through recursion */
29 int level; /* Recursion level */
30 OSSL_ENCODER_INSTANCE *next_encoder_inst;
31 int count_output_structure;
32
33 /* Processing data passed up through recursion */
34 OSSL_ENCODER_INSTANCE *prev_encoder_inst;
35 unsigned char *running_output;
36 size_t running_output_length;
37};
38
39static int encoder_process(struct encoder_process_data_st *data);
b8975c68 40
ece9304c 41int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
742496f1 42{
b9a2afdf
RL
43 struct encoder_process_data_st data;
44
45 memset(&data, 0, sizeof(data));
46 data.ctx = ctx;
47 data.bio = out;
48 data.current_encoder_inst_index = OSSL_ENCODER_CTX_get_num_encoders(ctx);
49
50 return encoder_process(&data) > 0;
742496f1
RL
51}
52
53#ifndef OPENSSL_NO_STDIO
54static BIO *bio_from_file(FILE *fp)
55{
56 BIO *b;
57
58 if ((b = BIO_new(BIO_s_file())) == NULL) {
ece9304c 59 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_BUF_LIB);
742496f1
RL
60 return NULL;
61 }
62 BIO_set_fp(b, fp, BIO_NOCLOSE);
63 return b;
64}
65
ece9304c 66int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp)
742496f1
RL
67{
68 BIO *b = bio_from_file(fp);
69 int ret = 0;
70
71 if (b != NULL)
ece9304c 72 ret = OSSL_ENCODER_to_bio(ctx, b);
742496f1
RL
73
74 BIO_free(b);
75 return ret;
76}
77#endif
b8975c68 78
25cf949f
RL
79int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata,
80 size_t *pdata_len)
81{
82 BIO *out = BIO_new(BIO_s_mem());
83 BUF_MEM *buf = NULL;
84 int ret = 0;
85
86 if (pdata_len == NULL) {
b9a2afdf 87 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
25cf949f
RL
88 return 0;
89 }
90
91 if (OSSL_ENCODER_to_bio(ctx, out)
92 && BIO_get_mem_ptr(out, &buf) > 0) {
93 ret = 1; /* Hope for the best. A too small buffer will clear this */
94
95 if (pdata != NULL && *pdata != NULL) {
96 if (*pdata_len < buf->length)
97 /*
98 * It's tempting to do |*pdata_len = (size_t)buf->length|
99 * However, it's believed to be confusing more than helpful,
100 * so we don't.
101 */
102 ret = 0;
103 else
104 *pdata_len -= buf->length;
105 } else {
106 /* The buffer with the right size is already allocated for us */
107 *pdata_len = (size_t)buf->length;
108 }
109
110 if (ret) {
111 if (pdata != NULL) {
112 if (*pdata != NULL) {
113 memcpy(*pdata, buf->data, buf->length);
114 *pdata += buf->length;
115 } else {
116 /* In this case, we steal the data from BIO_s_mem() */
117 *pdata = (unsigned char *)buf->data;
118 buf->data = NULL;
119 }
120 }
121 }
122 }
123 BIO_free(out);
124 return ret;
125}
126
8a98a507
RL
127int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
128{
129 if (!ossl_assert(ctx != NULL)) {
130 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
131 return 0;
132 }
133
134 if (!ossl_assert(selection != 0)) {
135 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
136 return 0;
137 }
138
139 ctx->selection = selection;
140 return 1;
141}
142
b8975c68
RL
143int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
144 const char *output_type)
145{
146 if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
147 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
148 return 0;
149 }
150
151 ctx->output_type = output_type;
152 return 1;
153}
154
8a98a507
RL
155int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
156 const char *output_structure)
b8975c68 157{
8a98a507 158 if (!ossl_assert(ctx != NULL) || !ossl_assert(output_structure != NULL)) {
b8975c68
RL
159 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
160 return 0;
161 }
162
8a98a507 163 ctx->output_structure = output_structure;
b8975c68
RL
164 return 1;
165}
166
167static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
168 void *encoderctx)
169{
170 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
8a98a507 171 OSSL_PARAM params[4];
b8975c68
RL
172
173 if (!ossl_assert(encoder != NULL)) {
174 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
175 return 0;
176 }
177
178 if (encoder->get_params == NULL) {
179 ERR_raise(ERR_LIB_OSSL_ENCODER,
180 OSSL_ENCODER_R_MISSING_GET_PARAMS);
181 return 0;
182 }
183
184 if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) {
185 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
186 return 0;
187 }
188
189 /*
190 * Cache the input and output types for this encoder. The output type
191 * is mandatory.
192 */
193 params[0] =
194 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
195 (char **)&encoder_inst->output_type, 0);
196 params[1] =
8a98a507
RL
197 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_STRUCTURE,
198 (char **)&encoder_inst->output_structure,
199 0);
200 params[2] =
b8975c68
RL
201 OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_INPUT_TYPE,
202 (char **)&encoder_inst->input_type, 0);
8a98a507 203 params[3] = OSSL_PARAM_construct_end();
b8975c68
RL
204
205 if (!encoder->get_params(params)
8a98a507 206 || !OSSL_PARAM_modified(&params[0]))
b8975c68
RL
207 goto err;
208
209 if (!OSSL_ENCODER_up_ref(encoder)) {
210 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
211 goto err;
212 }
213
214 encoder_inst->encoder = encoder;
215 encoder_inst->encoderctx = encoderctx;
216 return encoder_inst;
217 err:
218 ossl_encoder_instance_free(encoder_inst);
219 return NULL;
220}
221
222void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
223{
224 if (encoder_inst != NULL) {
225 if (encoder_inst->encoder != NULL)
226 encoder_inst->encoder->freectx(encoder_inst->encoderctx);
227 encoder_inst->encoderctx = NULL;
228 OSSL_ENCODER_free(encoder_inst->encoder);
229 encoder_inst->encoder = NULL;
230 OPENSSL_free(encoder_inst);
231 }
232}
233
234static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
235 OSSL_ENCODER_INSTANCE *ei)
236{
237 if (ctx->encoder_insts == NULL
238 && (ctx->encoder_insts =
239 sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) {
240 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
241 return 0;
242 }
243
244 return (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
245}
246
247int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
248{
249 OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
250 const OSSL_PROVIDER *prov = NULL;
251 void *encoderctx = NULL;
252 void *provctx = NULL;
253
254 if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
255 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
256 return 0;
257 }
258
259 prov = OSSL_ENCODER_provider(encoder);
260 provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
261
262 if ((encoderctx = encoder->newctx(provctx)) == NULL
263 || (encoder_inst =
264 ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
265 goto err;
266 /* Avoid double free of encoderctx on further errors */
267 encoderctx = NULL;
268
269 if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
270 goto err;
271
272 return 1;
273 err:
274 ossl_encoder_instance_free(encoder_inst);
275 if (encoderctx != NULL)
276 encoder->freectx(encoderctx);
277 return 0;
278}
279
280int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
b4250010 281 OSSL_LIB_CTX *libctx, const char *propq)
b8975c68
RL
282{
283 return 1;
284}
285
286int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
287{
288 if (ctx == NULL || ctx->encoder_insts == NULL)
289 return 0;
290 return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
291}
292
293int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
294 OSSL_ENCODER_CONSTRUCT *construct)
295{
296 if (!ossl_assert(ctx != NULL)) {
297 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
298 return 0;
299 }
300 ctx->construct = construct;
301 return 1;
302}
303
304int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
305 void *construct_data)
306{
307 if (!ossl_assert(ctx != NULL)) {
308 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
309 return 0;
310 }
311 ctx->construct_data = construct_data;
312 return 1;
313}
314
315int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
316 OSSL_ENCODER_CLEANUP *cleanup)
317{
318 if (!ossl_assert(ctx != NULL)) {
319 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
320 return 0;
321 }
322 ctx->cleanup = cleanup;
323 return 1;
324}
325
326OSSL_ENCODER *
327OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
328{
329 if (encoder_inst == NULL)
330 return NULL;
331 return encoder_inst->encoder;
332}
333
334void *
335OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
336{
337 if (encoder_inst == NULL)
338 return NULL;
339 return encoder_inst->encoderctx;
340}
341
342const char *
343OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst)
344{
345 if (encoder_inst == NULL)
346 return NULL;
347 return encoder_inst->input_type;
348}
349
350const char *
351OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
352{
353 if (encoder_inst == NULL)
354 return NULL;
355 return encoder_inst->output_type;
356}
357
8a98a507
RL
358const char *
359OSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE *encoder_inst)
360{
361 if (encoder_inst == NULL)
362 return NULL;
363 return encoder_inst->output_structure;
364}
365
b9a2afdf 366static int encoder_process(struct encoder_process_data_st *data)
b8975c68 367{
b9a2afdf
RL
368 OSSL_ENCODER_INSTANCE *current_encoder_inst = NULL;
369 OSSL_ENCODER *current_encoder = NULL;
370 OSSL_ENCODER_CTX *current_encoder_ctx = NULL;
371 BIO *allocated_out = NULL;
372 const void *original_data = NULL;
373 OSSL_PARAM abstract[10];
374 const OSSL_PARAM *current_abstract = NULL;
375 int i;
376 int ok = -1; /* -1 signifies that the lookup loop gave nothing */
377 int top = 0;
378
379 if (data->next_encoder_inst == NULL) {
380 /* First iteration, where we prepare for what is to come */
381
382 data->count_output_structure =
383 data->ctx->output_structure == NULL ? -1 : 0;
384 top = 1;
385 }
b8975c68 386
b9a2afdf
RL
387 for (i = data->current_encoder_inst_index; i-- > 0;) {
388 OSSL_ENCODER *next_encoder = NULL;
389 const char *current_output_type;
390 const char *current_output_structure;
391 struct encoder_process_data_st new_data;
392
393 if (!top)
394 next_encoder =
395 OSSL_ENCODER_INSTANCE_get_encoder(data->next_encoder_inst);
396
397 current_encoder_inst =
398 sk_OSSL_ENCODER_INSTANCE_value(data->ctx->encoder_insts, i);
399 current_encoder =
400 OSSL_ENCODER_INSTANCE_get_encoder(current_encoder_inst);
401 current_encoder_ctx =
402 OSSL_ENCODER_INSTANCE_get_encoder_ctx(current_encoder_inst);
403 current_output_type =
404 OSSL_ENCODER_INSTANCE_get_output_type(current_encoder_inst);
405 current_output_structure =
406 OSSL_ENCODER_INSTANCE_get_output_structure(current_encoder_inst);
407 memset(&new_data, 0, sizeof(new_data));
408 new_data.ctx = data->ctx;
409 new_data.current_encoder_inst_index = i;
410 new_data.next_encoder_inst = current_encoder_inst;
411 new_data.count_output_structure = data->count_output_structure;
412 new_data.level = data->level + 1;
b8975c68 413
b9a2afdf
RL
414 /*
415 * If this is the top call, we check if the output type of the current
416 * encoder matches the desired output type.
417 * If this isn't the top call, i.e. this is deeper in the recursion,
418 * we instead check if the output type of the current encoder matches
419 * the name of the next encoder (the one found by the parent call).
420 */
421 if (top) {
422 if (data->ctx->output_type != NULL
423 && strcasecmp(current_output_type,
424 data->ctx->output_type) != 0)
425 continue;
b8975c68 426 } else {
b9a2afdf 427 if (!OSSL_ENCODER_is_a(next_encoder, current_output_type))
b8975c68 428 continue;
b9a2afdf
RL
429 }
430
431 /*
432 * If the caller and the current encoder specify an output structure,
433 * Check if they match. If they do, count the match, otherwise skip
434 * the current encoder.
435 */
436 if (data->ctx->output_structure != NULL
437 && current_output_structure != NULL) {
438 if (strcasecmp(data->ctx->output_structure,
439 current_output_structure) != 0)
440 continue;
441
442 data->count_output_structure++;
443 }
444
445 /*
446 * Recurse to process the encoder implementations before the current
447 * one.
448 */
449 ok = encoder_process(&new_data);
450
451 data->prev_encoder_inst = new_data.prev_encoder_inst;
452 data->running_output = new_data.running_output;
453 data->running_output_length = new_data.running_output_length;
454
455 /*
456 * ok == -1 means that the recursion call above gave no further
457 * encoders, and that the one we're currently at should
458 * be tried.
459 * ok == 0 means that something failed in the recursion call
460 * above, making the result unsuitable for a chain.
461 * In this case, we simply continue to try finding a
462 * suitable encoder at this recursion level.
463 * ok == 1 means that the recursion call was successful, and we
464 * try to use the result at this recursion level.
465 */
466 if (ok != 0)
467 break;
468 }
b8975c68 469
b9a2afdf
RL
470 /*
471 * If |i < 0|, we didn't find any useful encoder in this recursion, so
472 * we do the rest of the process only if |i >= 0|.
473 */
474 if (i < 0) {
475 ok = -1;
476 } else {
477 /* Preparations */
478
479 switch (ok) {
480 case 0:
481 break;
482 case -1:
b8975c68 483 /*
b9a2afdf
RL
484 * We have reached the beginning of the encoder instance sequence,
485 * so we prepare the object to be encoded.
b8975c68 486 */
b8975c68
RL
487
488 /*
b9a2afdf
RL
489 * |data->count_output_structure| is one of these values:
490 *
491 * -1 There is no desired output structure
492 * 0 There is a desired output structure, and it wasn't
493 * matched by any of the encoder instances that were
494 * considered
495 * >0 There is a desired output structure, and at least one
496 * of the encoder instances matched it
b8975c68 497 */
b9a2afdf
RL
498 if (data->count_output_structure == 0)
499 return 0;
b8975c68 500
b9a2afdf
RL
501 original_data =
502 data->ctx->construct(current_encoder_inst,
503 data->ctx->construct_data);
504
505 /* Assume that the constructor recorded an error */
506 if (original_data != NULL)
507 ok = 1;
508 else
509 ok = 0;
510 break;
511 case 1:
512 if (!ossl_assert(data->running_output != NULL)) {
513 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
514 ok = 0;
515 break;
516 }
b8975c68 517
b9a2afdf
RL
518 {
519 /*
520 * Create an object abstraction from the latest output, which
521 * was stolen from the previous round.
522 */
b8975c68 523
b9a2afdf
RL
524 OSSL_PARAM *abstract_p = abstract;
525 const char *prev_input_type =
526 OSSL_ENCODER_INSTANCE_get_input_type(data->prev_encoder_inst);
527 const char *prev_output_structure =
528 OSSL_ENCODER_INSTANCE_get_output_structure(data->prev_encoder_inst);
529
530 if (prev_input_type != NULL)
531 *abstract_p++ =
532 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
533 (char *)prev_input_type, 0);
534 if (prev_output_structure != NULL)
535 *abstract_p++ =
536 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
537 (char *)prev_output_structure,
538 0);
539 *abstract_p++ =
540 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
541 data->running_output,
542 data->running_output_length);
543 *abstract_p = OSSL_PARAM_construct_end();
544 current_abstract = abstract;
545 }
546 break;
547 }
b8975c68 548
b9a2afdf 549 /* Calling the encoder implementation */
b8975c68 550
b9a2afdf
RL
551 if (ok) {
552 BIO *current_out = NULL;
b8975c68 553
b9a2afdf
RL
554 /*
555 * If we're at the last encoder instance to use, we're setting up
556 * final output. Otherwise, set up an intermediary memory output.
557 */
558 if (top)
559 current_out = data->bio;
560 else if ((current_out = allocated_out = BIO_new(BIO_s_mem()))
561 == NULL)
562 ok = 0; /* Assume BIO_new() recorded an error */
563
564 if (ok)
565 ok = current_encoder->encode(current_encoder_ctx,
566 (OSSL_CORE_BIO *)current_out,
567 original_data, current_abstract,
568 data->ctx->selection,
569 ossl_pw_passphrase_callback_enc,
570 &data->ctx->pwdata);
571
572 data->prev_encoder_inst = current_encoder_inst;
b8975c68 573 }
b9a2afdf 574 }
b8975c68 575
b9a2afdf 576 /* Cleanup and collecting the result */
8a98a507 577
b9a2afdf
RL
578 OPENSSL_free(data->running_output);
579 data->running_output = NULL;
b8975c68 580
b9a2afdf
RL
581 /*
582 * Steal the output from the BIO_s_mem, if we did allocate one.
583 * That'll be the data for an object abstraction in the next round.
584 */
585 if (allocated_out != NULL) {
586 BUF_MEM *buf;
587
588 BIO_get_mem_ptr(allocated_out, &buf);
589 data->running_output = (unsigned char *)buf->data;
590 data->running_output_length = buf->length;
591 memset(buf, 0, sizeof(*buf));
b8975c68
RL
592 }
593
b9a2afdf
RL
594 BIO_free(allocated_out);
595 if (original_data != NULL)
596 data->ctx->cleanup(data->ctx->construct_data);
b8975c68
RL
597 return ok;
598}