]>
Commit | Line | Data |
---|---|---|
866234ac | 1 | /* |
33388b44 | 2 | * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. |
866234ac RL |
3 | * |
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 | |
8 | */ | |
9 | ||
10 | #include <openssl/err.h> | |
11 | #include <openssl/ui.h> | |
12 | #include <openssl/params.h> | |
13 | #include <openssl/serializer.h> | |
14 | #include <openssl/core_names.h> | |
90cf3099 | 15 | #include <openssl/safestack.h> |
866234ac RL |
16 | #include "internal/provider.h" |
17 | #include "internal/property.h" | |
18 | #include "crypto/evp.h" | |
19 | #include "serializer_local.h" | |
20 | ||
90cf3099 P |
21 | DEFINE_STACK_OF_CSTRING() |
22 | ||
866234ac RL |
23 | int OSSL_SERIALIZER_CTX_set_cipher(OSSL_SERIALIZER_CTX *ctx, |
24 | const char *cipher_name, | |
25 | const char *propquery) | |
26 | { | |
27 | OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; | |
28 | ||
29 | params[0] = | |
30 | OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER, | |
31 | (void *)cipher_name, 0); | |
32 | params[1] = | |
33 | OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_PROPERTIES, | |
34 | (void *)propquery, 0); | |
35 | ||
36 | return OSSL_SERIALIZER_CTX_set_params(ctx, params); | |
37 | } | |
38 | ||
39 | int OSSL_SERIALIZER_CTX_set_passphrase(OSSL_SERIALIZER_CTX *ctx, | |
40 | const unsigned char *kstr, | |
41 | size_t klen) | |
42 | { | |
43 | OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
44 | ||
45 | params[0] = OSSL_PARAM_construct_octet_string(OSSL_SERIALIZER_PARAM_PASS, | |
46 | (void *)kstr, klen); | |
47 | ||
48 | return OSSL_SERIALIZER_CTX_set_params(ctx, params); | |
49 | } | |
50 | ||
51 | static void serializer_ctx_reset_passphrase_ui(OSSL_SERIALIZER_CTX *ctx) | |
52 | { | |
53 | UI_destroy_method(ctx->allocated_ui_method); | |
54 | ctx->allocated_ui_method = NULL; | |
55 | ctx->ui_method = NULL; | |
56 | ctx->ui_data = NULL; | |
57 | } | |
58 | ||
59 | int OSSL_SERIALIZER_CTX_set_passphrase_ui(OSSL_SERIALIZER_CTX *ctx, | |
60 | const UI_METHOD *ui_method, | |
61 | void *ui_data) | |
62 | { | |
63 | if (!ossl_assert(ctx != NULL)) { | |
64 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); | |
65 | return 0; | |
66 | } | |
67 | ||
68 | serializer_ctx_reset_passphrase_ui(ctx); | |
69 | ctx->ui_method = ui_method; | |
70 | ctx->ui_data = ui_data; | |
71 | return 1; | |
72 | } | |
73 | ||
45396db0 | 74 | int OSSL_SERIALIZER_CTX_set_passphrase_cb(OSSL_SERIALIZER_CTX *ctx, |
866234ac RL |
75 | pem_password_cb *cb, void *cbarg) |
76 | { | |
77 | if (!ossl_assert(ctx != NULL)) { | |
78 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); | |
79 | return 0; | |
80 | } | |
81 | ||
82 | serializer_ctx_reset_passphrase_ui(ctx); | |
83 | if (cb == NULL) | |
84 | return 1; | |
85 | ctx->ui_method = | |
45396db0 | 86 | ctx->allocated_ui_method = UI_UTIL_wrap_read_pem_callback(cb, 1); |
866234ac RL |
87 | ctx->ui_data = cbarg; |
88 | ||
89 | return ctx->ui_method != NULL; | |
90 | } | |
91 | ||
92 | /* | |
93 | * Support for OSSL_SERIALIZER_CTX_new_by_TYPE: | |
94 | * finding a suitable serializer | |
95 | */ | |
96 | ||
97 | struct selected_serializer_st { | |
90cf3099 P |
98 | STACK_OF(OPENSSL_CSTRING) *names; |
99 | int error; | |
866234ac RL |
100 | }; |
101 | ||
90cf3099 | 102 | static void cache_serializers(const char *name, void *data) |
866234ac RL |
103 | { |
104 | struct selected_serializer_st *d = data; | |
90cf3099 P |
105 | |
106 | if (sk_OPENSSL_CSTRING_push(d->names, name) <= 0) | |
107 | d->error = 1; | |
866234ac RL |
108 | } |
109 | ||
110 | /* | |
111 | * Support for OSSL_SERIALIZER_CTX_new_by_TYPE and OSSL_SERIALIZER_to_bio: | |
112 | * Passphrase callbacks | |
113 | */ | |
114 | ||
115 | /* | |
116 | * First, we define the generic passphrase function that supports both | |
117 | * outgoing (with passphrase verify) and incoming (without passphrase verify) | |
118 | * passphrase reading. | |
119 | */ | |
120 | static int serializer_passphrase(char *pass, size_t pass_size, | |
121 | size_t *pass_len, int verify, | |
122 | const OSSL_PARAM params[], void *arg) | |
123 | { | |
124 | OSSL_SERIALIZER_CTX *ctx = arg; | |
125 | const OSSL_PARAM *p; | |
126 | const char *prompt_info = NULL; | |
127 | char *prompt = NULL, *vpass = NULL; | |
128 | int prompt_idx = -1, verify_idx = -1; | |
129 | UI *ui = NULL; | |
130 | int ret = 0; | |
131 | ||
132 | if (!ossl_assert(ctx != NULL && pass != NULL | |
133 | && pass_size != 0 && pass_len != NULL)) { | |
134 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); | |
135 | return 0; | |
136 | } | |
137 | ||
138 | if ((p = OSSL_PARAM_locate_const(params, | |
139 | OSSL_PASSPHRASE_PARAM_INFO)) != NULL) { | |
140 | if (p->data_type != OSSL_PARAM_UTF8_STRING) | |
141 | return 0; | |
142 | prompt_info = p->data; | |
143 | } | |
144 | ||
145 | if ((ui = UI_new()) == NULL) { | |
146 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); | |
147 | return 0; | |
148 | } | |
149 | ||
150 | UI_set_method(ui, ctx->ui_method); | |
151 | UI_add_user_data(ui, ctx->ui_data); | |
152 | ||
153 | /* Get an application constructed prompt */ | |
154 | prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); | |
155 | if (prompt == NULL) { | |
156 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); | |
157 | goto end; | |
158 | } | |
159 | ||
160 | prompt_idx = UI_add_input_string(ui, prompt, | |
161 | UI_INPUT_FLAG_DEFAULT_PWD, | |
162 | pass, 0, pass_size - 1) - 1; | |
163 | if (prompt_idx < 0) { | |
164 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB); | |
165 | goto end; | |
166 | } | |
167 | ||
168 | if (verify) { | |
169 | /* Get a buffer for verification prompt */ | |
170 | vpass = OPENSSL_zalloc(pass_size); | |
171 | if (vpass == NULL) { | |
172 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); | |
173 | goto end; | |
174 | } | |
175 | verify_idx = UI_add_verify_string(ui, prompt, | |
176 | UI_INPUT_FLAG_DEFAULT_PWD, | |
177 | vpass, 0, pass_size - 1, | |
178 | pass) - 1; | |
179 | if (verify_idx < 0) { | |
180 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB); | |
181 | goto end; | |
182 | } | |
183 | } | |
184 | ||
185 | switch (UI_process(ui)) { | |
186 | case -2: | |
187 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_INTERRUPTED_OR_CANCELLED); | |
188 | break; | |
189 | case -1: | |
190 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB); | |
191 | break; | |
192 | default: | |
193 | *pass_len = (size_t)UI_get_result_length(ui, prompt_idx); | |
194 | ret = 1; | |
195 | break; | |
196 | } | |
197 | ||
198 | end: | |
199 | OPENSSL_free(vpass); | |
200 | OPENSSL_free(prompt); | |
201 | UI_free(ui); | |
202 | return ret; | |
203 | } | |
204 | ||
205 | /* Ensure correct function definition for outgoing passphrase reader */ | |
206 | static OSSL_PASSPHRASE_CALLBACK serializer_passphrase_out_cb; | |
207 | static int serializer_passphrase_out_cb(char *pass, size_t pass_size, | |
208 | size_t *pass_len, | |
209 | const OSSL_PARAM params[], void *arg) | |
210 | { | |
211 | return serializer_passphrase(pass, pass_size, pass_len, 1, params, arg); | |
212 | } | |
213 | ||
214 | /* | |
215 | * Support for OSSL_SERIALIZER_to_bio: | |
216 | * writing callback for the OSSL_PARAM (the implementation doesn't have | |
217 | * intimate knowledge of the provider side object) | |
218 | */ | |
219 | ||
220 | struct serializer_write_data_st { | |
221 | OSSL_SERIALIZER_CTX *ctx; | |
222 | BIO *out; | |
223 | }; | |
224 | ||
225 | static int serializer_write_cb(const OSSL_PARAM params[], void *arg) | |
226 | { | |
227 | struct serializer_write_data_st *write_data = arg; | |
228 | OSSL_SERIALIZER_CTX *ctx = write_data->ctx; | |
229 | BIO *out = write_data->out; | |
230 | ||
d40b42ab | 231 | return ctx->ser->serialize_data(ctx->serctx, params, (OSSL_CORE_BIO *)out, |
866234ac RL |
232 | serializer_passphrase_out_cb, ctx); |
233 | } | |
234 | ||
235 | /* | |
236 | * Support for OSSL_SERIALIZER_to_bio: | |
237 | * Perform the actual output. | |
238 | */ | |
239 | ||
240 | static int serializer_EVP_PKEY_to_bio(OSSL_SERIALIZER_CTX *ctx, BIO *out) | |
241 | { | |
242 | const EVP_PKEY *pkey = ctx->object; | |
3c6ed955 RL |
243 | void *keydata = pkey->keydata; |
244 | EVP_KEYMGMT *keymgmt = pkey->keymgmt; | |
866234ac RL |
245 | |
246 | /* | |
247 | * OSSL_SERIALIZER_CTX_new() creates a context, even when the | |
248 | * serializer it's given is NULL. Callers can detect the lack | |
249 | * of serializer with OSSL_SERIALIZER_CTX_get_serializer() and | |
250 | * should take precautions, possibly call a fallback instead of | |
251 | * OSSL_SERIALIZER_to_bio() / OSSL_SERIALIZER_to_fp(). If it's | |
252 | * come this far, we return an error. | |
253 | */ | |
254 | if (ctx->ser == NULL) | |
255 | return 0; | |
256 | ||
257 | if (ctx->ser->serialize_object == NULL) { | |
258 | struct serializer_write_data_st write_data; | |
259 | ||
260 | write_data.ctx = ctx; | |
261 | write_data.out = out; | |
262 | ||
b305452f RL |
263 | return evp_keymgmt_export(keymgmt, keydata, ctx->selection, |
264 | &serializer_write_cb, &write_data); | |
866234ac RL |
265 | } |
266 | ||
d40b42ab MC |
267 | return ctx->ser->serialize_object(ctx->serctx, keydata, |
268 | (OSSL_CORE_BIO *)out, | |
866234ac RL |
269 | serializer_passphrase_out_cb, ctx); |
270 | } | |
271 | ||
272 | /* | |
273 | * OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() returns a ctx with no serializer if | |
274 | * it couldn't find a suitable serializer. This allows a caller to detect if | |
275 | * a suitable serializer was found, with OSSL_SERIALIZER_CTX_get_serializer(), | |
276 | * and to use fallback methods if the result is NULL. | |
277 | */ | |
278 | OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey, | |
279 | const char *propquery) | |
280 | { | |
281 | OSSL_SERIALIZER_CTX *ctx = NULL; | |
282 | OSSL_SERIALIZER *ser = NULL; | |
3c6ed955 | 283 | EVP_KEYMGMT *keymgmt = pkey->keymgmt; |
b305452f | 284 | int selection = OSSL_KEYMGMT_SELECT_ALL; |
866234ac RL |
285 | |
286 | if (!ossl_assert(pkey != NULL && propquery != NULL)) { | |
287 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); | |
288 | return NULL; | |
289 | } | |
290 | ||
291 | if (keymgmt != NULL) { | |
292 | const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(keymgmt); | |
293 | OPENSSL_CTX *libctx = ossl_provider_library_context(desired_prov); | |
294 | struct selected_serializer_st sel_data; | |
90cf3099 P |
295 | OSSL_SERIALIZER *first = NULL; |
296 | const char *name; | |
297 | int i; | |
298 | ||
299 | /* | |
300 | * Select the serializer in two steps. First, get the names of all of | |
301 | * the serializers. Then determine which is the best one to use. | |
302 | * This has to be broken because it isn't possible to fetch the | |
303 | * serialisers inside EVP_KEYMGMT_names_do_all() due to locking | |
304 | * order inversions with the store lock. | |
305 | */ | |
306 | sel_data.error = 0; | |
307 | sel_data.names = sk_OPENSSL_CSTRING_new_null(); | |
308 | if (sel_data.names == NULL) | |
309 | return NULL; | |
310 | EVP_KEYMGMT_names_do_all(keymgmt, cache_serializers, &sel_data); | |
311 | /* | |
312 | * Ignore memory allocation errors that are indicated in sel_data.error | |
313 | * in case a suitable provider does get found regardless. | |
314 | */ | |
315 | ||
316 | /* | |
317 | * Serializers offer two functions, one that handles object data in | |
318 | * the form of a OSSL_PARAM array, and one that directly handles a | |
319 | * provider side object. The latter requires that the serializer | |
320 | * is offered by the same provider that holds that object, but is | |
321 | * more desirable because it usually provides faster serialization. | |
322 | * | |
323 | * When looking up possible serializers, we save the first that can | |
324 | * handle an OSSL_PARAM array in |first| and use that if nothing | |
325 | * better turns up. | |
326 | */ | |
327 | for (i = 0; i < sk_OPENSSL_CSTRING_num(sel_data.names); i++) { | |
328 | name = sk_OPENSSL_CSTRING_value(sel_data.names, i); | |
329 | ser = OSSL_SERIALIZER_fetch(libctx, name, propquery); | |
330 | if (ser != NULL) { | |
331 | if (OSSL_SERIALIZER_provider(ser) == desired_prov | |
332 | && ser->serialize_object != NULL) { | |
333 | OSSL_SERIALIZER_free(first); | |
334 | break; | |
335 | } | |
336 | if (first == NULL && ser->serialize_data != NULL) | |
337 | first = ser; | |
338 | else | |
339 | OSSL_SERIALIZER_free(ser); | |
340 | ser = NULL; | |
341 | } | |
866234ac | 342 | } |
90cf3099 P |
343 | sk_OPENSSL_CSTRING_free(sel_data.names); |
344 | if (ser == NULL) | |
345 | ser = first; | |
b305452f | 346 | |
55ecb812 | 347 | if (ser != NULL) { |
587e4e53 NT |
348 | OSSL_PROPERTY_LIST *check = NULL, *current_props = NULL; |
349 | ||
350 | check = ossl_parse_query(libctx, "type=parameters"); | |
55ecb812 MC |
351 | current_props = |
352 | ossl_parse_property(libctx, OSSL_SERIALIZER_properties(ser)); | |
353 | if (ossl_property_match_count(check, current_props) > 0) | |
354 | selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS; | |
355 | ossl_property_free(current_props); | |
90cf3099 P |
356 | ossl_property_free(check); |
357 | } else { | |
358 | if (sel_data.error) | |
359 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); | |
360 | else | |
361 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, | |
362 | OSSL_SERIALIZER_R_SERIALIZER_NOT_FOUND); | |
55ecb812 | 363 | } |
866234ac RL |
364 | } |
365 | ||
366 | ctx = OSSL_SERIALIZER_CTX_new(ser); /* refcnt(ser)++ */ | |
367 | OSSL_SERIALIZER_free(ser); /* refcnt(ser)-- */ | |
368 | ||
369 | if (ctx != NULL) { | |
370 | /* Setup for OSSL_SERIALIZE_to_bio() */ | |
b305452f | 371 | ctx->selection = selection; |
866234ac RL |
372 | ctx->object = pkey; |
373 | ctx->do_output = serializer_EVP_PKEY_to_bio; | |
374 | } | |
375 | ||
376 | return ctx; | |
377 | } | |
378 |