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