xref: /freebsd/crypto/openssl/crypto/encode_decode/encoder_lib.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2019-2025 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 <ctype.h>
11 
12 #include <openssl/core_names.h>
13 #include <openssl/bio.h>
14 #include <openssl/encoder.h>
15 #include <openssl/buffer.h>
16 #include <openssl/params.h>
17 #include <openssl/provider.h>
18 #include <openssl/trace.h>
19 #include <crypto/bn.h>
20 #include "internal/bio.h"
21 #include "internal/ffc.h"
22 #include "internal/provider.h"
23 #include "internal/encoder.h"
24 #include "encoder_local.h"
25 
26 /* Number of octets per line */
27 #define LABELED_BUF_PRINT_WIDTH 15
28 
29 #ifdef SIXTY_FOUR_BIT_LONG
30 #define BN_FMTu "%lu"
31 #define BN_FMTx "%lx"
32 #endif
33 
34 #ifdef SIXTY_FOUR_BIT
35 #define BN_FMTu "%llu"
36 #define BN_FMTx "%llx"
37 #endif
38 
39 #ifdef THIRTY_TWO_BIT
40 #define BN_FMTu "%u"
41 #define BN_FMTx "%x"
42 #endif
43 
44 struct encoder_process_data_st {
45     OSSL_ENCODER_CTX *ctx;
46 
47     /* Current BIO */
48     BIO *bio;
49 
50     /* Index of the current encoder instance to be processed */
51     int current_encoder_inst_index;
52 
53     /* Processing data passed down through recursion */
54     int level; /* Recursion level */
55     OSSL_ENCODER_INSTANCE *next_encoder_inst;
56     int count_output_structure;
57 
58     /* Processing data passed up through recursion */
59     OSSL_ENCODER_INSTANCE *prev_encoder_inst;
60     unsigned char *running_output;
61     size_t running_output_length;
62     /* Data type = the name of the first succeeding encoder implementation */
63     const char *data_type;
64 };
65 
66 static int encoder_process(struct encoder_process_data_st *data);
67 
OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX * ctx,BIO * out)68 int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
69 {
70     struct encoder_process_data_st data;
71 
72     memset(&data, 0, sizeof(data));
73     data.ctx = ctx;
74     data.bio = out;
75     data.current_encoder_inst_index = OSSL_ENCODER_CTX_get_num_encoders(ctx);
76 
77     if (data.current_encoder_inst_index == 0) {
78         ERR_raise_data(ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_ENCODER_NOT_FOUND,
79             "No encoders were found. For standard encoders you need "
80             "at least one of the default or base providers "
81             "available. Did you forget to load them?");
82         return 0;
83     }
84 
85     if (ctx->cleanup == NULL || ctx->construct == NULL) {
86         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INIT_FAIL);
87         return 0;
88     }
89 
90     return encoder_process(&data) > 0;
91 }
92 
93 #ifndef OPENSSL_NO_STDIO
bio_from_file(FILE * fp)94 static BIO *bio_from_file(FILE *fp)
95 {
96     BIO *b;
97 
98     if ((b = BIO_new(BIO_s_file())) == NULL) {
99         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_BUF_LIB);
100         return NULL;
101     }
102     BIO_set_fp(b, fp, BIO_NOCLOSE);
103     return b;
104 }
105 
OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX * ctx,FILE * fp)106 int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp)
107 {
108     BIO *b = bio_from_file(fp);
109     int ret = 0;
110 
111     if (b != NULL)
112         ret = OSSL_ENCODER_to_bio(ctx, b);
113 
114     BIO_free(b);
115     return ret;
116 }
117 #endif
118 
OSSL_ENCODER_to_data(OSSL_ENCODER_CTX * ctx,unsigned char ** pdata,size_t * pdata_len)119 int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata,
120     size_t *pdata_len)
121 {
122     BIO *out;
123     BUF_MEM *buf = NULL;
124     int ret = 0;
125 
126     if (pdata_len == NULL) {
127         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
128         return 0;
129     }
130 
131     out = BIO_new(BIO_s_mem());
132 
133     if (out != NULL
134         && OSSL_ENCODER_to_bio(ctx, out)
135         && BIO_get_mem_ptr(out, &buf) > 0) {
136         ret = 1; /* Hope for the best. A too small buffer will clear this */
137 
138         if (pdata != NULL && *pdata != NULL) {
139             if (*pdata_len < buf->length)
140                 /*
141                  * It's tempting to do |*pdata_len = (size_t)buf->length|
142                  * However, it's believed to be confusing more than helpful,
143                  * so we don't.
144                  */
145                 ret = 0;
146             else
147                 *pdata_len -= buf->length;
148         } else {
149             /* The buffer with the right size is already allocated for us */
150             *pdata_len = (size_t)buf->length;
151         }
152 
153         if (ret) {
154             if (pdata != NULL) {
155                 if (*pdata != NULL) {
156                     memcpy(*pdata, buf->data, buf->length);
157                     *pdata += buf->length;
158                 } else {
159                     /* In this case, we steal the data from BIO_s_mem() */
160                     *pdata = (unsigned char *)buf->data;
161                     buf->data = NULL;
162                 }
163             }
164         }
165     }
166     BIO_free(out);
167     return ret;
168 }
169 
OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX * ctx,int selection)170 int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
171 {
172     if (!ossl_assert(ctx != NULL)) {
173         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
174         return 0;
175     }
176 
177     if (!ossl_assert(selection != 0)) {
178         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
179         return 0;
180     }
181 
182     ctx->selection = selection;
183     return 1;
184 }
185 
OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX * ctx,const char * output_type)186 int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
187     const char *output_type)
188 {
189     if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
190         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
191         return 0;
192     }
193 
194     ctx->output_type = output_type;
195     return 1;
196 }
197 
OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX * ctx,const char * output_structure)198 int OSSL_ENCODER_CTX_set_output_structure(OSSL_ENCODER_CTX *ctx,
199     const char *output_structure)
200 {
201     if (!ossl_assert(ctx != NULL) || !ossl_assert(output_structure != NULL)) {
202         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
203         return 0;
204     }
205 
206     ctx->output_structure = output_structure;
207     return 1;
208 }
209 
ossl_encoder_instance_new(OSSL_ENCODER * encoder,void * encoderctx)210 static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
211     void *encoderctx)
212 {
213     OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
214     const OSSL_PROVIDER *prov;
215     OSSL_LIB_CTX *libctx;
216     const OSSL_PROPERTY_LIST *props;
217     const OSSL_PROPERTY_DEFINITION *prop;
218 
219     if (!ossl_assert(encoder != NULL)) {
220         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
221         return 0;
222     }
223 
224     if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL)
225         return 0;
226 
227     if (!OSSL_ENCODER_up_ref(encoder)) {
228         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
229         goto err;
230     }
231 
232     prov = OSSL_ENCODER_get0_provider(encoder);
233     libctx = ossl_provider_libctx(prov);
234     props = ossl_encoder_parsed_properties(encoder);
235     if (props == NULL) {
236         ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION,
237             "there are no property definitions with encoder %s",
238             OSSL_ENCODER_get0_name(encoder));
239         goto err;
240     }
241 
242     /* The "output" property is mandatory */
243     prop = ossl_property_find_property(props, libctx, "output");
244     encoder_inst->output_type = ossl_property_get_string_value(libctx, prop);
245     if (encoder_inst->output_type == NULL) {
246         ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION,
247             "the mandatory 'output' property is missing "
248             "for encoder %s (properties: %s)",
249             OSSL_ENCODER_get0_name(encoder),
250             OSSL_ENCODER_get0_properties(encoder));
251         goto err;
252     }
253 
254     /* The "structure" property is optional */
255     prop = ossl_property_find_property(props, libctx, "structure");
256     if (prop != NULL)
257         encoder_inst->output_structure
258             = ossl_property_get_string_value(libctx, prop);
259 
260     encoder_inst->encoder = encoder;
261     encoder_inst->encoderctx = encoderctx;
262     return encoder_inst;
263 err:
264     ossl_encoder_instance_free(encoder_inst);
265     return NULL;
266 }
267 
ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE * encoder_inst)268 void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
269 {
270     if (encoder_inst != NULL) {
271         if (encoder_inst->encoder != NULL)
272             encoder_inst->encoder->freectx(encoder_inst->encoderctx);
273         encoder_inst->encoderctx = NULL;
274         OSSL_ENCODER_free(encoder_inst->encoder);
275         encoder_inst->encoder = NULL;
276         OPENSSL_free(encoder_inst);
277     }
278 }
279 
ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX * ctx,OSSL_ENCODER_INSTANCE * ei)280 static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
281     OSSL_ENCODER_INSTANCE *ei)
282 {
283     int ok;
284 
285     if (ctx->encoder_insts == NULL
286         && (ctx->encoder_insts = sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) {
287         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_CRYPTO_LIB);
288         return 0;
289     }
290 
291     ok = (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
292     if (ok) {
293         OSSL_TRACE_BEGIN(ENCODER)
294         {
295             BIO_printf(trc_out,
296                 "(ctx %p) Added encoder instance %p (encoder %p):\n"
297                 "    %s with %s\n",
298                 (void *)ctx, (void *)ei, (void *)ei->encoder,
299                 OSSL_ENCODER_get0_name(ei->encoder),
300                 OSSL_ENCODER_get0_properties(ei->encoder));
301         }
302         OSSL_TRACE_END(ENCODER);
303     }
304     return ok;
305 }
306 
OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX * ctx,OSSL_ENCODER * encoder)307 int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
308 {
309     OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
310     const OSSL_PROVIDER *prov = NULL;
311     void *encoderctx = NULL;
312     void *provctx = NULL;
313 
314     if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
315         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
316         return 0;
317     }
318 
319     prov = OSSL_ENCODER_get0_provider(encoder);
320     provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
321 
322     if ((encoderctx = encoder->newctx(provctx)) == NULL
323         || (encoder_inst = ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
324         goto err;
325     /* Avoid double free of encoderctx on further errors */
326     encoderctx = NULL;
327 
328     if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
329         goto err;
330 
331     return 1;
332 err:
333     ossl_encoder_instance_free(encoder_inst);
334     if (encoderctx != NULL)
335         encoder->freectx(encoderctx);
336     return 0;
337 }
338 
OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX * ctx,OSSL_LIB_CTX * libctx,const char * propq)339 int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
340     OSSL_LIB_CTX *libctx, const char *propq)
341 {
342     return 1;
343 }
344 
OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX * ctx)345 int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
346 {
347     if (ctx == NULL || ctx->encoder_insts == NULL)
348         return 0;
349     return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
350 }
351 
OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX * ctx,OSSL_ENCODER_CONSTRUCT * construct)352 int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
353     OSSL_ENCODER_CONSTRUCT *construct)
354 {
355     if (!ossl_assert(ctx != NULL)) {
356         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
357         return 0;
358     }
359     ctx->construct = construct;
360     return 1;
361 }
362 
OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX * ctx,void * construct_data)363 int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
364     void *construct_data)
365 {
366     if (!ossl_assert(ctx != NULL)) {
367         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
368         return 0;
369     }
370     ctx->construct_data = construct_data;
371     return 1;
372 }
373 
OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX * ctx,OSSL_ENCODER_CLEANUP * cleanup)374 int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
375     OSSL_ENCODER_CLEANUP *cleanup)
376 {
377     if (!ossl_assert(ctx != NULL)) {
378         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
379         return 0;
380     }
381     ctx->cleanup = cleanup;
382     return 1;
383 }
384 
385 OSSL_ENCODER *
OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE * encoder_inst)386 OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
387 {
388     if (encoder_inst == NULL)
389         return NULL;
390     return encoder_inst->encoder;
391 }
392 
393 void *
OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE * encoder_inst)394 OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
395 {
396     if (encoder_inst == NULL)
397         return NULL;
398     return encoder_inst->encoderctx;
399 }
400 
401 const char *
OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE * encoder_inst)402 OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
403 {
404     if (encoder_inst == NULL)
405         return NULL;
406     return encoder_inst->output_type;
407 }
408 
409 const char *
OSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE * encoder_inst)410 OSSL_ENCODER_INSTANCE_get_output_structure(OSSL_ENCODER_INSTANCE *encoder_inst)
411 {
412     if (encoder_inst == NULL)
413         return NULL;
414     return encoder_inst->output_structure;
415 }
416 
encoder_process(struct encoder_process_data_st * data)417 static int encoder_process(struct encoder_process_data_st *data)
418 {
419     OSSL_ENCODER_INSTANCE *current_encoder_inst = NULL;
420     OSSL_ENCODER *current_encoder = NULL;
421     OSSL_ENCODER_CTX *current_encoder_ctx = NULL;
422     BIO *allocated_out = NULL;
423     const void *original_data = NULL;
424     OSSL_PARAM abstract[10];
425     const OSSL_PARAM *current_abstract = NULL;
426     int i;
427     int ok = -1; /* -1 signifies that the lookup loop gave nothing */
428     int top = 0;
429 
430     if (data->next_encoder_inst == NULL) {
431         /* First iteration, where we prepare for what is to come */
432 
433         data->count_output_structure = data->ctx->output_structure == NULL ? -1 : 0;
434         top = 1;
435     }
436 
437     for (i = data->current_encoder_inst_index; i-- > 0;) {
438         OSSL_ENCODER *next_encoder = NULL;
439         const char *current_output_type;
440         const char *current_output_structure;
441         struct encoder_process_data_st new_data;
442 
443         if (!top)
444             next_encoder = OSSL_ENCODER_INSTANCE_get_encoder(data->next_encoder_inst);
445 
446         current_encoder_inst = sk_OSSL_ENCODER_INSTANCE_value(data->ctx->encoder_insts, i);
447         current_encoder = OSSL_ENCODER_INSTANCE_get_encoder(current_encoder_inst);
448         current_encoder_ctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(current_encoder_inst);
449         current_output_type = OSSL_ENCODER_INSTANCE_get_output_type(current_encoder_inst);
450         current_output_structure = OSSL_ENCODER_INSTANCE_get_output_structure(current_encoder_inst);
451         memset(&new_data, 0, sizeof(new_data));
452         new_data.ctx = data->ctx;
453         new_data.current_encoder_inst_index = i;
454         new_data.next_encoder_inst = current_encoder_inst;
455         new_data.count_output_structure = data->count_output_structure;
456         new_data.level = data->level + 1;
457 
458         OSSL_TRACE_BEGIN(ENCODER)
459         {
460             BIO_printf(trc_out,
461                 "[%d] (ctx %p) Considering encoder instance %p (encoder %p)\n",
462                 data->level, (void *)data->ctx,
463                 (void *)current_encoder_inst, (void *)current_encoder);
464         }
465         OSSL_TRACE_END(ENCODER);
466 
467         /*
468          * If this is the top call, we check if the output type of the current
469          * encoder matches the desired output type.
470          * If this isn't the top call, i.e. this is deeper in the recursion,
471          * we instead check if the output type of the current encoder matches
472          * the name of the next encoder (the one found by the parent call).
473          */
474         if (top) {
475             if (data->ctx->output_type != NULL
476                 && OPENSSL_strcasecmp(current_output_type,
477                        data->ctx->output_type)
478                     != 0) {
479                 OSSL_TRACE_BEGIN(ENCODER)
480                 {
481                     BIO_printf(trc_out,
482                         "[%d]    Skipping because current encoder output type (%s) != desired output type (%s)\n",
483                         data->level,
484                         current_output_type, data->ctx->output_type);
485                 }
486                 OSSL_TRACE_END(ENCODER);
487                 continue;
488             }
489         } else {
490             if (!OSSL_ENCODER_is_a(next_encoder, current_output_type)) {
491                 OSSL_TRACE_BEGIN(ENCODER)
492                 {
493                     BIO_printf(trc_out,
494                         "[%d]    Skipping because current encoder output type (%s) != name of encoder %p\n",
495                         data->level,
496                         current_output_type, (void *)next_encoder);
497                 }
498                 OSSL_TRACE_END(ENCODER);
499                 continue;
500             }
501         }
502 
503         /*
504          * If the caller and the current encoder specify an output structure,
505          * Check if they match.  If they do, count the match, otherwise skip
506          * the current encoder.
507          */
508         if (data->ctx->output_structure != NULL
509             && current_output_structure != NULL) {
510             if (OPENSSL_strcasecmp(data->ctx->output_structure,
511                     current_output_structure)
512                 != 0) {
513                 OSSL_TRACE_BEGIN(ENCODER)
514                 {
515                     BIO_printf(trc_out,
516                         "[%d]    Skipping because current encoder output structure (%s) != ctx output structure (%s)\n",
517                         data->level,
518                         current_output_structure,
519                         data->ctx->output_structure);
520                 }
521                 OSSL_TRACE_END(ENCODER);
522                 continue;
523             }
524 
525             data->count_output_structure++;
526         }
527 
528         /*
529          * Recurse to process the encoder implementations before the current
530          * one.
531          */
532         ok = encoder_process(&new_data);
533 
534         data->prev_encoder_inst = new_data.prev_encoder_inst;
535         data->running_output = new_data.running_output;
536         data->running_output_length = new_data.running_output_length;
537 
538         /*
539          * ok == -1     means that the recursion call above gave no further
540          *              encoders, and that the one we're currently at should
541          *              be tried.
542          * ok == 0      means that something failed in the recursion call
543          *              above, making the result unsuitable for a chain.
544          *              In this case, we simply continue to try finding a
545          *              suitable encoder at this recursion level.
546          * ok == 1      means that the recursion call was successful, and we
547          *              try to use the result at this recursion level.
548          */
549         if (ok != 0)
550             break;
551 
552         OSSL_TRACE_BEGIN(ENCODER)
553         {
554             BIO_printf(trc_out,
555                 "[%d]    Skipping because recursion level %d failed\n",
556                 data->level, new_data.level);
557         }
558         OSSL_TRACE_END(ENCODER);
559     }
560 
561     /*
562      * If |i < 0|, we didn't find any useful encoder in this recursion, so
563      * we do the rest of the process only if |i >= 0|.
564      */
565     if (i < 0) {
566         ok = -1;
567 
568         OSSL_TRACE_BEGIN(ENCODER)
569         {
570             BIO_printf(trc_out,
571                 "[%d] (ctx %p) No suitable encoder found\n",
572                 data->level, (void *)data->ctx);
573         }
574         OSSL_TRACE_END(ENCODER);
575     } else {
576         /* Preparations */
577 
578         switch (ok) {
579         case 0:
580             break;
581         case -1:
582             /*
583              * We have reached the beginning of the encoder instance sequence,
584              * so we prepare the object to be encoded.
585              */
586 
587             /*
588              * |data->count_output_structure| is one of these values:
589              *
590              * -1       There is no desired output structure
591              *  0       There is a desired output structure, and it wasn't
592              *          matched by any of the encoder instances that were
593              *          considered
594              * >0       There is a desired output structure, and at least one
595              *          of the encoder instances matched it
596              */
597             if (data->count_output_structure == 0)
598                 return 0;
599 
600             original_data = data->ctx->construct(current_encoder_inst,
601                 data->ctx->construct_data);
602 
603             /* Also set the data type, using the encoder implementation name */
604             data->data_type = OSSL_ENCODER_get0_name(current_encoder);
605 
606             /* Assume that the constructor recorded an error */
607             if (original_data != NULL)
608                 ok = 1;
609             else
610                 ok = 0;
611             break;
612         case 1:
613             if (!ossl_assert(data->running_output != NULL)) {
614                 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
615                 ok = 0;
616                 break;
617             }
618 
619             {
620                 /*
621                  * Create an object abstraction from the latest output, which
622                  * was stolen from the previous round.
623                  */
624 
625                 OSSL_PARAM *abstract_p = abstract;
626                 const char *prev_output_structure = OSSL_ENCODER_INSTANCE_get_output_structure(data->prev_encoder_inst);
627 
628                 *abstract_p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
629                     (char *)data->data_type, 0);
630                 if (prev_output_structure != NULL)
631                     *abstract_p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
632                         (char *)prev_output_structure,
633                         0);
634                 *abstract_p++ = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
635                     data->running_output,
636                     data->running_output_length);
637                 *abstract_p = OSSL_PARAM_construct_end();
638                 current_abstract = abstract;
639             }
640             break;
641         }
642 
643         /* Calling the encoder implementation */
644 
645         if (ok) {
646             OSSL_CORE_BIO *cbio = NULL;
647             BIO *current_out = NULL;
648 
649             /*
650              * If we're at the last encoder instance to use, we're setting up
651              * final output.  Otherwise, set up an intermediary memory output.
652              */
653             if (top)
654                 current_out = data->bio;
655             else if ((current_out = allocated_out = BIO_new(BIO_s_mem()))
656                 == NULL)
657                 ok = 0; /* Assume BIO_new() recorded an error */
658 
659             if (ok)
660                 ok = (cbio = ossl_core_bio_new_from_bio(current_out)) != NULL;
661             if (ok) {
662                 ok = current_encoder->encode(current_encoder_ctx, cbio,
663                     original_data, current_abstract,
664                     data->ctx->selection,
665                     ossl_pw_passphrase_callback_enc,
666                     &data->ctx->pwdata);
667                 OSSL_TRACE_BEGIN(ENCODER)
668                 {
669                     BIO_printf(trc_out,
670                         "[%d] (ctx %p) Running encoder instance %p => %d\n",
671                         data->level, (void *)data->ctx,
672                         (void *)current_encoder_inst, ok);
673                 }
674                 OSSL_TRACE_END(ENCODER);
675             }
676 
677             ossl_core_bio_free(cbio);
678             data->prev_encoder_inst = current_encoder_inst;
679         }
680     }
681 
682     /* Cleanup and collecting the result */
683 
684     OPENSSL_free(data->running_output);
685     data->running_output = NULL;
686 
687     /*
688      * Steal the output from the BIO_s_mem, if we did allocate one.
689      * That'll be the data for an object abstraction in the next round.
690      */
691     if (allocated_out != NULL) {
692         BUF_MEM *buf;
693 
694         BIO_get_mem_ptr(allocated_out, &buf);
695         data->running_output = (unsigned char *)buf->data;
696         data->running_output_length = buf->length;
697         memset(buf, 0, sizeof(*buf));
698     }
699 
700     BIO_free(allocated_out);
701     if (original_data != NULL)
702         data->ctx->cleanup(data->ctx->construct_data);
703     return ok;
704 }
705 
ossl_bio_print_labeled_bignum(BIO * out,const char * label,const BIGNUM * bn)706 int ossl_bio_print_labeled_bignum(BIO *out, const char *label, const BIGNUM *bn)
707 {
708     int ret = 0, use_sep = 0;
709     char *hex_str = NULL, *p;
710     const char spaces[] = "    ";
711     const char *post_label_spc = " ";
712 
713     const char *neg = "";
714     int bytes;
715 
716     if (bn == NULL)
717         return 0;
718     if (label == NULL) {
719         label = "";
720         post_label_spc = "";
721     }
722 
723     if (BN_is_zero(bn))
724         return BIO_printf(out, "%s%s0\n", label, post_label_spc);
725 
726     if (BN_num_bytes(bn) <= BN_BYTES) {
727         BN_ULONG *words = bn_get_words(bn);
728 
729         if (BN_is_negative(bn))
730             neg = "-";
731 
732         return BIO_printf(out, "%s%s%s" BN_FMTu " (%s0x" BN_FMTx ")\n",
733             label, post_label_spc, neg, words[0], neg, words[0]);
734     }
735 
736     hex_str = BN_bn2hex(bn);
737     if (hex_str == NULL)
738         return 0;
739 
740     p = hex_str;
741     if (*p == '-') {
742         ++p;
743         neg = " (Negative)";
744     }
745     if (BIO_printf(out, "%s%s\n", label, neg) <= 0)
746         goto err;
747 
748     /* Keep track of how many bytes we have printed out so far */
749     bytes = 0;
750 
751     if (BIO_printf(out, "%s", spaces) <= 0)
752         goto err;
753 
754     /* Add a leading 00 if the top bit is set */
755     if (*p >= '8') {
756         if (BIO_printf(out, "%02x", 0) <= 0)
757             goto err;
758         ++bytes;
759         use_sep = 1;
760     }
761     while (*p != '\0') {
762         /* Do a newline after every 15 hex bytes + add the space indent */
763         if ((bytes % 15) == 0 && bytes > 0) {
764             if (BIO_printf(out, ":\n%s", spaces) <= 0)
765                 goto err;
766             use_sep = 0; /* The first byte on the next line doesn't have a : */
767         }
768         if (BIO_printf(out, "%s%c%c", use_sep ? ":" : "",
769                 tolower((unsigned char)p[0]),
770                 tolower((unsigned char)p[1]))
771             <= 0)
772             goto err;
773         ++bytes;
774         p += 2;
775         use_sep = 1;
776     }
777     if (BIO_printf(out, "\n") <= 0)
778         goto err;
779     ret = 1;
780 err:
781     OPENSSL_free(hex_str);
782     return ret;
783 }
784 
ossl_bio_print_labeled_buf(BIO * out,const char * label,const unsigned char * buf,size_t buflen)785 int ossl_bio_print_labeled_buf(BIO *out, const char *label,
786     const unsigned char *buf, size_t buflen)
787 {
788     size_t i;
789 
790     if (BIO_printf(out, "%s\n", label) <= 0)
791         return 0;
792 
793     for (i = 0; i < buflen; i++) {
794         if ((i % LABELED_BUF_PRINT_WIDTH) == 0) {
795             if (i > 0 && BIO_printf(out, "\n") <= 0)
796                 return 0;
797             if (BIO_printf(out, "    ") <= 0)
798                 return 0;
799         }
800 
801         if (BIO_printf(out, "%02x%s", buf[i],
802                 (i == buflen - 1) ? "" : ":")
803             <= 0)
804             return 0;
805     }
806     if (BIO_printf(out, "\n") <= 0)
807         return 0;
808 
809     return 1;
810 }
811 
812 #if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA)
ossl_bio_print_ffc_params(BIO * out,const FFC_PARAMS * ffc)813 int ossl_bio_print_ffc_params(BIO *out, const FFC_PARAMS *ffc)
814 {
815     if (ffc->nid != NID_undef) {
816 #ifndef OPENSSL_NO_DH
817         const DH_NAMED_GROUP *group = ossl_ffc_uid_to_dh_named_group(ffc->nid);
818         const char *name = ossl_ffc_named_group_get_name(group);
819 
820         if (name == NULL)
821             goto err;
822         if (BIO_printf(out, "GROUP: %s\n", name) <= 0)
823             goto err;
824         return 1;
825 #else
826         /* How could this be? We should not have a nid in a no-dh build. */
827         goto err;
828 #endif
829     }
830 
831     if (!ossl_bio_print_labeled_bignum(out, "P:   ", ffc->p))
832         goto err;
833     if (ffc->q != NULL) {
834         if (!ossl_bio_print_labeled_bignum(out, "Q:   ", ffc->q))
835             goto err;
836     }
837     if (!ossl_bio_print_labeled_bignum(out, "G:   ", ffc->g))
838         goto err;
839     if (ffc->j != NULL) {
840         if (!ossl_bio_print_labeled_bignum(out, "J:   ", ffc->j))
841             goto err;
842     }
843     if (ffc->seed != NULL) {
844         if (!ossl_bio_print_labeled_buf(out, "SEED:", ffc->seed, ffc->seedlen))
845             goto err;
846     }
847     if (ffc->gindex != -1) {
848         if (BIO_printf(out, "gindex: %d\n", ffc->gindex) <= 0)
849             goto err;
850     }
851     if (ffc->pcounter != -1) {
852         if (BIO_printf(out, "pcounter: %d\n", ffc->pcounter) <= 0)
853             goto err;
854     }
855     if (ffc->h != 0) {
856         if (BIO_printf(out, "h: %d\n", ffc->h) <= 0)
857             goto err;
858     }
859     return 1;
860 err:
861     return 0;
862 }
863 
864 #endif
865