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