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