2 * Copyright 2019-2020 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/safestack.h>
16 #include "internal/provider.h"
17 #include "internal/property.h"
18 #include "crypto/evp.h"
19 #include "encoder_local.h"
21 DEFINE_STACK_OF_CSTRING()
23 int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX
*ctx
,
24 const char *cipher_name
,
25 const char *propquery
)
27 OSSL_PARAM params
[] = { OSSL_PARAM_END
, OSSL_PARAM_END
, OSSL_PARAM_END
};
30 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_CIPHER
,
31 (void *)cipher_name
, 0);
33 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES
,
34 (void *)propquery
, 0);
36 return OSSL_ENCODER_CTX_set_params(ctx
, params
);
39 int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX
*ctx
,
40 const unsigned char *kstr
,
43 OSSL_PARAM params
[] = { OSSL_PARAM_END
, OSSL_PARAM_END
};
45 params
[0] = OSSL_PARAM_construct_octet_string(OSSL_ENCODER_PARAM_PASS
,
48 return OSSL_ENCODER_CTX_set_params(ctx
, params
);
51 static void encoder_ctx_reset_passphrase_ui(OSSL_ENCODER_CTX
*ctx
)
53 UI_destroy_method(ctx
->allocated_ui_method
);
54 ctx
->allocated_ui_method
= NULL
;
55 ctx
->ui_method
= NULL
;
59 int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX
*ctx
,
60 const UI_METHOD
*ui_method
,
63 if (!ossl_assert(ctx
!= NULL
)) {
64 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_NULL_PARAMETER
);
68 encoder_ctx_reset_passphrase_ui(ctx
);
69 ctx
->ui_method
= ui_method
;
70 ctx
->ui_data
= ui_data
;
74 int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX
*ctx
,
75 pem_password_cb
*cb
, void *cbarg
)
77 if (!ossl_assert(ctx
!= NULL
)) {
78 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_NULL_PARAMETER
);
82 encoder_ctx_reset_passphrase_ui(ctx
);
86 ctx
->allocated_ui_method
= UI_UTIL_wrap_read_pem_callback(cb
, 1);
89 return ctx
->ui_method
!= NULL
;
93 * Support for OSSL_ENCODER_CTX_new_by_TYPE:
94 * finding a suitable encoder
97 struct selected_encoder_st
{
98 STACK_OF(OPENSSL_CSTRING
) *names
;
102 static void cache_encoders(const char *name
, void *data
)
104 struct selected_encoder_st
*d
= data
;
106 if (sk_OPENSSL_CSTRING_push(d
->names
, name
) <= 0)
111 * Support for OSSL_ENCODER_to_bio:
112 * writing callback for the OSSL_PARAM (the implementation doesn't have
113 * intimate knowledge of the provider side object)
116 struct encoder_write_data_st
{
117 OSSL_ENCODER_CTX
*ctx
;
121 static int encoder_write_cb(const OSSL_PARAM params
[], void *arg
)
123 struct encoder_write_data_st
*write_data
= arg
;
124 OSSL_ENCODER_CTX
*ctx
= write_data
->ctx
;
125 BIO
*out
= write_data
->out
;
127 return ctx
->encoder
->encode_data(ctx
->serctx
, params
, (OSSL_CORE_BIO
*)out
,
128 ossl_encoder_passphrase_out_cb
, ctx
);
132 * Support for OSSL_ENCODER_to_bio:
133 * Perform the actual output.
136 static int encoder_EVP_PKEY_to_bio(OSSL_ENCODER_CTX
*ctx
, BIO
*out
)
138 const EVP_PKEY
*pkey
= ctx
->object
;
139 void *keydata
= pkey
->keydata
;
140 EVP_KEYMGMT
*keymgmt
= pkey
->keymgmt
;
143 * OSSL_ENCODER_CTX_new() creates a context, even when the
144 * encoder it's given is NULL. Callers can detect the lack
145 * of encoder with OSSL_ENCODER_CTX_get_encoder() and
146 * should take precautions, possibly call a fallback instead of
147 * OSSL_ENCODER_to_bio() / OSSL_ENCODER_to_fp(). If it's
148 * come this far, we return an error.
150 if (ctx
->encoder
== NULL
)
153 if (ctx
->encoder
->encode_object
== NULL
154 || (OSSL_ENCODER_provider(ctx
->encoder
)
155 != EVP_KEYMGMT_provider(keymgmt
))) {
156 struct encoder_write_data_st write_data
;
158 write_data
.ctx
= ctx
;
159 write_data
.out
= out
;
161 return evp_keymgmt_export(keymgmt
, keydata
, ctx
->selection
,
162 &encoder_write_cb
, &write_data
);
165 return ctx
->encoder
->encode_object(ctx
->serctx
, keydata
,
166 (OSSL_CORE_BIO
*)out
,
167 ossl_encoder_passphrase_out_cb
, ctx
);
171 * OSSL_ENCODER_CTX_new_by_EVP_PKEY() returns a ctx with no encoder if
172 * it couldn't find a suitable encoder. This allows a caller to detect if
173 * a suitable encoder was found, with OSSL_ENCODER_CTX_get_encoder(),
174 * and to use fallback methods if the result is NULL.
176 OSSL_ENCODER_CTX
*OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY
*pkey
,
177 const char *propquery
)
179 OSSL_ENCODER_CTX
*ctx
= NULL
;
180 OSSL_ENCODER
*encoder
= NULL
;
181 EVP_KEYMGMT
*keymgmt
= pkey
->keymgmt
;
182 int selection
= OSSL_KEYMGMT_SELECT_ALL
;
184 if (!ossl_assert(pkey
!= NULL
&& propquery
!= NULL
)) {
185 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_PASSED_NULL_PARAMETER
);
189 if (keymgmt
!= NULL
) {
190 const OSSL_PROVIDER
*desired_prov
= EVP_KEYMGMT_provider(keymgmt
);
191 OPENSSL_CTX
*libctx
= ossl_provider_library_context(desired_prov
);
192 struct selected_encoder_st sel_data
;
193 OSSL_ENCODER
*first
= NULL
;
198 * Select the encoder in two steps. First, get the names of all of
199 * the encoders. Then determine which is the best one to use.
200 * This has to be broken because it isn't possible to fetch the
201 * serialisers inside EVP_KEYMGMT_names_do_all() due to locking
202 * order inversions with the store lock.
205 sel_data
.names
= sk_OPENSSL_CSTRING_new_null();
206 if (sel_data
.names
== NULL
)
208 EVP_KEYMGMT_names_do_all(keymgmt
, cache_encoders
, &sel_data
);
210 * Ignore memory allocation errors that are indicated in sel_data.error
211 * in case a suitable provider does get found regardless.
215 * Encoders offer two functions, one that handles object data in
216 * the form of a OSSL_PARAM array, and one that directly handles a
217 * provider side object. The latter requires that the encoder
218 * is offered by the same provider that holds that object, but is
219 * more desirable because it usually provides faster encoding.
221 * When looking up possible encoders, we save the first that can
222 * handle an OSSL_PARAM array in |first| and use that if nothing
225 for (i
= 0; i
< sk_OPENSSL_CSTRING_num(sel_data
.names
); i
++) {
226 name
= sk_OPENSSL_CSTRING_value(sel_data
.names
, i
);
227 encoder
= OSSL_ENCODER_fetch(libctx
, name
, propquery
);
228 if (encoder
!= NULL
) {
229 if (OSSL_ENCODER_provider(encoder
) == desired_prov
230 && encoder
->encode_object
!= NULL
) {
231 OSSL_ENCODER_free(first
);
234 if (first
== NULL
&& encoder
->encode_data
!= NULL
)
237 OSSL_ENCODER_free(encoder
);
241 sk_OPENSSL_CSTRING_free(sel_data
.names
);
245 if (encoder
!= NULL
) {
246 OSSL_PROPERTY_LIST
*check
= NULL
, *current_props
= NULL
;
248 check
= ossl_parse_query(libctx
, "type=parameters");
250 ossl_parse_property(libctx
, OSSL_ENCODER_properties(encoder
));
251 if (ossl_property_match_count(check
, current_props
) > 0)
252 selection
= OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
;
253 ossl_property_free(current_props
);
254 ossl_property_free(check
);
257 ERR_raise(ERR_LIB_OSSL_ENCODER
, ERR_R_MALLOC_FAILURE
);
259 ERR_raise(ERR_LIB_OSSL_ENCODER
,
260 OSSL_ENCODER_R_ENCODER_NOT_FOUND
);
264 ctx
= OSSL_ENCODER_CTX_new(encoder
); /* refcnt(encoder)++ */
265 OSSL_ENCODER_free(encoder
); /* refcnt(encoder)-- */
268 /* Setup for OSSL_ENCODE_to_bio() */
269 ctx
->selection
= selection
;
271 ctx
->do_output
= encoder_EVP_PKEY_to_bio
;