VirtualBox

source: vbox/trunk/src/libs/openssl-3.0.2/crypto/context.c@ 95087

Last change on this file since 95087 was 94404, checked in by vboxsync, 3 years ago

libs/openssl: Update to 3.0.2 and switch to it, bugref:10128

File size: 13.0 KB
Line 
1/*
2 * Copyright 2019-2022 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 "crypto/cryptlib.h"
11#include <openssl/conf.h>
12#include "internal/thread_once.h"
13#include "internal/property.h"
14#include "internal/core.h"
15#include "internal/bio.h"
16#include "internal/provider.h"
17
18struct ossl_lib_ctx_onfree_list_st {
19 ossl_lib_ctx_onfree_fn *fn;
20 struct ossl_lib_ctx_onfree_list_st *next;
21};
22
23struct ossl_lib_ctx_st {
24 CRYPTO_RWLOCK *lock;
25 CRYPTO_EX_DATA data;
26
27 /*
28 * For most data in the OSSL_LIB_CTX we just use ex_data to store it. But
29 * that doesn't work for ex_data itself - so we store that directly.
30 */
31 OSSL_EX_DATA_GLOBAL global;
32
33 /* Map internal static indexes to dynamically created indexes */
34 int dyn_indexes[OSSL_LIB_CTX_MAX_INDEXES];
35
36 /* Keep a separate lock for each index */
37 CRYPTO_RWLOCK *index_locks[OSSL_LIB_CTX_MAX_INDEXES];
38
39 CRYPTO_RWLOCK *oncelock;
40 int run_once_done[OSSL_LIB_CTX_MAX_RUN_ONCE];
41 int run_once_ret[OSSL_LIB_CTX_MAX_RUN_ONCE];
42 struct ossl_lib_ctx_onfree_list_st *onfreelist;
43 unsigned int ischild:1;
44};
45
46int ossl_lib_ctx_write_lock(OSSL_LIB_CTX *ctx)
47{
48 return CRYPTO_THREAD_write_lock(ossl_lib_ctx_get_concrete(ctx)->lock);
49}
50
51int ossl_lib_ctx_read_lock(OSSL_LIB_CTX *ctx)
52{
53 return CRYPTO_THREAD_read_lock(ossl_lib_ctx_get_concrete(ctx)->lock);
54}
55
56int ossl_lib_ctx_unlock(OSSL_LIB_CTX *ctx)
57{
58 return CRYPTO_THREAD_unlock(ossl_lib_ctx_get_concrete(ctx)->lock);
59}
60
61int ossl_lib_ctx_is_child(OSSL_LIB_CTX *ctx)
62{
63 ctx = ossl_lib_ctx_get_concrete(ctx);
64
65 if (ctx == NULL)
66 return 0;
67 return ctx->ischild;
68}
69
70static int context_init(OSSL_LIB_CTX *ctx)
71{
72 size_t i;
73 int exdata_done = 0;
74
75 ctx->lock = CRYPTO_THREAD_lock_new();
76 if (ctx->lock == NULL)
77 return 0;
78
79 ctx->oncelock = CRYPTO_THREAD_lock_new();
80 if (ctx->oncelock == NULL)
81 goto err;
82
83 for (i = 0; i < OSSL_LIB_CTX_MAX_INDEXES; i++) {
84 ctx->index_locks[i] = CRYPTO_THREAD_lock_new();
85 ctx->dyn_indexes[i] = -1;
86 if (ctx->index_locks[i] == NULL)
87 goto err;
88 }
89
90 /* OSSL_LIB_CTX is built on top of ex_data so we initialise that directly */
91 if (!ossl_do_ex_data_init(ctx))
92 goto err;
93 exdata_done = 1;
94
95 if (!ossl_crypto_new_ex_data_ex(ctx, CRYPTO_EX_INDEX_OSSL_LIB_CTX, NULL,
96 &ctx->data))
97 goto err;
98
99 /* Everything depends on properties, so we also pre-initialise that */
100 if (!ossl_property_parse_init(ctx))
101 goto err;
102
103 return 1;
104 err:
105 if (exdata_done)
106 ossl_crypto_cleanup_all_ex_data_int(ctx);
107 for (i = 0; i < OSSL_LIB_CTX_MAX_INDEXES; i++)
108 CRYPTO_THREAD_lock_free(ctx->index_locks[i]);
109 CRYPTO_THREAD_lock_free(ctx->oncelock);
110 CRYPTO_THREAD_lock_free(ctx->lock);
111 memset(ctx, '\0', sizeof(*ctx));
112 return 0;
113}
114
115static int context_deinit(OSSL_LIB_CTX *ctx)
116{
117 struct ossl_lib_ctx_onfree_list_st *tmp, *onfree;
118 int i;
119
120 if (ctx == NULL)
121 return 1;
122
123 ossl_ctx_thread_stop(ctx);
124
125 onfree = ctx->onfreelist;
126 while (onfree != NULL) {
127 onfree->fn(ctx);
128 tmp = onfree;
129 onfree = onfree->next;
130 OPENSSL_free(tmp);
131 }
132 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_OSSL_LIB_CTX, NULL, &ctx->data);
133 ossl_crypto_cleanup_all_ex_data_int(ctx);
134 for (i = 0; i < OSSL_LIB_CTX_MAX_INDEXES; i++)
135 CRYPTO_THREAD_lock_free(ctx->index_locks[i]);
136
137 CRYPTO_THREAD_lock_free(ctx->oncelock);
138 CRYPTO_THREAD_lock_free(ctx->lock);
139 ctx->lock = NULL;
140 return 1;
141}
142
143#ifndef FIPS_MODULE
144/* The default default context */
145static OSSL_LIB_CTX default_context_int;
146
147static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT;
148static CRYPTO_THREAD_LOCAL default_context_thread_local;
149
150DEFINE_RUN_ONCE_STATIC(default_context_do_init)
151{
152 return CRYPTO_THREAD_init_local(&default_context_thread_local, NULL)
153 && context_init(&default_context_int);
154}
155
156void ossl_lib_ctx_default_deinit(void)
157{
158 context_deinit(&default_context_int);
159 CRYPTO_THREAD_cleanup_local(&default_context_thread_local);
160}
161
162static OSSL_LIB_CTX *get_thread_default_context(void)
163{
164 if (!RUN_ONCE(&default_context_init, default_context_do_init))
165 return NULL;
166
167 return CRYPTO_THREAD_get_local(&default_context_thread_local);
168}
169
170static OSSL_LIB_CTX *get_default_context(void)
171{
172 OSSL_LIB_CTX *current_defctx = get_thread_default_context();
173
174 if (current_defctx == NULL)
175 current_defctx = &default_context_int;
176 return current_defctx;
177}
178
179static int set_default_context(OSSL_LIB_CTX *defctx)
180{
181 if (defctx == &default_context_int)
182 defctx = NULL;
183
184 return CRYPTO_THREAD_set_local(&default_context_thread_local, defctx);
185}
186#endif
187
188OSSL_LIB_CTX *OSSL_LIB_CTX_new(void)
189{
190 OSSL_LIB_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
191
192 if (ctx != NULL && !context_init(ctx)) {
193 OPENSSL_free(ctx);
194 ctx = NULL;
195 }
196 return ctx;
197}
198
199#ifndef FIPS_MODULE
200OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_CORE_HANDLE *handle,
201 const OSSL_DISPATCH *in)
202{
203 OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new();
204
205 if (ctx == NULL)
206 return NULL;
207
208 if (!ossl_bio_init_core(ctx, in)) {
209 OSSL_LIB_CTX_free(ctx);
210 return NULL;
211 }
212
213 return ctx;
214}
215
216OSSL_LIB_CTX *OSSL_LIB_CTX_new_child(const OSSL_CORE_HANDLE *handle,
217 const OSSL_DISPATCH *in)
218{
219 OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new_from_dispatch(handle, in);
220
221 if (ctx == NULL)
222 return NULL;
223
224 if (!ossl_provider_init_as_child(ctx, handle, in)) {
225 OSSL_LIB_CTX_free(ctx);
226 return NULL;
227 }
228 ctx->ischild = 1;
229
230 return ctx;
231}
232
233int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file)
234{
235 return CONF_modules_load_file_ex(ctx, config_file, NULL, 0) > 0;
236}
237#endif
238
239void OSSL_LIB_CTX_free(OSSL_LIB_CTX *ctx)
240{
241 if (ossl_lib_ctx_is_default(ctx))
242 return;
243
244#ifndef FIPS_MODULE
245 if (ctx->ischild)
246 ossl_provider_deinit_child(ctx);
247#endif
248 context_deinit(ctx);
249 OPENSSL_free(ctx);
250}
251
252#ifndef FIPS_MODULE
253OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void)
254{
255 if (!RUN_ONCE(&default_context_init, default_context_do_init))
256 return NULL;
257
258 return &default_context_int;
259}
260
261OSSL_LIB_CTX *OSSL_LIB_CTX_set0_default(OSSL_LIB_CTX *libctx)
262{
263 OSSL_LIB_CTX *current_defctx;
264
265 if ((current_defctx = get_default_context()) != NULL) {
266 if (libctx != NULL)
267 set_default_context(libctx);
268 return current_defctx;
269 }
270
271 return NULL;
272}
273#endif
274
275OSSL_LIB_CTX *ossl_lib_ctx_get_concrete(OSSL_LIB_CTX *ctx)
276{
277#ifndef FIPS_MODULE
278 if (ctx == NULL)
279 return get_default_context();
280#endif
281 return ctx;
282}
283
284int ossl_lib_ctx_is_default(OSSL_LIB_CTX *ctx)
285{
286#ifndef FIPS_MODULE
287 if (ctx == NULL || ctx == get_default_context())
288 return 1;
289#endif
290 return 0;
291}
292
293int ossl_lib_ctx_is_global_default(OSSL_LIB_CTX *ctx)
294{
295#ifndef FIPS_MODULE
296 if (ossl_lib_ctx_get_concrete(ctx) == &default_context_int)
297 return 1;
298#endif
299 return 0;
300}
301
302static void ossl_lib_ctx_generic_new(void *parent_ign, void *ptr_ign,
303 CRYPTO_EX_DATA *ad, int index,
304 long argl_ign, void *argp)
305{
306 const OSSL_LIB_CTX_METHOD *meth = argp;
307 OSSL_LIB_CTX *ctx = ossl_crypto_ex_data_get_ossl_lib_ctx(ad);
308 void *ptr = meth->new_func(ctx);
309
310 if (ptr != NULL) {
311 if (!CRYPTO_THREAD_write_lock(ctx->lock))
312 /*
313 * Can't return something, so best to hope that something will
314 * fail later. :(
315 */
316 return;
317 CRYPTO_set_ex_data(ad, index, ptr);
318 CRYPTO_THREAD_unlock(ctx->lock);
319 }
320}
321static void ossl_lib_ctx_generic_free(void *parent_ign, void *ptr,
322 CRYPTO_EX_DATA *ad, int index,
323 long argl_ign, void *argp)
324{
325 const OSSL_LIB_CTX_METHOD *meth = argp;
326
327 meth->free_func(ptr);
328}
329
330static int ossl_lib_ctx_init_index(OSSL_LIB_CTX *ctx, int static_index,
331 const OSSL_LIB_CTX_METHOD *meth)
332{
333 int idx;
334
335 ctx = ossl_lib_ctx_get_concrete(ctx);
336 if (ctx == NULL)
337 return 0;
338
339 idx = ossl_crypto_get_ex_new_index_ex(ctx, CRYPTO_EX_INDEX_OSSL_LIB_CTX, 0,
340 (void *)meth,
341 ossl_lib_ctx_generic_new,
342 NULL, ossl_lib_ctx_generic_free,
343 meth->priority);
344 if (idx < 0)
345 return 0;
346
347 ctx->dyn_indexes[static_index] = idx;
348 return 1;
349}
350
351void *ossl_lib_ctx_get_data(OSSL_LIB_CTX *ctx, int index,
352 const OSSL_LIB_CTX_METHOD *meth)
353{
354 void *data = NULL;
355 int dynidx;
356
357 ctx = ossl_lib_ctx_get_concrete(ctx);
358 if (ctx == NULL)
359 return NULL;
360
361 if (!CRYPTO_THREAD_read_lock(ctx->lock))
362 return NULL;
363 dynidx = ctx->dyn_indexes[index];
364 CRYPTO_THREAD_unlock(ctx->lock);
365
366 if (dynidx != -1) {
367 if (!CRYPTO_THREAD_read_lock(ctx->index_locks[index]))
368 return NULL;
369 if (!CRYPTO_THREAD_read_lock(ctx->lock)) {
370 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
371 return NULL;
372 }
373 data = CRYPTO_get_ex_data(&ctx->data, dynidx);
374 CRYPTO_THREAD_unlock(ctx->lock);
375 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
376 return data;
377 }
378
379 if (!CRYPTO_THREAD_write_lock(ctx->index_locks[index]))
380 return NULL;
381 if (!CRYPTO_THREAD_write_lock(ctx->lock)) {
382 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
383 return NULL;
384 }
385
386 dynidx = ctx->dyn_indexes[index];
387 if (dynidx != -1) {
388 data = CRYPTO_get_ex_data(&ctx->data, dynidx);
389 CRYPTO_THREAD_unlock(ctx->lock);
390 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
391 return data;
392 }
393
394 if (!ossl_lib_ctx_init_index(ctx, index, meth)) {
395 CRYPTO_THREAD_unlock(ctx->lock);
396 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
397 return NULL;
398 }
399
400 CRYPTO_THREAD_unlock(ctx->lock);
401
402 /*
403 * The alloc call ensures there's a value there. We release the ctx->lock
404 * for this, because the allocation itself may recursively call
405 * ossl_lib_ctx_get_data for other indexes (never this one). The allocation
406 * will itself aquire the ctx->lock when it actually comes to store the
407 * allocated data (see ossl_lib_ctx_generic_new() above). We call
408 * ossl_crypto_alloc_ex_data_intern() here instead of CRYPTO_alloc_ex_data().
409 * They do the same thing except that the latter calls CRYPTO_get_ex_data()
410 * as well - which we must not do without holding the ctx->lock.
411 */
412 if (ossl_crypto_alloc_ex_data_intern(CRYPTO_EX_INDEX_OSSL_LIB_CTX, NULL,
413 &ctx->data, ctx->dyn_indexes[index])) {
414 if (!CRYPTO_THREAD_read_lock(ctx->lock))
415 goto end;
416 data = CRYPTO_get_ex_data(&ctx->data, ctx->dyn_indexes[index]);
417 CRYPTO_THREAD_unlock(ctx->lock);
418 }
419
420end:
421 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
422 return data;
423}
424
425OSSL_EX_DATA_GLOBAL *ossl_lib_ctx_get_ex_data_global(OSSL_LIB_CTX *ctx)
426{
427 ctx = ossl_lib_ctx_get_concrete(ctx);
428 if (ctx == NULL)
429 return NULL;
430 return &ctx->global;
431}
432
433int ossl_lib_ctx_run_once(OSSL_LIB_CTX *ctx, unsigned int idx,
434 ossl_lib_ctx_run_once_fn run_once_fn)
435{
436 int done = 0, ret = 0;
437
438 ctx = ossl_lib_ctx_get_concrete(ctx);
439 if (ctx == NULL)
440 return 0;
441
442 if (!CRYPTO_THREAD_read_lock(ctx->oncelock))
443 return 0;
444 done = ctx->run_once_done[idx];
445 if (done)
446 ret = ctx->run_once_ret[idx];
447 CRYPTO_THREAD_unlock(ctx->oncelock);
448
449 if (done)
450 return ret;
451
452 if (!CRYPTO_THREAD_write_lock(ctx->oncelock))
453 return 0;
454 if (ctx->run_once_done[idx]) {
455 ret = ctx->run_once_ret[idx];
456 CRYPTO_THREAD_unlock(ctx->oncelock);
457 return ret;
458 }
459
460 ret = run_once_fn(ctx);
461 ctx->run_once_done[idx] = 1;
462 ctx->run_once_ret[idx] = ret;
463 CRYPTO_THREAD_unlock(ctx->oncelock);
464
465 return ret;
466}
467
468int ossl_lib_ctx_onfree(OSSL_LIB_CTX *ctx, ossl_lib_ctx_onfree_fn onfreefn)
469{
470 struct ossl_lib_ctx_onfree_list_st *newonfree
471 = OPENSSL_malloc(sizeof(*newonfree));
472
473 if (newonfree == NULL)
474 return 0;
475
476 newonfree->fn = onfreefn;
477 newonfree->next = ctx->onfreelist;
478 ctx->onfreelist = newonfree;
479
480 return 1;
481}
482
483const char *ossl_lib_ctx_get_descriptor(OSSL_LIB_CTX *libctx)
484{
485#ifdef FIPS_MODULE
486 return "FIPS internal library context";
487#else
488 if (ossl_lib_ctx_is_global_default(libctx))
489 return "Global default library context";
490 if (ossl_lib_ctx_is_default(libctx))
491 return "Thread-local default library context";
492 return "Non-default library context";
493#endif
494}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette