]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/encode_decode/decoder_pkey.c
Decoder resolution performance optimizations
[thirdparty/openssl.git] / crypto / encode_decode / decoder_pkey.c
1 /*
2 * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
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/core_names.h>
11 #include <openssl/core_object.h>
12 #include <openssl/provider.h>
13 #include <openssl/evp.h>
14 #include <openssl/ui.h>
15 #include <openssl/decoder.h>
16 #include <openssl/safestack.h>
17 #include <openssl/trace.h>
18 #include "crypto/evp.h"
19 #include "crypto/decoder.h"
20 #include "crypto/evp/evp_local.h"
21 #include "encoder_local.h"
22 #include "internal/e_os.h" /* strcasecmp on Windows */
23 #include "internal/namemap.h"
24
25 int OSSL_DECODER_CTX_set_passphrase(OSSL_DECODER_CTX *ctx,
26 const unsigned char *kstr,
27 size_t klen)
28 {
29 return ossl_pw_set_passphrase(&ctx->pwdata, kstr, klen);
30 }
31
32 int OSSL_DECODER_CTX_set_passphrase_ui(OSSL_DECODER_CTX *ctx,
33 const UI_METHOD *ui_method,
34 void *ui_data)
35 {
36 return ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data);
37 }
38
39 int OSSL_DECODER_CTX_set_pem_password_cb(OSSL_DECODER_CTX *ctx,
40 pem_password_cb *cb, void *cbarg)
41 {
42 return ossl_pw_set_pem_password_cb(&ctx->pwdata, cb, cbarg);
43 }
44
45 int OSSL_DECODER_CTX_set_passphrase_cb(OSSL_DECODER_CTX *ctx,
46 OSSL_PASSPHRASE_CALLBACK *cb,
47 void *cbarg)
48 {
49 return ossl_pw_set_ossl_passphrase_cb(&ctx->pwdata, cb, cbarg);
50 }
51
52 /*
53 * Support for OSSL_DECODER_CTX_new_for_pkey:
54 * The construct data, and collecting keymgmt information for it
55 */
56
57 DEFINE_STACK_OF(EVP_KEYMGMT)
58
59 struct decoder_pkey_data_st {
60 OSSL_LIB_CTX *libctx;
61 char *propq;
62 int selection;
63
64 STACK_OF(EVP_KEYMGMT) *keymgmts;
65 char *object_type; /* recorded object data type, may be NULL */
66 void **object; /* Where the result should end up */
67 };
68
69 static int decoder_construct_pkey(OSSL_DECODER_INSTANCE *decoder_inst,
70 const OSSL_PARAM *params,
71 void *construct_data)
72 {
73 struct decoder_pkey_data_st *data = construct_data;
74 OSSL_DECODER *decoder = OSSL_DECODER_INSTANCE_get_decoder(decoder_inst);
75 void *decoderctx = OSSL_DECODER_INSTANCE_get_decoder_ctx(decoder_inst);
76 const OSSL_PROVIDER *decoder_prov = OSSL_DECODER_get0_provider(decoder);
77 EVP_KEYMGMT *keymgmt = NULL;
78 const OSSL_PROVIDER *keymgmt_prov = NULL;
79 int i, end;
80 /*
81 * |object_ref| points to a provider reference to an object, its exact
82 * contents entirely opaque to us, but may be passed to any provider
83 * function that expects this (such as OSSL_FUNC_keymgmt_load().
84 *
85 * This pointer is considered volatile, i.e. whatever it points at
86 * is assumed to be freed as soon as this function returns.
87 */
88 void *object_ref = NULL;
89 size_t object_ref_sz = 0;
90 const OSSL_PARAM *p;
91
92 p = OSSL_PARAM_locate_const(params, OSSL_OBJECT_PARAM_DATA_TYPE);
93 if (p != NULL) {
94 char *object_type = NULL;
95
96 if (!OSSL_PARAM_get_utf8_string(p, &object_type, 0))
97 return 0;
98 OPENSSL_free(data->object_type);
99 data->object_type = object_type;
100 }
101
102 /*
103 * For stuff that should end up in an EVP_PKEY, we only accept an object
104 * reference for the moment. This enforces that the key data itself
105 * remains with the provider.
106 */
107 p = OSSL_PARAM_locate_const(params, OSSL_OBJECT_PARAM_REFERENCE);
108 if (p == NULL || p->data_type != OSSL_PARAM_OCTET_STRING)
109 return 0;
110 object_ref = p->data;
111 object_ref_sz = p->data_size;
112
113 /*
114 * First, we try to find a keymgmt that comes from the same provider as
115 * the decoder that passed the params.
116 */
117 end = sk_EVP_KEYMGMT_num(data->keymgmts);
118 for (i = 0; i < end; i++) {
119 keymgmt = sk_EVP_KEYMGMT_value(data->keymgmts, i);
120 keymgmt_prov = EVP_KEYMGMT_get0_provider(keymgmt);
121
122 if (keymgmt_prov == decoder_prov
123 && evp_keymgmt_has_load(keymgmt)
124 && EVP_KEYMGMT_is_a(keymgmt, data->object_type))
125 break;
126 }
127 if (i < end) {
128 /* To allow it to be freed further down */
129 if (!EVP_KEYMGMT_up_ref(keymgmt))
130 return 0;
131 } else if ((keymgmt = EVP_KEYMGMT_fetch(data->libctx,
132 data->object_type,
133 data->propq)) != NULL) {
134 keymgmt_prov = EVP_KEYMGMT_get0_provider(keymgmt);
135 }
136
137 if (keymgmt != NULL) {
138 EVP_PKEY *pkey = NULL;
139 void *keydata = NULL;
140
141 /*
142 * If the EVP_KEYMGMT and the OSSL_DECODER are from the
143 * same provider, we assume that the KEYMGMT has a key loading
144 * function that can handle the provider reference we hold.
145 *
146 * Otherwise, we export from the decoder and import the
147 * result in the keymgmt.
148 */
149 if (keymgmt_prov == decoder_prov) {
150 keydata = evp_keymgmt_load(keymgmt, object_ref, object_ref_sz);
151 } else {
152 struct evp_keymgmt_util_try_import_data_st import_data;
153
154 import_data.keymgmt = keymgmt;
155 import_data.keydata = NULL;
156 import_data.selection = data->selection;
157
158 /*
159 * No need to check for errors here, the value of
160 * |import_data.keydata| is as much an indicator.
161 */
162 (void)decoder->export_object(decoderctx,
163 object_ref, object_ref_sz,
164 &evp_keymgmt_util_try_import,
165 &import_data);
166 keydata = import_data.keydata;
167 import_data.keydata = NULL;
168 }
169
170 if (keydata != NULL
171 && (pkey = evp_keymgmt_util_make_pkey(keymgmt, keydata)) == NULL)
172 evp_keymgmt_freedata(keymgmt, keydata);
173
174 *data->object = pkey;
175
176 /*
177 * evp_keymgmt_util_make_pkey() increments the reference count when
178 * assigning the EVP_PKEY, so we can free the keymgmt here.
179 */
180 EVP_KEYMGMT_free(keymgmt);
181 }
182 /*
183 * We successfully looked through, |*ctx->object| determines if we
184 * actually found something.
185 */
186 return (*data->object != NULL);
187 }
188
189 static void decoder_clean_pkey_construct_arg(void *construct_data)
190 {
191 struct decoder_pkey_data_st *data = construct_data;
192
193 if (data != NULL) {
194 sk_EVP_KEYMGMT_pop_free(data->keymgmts, EVP_KEYMGMT_free);
195 OPENSSL_free(data->propq);
196 OPENSSL_free(data->object_type);
197 OPENSSL_free(data);
198 }
199 }
200
201 struct collect_data_st {
202 OSSL_LIB_CTX *libctx;
203 OSSL_DECODER_CTX *ctx;
204
205 const char *keytype; /* the keytype requested, if any */
206 int keytype_id; /* if keytype_resolved is set, keymgmt name_id; else 0 */
207 int sm2_id; /* if keytype_resolved is set and EC, SM2 name_id; else 0 */
208 int total; /* number of matching results */
209 char error_occurred;
210 char keytype_resolved;
211
212 STACK_OF(EVP_KEYMGMT) *keymgmts;
213 };
214
215 static void collect_decoder_keymgmt(EVP_KEYMGMT *keymgmt, OSSL_DECODER *decoder,
216 void *provctx, struct collect_data_st *data)
217 {
218 void *decoderctx = NULL;
219 OSSL_DECODER_INSTANCE *di = NULL;
220
221 /*
222 * We already checked the EVP_KEYMGMT is applicable in check_keymgmt so we
223 * don't check it again here.
224 */
225
226 if (keymgmt->name_id != decoder->base.id)
227 /* Mismatch is not an error, continue. */
228 return;
229
230 if ((decoderctx = decoder->newctx(provctx)) == NULL) {
231 data->error_occurred = 1;
232 return;
233 }
234
235 if ((di = ossl_decoder_instance_new(decoder, decoderctx)) == NULL) {
236 decoder->freectx(decoderctx);
237 data->error_occurred = 1;
238 return;
239 }
240
241 OSSL_TRACE_BEGIN(DECODER) {
242 BIO_printf(trc_out,
243 "(ctx %p) Checking out decoder %p:\n"
244 " %s with %s\n",
245 (void *)data->ctx, (void *)decoder,
246 OSSL_DECODER_get0_name(decoder),
247 OSSL_DECODER_get0_properties(decoder));
248 } OSSL_TRACE_END(DECODER);
249
250 if (!ossl_decoder_ctx_add_decoder_inst(data->ctx, di)) {
251 ossl_decoder_instance_free(di);
252 data->error_occurred = 1;
253 return;
254 }
255
256 ++data->total;
257 }
258
259 static void collect_decoder(OSSL_DECODER *decoder, void *arg)
260 {
261 struct collect_data_st *data = arg;
262 STACK_OF(EVP_KEYMGMT) *keymgmts = data->keymgmts;
263 size_t i, end_i;
264 EVP_KEYMGMT *keymgmt;
265 const OSSL_PROVIDER *prov;
266 void *provctx;
267
268 if (data->error_occurred)
269 return;
270
271 prov = OSSL_DECODER_get0_provider(decoder);
272 provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
273
274 /*
275 * Either the caller didn't give us a selection, or if they did, the decoder
276 * must tell us if it supports that selection to be accepted. If the decoder
277 * doesn't have |does_selection|, it's seen as taking anything.
278 */
279 if (decoder->does_selection != NULL
280 && !decoder->does_selection(provctx, data->ctx->selection))
281 return;
282
283 OSSL_TRACE_BEGIN(DECODER) {
284 BIO_printf(trc_out,
285 "(ctx %p) Checking out decoder %p:\n"
286 " %s with %s\n",
287 (void *)data->ctx, (void *)decoder,
288 OSSL_DECODER_get0_name(decoder),
289 OSSL_DECODER_get0_properties(decoder));
290 } OSSL_TRACE_END(DECODER);
291
292 end_i = sk_EVP_KEYMGMT_num(keymgmts);
293 for (i = 0; i < end_i; ++i) {
294 keymgmt = sk_EVP_KEYMGMT_value(keymgmts, i);
295
296 collect_decoder_keymgmt(keymgmt, decoder, provctx, data);
297 if (data->error_occurred)
298 return;
299 }
300 }
301
302 /*
303 * Is this EVP_KEYMGMT applicable given the key type given in the call to
304 * ossl_decoder_ctx_setup_for_pkey (if any)?
305 */
306 static int check_keymgmt(EVP_KEYMGMT *keymgmt, struct collect_data_st *data)
307 {
308 /* If no keytype was specified, everything matches. */
309 if (data->keytype == NULL)
310 return 1;
311
312 if (!data->keytype_resolved) {
313 /* We haven't cached the IDs from the keytype string yet. */
314 OSSL_NAMEMAP *namemap = ossl_namemap_stored(data->libctx);
315 data->keytype_id = ossl_namemap_name2num(namemap, data->keytype);
316
317 /*
318 * If keytype is a value ambiguously used for both EC and SM2,
319 * collect the ID for SM2 as well.
320 */
321 if (data->keytype_id != 0
322 && (strcmp(data->keytype, "id-ecPublicKey") == 0
323 || strcmp(data->keytype, "1.2.840.10045.2.1") == 0))
324 data->sm2_id = ossl_namemap_name2num(namemap, "SM2");
325
326 /*
327 * If keytype_id is zero the name was not found, but we still
328 * set keytype_resolved to avoid trying all this again.
329 */
330 data->keytype_resolved = 1;
331 }
332
333 /* Specified keytype could not be resolved, so nothing matches. */
334 if (data->keytype_id == 0)
335 return 0;
336
337 /* Does not match the keytype specified, so skip. */
338 if (keymgmt->name_id != data->keytype_id
339 && keymgmt->name_id != data->sm2_id)
340 return 0;
341
342 return 1;
343 }
344
345 static void collect_keymgmt(EVP_KEYMGMT *keymgmt, void *arg)
346 {
347 struct collect_data_st *data = arg;
348
349 if (!check_keymgmt(keymgmt, data))
350 return;
351
352 /*
353 * We have to ref EVP_KEYMGMT here because in the success case,
354 * data->keymgmts is referenced by the constructor we register in the
355 * OSSL_DECODER_CTX. The registered cleanup function
356 * (decoder_clean_pkey_construct_arg) unrefs every element of the stack and
357 * frees it.
358 */
359 if (!EVP_KEYMGMT_up_ref(keymgmt))
360 return;
361
362 if (sk_EVP_KEYMGMT_push(data->keymgmts, keymgmt) <= 0) {
363 EVP_KEYMGMT_free(keymgmt);
364 data->error_occurred = 1;
365 }
366 }
367
368 /*
369 * This function does the actual binding of decoders to the OSSL_DECODER_CTX. It
370 * searches for decoders matching 'keytype', which is a string like "RSA", "DH",
371 * etc. If 'keytype' is NULL, decoders for all keytypes are bound.
372 */
373 int ossl_decoder_ctx_setup_for_pkey(OSSL_DECODER_CTX *ctx,
374 EVP_PKEY **pkey, const char *keytype,
375 OSSL_LIB_CTX *libctx,
376 const char *propquery)
377 {
378 int ok = 0;
379 struct decoder_pkey_data_st *process_data = NULL;
380 struct collect_data_st collect_data = { NULL };
381 STACK_OF(EVP_KEYMGMT) *keymgmts = NULL;
382
383 OSSL_TRACE_BEGIN(DECODER) {
384 const char *input_type = ctx->start_input_type;
385 const char *input_structure = ctx->input_structure;
386
387 BIO_printf(trc_out,
388 "(ctx %p) Looking for decoders producing %s%s%s%s%s%s\n",
389 (void *)ctx,
390 keytype != NULL ? keytype : "",
391 keytype != NULL ? " keys" : "keys of any type",
392 input_type != NULL ? " from " : "",
393 input_type != NULL ? input_type : "",
394 input_structure != NULL ? " with " : "",
395 input_structure != NULL ? input_structure : "");
396 } OSSL_TRACE_END(DECODER);
397
398 /* Allocate data. */
399 if ((process_data = OPENSSL_zalloc(sizeof(*process_data))) == NULL
400 || (propquery != NULL
401 && (process_data->propq = OPENSSL_strdup(propquery)) == NULL)) {
402 ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
403 goto err;
404 }
405
406 /* Allocate our list of EVP_KEYMGMTs. */
407 keymgmts = sk_EVP_KEYMGMT_new_null();
408 if (keymgmts == NULL) {
409 ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
410 goto err;
411 }
412
413 process_data->object = (void **)pkey;
414 process_data->libctx = libctx;
415 process_data->selection = ctx->selection;
416 process_data->keymgmts = keymgmts;
417
418 /*
419 * Enumerate all keymgmts into a stack.
420 *
421 * We could nest EVP_KEYMGMT_do_all_provided inside
422 * OSSL_DECODER_do_all_provided or vice versa but these functions become
423 * bottlenecks if called repeatedly, which is why we collect the
424 * EVP_KEYMGMTs into a stack here and call both functions only once.
425 *
426 * We resolve the keytype string to a name ID so we don't have to resolve it
427 * multiple times, avoiding repeated calls to EVP_KEYMGMT_is_a, which is a
428 * performance bottleneck. However, we do this lazily on the first call to
429 * collect_keymgmt made by EVP_KEYMGMT_do_all_provided, rather than do it
430 * upfront, as this ensures that the names for all loaded providers have
431 * been registered by the time we try to resolve the keytype string.
432 */
433 collect_data.ctx = ctx;
434 collect_data.libctx = libctx;
435 collect_data.keymgmts = keymgmts;
436 collect_data.keytype = keytype;
437 EVP_KEYMGMT_do_all_provided(libctx, collect_keymgmt, &collect_data);
438
439 if (collect_data.error_occurred)
440 goto err;
441
442 /* Enumerate all matching decoders. */
443 OSSL_DECODER_do_all_provided(libctx, collect_decoder, &collect_data);
444
445 if (collect_data.error_occurred)
446 goto err;
447
448 OSSL_TRACE_BEGIN(DECODER) {
449 BIO_printf(trc_out,
450 "(ctx %p) Got %d decoders producing keys\n",
451 (void *)ctx, collect_data.total);
452 } OSSL_TRACE_END(DECODER);
453
454 /*
455 * Finish initializing the decoder context. If one or more decoders matched
456 * above then the number of decoders attached to the OSSL_DECODER_CTX will
457 * be nonzero. Else nothing was found and we do nothing.
458 */
459 if (OSSL_DECODER_CTX_get_num_decoders(ctx) != 0) {
460 if (!OSSL_DECODER_CTX_set_construct(ctx, decoder_construct_pkey)
461 || !OSSL_DECODER_CTX_set_construct_data(ctx, process_data)
462 || !OSSL_DECODER_CTX_set_cleanup(ctx,
463 decoder_clean_pkey_construct_arg))
464 goto err;
465
466 process_data = NULL; /* Avoid it being freed */
467 }
468
469 ok = 1;
470 err:
471 decoder_clean_pkey_construct_arg(process_data);
472 return ok;
473 }
474
475 OSSL_DECODER_CTX *
476 OSSL_DECODER_CTX_new_for_pkey(EVP_PKEY **pkey,
477 const char *input_type,
478 const char *input_structure,
479 const char *keytype, int selection,
480 OSSL_LIB_CTX *libctx, const char *propquery)
481 {
482 OSSL_DECODER_CTX *ctx = NULL;
483
484 if ((ctx = OSSL_DECODER_CTX_new()) == NULL) {
485 ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
486 return NULL;
487 }
488
489 OSSL_TRACE_BEGIN(DECODER) {
490 BIO_printf(trc_out,
491 "(ctx %p) Looking for %s decoders with selection %d\n",
492 (void *)ctx, keytype, selection);
493 BIO_printf(trc_out, " input type: %s, input structure: %s\n",
494 input_type, input_structure);
495 } OSSL_TRACE_END(DECODER);
496
497 if (OSSL_DECODER_CTX_set_input_type(ctx, input_type)
498 && OSSL_DECODER_CTX_set_input_structure(ctx, input_structure)
499 && OSSL_DECODER_CTX_set_selection(ctx, selection)
500 && ossl_decoder_ctx_setup_for_pkey(ctx, pkey, keytype,
501 libctx, propquery)
502 && OSSL_DECODER_CTX_add_extra(ctx, libctx, propquery)) {
503 OSSL_TRACE_BEGIN(DECODER) {
504 BIO_printf(trc_out, "(ctx %p) Got %d decoders\n",
505 (void *)ctx, OSSL_DECODER_CTX_get_num_decoders(ctx));
506 } OSSL_TRACE_END(DECODER);
507 return ctx;
508 }
509
510 OSSL_DECODER_CTX_free(ctx);
511 return NULL;
512 }