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
21struct 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
43static int encoder_process(struct encoder_process_data_st *data);
44
45int 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
66static 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
78int 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
91int 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
142int 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
158int 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
170int 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
182static 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
242void 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
254static 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
280int 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
313int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
314                               OSSL_LIB_CTX *libctx, const char *propq)
315{
316    return 1;
317}
318
319int 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
326int 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
337int 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
348int 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
359OSSL_ENCODER *
360OSSL_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
367void *
368OSSL_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
375const char *
376OSSL_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
383const char *
384OSSL_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
391static 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