2 * Copyright 2019-2021 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 "e_os.h" /* strcasecmp on Windows */
11 #include <openssl/err.h>
12 #include <openssl/ui.h>
13 #include <openssl/params.h>
14 #include <openssl/encoder.h>
15 #include <openssl/core_names.h>
16 #include <openssl/provider.h>
17 #include <openssl/safestack.h>
18 #include <openssl/trace.h>
19 #include "internal/provider.h"
20 #include "internal/property.h"
21 #include "crypto/evp.h"
22 #include "encoder_local.h"
24 DEFINE_STACK_OF(OSSL_ENCODER
)
26 int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX
*ctx
,
27 const char *cipher_name
,
28 const char *propquery
)
30 OSSL_PARAM params
[] = { OSSL_PARAM_END
, OSSL_PARAM_END
, OSSL_PARAM_END
};
33 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_CIPHER
,
34 (void *)cipher_name
, 0);
36 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES
,
37 (void *)propquery
, 0);
39 return OSSL_ENCODER_CTX_set_params(ctx
, params
);
42 int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX
*ctx
,
43 const unsigned char *kstr
,
46 return ossl_pw_set_passphrase(&ctx
->pwdata
, kstr
, klen
);
49 int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX
*ctx
,
50 const UI_METHOD
*ui_method
,
53 return ossl_pw_set_ui_method(&ctx
->pwdata
, ui_method
, ui_data
);
56 int OSSL_ENCODER_CTX_set_pem_password_cb(OSSL_ENCODER_CTX
*ctx
,
57 pem_password_cb
*cb
, void *cbarg
)
59 return ossl_pw_set_pem_password_cb(&ctx
->pwdata
, cb
, cbarg
);
62 int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX
*ctx
,
63 OSSL_PASSPHRASE_CALLBACK
*cb
,
66 return ossl_pw_set_ossl_passphrase_cb(&ctx
->pwdata
, cb
, cbarg
);
70 * Support for OSSL_ENCODER_CTX_new_for_type:
71 * finding a suitable encoder
74 struct collected_encoder_st
{
75 STACK_OF(OPENSSL_CSTRING
) *names
;
76 const char *output_structure
;
77 const char *output_type
;
79 OSSL_ENCODER_CTX
*ctx
;
84 static void collect_encoder(OSSL_ENCODER
*encoder
, void *arg
)
86 struct collected_encoder_st
*data
= arg
;
89 if (data
->error_occurred
)
92 data
->error_occurred
= 1; /* Assume the worst */
94 if (data
->names
== NULL
)
97 end_i
= sk_OPENSSL_CSTRING_num(data
->names
);
98 for (i
= 0; i
< end_i
; i
++) {
99 const char *name
= sk_OPENSSL_CSTRING_value(data
->names
, i
);
100 const OSSL_PROVIDER
*prov
= OSSL_ENCODER_provider(encoder
);
101 void *provctx
= OSSL_PROVIDER_get0_provider_ctx(prov
);
103 if (!OSSL_ENCODER_is_a(encoder
, name
)
104 || (encoder
->does_selection
!= NULL
105 && !encoder
->does_selection(provctx
, data
->ctx
->selection
)))
108 /* Only add each encoder implementation once */
109 if (OSSL_ENCODER_CTX_add_encoder(data
->ctx
, encoder
))
113 data
->error_occurred
= 0; /* All is good now */
116 struct collected_names_st
{
117 STACK_OF(OPENSSL_CSTRING
) *names
;
118 unsigned int error_occurred
:1;
121 static void collect_name(const char *name
, void *arg
)
123 struct collected_names_st
*data
= arg
;
125 if (data
->error_occurred
)
128 data
->error_occurred
= 1; /* Assume the worst */
130 if (sk_OPENSSL_CSTRING_push(data
->names
, name
) <= 0)
133 data
->error_occurred
= 0; /* All is good now */
137 * Support for OSSL_ENCODER_to_bio:
138 * writing callback for the OSSL_PARAM (the implementation doesn't have
139 * intimate knowledge of the provider side object)
142 struct construct_data_st
{
146 OSSL_ENCODER_INSTANCE
*encoder_inst
;
148 void *constructed_obj
;
151 static int encoder_import_cb(const OSSL_PARAM params
[], void *arg
)
153 struct construct_data_st
*construct_data
= arg
;
154 OSSL_ENCODER_INSTANCE
*encoder_inst
= construct_data
->encoder_inst
;
155 OSSL_ENCODER
*encoder
= OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst
);
156 void *encoderctx
= OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst
);
158 construct_data
->constructed_obj
=
159 encoder
->import_object(encoderctx
, construct_data
->selection
, params
);
161 return (construct_data
->constructed_obj
!= NULL
);
165 encoder_construct_pkey(OSSL_ENCODER_INSTANCE
*encoder_inst
, void *arg
)
167 struct construct_data_st
*data
= arg
;
169 if (data
->obj
== NULL
) {
170 OSSL_ENCODER
*encoder
=
171 OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst
);
172 const EVP_PKEY
*pk
= data
->pk
;
173 const OSSL_PROVIDER
*k_prov
= EVP_KEYMGMT_provider(pk
->keymgmt
);
174 const OSSL_PROVIDER
*e_prov
= OSSL_ENCODER_provider(encoder
);
176 if (k_prov
!= e_prov
) {
177 data
->encoder_inst
= encoder_inst
;
179 if (!evp_keymgmt_export(pk
->keymgmt
, pk
->keydata
, data
->selection
,
180 &encoder_import_cb
, data
))
182 data
->obj
= data
->constructed_obj
;
184 data
->obj
= pk
->keydata
;
191 static void encoder_destruct_pkey(void *arg
)
193 struct construct_data_st
*data
= arg
;
195 if (data
->encoder_inst
!= NULL
) {
196 OSSL_ENCODER
*encoder
=
197 OSSL_ENCODER_INSTANCE_get_encoder(data
->encoder_inst
);
199 encoder
->free_object(data
->constructed_obj
);
201 data
->constructed_obj
= NULL
;
205 * OSSL_ENCODER_CTX_new_for_pkey() returns a ctx with no encoder if
206 * it couldn't find a suitable encoder. This allows a caller to detect if
207 * a suitable encoder was found, with OSSL_ENCODER_CTX_get_num_encoder(),
208 * and to use fallback methods if the result is NULL.
210 static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX
*ctx
,
211 const EVP_PKEY
*pkey
,
213 const char *propquery
)
215 struct construct_data_st
*data
= NULL
;
216 OSSL_LIB_CTX
*libctx
= NULL
;
219 if (!ossl_assert(ctx
!= NULL
) || !ossl_assert(pkey
!= NULL
)) {
220 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_NULL_PARAMETER
);
224 if (evp_pkey_is_provided(pkey
)) {
225 const OSSL_PROVIDER
*prov
= EVP_KEYMGMT_provider(pkey
->keymgmt
);
227 libctx
= ossl_provider_libctx(prov
);
230 if (pkey
->keymgmt
!= NULL
) {
231 struct collected_encoder_st encoder_data
;
232 struct collected_names_st keymgmt_data
;
234 if ((data
= OPENSSL_zalloc(sizeof(*data
))) == NULL
) {
235 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
240 * Select the first encoder implementations in two steps.
241 * First, collect the keymgmt names, then the encoders that match.
243 keymgmt_data
.names
= sk_OPENSSL_CSTRING_new_null();
244 keymgmt_data
.error_occurred
= 0;
245 EVP_KEYMGMT_names_do_all(pkey
->keymgmt
, collect_name
, &keymgmt_data
);
246 if (keymgmt_data
.error_occurred
) {
247 sk_OPENSSL_CSTRING_free(keymgmt_data
.names
);
251 encoder_data
.names
= keymgmt_data
.names
;
252 encoder_data
.output_type
= ctx
->output_type
;
253 encoder_data
.output_structure
= ctx
->output_structure
;
254 encoder_data
.error_occurred
= 0;
255 encoder_data
.ctx
= ctx
;
256 OSSL_ENCODER_do_all_provided(libctx
, collect_encoder
, &encoder_data
);
257 sk_OPENSSL_CSTRING_free(keymgmt_data
.names
);
258 if (encoder_data
.error_occurred
) {
259 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
264 if (data
!= NULL
&& OSSL_ENCODER_CTX_get_num_encoders(ctx
) != 0) {
265 if (!OSSL_ENCODER_CTX_set_construct(ctx
, encoder_construct_pkey
)
266 || !OSSL_ENCODER_CTX_set_construct_data(ctx
, data
)
267 || !OSSL_ENCODER_CTX_set_cleanup(ctx
, encoder_destruct_pkey
))
271 data
->selection
= selection
;
273 data
= NULL
; /* Avoid it being freed */
279 OSSL_ENCODER_CTX_set_construct_data(ctx
, NULL
);
285 OSSL_ENCODER_CTX
*OSSL_ENCODER_CTX_new_for_pkey(const EVP_PKEY
*pkey
,
287 const char *output_type
,
288 const char *output_struct
,
289 const char *propquery
)
291 OSSL_ENCODER_CTX
*ctx
= NULL
;
292 OSSL_LIB_CTX
*libctx
= NULL
;
295 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_NULL_PARAMETER
);
299 if (!evp_pkey_is_assigned(pkey
)) {
300 ERR_raise_data(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_INVALID_ARGUMENT
,
301 "The passed EVP_PKEY must be assigned a key");
305 if ((ctx
= OSSL_ENCODER_CTX_new()) == NULL
) {
306 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
310 if (evp_pkey_is_provided(pkey
)) {
311 const OSSL_PROVIDER
*prov
= EVP_KEYMGMT_provider(pkey
->keymgmt
);
313 libctx
= ossl_provider_libctx(prov
);
316 OSSL_TRACE_BEGIN(ENCODER
) {
318 "(ctx %p) Looking for %s encoders with selection %d\n",
319 (void *)ctx
, EVP_PKEY_get0_first_alg_name(pkey
), selection
);
320 BIO_printf(trc_out
, " output type: %s, output structure: %s\n",
321 output_type
, output_struct
);
322 } OSSL_TRACE_END(ENCODER
);
324 if (OSSL_ENCODER_CTX_set_output_type(ctx
, output_type
)
325 && (output_struct
== NULL
326 || OSSL_ENCODER_CTX_set_output_structure(ctx
, output_struct
))
327 && OSSL_ENCODER_CTX_set_selection(ctx
, selection
)
328 && ossl_encoder_ctx_setup_for_pkey(ctx
, pkey
, selection
, propquery
)
329 && OSSL_ENCODER_CTX_add_extra(ctx
, libctx
, propquery
)) {
330 OSSL_PARAM params
[2] = { OSSL_PARAM_END
, OSSL_PARAM_END
};
331 int save_parameters
= pkey
->save_parameters
;
333 params
[0] = OSSL_PARAM_construct_int(OSSL_ENCODER_PARAM_SAVE_PARAMETERS
,
335 /* ignoring error as this is only auxiliary parameter */
336 (void)OSSL_ENCODER_CTX_set_params(ctx
, params
);
338 OSSL_TRACE_BEGIN(ENCODER
) {
339 BIO_printf(trc_out
, "(ctx %p) Got %d encoders\n",
340 (void *)ctx
, OSSL_ENCODER_CTX_get_num_encoders(ctx
));
341 } OSSL_TRACE_END(ENCODER
);
345 OSSL_ENCODER_CTX_free(ctx
);