2 * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include <openssl/err.h>
11 #include <openssl/ui.h>
12 #include <openssl/params.h>
13 #include <openssl/encoder.h>
14 #include <openssl/core_names.h>
15 #include <openssl/provider.h>
16 #include <openssl/safestack.h>
17 #include <openssl/trace.h>
18 #include "internal/provider.h"
19 #include "internal/property.h"
20 #include "crypto/evp.h"
21 #include "encoder_local.h"
23 DEFINE_STACK_OF(OSSL_ENCODER
)
25 int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX
*ctx
,
26 const char *cipher_name
,
27 const char *propquery
)
29 OSSL_PARAM params
[] = { OSSL_PARAM_END
, OSSL_PARAM_END
, OSSL_PARAM_END
};
32 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_CIPHER
,
33 (void *)cipher_name
, 0);
35 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES
,
36 (void *)propquery
, 0);
38 return OSSL_ENCODER_CTX_set_params(ctx
, params
);
41 int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX
*ctx
,
42 const unsigned char *kstr
,
45 return ossl_pw_set_passphrase(&ctx
->pwdata
, kstr
, klen
);
48 int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX
*ctx
,
49 const UI_METHOD
*ui_method
,
52 return ossl_pw_set_ui_method(&ctx
->pwdata
, ui_method
, ui_data
);
55 int OSSL_ENCODER_CTX_set_pem_password_cb(OSSL_ENCODER_CTX
*ctx
,
56 pem_password_cb
*cb
, void *cbarg
)
58 return ossl_pw_set_pem_password_cb(&ctx
->pwdata
, cb
, cbarg
);
61 int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX
*ctx
,
62 OSSL_PASSPHRASE_CALLBACK
*cb
,
65 return ossl_pw_set_ossl_passphrase_cb(&ctx
->pwdata
, cb
, cbarg
);
69 * Support for OSSL_ENCODER_CTX_new_for_type:
70 * finding a suitable encoder
73 struct collected_encoder_st
{
74 STACK_OF(OPENSSL_CSTRING
) *names
;
75 const char *output_structure
;
76 const char *output_type
;
78 const OSSL_PROVIDER
*keymgmt_prov
;
79 OSSL_ENCODER_CTX
*ctx
;
80 unsigned int flag_find_same_provider
:1;
85 static void collect_encoder(OSSL_ENCODER
*encoder
, void *arg
)
87 struct collected_encoder_st
*data
= arg
;
90 if (data
->error_occurred
)
93 data
->error_occurred
= 1; /* Assume the worst */
95 if (data
->names
== NULL
)
98 end_i
= sk_OPENSSL_CSTRING_num(data
->names
);
99 for (i
= 0; i
< end_i
; i
++) {
100 const char *name
= sk_OPENSSL_CSTRING_value(data
->names
, i
);
101 const OSSL_PROVIDER
*prov
= OSSL_ENCODER_get0_provider(encoder
);
102 void *provctx
= OSSL_PROVIDER_get0_provider_ctx(prov
);
105 * collect_encoder() is called in two passes, one where the encoders
106 * from the same provider as the keymgmt are looked up, and one where
107 * the other encoders are looked up. |data->flag_find_same_provider|
108 * tells us which pass we're in.
110 if ((data
->keymgmt_prov
== prov
) != data
->flag_find_same_provider
)
113 if (!OSSL_ENCODER_is_a(encoder
, name
)
114 || (encoder
->does_selection
!= NULL
115 && !encoder
->does_selection(provctx
, data
->ctx
->selection
))
116 || (data
->keymgmt_prov
!= prov
117 && encoder
->import_object
== NULL
))
120 /* Only add each encoder implementation once */
121 if (OSSL_ENCODER_CTX_add_encoder(data
->ctx
, encoder
))
125 data
->error_occurred
= 0; /* All is good now */
128 struct collected_names_st
{
129 STACK_OF(OPENSSL_CSTRING
) *names
;
130 unsigned int error_occurred
:1;
133 static void collect_name(const char *name
, void *arg
)
135 struct collected_names_st
*data
= arg
;
137 if (data
->error_occurred
)
140 data
->error_occurred
= 1; /* Assume the worst */
142 if (sk_OPENSSL_CSTRING_push(data
->names
, name
) <= 0)
145 data
->error_occurred
= 0; /* All is good now */
149 * Support for OSSL_ENCODER_to_bio:
150 * writing callback for the OSSL_PARAM (the implementation doesn't have
151 * intimate knowledge of the provider side object)
154 struct construct_data_st
{
158 OSSL_ENCODER_INSTANCE
*encoder_inst
;
160 void *constructed_obj
;
163 static int encoder_import_cb(const OSSL_PARAM params
[], void *arg
)
165 struct construct_data_st
*construct_data
= arg
;
166 OSSL_ENCODER_INSTANCE
*encoder_inst
= construct_data
->encoder_inst
;
167 OSSL_ENCODER
*encoder
= OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst
);
168 void *encoderctx
= OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst
);
170 construct_data
->constructed_obj
=
171 encoder
->import_object(encoderctx
, construct_data
->selection
, params
);
173 return (construct_data
->constructed_obj
!= NULL
);
177 encoder_construct_pkey(OSSL_ENCODER_INSTANCE
*encoder_inst
, void *arg
)
179 struct construct_data_st
*data
= arg
;
181 if (data
->obj
== NULL
) {
182 OSSL_ENCODER
*encoder
=
183 OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst
);
184 const EVP_PKEY
*pk
= data
->pk
;
185 const OSSL_PROVIDER
*k_prov
= EVP_KEYMGMT_get0_provider(pk
->keymgmt
);
186 const OSSL_PROVIDER
*e_prov
= OSSL_ENCODER_get0_provider(encoder
);
188 if (k_prov
!= e_prov
) {
189 data
->encoder_inst
= encoder_inst
;
191 if (!evp_keymgmt_export(pk
->keymgmt
, pk
->keydata
, data
->selection
,
192 &encoder_import_cb
, data
))
194 data
->obj
= data
->constructed_obj
;
196 data
->obj
= pk
->keydata
;
203 static void encoder_destruct_pkey(void *arg
)
205 struct construct_data_st
*data
= arg
;
207 if (data
->encoder_inst
!= NULL
) {
208 OSSL_ENCODER
*encoder
=
209 OSSL_ENCODER_INSTANCE_get_encoder(data
->encoder_inst
);
211 encoder
->free_object(data
->constructed_obj
);
213 data
->constructed_obj
= NULL
;
217 * OSSL_ENCODER_CTX_new_for_pkey() returns a ctx with no encoder if
218 * it couldn't find a suitable encoder. This allows a caller to detect if
219 * a suitable encoder was found, with OSSL_ENCODER_CTX_get_num_encoder(),
220 * and to use fallback methods if the result is NULL.
222 static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX
*ctx
,
223 const EVP_PKEY
*pkey
,
225 const char *propquery
)
227 struct construct_data_st
*data
= NULL
;
228 const OSSL_PROVIDER
*prov
= NULL
;
229 OSSL_LIB_CTX
*libctx
= NULL
;
232 if (!ossl_assert(ctx
!= NULL
) || !ossl_assert(pkey
!= NULL
)) {
233 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_NULL_PARAMETER
);
237 if (evp_pkey_is_provided(pkey
)) {
238 prov
= EVP_KEYMGMT_get0_provider(pkey
->keymgmt
);
239 libctx
= ossl_provider_libctx(prov
);
242 if (pkey
->keymgmt
!= NULL
) {
243 struct collected_encoder_st encoder_data
;
244 struct collected_names_st keymgmt_data
;
246 if ((data
= OPENSSL_zalloc(sizeof(*data
))) == NULL
) {
247 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
252 * Select the first encoder implementations in two steps.
253 * First, collect the keymgmt names, then the encoders that match.
255 keymgmt_data
.names
= sk_OPENSSL_CSTRING_new_null();
256 if (keymgmt_data
.names
== NULL
) {
257 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
261 keymgmt_data
.error_occurred
= 0;
262 EVP_KEYMGMT_names_do_all(pkey
->keymgmt
, collect_name
, &keymgmt_data
);
263 if (keymgmt_data
.error_occurred
) {
264 sk_OPENSSL_CSTRING_free(keymgmt_data
.names
);
268 encoder_data
.names
= keymgmt_data
.names
;
269 encoder_data
.output_type
= ctx
->output_type
;
270 encoder_data
.output_structure
= ctx
->output_structure
;
271 encoder_data
.error_occurred
= 0;
272 encoder_data
.keymgmt_prov
= prov
;
273 encoder_data
.ctx
= ctx
;
276 * Place the encoders with the a different provider as the keymgmt
277 * last (the chain is processed in reverse order)
279 encoder_data
.flag_find_same_provider
= 0;
280 OSSL_ENCODER_do_all_provided(libctx
, collect_encoder
, &encoder_data
);
283 * Place the encoders with the same provider as the keymgmt first
284 * (the chain is processed in reverse order)
286 encoder_data
.flag_find_same_provider
= 1;
287 OSSL_ENCODER_do_all_provided(libctx
, collect_encoder
, &encoder_data
);
289 sk_OPENSSL_CSTRING_free(keymgmt_data
.names
);
290 if (encoder_data
.error_occurred
) {
291 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
296 if (data
!= NULL
&& OSSL_ENCODER_CTX_get_num_encoders(ctx
) != 0) {
297 if (!OSSL_ENCODER_CTX_set_construct(ctx
, encoder_construct_pkey
)
298 || !OSSL_ENCODER_CTX_set_construct_data(ctx
, data
)
299 || !OSSL_ENCODER_CTX_set_cleanup(ctx
, encoder_destruct_pkey
))
303 data
->selection
= selection
;
305 data
= NULL
; /* Avoid it being freed */
311 OSSL_ENCODER_CTX_set_construct_data(ctx
, NULL
);
317 OSSL_ENCODER_CTX
*OSSL_ENCODER_CTX_new_for_pkey(const EVP_PKEY
*pkey
,
319 const char *output_type
,
320 const char *output_struct
,
321 const char *propquery
)
323 OSSL_ENCODER_CTX
*ctx
= NULL
;
324 OSSL_LIB_CTX
*libctx
= NULL
;
327 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_NULL_PARAMETER
);
331 if (!evp_pkey_is_assigned(pkey
)) {
332 ERR_raise_data(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_INVALID_ARGUMENT
,
333 "The passed EVP_PKEY must be assigned a key");
337 if ((ctx
= OSSL_ENCODER_CTX_new()) == NULL
) {
338 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
342 if (evp_pkey_is_provided(pkey
)) {
343 const OSSL_PROVIDER
*prov
= EVP_KEYMGMT_get0_provider(pkey
->keymgmt
);
345 libctx
= ossl_provider_libctx(prov
);
348 OSSL_TRACE_BEGIN(ENCODER
) {
350 "(ctx %p) Looking for %s encoders with selection %d\n",
351 (void *)ctx
, EVP_PKEY_get0_type_name(pkey
), selection
);
352 BIO_printf(trc_out
, " output type: %s, output structure: %s\n",
353 output_type
, output_struct
);
354 } OSSL_TRACE_END(ENCODER
);
356 if (OSSL_ENCODER_CTX_set_output_type(ctx
, output_type
)
357 && (output_struct
== NULL
358 || OSSL_ENCODER_CTX_set_output_structure(ctx
, output_struct
))
359 && OSSL_ENCODER_CTX_set_selection(ctx
, selection
)
360 && ossl_encoder_ctx_setup_for_pkey(ctx
, pkey
, selection
, propquery
)
361 && OSSL_ENCODER_CTX_add_extra(ctx
, libctx
, propquery
)) {
362 OSSL_PARAM params
[2] = { OSSL_PARAM_END
, OSSL_PARAM_END
};
363 int save_parameters
= pkey
->save_parameters
;
365 params
[0] = OSSL_PARAM_construct_int(OSSL_ENCODER_PARAM_SAVE_PARAMETERS
,
367 /* ignoring error as this is only auxiliary parameter */
368 (void)OSSL_ENCODER_CTX_set_params(ctx
, params
);
370 OSSL_TRACE_BEGIN(ENCODER
) {
371 BIO_printf(trc_out
, "(ctx %p) Got %d encoders\n",
372 (void *)ctx
, OSSL_ENCODER_CTX_get_num_encoders(ctx
));
373 } OSSL_TRACE_END(ENCODER
);
377 OSSL_ENCODER_CTX_free(ctx
);