1/*
2 * Copyright 2020-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.h>
11#include <openssl/core_dispatch.h>
12#include <openssl/decoder.h>
13#include <openssl/ui.h>
14#include "internal/core.h"
15#include "internal/namemap.h"
16#include "internal/property.h"
17#include "internal/provider.h"
18#include "crypto/decoder.h"
19#include "encoder_local.h"
20
21/*
22 * Decoder can have multiple names, separated with colons in a name string
23 */
24#define NAME_SEPARATOR ':'
25
26/* Simple method structure constructor and destructor */
27static OSSL_DECODER *ossl_decoder_new(void)
28{
29    OSSL_DECODER *decoder = NULL;
30
31    if ((decoder = OPENSSL_zalloc(sizeof(*decoder))) == NULL
32        || (decoder->base.lock = CRYPTO_THREAD_lock_new()) == NULL) {
33        OSSL_DECODER_free(decoder);
34        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
35        return NULL;
36    }
37
38    decoder->base.refcnt = 1;
39
40    return decoder;
41}
42
43int OSSL_DECODER_up_ref(OSSL_DECODER *decoder)
44{
45    int ref = 0;
46
47    CRYPTO_UP_REF(&decoder->base.refcnt, &ref, decoder->base.lock);
48    return 1;
49}
50
51void OSSL_DECODER_free(OSSL_DECODER *decoder)
52{
53    int ref = 0;
54
55    if (decoder == NULL)
56        return;
57
58    CRYPTO_DOWN_REF(&decoder->base.refcnt, &ref, decoder->base.lock);
59    if (ref > 0)
60        return;
61    OPENSSL_free(decoder->base.name);
62    ossl_property_free(decoder->base.parsed_propdef);
63    ossl_provider_free(decoder->base.prov);
64    CRYPTO_THREAD_lock_free(decoder->base.lock);
65    OPENSSL_free(decoder);
66}
67
68/* Permanent decoder method store, constructor and destructor */
69static void decoder_store_free(void *vstore)
70{
71    ossl_method_store_free(vstore);
72}
73
74static void *decoder_store_new(OSSL_LIB_CTX *ctx)
75{
76    return ossl_method_store_new(ctx);
77}
78
79
80static const OSSL_LIB_CTX_METHOD decoder_store_method = {
81    /* We want decoder_store to be cleaned up before the provider store */
82    OSSL_LIB_CTX_METHOD_PRIORITY_2,
83    decoder_store_new,
84    decoder_store_free,
85};
86
87/* Data to be passed through ossl_method_construct() */
88struct decoder_data_st {
89    OSSL_LIB_CTX *libctx;
90    int id;                      /* For get_decoder_from_store() */
91    const char *names;           /* For get_decoder_from_store() */
92    const char *propquery;       /* For get_decoder_from_store() */
93
94    OSSL_METHOD_STORE *tmp_store; /* For get_tmp_decoder_store() */
95
96    unsigned int flag_construct_error_occurred : 1;
97};
98
99/*
100 * Generic routines to fetch / create DECODER methods with
101 * ossl_method_construct()
102 */
103
104/* Temporary decoder method store, constructor and destructor */
105static void *get_tmp_decoder_store(void *data)
106{
107    struct decoder_data_st *methdata = data;
108
109    if (methdata->tmp_store == NULL)
110        methdata->tmp_store = ossl_method_store_new(methdata->libctx);
111    return methdata->tmp_store;
112}
113
114static void dealloc_tmp_decoder_store(void *store)
115{
116    if (store != NULL)
117        ossl_method_store_free(store);
118}
119
120/* Get the permanent decoder store */
121static OSSL_METHOD_STORE *get_decoder_store(OSSL_LIB_CTX *libctx)
122{
123    return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_DECODER_STORE_INDEX,
124                                 &decoder_store_method);
125}
126
127static int reserve_decoder_store(void *store, void *data)
128{
129    struct decoder_data_st *methdata = data;
130
131    if (store == NULL
132        && (store = get_decoder_store(methdata->libctx)) == NULL)
133        return 0;
134
135    return ossl_method_lock_store(store);
136}
137
138static int unreserve_decoder_store(void *store, void *data)
139{
140    struct decoder_data_st *methdata = data;
141
142    if (store == NULL
143        && (store = get_decoder_store(methdata->libctx)) == NULL)
144        return 0;
145
146    return ossl_method_unlock_store(store);
147}
148
149/* Get decoder methods from a store, or put one in */
150static void *get_decoder_from_store(void *store, const OSSL_PROVIDER **prov,
151                                    void *data)
152{
153    struct decoder_data_st *methdata = data;
154    void *method = NULL;
155    int id;
156
157    /*
158     * get_decoder_from_store() is only called to try and get the method
159     * that OSSL_DECODER_fetch() is asking for, and the name or name id are
160     * passed via methdata.
161     */
162    if ((id = methdata->id) == 0 && methdata->names != NULL) {
163        OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
164        const char *names = methdata->names;
165        const char *q = strchr(names, NAME_SEPARATOR);
166        size_t l = (q == NULL ? strlen(names) : (size_t)(q - names));
167
168        if (namemap == 0)
169            return NULL;
170        id = ossl_namemap_name2num_n(namemap, names, l);
171    }
172
173    if (id == 0)
174        return NULL;
175
176    if (store == NULL
177        && (store = get_decoder_store(methdata->libctx)) == NULL)
178        return NULL;
179
180    if (!ossl_method_store_fetch(store, id, methdata->propquery, prov, &method))
181        return NULL;
182    return method;
183}
184
185static int put_decoder_in_store(void *store, void *method,
186                                const OSSL_PROVIDER *prov,
187                                const char *names, const char *propdef,
188                                void *data)
189{
190    struct decoder_data_st *methdata = data;
191    OSSL_NAMEMAP *namemap;
192    int id;
193    size_t l = 0;
194
195    /*
196     * put_decoder_in_store() is only called with an OSSL_DECODER method that
197     * was successfully created by construct_decoder() below, which means that
198     * all the names should already be stored in the namemap with the same
199     * numeric identity, so just use the first to get that identity.
200     */
201    if (names != NULL) {
202        const char *q = strchr(names, NAME_SEPARATOR);
203
204        l = (q == NULL ? strlen(names) : (size_t)(q - names));
205    }
206
207    if ((namemap = ossl_namemap_stored(methdata->libctx)) == NULL
208        || (id = ossl_namemap_name2num_n(namemap, names, l)) == 0)
209        return 0;
210
211    if (store == NULL && (store = get_decoder_store(methdata->libctx)) == NULL)
212        return 0;
213
214    return ossl_method_store_add(store, prov, id, propdef, method,
215                                 (int (*)(void *))OSSL_DECODER_up_ref,
216                                 (void (*)(void *))OSSL_DECODER_free);
217}
218
219/* Create and populate a decoder method */
220void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
221                                  OSSL_PROVIDER *prov)
222{
223    OSSL_DECODER *decoder = NULL;
224    const OSSL_DISPATCH *fns = algodef->implementation;
225    OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
226
227    if ((decoder = ossl_decoder_new()) == NULL)
228        return NULL;
229    decoder->base.id = id;
230    if ((decoder->base.name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
231        OSSL_DECODER_free(decoder);
232        return NULL;
233    }
234    decoder->base.algodef = algodef;
235    if ((decoder->base.parsed_propdef
236         = ossl_parse_property(libctx, algodef->property_definition)) == NULL) {
237        OSSL_DECODER_free(decoder);
238        return NULL;
239    }
240
241    for (; fns->function_id != 0; fns++) {
242        switch (fns->function_id) {
243        case OSSL_FUNC_DECODER_NEWCTX:
244            if (decoder->newctx == NULL)
245                decoder->newctx = OSSL_FUNC_decoder_newctx(fns);
246            break;
247        case OSSL_FUNC_DECODER_FREECTX:
248            if (decoder->freectx == NULL)
249                decoder->freectx = OSSL_FUNC_decoder_freectx(fns);
250            break;
251        case OSSL_FUNC_DECODER_GET_PARAMS:
252            if (decoder->get_params == NULL)
253                decoder->get_params =
254                    OSSL_FUNC_decoder_get_params(fns);
255            break;
256        case OSSL_FUNC_DECODER_GETTABLE_PARAMS:
257            if (decoder->gettable_params == NULL)
258                decoder->gettable_params =
259                    OSSL_FUNC_decoder_gettable_params(fns);
260            break;
261        case OSSL_FUNC_DECODER_SET_CTX_PARAMS:
262            if (decoder->set_ctx_params == NULL)
263                decoder->set_ctx_params =
264                    OSSL_FUNC_decoder_set_ctx_params(fns);
265            break;
266        case OSSL_FUNC_DECODER_SETTABLE_CTX_PARAMS:
267            if (decoder->settable_ctx_params == NULL)
268                decoder->settable_ctx_params =
269                    OSSL_FUNC_decoder_settable_ctx_params(fns);
270            break;
271        case OSSL_FUNC_DECODER_DOES_SELECTION:
272            if (decoder->does_selection == NULL)
273                decoder->does_selection =
274                    OSSL_FUNC_decoder_does_selection(fns);
275            break;
276        case OSSL_FUNC_DECODER_DECODE:
277            if (decoder->decode == NULL)
278                decoder->decode = OSSL_FUNC_decoder_decode(fns);
279            break;
280        case OSSL_FUNC_DECODER_EXPORT_OBJECT:
281            if (decoder->export_object == NULL)
282                decoder->export_object = OSSL_FUNC_decoder_export_object(fns);
283            break;
284        }
285    }
286    /*
287     * Try to check that the method is sensible.
288     * If you have a constructor, you must have a destructor and vice versa.
289     * You must have at least one of the encoding driver functions.
290     */
291    if (!((decoder->newctx == NULL && decoder->freectx == NULL)
292          || (decoder->newctx != NULL && decoder->freectx != NULL))
293        || decoder->decode == NULL) {
294        OSSL_DECODER_free(decoder);
295        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
296        return NULL;
297    }
298
299    if (prov != NULL && !ossl_provider_up_ref(prov)) {
300        OSSL_DECODER_free(decoder);
301        return NULL;
302    }
303
304    decoder->base.prov = prov;
305    return decoder;
306}
307
308
309/*
310 * The core fetching functionality passes the names of the implementation.
311 * This function is responsible to getting an identity number for them,
312 * then call ossl_decoder_from_algorithm() with that identity number.
313 */
314static void *construct_decoder(const OSSL_ALGORITHM *algodef,
315                               OSSL_PROVIDER *prov, void *data)
316{
317    /*
318     * This function is only called if get_decoder_from_store() returned
319     * NULL, so it's safe to say that of all the spots to create a new
320     * namemap entry, this is it.  Should the name already exist there, we
321     * know that ossl_namemap_add() will return its corresponding number.
322     */
323    struct decoder_data_st *methdata = data;
324    OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
325    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
326    const char *names = algodef->algorithm_names;
327    int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
328    void *method = NULL;
329
330    if (id != 0)
331        method = ossl_decoder_from_algorithm(id, algodef, prov);
332
333    /*
334     * Flag to indicate that there was actual construction errors.  This
335     * helps inner_evp_generic_fetch() determine what error it should
336     * record on inaccessible algorithms.
337     */
338    if (method == NULL)
339        methdata->flag_construct_error_occurred = 1;
340
341    return method;
342}
343
344/* Intermediary function to avoid ugly casts, used below */
345static void destruct_decoder(void *method, void *data)
346{
347    OSSL_DECODER_free(method);
348}
349
350static int up_ref_decoder(void *method)
351{
352    return OSSL_DECODER_up_ref(method);
353}
354
355static void free_decoder(void *method)
356{
357    OSSL_DECODER_free(method);
358}
359
360/* Fetching support.  Can fetch by numeric identity or by name */
361static OSSL_DECODER *
362inner_ossl_decoder_fetch(struct decoder_data_st *methdata, int id,
363                         const char *name, const char *properties)
364{
365    OSSL_METHOD_STORE *store = get_decoder_store(methdata->libctx);
366    OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
367    const char *const propq = properties != NULL ? properties : "";
368    void *method = NULL;
369    int unsupported = 0;
370
371    if (store == NULL || namemap == NULL) {
372        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_INVALID_ARGUMENT);
373        return NULL;
374    }
375
376    /*
377     * If we have been passed both an id and a name, we have an
378     * internal programming error.
379     */
380    if (!ossl_assert(id == 0 || name == NULL)) {
381        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INTERNAL_ERROR);
382        return NULL;
383    }
384
385    if (id == 0 && name != NULL)
386        id = ossl_namemap_name2num(namemap, name);
387
388    /*
389     * If we haven't found the name yet, chances are that the algorithm to
390     * be fetched is unsupported.
391     */
392    if (id == 0)
393        unsupported = 1;
394
395    if (id == 0
396        || !ossl_method_store_cache_get(store, NULL, id, propq, &method)) {
397        OSSL_METHOD_CONSTRUCT_METHOD mcm = {
398            get_tmp_decoder_store,
399            reserve_decoder_store,
400            unreserve_decoder_store,
401            get_decoder_from_store,
402            put_decoder_in_store,
403            construct_decoder,
404            destruct_decoder
405        };
406        OSSL_PROVIDER *prov = NULL;
407
408        methdata->id = id;
409        methdata->names = name;
410        methdata->propquery = propq;
411        methdata->flag_construct_error_occurred = 0;
412        if ((method = ossl_method_construct(methdata->libctx, OSSL_OP_DECODER,
413                                            &prov, 0 /* !force_cache */,
414                                            &mcm, methdata)) != NULL) {
415            /*
416             * If construction did create a method for us, we know that
417             * there is a correct name_id and meth_id, since those have
418             * already been calculated in get_decoder_from_store() and
419             * put_decoder_in_store() above.
420             */
421            if (id == 0 && name != NULL)
422                id = ossl_namemap_name2num(namemap, name);
423            if (id != 0)
424                ossl_method_store_cache_set(store, prov, id, propq, method,
425                                            up_ref_decoder, free_decoder);
426        }
427
428        /*
429         * If we never were in the constructor, the algorithm to be fetched
430         * is unsupported.
431         */
432        unsupported = !methdata->flag_construct_error_occurred;
433    }
434
435    if ((id != 0 || name != NULL) && method == NULL) {
436        int code = unsupported ? ERR_R_UNSUPPORTED : ERR_R_FETCH_FAILED;
437
438        if (name == NULL)
439            name = ossl_namemap_num2name(namemap, id, 0);
440        ERR_raise_data(ERR_LIB_OSSL_DECODER, code,
441                       "%s, Name (%s : %d), Properties (%s)",
442                       ossl_lib_ctx_get_descriptor(methdata->libctx),
443                       name == NULL ? "<null>" : name, id,
444                       properties == NULL ? "<null>" : properties);
445    }
446
447    return method;
448}
449
450OSSL_DECODER *OSSL_DECODER_fetch(OSSL_LIB_CTX *libctx, const char *name,
451                                 const char *properties)
452{
453    struct decoder_data_st methdata;
454    void *method;
455
456    methdata.libctx = libctx;
457    methdata.tmp_store = NULL;
458    method = inner_ossl_decoder_fetch(&methdata, 0, name, properties);
459    dealloc_tmp_decoder_store(methdata.tmp_store);
460    return method;
461}
462
463OSSL_DECODER *ossl_decoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id,
464                                           const char *properties)
465{
466    struct decoder_data_st methdata;
467    void *method;
468
469    methdata.libctx = libctx;
470    methdata.tmp_store = NULL;
471    method = inner_ossl_decoder_fetch(&methdata, id, NULL, properties);
472    dealloc_tmp_decoder_store(methdata.tmp_store);
473    return method;
474}
475
476int ossl_decoder_store_cache_flush(OSSL_LIB_CTX *libctx)
477{
478    OSSL_METHOD_STORE *store = get_decoder_store(libctx);
479
480    if (store != NULL)
481        return ossl_method_store_cache_flush_all(store);
482    return 1;
483}
484
485int ossl_decoder_store_remove_all_provided(const OSSL_PROVIDER *prov)
486{
487    OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
488    OSSL_METHOD_STORE *store = get_decoder_store(libctx);
489
490    if (store != NULL)
491        return ossl_method_store_remove_all_provided(store, prov);
492    return 1;
493}
494
495/*
496 * Library of basic method functions
497 */
498
499const OSSL_PROVIDER *OSSL_DECODER_get0_provider(const OSSL_DECODER *decoder)
500{
501    if (!ossl_assert(decoder != NULL)) {
502        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
503        return 0;
504    }
505
506    return decoder->base.prov;
507}
508
509const char *OSSL_DECODER_get0_properties(const OSSL_DECODER *decoder)
510{
511    if (!ossl_assert(decoder != NULL)) {
512        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
513        return 0;
514    }
515
516    return decoder->base.algodef->property_definition;
517}
518
519const OSSL_PROPERTY_LIST *
520ossl_decoder_parsed_properties(const OSSL_DECODER *decoder)
521{
522    if (!ossl_assert(decoder != NULL)) {
523        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
524        return 0;
525    }
526
527    return decoder->base.parsed_propdef;
528}
529
530int ossl_decoder_get_number(const OSSL_DECODER *decoder)
531{
532    if (!ossl_assert(decoder != NULL)) {
533        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
534        return 0;
535    }
536
537    return decoder->base.id;
538}
539
540const char *OSSL_DECODER_get0_name(const OSSL_DECODER *decoder)
541{
542    return decoder->base.name;
543}
544
545const char *OSSL_DECODER_get0_description(const OSSL_DECODER *decoder)
546{
547    return decoder->base.algodef->algorithm_description;
548}
549
550int OSSL_DECODER_is_a(const OSSL_DECODER *decoder, const char *name)
551{
552    if (decoder->base.prov != NULL) {
553        OSSL_LIB_CTX *libctx = ossl_provider_libctx(decoder->base.prov);
554        OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
555
556        return ossl_namemap_name2num(namemap, name) == decoder->base.id;
557    }
558    return 0;
559}
560
561struct do_one_data_st {
562    void (*user_fn)(OSSL_DECODER *decoder, void *arg);
563    void *user_arg;
564};
565
566static void do_one(ossl_unused int id, void *method, void *arg)
567{
568    struct do_one_data_st *data = arg;
569
570    data->user_fn(method, data->user_arg);
571}
572
573void OSSL_DECODER_do_all_provided(OSSL_LIB_CTX *libctx,
574                                  void (*user_fn)(OSSL_DECODER *decoder,
575                                                  void *arg),
576                                  void *user_arg)
577{
578    struct decoder_data_st methdata;
579    struct do_one_data_st data;
580
581    methdata.libctx = libctx;
582    methdata.tmp_store = NULL;
583    (void)inner_ossl_decoder_fetch(&methdata, 0, NULL, NULL /* properties */);
584
585    data.user_fn = user_fn;
586    data.user_arg = user_arg;
587    if (methdata.tmp_store != NULL)
588        ossl_method_store_do_all(methdata.tmp_store, &do_one, &data);
589    ossl_method_store_do_all(get_decoder_store(libctx), &do_one, &data);
590    dealloc_tmp_decoder_store(methdata.tmp_store);
591}
592
593int OSSL_DECODER_names_do_all(const OSSL_DECODER *decoder,
594                              void (*fn)(const char *name, void *data),
595                              void *data)
596{
597    if (decoder == NULL)
598        return 0;
599
600    if (decoder->base.prov != NULL) {
601        OSSL_LIB_CTX *libctx = ossl_provider_libctx(decoder->base.prov);
602        OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
603
604        return ossl_namemap_doall_names(namemap, decoder->base.id, fn, data);
605    }
606
607    return 1;
608}
609
610const OSSL_PARAM *
611OSSL_DECODER_gettable_params(OSSL_DECODER *decoder)
612{
613    if (decoder != NULL && decoder->gettable_params != NULL) {
614        void *provctx = ossl_provider_ctx(OSSL_DECODER_get0_provider(decoder));
615
616        return decoder->gettable_params(provctx);
617    }
618    return NULL;
619}
620
621int OSSL_DECODER_get_params(OSSL_DECODER *decoder, OSSL_PARAM params[])
622{
623    if (decoder != NULL && decoder->get_params != NULL)
624        return decoder->get_params(params);
625    return 0;
626}
627
628const OSSL_PARAM *
629OSSL_DECODER_settable_ctx_params(OSSL_DECODER *decoder)
630{
631    if (decoder != NULL && decoder->settable_ctx_params != NULL) {
632        void *provctx = ossl_provider_ctx(OSSL_DECODER_get0_provider(decoder));
633
634        return decoder->settable_ctx_params(provctx);
635    }
636    return NULL;
637}
638
639/*
640 * Decoder context support
641 */
642
643/*
644 * |encoder| value NULL is valid, and signifies that there is no decoder.
645 * This is useful to provide fallback mechanisms.
646 *  Functions that want to verify if there is a decoder can do so with
647 * OSSL_DECODER_CTX_get_decoder()
648 */
649OSSL_DECODER_CTX *OSSL_DECODER_CTX_new(void)
650{
651    OSSL_DECODER_CTX *ctx;
652
653    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
654        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
655
656    return ctx;
657}
658
659int OSSL_DECODER_CTX_set_params(OSSL_DECODER_CTX *ctx,
660                                const OSSL_PARAM params[])
661{
662    int ok = 1;
663    size_t i;
664    size_t l;
665
666    if (!ossl_assert(ctx != NULL)) {
667        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
668        return 0;
669    }
670
671    if (ctx->decoder_insts == NULL)
672        return 1;
673
674    l = OSSL_DECODER_CTX_get_num_decoders(ctx);
675    for (i = 0; i < l; i++) {
676        OSSL_DECODER_INSTANCE *decoder_inst =
677            sk_OSSL_DECODER_INSTANCE_value(ctx->decoder_insts, i);
678        OSSL_DECODER *decoder =
679            OSSL_DECODER_INSTANCE_get_decoder(decoder_inst);
680        OSSL_DECODER *decoderctx =
681            OSSL_DECODER_INSTANCE_get_decoder_ctx(decoder_inst);
682
683        if (decoderctx == NULL || decoder->set_ctx_params == NULL)
684            continue;
685        if (!decoder->set_ctx_params(decoderctx, params))
686            ok = 0;
687    }
688    return ok;
689}
690
691void OSSL_DECODER_CTX_free(OSSL_DECODER_CTX *ctx)
692{
693    if (ctx != NULL) {
694        if (ctx->cleanup != NULL)
695            ctx->cleanup(ctx->construct_data);
696        sk_OSSL_DECODER_INSTANCE_pop_free(ctx->decoder_insts,
697                                          ossl_decoder_instance_free);
698        ossl_pw_clear_passphrase_data(&ctx->pwdata);
699        OPENSSL_free(ctx);
700    }
701}
702