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/err.h>
11e1051a39Sopenharmony_ci#include <openssl/ui.h>
12e1051a39Sopenharmony_ci#include <openssl/params.h>
13e1051a39Sopenharmony_ci#include <openssl/encoder.h>
14e1051a39Sopenharmony_ci#include <openssl/core_names.h>
15e1051a39Sopenharmony_ci#include <openssl/provider.h>
16e1051a39Sopenharmony_ci#include <openssl/safestack.h>
17e1051a39Sopenharmony_ci#include <openssl/trace.h>
18e1051a39Sopenharmony_ci#include "internal/provider.h"
19e1051a39Sopenharmony_ci#include "internal/property.h"
20e1051a39Sopenharmony_ci#include "crypto/evp.h"
21e1051a39Sopenharmony_ci#include "encoder_local.h"
22e1051a39Sopenharmony_ci
23e1051a39Sopenharmony_ciDEFINE_STACK_OF(OSSL_ENCODER)
24e1051a39Sopenharmony_ci
25e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
26e1051a39Sopenharmony_ci                                const char *cipher_name,
27e1051a39Sopenharmony_ci                                const char *propquery)
28e1051a39Sopenharmony_ci{
29e1051a39Sopenharmony_ci    OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_ci    params[0] =
32e1051a39Sopenharmony_ci        OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_CIPHER,
33e1051a39Sopenharmony_ci                                         (void *)cipher_name, 0);
34e1051a39Sopenharmony_ci    params[1] =
35e1051a39Sopenharmony_ci        OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES,
36e1051a39Sopenharmony_ci                                         (void *)propquery, 0);
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ci    return OSSL_ENCODER_CTX_set_params(ctx, params);
39e1051a39Sopenharmony_ci}
40e1051a39Sopenharmony_ci
41e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX *ctx,
42e1051a39Sopenharmony_ci                                    const unsigned char *kstr,
43e1051a39Sopenharmony_ci                                    size_t klen)
44e1051a39Sopenharmony_ci{
45e1051a39Sopenharmony_ci    return ossl_pw_set_passphrase(&ctx->pwdata, kstr, klen);
46e1051a39Sopenharmony_ci}
47e1051a39Sopenharmony_ci
48e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
49e1051a39Sopenharmony_ci                                       const UI_METHOD *ui_method,
50e1051a39Sopenharmony_ci                                       void *ui_data)
51e1051a39Sopenharmony_ci{
52e1051a39Sopenharmony_ci    return ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data);
53e1051a39Sopenharmony_ci}
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_pem_password_cb(OSSL_ENCODER_CTX *ctx,
56e1051a39Sopenharmony_ci                                         pem_password_cb *cb, void *cbarg)
57e1051a39Sopenharmony_ci{
58e1051a39Sopenharmony_ci    return ossl_pw_set_pem_password_cb(&ctx->pwdata, cb, cbarg);
59e1051a39Sopenharmony_ci}
60e1051a39Sopenharmony_ci
61e1051a39Sopenharmony_ciint OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
62e1051a39Sopenharmony_ci                                       OSSL_PASSPHRASE_CALLBACK *cb,
63e1051a39Sopenharmony_ci                                       void *cbarg)
64e1051a39Sopenharmony_ci{
65e1051a39Sopenharmony_ci    return ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, cb, cbarg);
66e1051a39Sopenharmony_ci}
67e1051a39Sopenharmony_ci
68e1051a39Sopenharmony_ci/*
69e1051a39Sopenharmony_ci * Support for OSSL_ENCODER_CTX_new_for_type:
70e1051a39Sopenharmony_ci * finding a suitable encoder
71e1051a39Sopenharmony_ci */
72e1051a39Sopenharmony_ci
73e1051a39Sopenharmony_cistruct collected_encoder_st {
74e1051a39Sopenharmony_ci    STACK_OF(OPENSSL_CSTRING) *names;
75e1051a39Sopenharmony_ci    const char *output_structure;
76e1051a39Sopenharmony_ci    const char *output_type;
77e1051a39Sopenharmony_ci
78e1051a39Sopenharmony_ci    const OSSL_PROVIDER *keymgmt_prov;
79e1051a39Sopenharmony_ci    OSSL_ENCODER_CTX *ctx;
80e1051a39Sopenharmony_ci    unsigned int flag_find_same_provider:1;
81e1051a39Sopenharmony_ci
82e1051a39Sopenharmony_ci    int error_occurred;
83e1051a39Sopenharmony_ci};
84e1051a39Sopenharmony_ci
85e1051a39Sopenharmony_cistatic void collect_encoder(OSSL_ENCODER *encoder, void *arg)
86e1051a39Sopenharmony_ci{
87e1051a39Sopenharmony_ci    struct collected_encoder_st *data = arg;
88e1051a39Sopenharmony_ci    size_t i, end_i;
89e1051a39Sopenharmony_ci
90e1051a39Sopenharmony_ci    if (data->error_occurred)
91e1051a39Sopenharmony_ci        return;
92e1051a39Sopenharmony_ci
93e1051a39Sopenharmony_ci    data->error_occurred = 1;     /* Assume the worst */
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ci    if (data->names == NULL)
96e1051a39Sopenharmony_ci        return;
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci    end_i = sk_OPENSSL_CSTRING_num(data->names);
99e1051a39Sopenharmony_ci    for (i = 0; i < end_i; i++) {
100e1051a39Sopenharmony_ci        const char *name = sk_OPENSSL_CSTRING_value(data->names, i);
101e1051a39Sopenharmony_ci        const OSSL_PROVIDER *prov = OSSL_ENCODER_get0_provider(encoder);
102e1051a39Sopenharmony_ci        void *provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_ci        /*
105e1051a39Sopenharmony_ci         * collect_encoder() is called in two passes, one where the encoders
106e1051a39Sopenharmony_ci         * from the same provider as the keymgmt are looked up, and one where
107e1051a39Sopenharmony_ci         * the other encoders are looked up.  |data->flag_find_same_provider|
108e1051a39Sopenharmony_ci         * tells us which pass we're in.
109e1051a39Sopenharmony_ci         */
110e1051a39Sopenharmony_ci        if ((data->keymgmt_prov == prov) != data->flag_find_same_provider)
111e1051a39Sopenharmony_ci            continue;
112e1051a39Sopenharmony_ci
113e1051a39Sopenharmony_ci        if (!OSSL_ENCODER_is_a(encoder, name)
114e1051a39Sopenharmony_ci            || (encoder->does_selection != NULL
115e1051a39Sopenharmony_ci                && !encoder->does_selection(provctx, data->ctx->selection))
116e1051a39Sopenharmony_ci            || (data->keymgmt_prov != prov
117e1051a39Sopenharmony_ci                && encoder->import_object == NULL))
118e1051a39Sopenharmony_ci            continue;
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci        /* Only add each encoder implementation once */
121e1051a39Sopenharmony_ci        if (OSSL_ENCODER_CTX_add_encoder(data->ctx, encoder))
122e1051a39Sopenharmony_ci            break;
123e1051a39Sopenharmony_ci    }
124e1051a39Sopenharmony_ci
125e1051a39Sopenharmony_ci    data->error_occurred = 0;         /* All is good now */
126e1051a39Sopenharmony_ci}
127e1051a39Sopenharmony_ci
128e1051a39Sopenharmony_cistruct collected_names_st {
129e1051a39Sopenharmony_ci    STACK_OF(OPENSSL_CSTRING) *names;
130e1051a39Sopenharmony_ci    unsigned int error_occurred:1;
131e1051a39Sopenharmony_ci};
132e1051a39Sopenharmony_ci
133e1051a39Sopenharmony_cistatic void collect_name(const char *name, void *arg)
134e1051a39Sopenharmony_ci{
135e1051a39Sopenharmony_ci    struct collected_names_st *data = arg;
136e1051a39Sopenharmony_ci
137e1051a39Sopenharmony_ci    if (data->error_occurred)
138e1051a39Sopenharmony_ci        return;
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    data->error_occurred = 1;         /* Assume the worst */
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_ci    if (sk_OPENSSL_CSTRING_push(data->names, name) <= 0)
143e1051a39Sopenharmony_ci        return;
144e1051a39Sopenharmony_ci
145e1051a39Sopenharmony_ci    data->error_occurred = 0;         /* All is good now */
146e1051a39Sopenharmony_ci}
147e1051a39Sopenharmony_ci
148e1051a39Sopenharmony_ci/*
149e1051a39Sopenharmony_ci * Support for OSSL_ENCODER_to_bio:
150e1051a39Sopenharmony_ci * writing callback for the OSSL_PARAM (the implementation doesn't have
151e1051a39Sopenharmony_ci * intimate knowledge of the provider side object)
152e1051a39Sopenharmony_ci */
153e1051a39Sopenharmony_ci
154e1051a39Sopenharmony_cistruct construct_data_st {
155e1051a39Sopenharmony_ci    const EVP_PKEY *pk;
156e1051a39Sopenharmony_ci    int selection;
157e1051a39Sopenharmony_ci
158e1051a39Sopenharmony_ci    OSSL_ENCODER_INSTANCE *encoder_inst;
159e1051a39Sopenharmony_ci    const void *obj;
160e1051a39Sopenharmony_ci    void *constructed_obj;
161e1051a39Sopenharmony_ci};
162e1051a39Sopenharmony_ci
163e1051a39Sopenharmony_cistatic int encoder_import_cb(const OSSL_PARAM params[], void *arg)
164e1051a39Sopenharmony_ci{
165e1051a39Sopenharmony_ci    struct construct_data_st *construct_data = arg;
166e1051a39Sopenharmony_ci    OSSL_ENCODER_INSTANCE *encoder_inst = construct_data->encoder_inst;
167e1051a39Sopenharmony_ci    OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
168e1051a39Sopenharmony_ci    void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
169e1051a39Sopenharmony_ci
170e1051a39Sopenharmony_ci    construct_data->constructed_obj =
171e1051a39Sopenharmony_ci        encoder->import_object(encoderctx, construct_data->selection, params);
172e1051a39Sopenharmony_ci
173e1051a39Sopenharmony_ci    return (construct_data->constructed_obj != NULL);
174e1051a39Sopenharmony_ci}
175e1051a39Sopenharmony_ci
176e1051a39Sopenharmony_cistatic const void *
177e1051a39Sopenharmony_ciencoder_construct_pkey(OSSL_ENCODER_INSTANCE *encoder_inst, void *arg)
178e1051a39Sopenharmony_ci{
179e1051a39Sopenharmony_ci    struct construct_data_st *data = arg;
180e1051a39Sopenharmony_ci
181e1051a39Sopenharmony_ci    if (data->obj == NULL) {
182e1051a39Sopenharmony_ci        OSSL_ENCODER *encoder =
183e1051a39Sopenharmony_ci            OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
184e1051a39Sopenharmony_ci        const EVP_PKEY *pk = data->pk;
185e1051a39Sopenharmony_ci        const OSSL_PROVIDER *k_prov = EVP_KEYMGMT_get0_provider(pk->keymgmt);
186e1051a39Sopenharmony_ci        const OSSL_PROVIDER *e_prov = OSSL_ENCODER_get0_provider(encoder);
187e1051a39Sopenharmony_ci
188e1051a39Sopenharmony_ci        if (k_prov != e_prov) {
189e1051a39Sopenharmony_ci            data->encoder_inst = encoder_inst;
190e1051a39Sopenharmony_ci
191e1051a39Sopenharmony_ci            if (!evp_keymgmt_export(pk->keymgmt, pk->keydata, data->selection,
192e1051a39Sopenharmony_ci                                    &encoder_import_cb, data))
193e1051a39Sopenharmony_ci                return NULL;
194e1051a39Sopenharmony_ci            data->obj = data->constructed_obj;
195e1051a39Sopenharmony_ci        } else {
196e1051a39Sopenharmony_ci            data->obj = pk->keydata;
197e1051a39Sopenharmony_ci        }
198e1051a39Sopenharmony_ci    }
199e1051a39Sopenharmony_ci
200e1051a39Sopenharmony_ci    return data->obj;
201e1051a39Sopenharmony_ci}
202e1051a39Sopenharmony_ci
203e1051a39Sopenharmony_cistatic void encoder_destruct_pkey(void *arg)
204e1051a39Sopenharmony_ci{
205e1051a39Sopenharmony_ci    struct construct_data_st *data = arg;
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    if (data->encoder_inst != NULL) {
208e1051a39Sopenharmony_ci        OSSL_ENCODER *encoder =
209e1051a39Sopenharmony_ci            OSSL_ENCODER_INSTANCE_get_encoder(data->encoder_inst);
210e1051a39Sopenharmony_ci
211e1051a39Sopenharmony_ci        encoder->free_object(data->constructed_obj);
212e1051a39Sopenharmony_ci    }
213e1051a39Sopenharmony_ci    data->constructed_obj = NULL;
214e1051a39Sopenharmony_ci}
215e1051a39Sopenharmony_ci
216e1051a39Sopenharmony_ci/*
217e1051a39Sopenharmony_ci * OSSL_ENCODER_CTX_new_for_pkey() returns a ctx with no encoder if
218e1051a39Sopenharmony_ci * it couldn't find a suitable encoder.  This allows a caller to detect if
219e1051a39Sopenharmony_ci * a suitable encoder was found, with OSSL_ENCODER_CTX_get_num_encoder(),
220e1051a39Sopenharmony_ci * and to use fallback methods if the result is NULL.
221e1051a39Sopenharmony_ci */
222e1051a39Sopenharmony_cistatic int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX *ctx,
223e1051a39Sopenharmony_ci                                           const EVP_PKEY *pkey,
224e1051a39Sopenharmony_ci                                           int selection,
225e1051a39Sopenharmony_ci                                           const char *propquery)
226e1051a39Sopenharmony_ci{
227e1051a39Sopenharmony_ci    struct construct_data_st *data = NULL;
228e1051a39Sopenharmony_ci    const OSSL_PROVIDER *prov = NULL;
229e1051a39Sopenharmony_ci    OSSL_LIB_CTX *libctx = NULL;
230e1051a39Sopenharmony_ci    int ok = 0;
231e1051a39Sopenharmony_ci
232e1051a39Sopenharmony_ci    if (!ossl_assert(ctx != NULL) || !ossl_assert(pkey != NULL)) {
233e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
234e1051a39Sopenharmony_ci        return 0;
235e1051a39Sopenharmony_ci    }
236e1051a39Sopenharmony_ci
237e1051a39Sopenharmony_ci    if (evp_pkey_is_provided(pkey)) {
238e1051a39Sopenharmony_ci        prov = EVP_KEYMGMT_get0_provider(pkey->keymgmt);
239e1051a39Sopenharmony_ci        libctx = ossl_provider_libctx(prov);
240e1051a39Sopenharmony_ci    }
241e1051a39Sopenharmony_ci
242e1051a39Sopenharmony_ci    if (pkey->keymgmt != NULL) {
243e1051a39Sopenharmony_ci        struct collected_encoder_st encoder_data;
244e1051a39Sopenharmony_ci        struct collected_names_st keymgmt_data;
245e1051a39Sopenharmony_ci
246e1051a39Sopenharmony_ci        if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) {
247e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
248e1051a39Sopenharmony_ci            goto err;
249e1051a39Sopenharmony_ci        }
250e1051a39Sopenharmony_ci
251e1051a39Sopenharmony_ci        /*
252e1051a39Sopenharmony_ci         * Select the first encoder implementations in two steps.
253e1051a39Sopenharmony_ci         * First, collect the keymgmt names, then the encoders that match.
254e1051a39Sopenharmony_ci         */
255e1051a39Sopenharmony_ci        keymgmt_data.names = sk_OPENSSL_CSTRING_new_null();
256e1051a39Sopenharmony_ci        if (keymgmt_data.names == NULL) {
257e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
258e1051a39Sopenharmony_ci            goto err;
259e1051a39Sopenharmony_ci        }
260e1051a39Sopenharmony_ci
261e1051a39Sopenharmony_ci        keymgmt_data.error_occurred = 0;
262e1051a39Sopenharmony_ci        EVP_KEYMGMT_names_do_all(pkey->keymgmt, collect_name, &keymgmt_data);
263e1051a39Sopenharmony_ci        if (keymgmt_data.error_occurred) {
264e1051a39Sopenharmony_ci            sk_OPENSSL_CSTRING_free(keymgmt_data.names);
265e1051a39Sopenharmony_ci            goto err;
266e1051a39Sopenharmony_ci        }
267e1051a39Sopenharmony_ci
268e1051a39Sopenharmony_ci        encoder_data.names = keymgmt_data.names;
269e1051a39Sopenharmony_ci        encoder_data.output_type = ctx->output_type;
270e1051a39Sopenharmony_ci        encoder_data.output_structure = ctx->output_structure;
271e1051a39Sopenharmony_ci        encoder_data.error_occurred = 0;
272e1051a39Sopenharmony_ci        encoder_data.keymgmt_prov = prov;
273e1051a39Sopenharmony_ci        encoder_data.ctx = ctx;
274e1051a39Sopenharmony_ci
275e1051a39Sopenharmony_ci        /*
276e1051a39Sopenharmony_ci         * Place the encoders with the a different provider as the keymgmt
277e1051a39Sopenharmony_ci         * last (the chain is processed in reverse order)
278e1051a39Sopenharmony_ci         */
279e1051a39Sopenharmony_ci        encoder_data.flag_find_same_provider = 0;
280e1051a39Sopenharmony_ci        OSSL_ENCODER_do_all_provided(libctx, collect_encoder, &encoder_data);
281e1051a39Sopenharmony_ci
282e1051a39Sopenharmony_ci        /*
283e1051a39Sopenharmony_ci         * Place the encoders with the same provider as the keymgmt first
284e1051a39Sopenharmony_ci         * (the chain is processed in reverse order)
285e1051a39Sopenharmony_ci         */
286e1051a39Sopenharmony_ci        encoder_data.flag_find_same_provider = 1;
287e1051a39Sopenharmony_ci        OSSL_ENCODER_do_all_provided(libctx, collect_encoder, &encoder_data);
288e1051a39Sopenharmony_ci
289e1051a39Sopenharmony_ci        sk_OPENSSL_CSTRING_free(keymgmt_data.names);
290e1051a39Sopenharmony_ci        if (encoder_data.error_occurred) {
291e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
292e1051a39Sopenharmony_ci            goto err;
293e1051a39Sopenharmony_ci        }
294e1051a39Sopenharmony_ci    }
295e1051a39Sopenharmony_ci
296e1051a39Sopenharmony_ci    if (data != NULL && OSSL_ENCODER_CTX_get_num_encoders(ctx) != 0) {
297e1051a39Sopenharmony_ci        if (!OSSL_ENCODER_CTX_set_construct(ctx, encoder_construct_pkey)
298e1051a39Sopenharmony_ci            || !OSSL_ENCODER_CTX_set_construct_data(ctx, data)
299e1051a39Sopenharmony_ci            || !OSSL_ENCODER_CTX_set_cleanup(ctx, encoder_destruct_pkey))
300e1051a39Sopenharmony_ci            goto err;
301e1051a39Sopenharmony_ci
302e1051a39Sopenharmony_ci        data->pk = pkey;
303e1051a39Sopenharmony_ci        data->selection = selection;
304e1051a39Sopenharmony_ci
305e1051a39Sopenharmony_ci        data = NULL;             /* Avoid it being freed */
306e1051a39Sopenharmony_ci    }
307e1051a39Sopenharmony_ci
308e1051a39Sopenharmony_ci    ok = 1;
309e1051a39Sopenharmony_ci err:
310e1051a39Sopenharmony_ci    if (data != NULL) {
311e1051a39Sopenharmony_ci        OSSL_ENCODER_CTX_set_construct_data(ctx, NULL);
312e1051a39Sopenharmony_ci        OPENSSL_free(data);
313e1051a39Sopenharmony_ci    }
314e1051a39Sopenharmony_ci    return ok;
315e1051a39Sopenharmony_ci}
316e1051a39Sopenharmony_ci
317e1051a39Sopenharmony_ciOSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_for_pkey(const EVP_PKEY *pkey,
318e1051a39Sopenharmony_ci                                                int selection,
319e1051a39Sopenharmony_ci                                                const char *output_type,
320e1051a39Sopenharmony_ci                                                const char *output_struct,
321e1051a39Sopenharmony_ci                                                const char *propquery)
322e1051a39Sopenharmony_ci{
323e1051a39Sopenharmony_ci    OSSL_ENCODER_CTX *ctx = NULL;
324e1051a39Sopenharmony_ci    OSSL_LIB_CTX *libctx = NULL;
325e1051a39Sopenharmony_ci
326e1051a39Sopenharmony_ci    if (pkey == NULL) {
327e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
328e1051a39Sopenharmony_ci        return NULL;
329e1051a39Sopenharmony_ci    }
330e1051a39Sopenharmony_ci
331e1051a39Sopenharmony_ci    if (!evp_pkey_is_assigned(pkey)) {
332e1051a39Sopenharmony_ci        ERR_raise_data(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT,
333e1051a39Sopenharmony_ci                       "The passed EVP_PKEY must be assigned a key");
334e1051a39Sopenharmony_ci        return NULL;
335e1051a39Sopenharmony_ci    }
336e1051a39Sopenharmony_ci
337e1051a39Sopenharmony_ci    if ((ctx = OSSL_ENCODER_CTX_new()) == NULL) {
338e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
339e1051a39Sopenharmony_ci        return NULL;
340e1051a39Sopenharmony_ci    }
341e1051a39Sopenharmony_ci
342e1051a39Sopenharmony_ci    if (evp_pkey_is_provided(pkey)) {
343e1051a39Sopenharmony_ci        const OSSL_PROVIDER *prov = EVP_KEYMGMT_get0_provider(pkey->keymgmt);
344e1051a39Sopenharmony_ci
345e1051a39Sopenharmony_ci        libctx = ossl_provider_libctx(prov);
346e1051a39Sopenharmony_ci    }
347e1051a39Sopenharmony_ci
348e1051a39Sopenharmony_ci    OSSL_TRACE_BEGIN(ENCODER) {
349e1051a39Sopenharmony_ci        BIO_printf(trc_out,
350e1051a39Sopenharmony_ci                   "(ctx %p) Looking for %s encoders with selection %d\n",
351e1051a39Sopenharmony_ci                   (void *)ctx, EVP_PKEY_get0_type_name(pkey), selection);
352e1051a39Sopenharmony_ci        BIO_printf(trc_out, "    output type: %s, output structure: %s\n",
353e1051a39Sopenharmony_ci                   output_type, output_struct);
354e1051a39Sopenharmony_ci    } OSSL_TRACE_END(ENCODER);
355e1051a39Sopenharmony_ci
356e1051a39Sopenharmony_ci    if (OSSL_ENCODER_CTX_set_output_type(ctx, output_type)
357e1051a39Sopenharmony_ci        && (output_struct == NULL
358e1051a39Sopenharmony_ci            || OSSL_ENCODER_CTX_set_output_structure(ctx, output_struct))
359e1051a39Sopenharmony_ci        && OSSL_ENCODER_CTX_set_selection(ctx, selection)
360e1051a39Sopenharmony_ci        && ossl_encoder_ctx_setup_for_pkey(ctx, pkey, selection, propquery)
361e1051a39Sopenharmony_ci        && OSSL_ENCODER_CTX_add_extra(ctx, libctx, propquery)) {
362e1051a39Sopenharmony_ci        OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
363e1051a39Sopenharmony_ci        int save_parameters = pkey->save_parameters;
364e1051a39Sopenharmony_ci
365e1051a39Sopenharmony_ci        params[0] = OSSL_PARAM_construct_int(OSSL_ENCODER_PARAM_SAVE_PARAMETERS,
366e1051a39Sopenharmony_ci                                             &save_parameters);
367e1051a39Sopenharmony_ci        /* ignoring error as this is only auxiliary parameter */
368e1051a39Sopenharmony_ci        (void)OSSL_ENCODER_CTX_set_params(ctx, params);
369e1051a39Sopenharmony_ci
370e1051a39Sopenharmony_ci        OSSL_TRACE_BEGIN(ENCODER) {
371e1051a39Sopenharmony_ci            BIO_printf(trc_out, "(ctx %p) Got %d encoders\n",
372e1051a39Sopenharmony_ci                       (void *)ctx, OSSL_ENCODER_CTX_get_num_encoders(ctx));
373e1051a39Sopenharmony_ci        } OSSL_TRACE_END(ENCODER);
374e1051a39Sopenharmony_ci        return ctx;
375e1051a39Sopenharmony_ci    }
376e1051a39Sopenharmony_ci
377e1051a39Sopenharmony_ci    OSSL_ENCODER_CTX_free(ctx);
378e1051a39Sopenharmony_ci    return NULL;
379e1051a39Sopenharmony_ci}
380