]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/context.c
Add the ability for ex_data to have a priority
[thirdparty/openssl.git] / crypto / context.c
1 /*
2 * Copyright 2019-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 "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
17 struct ossl_lib_ctx_onfree_list_st {
18 ossl_lib_ctx_onfree_fn *fn;
19 struct ossl_lib_ctx_onfree_list_st *next;
20 };
21
22 struct ossl_lib_ctx_st {
23 CRYPTO_RWLOCK *lock;
24 CRYPTO_EX_DATA data;
25
26 /*
27 * For most data in the OSSL_LIB_CTX we just use ex_data to store it. But
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 */
33 int dyn_indexes[OSSL_LIB_CTX_MAX_INDEXES];
34
35 /* Keep a separate lock for each index */
36 CRYPTO_RWLOCK *index_locks[OSSL_LIB_CTX_MAX_INDEXES];
37
38 CRYPTO_RWLOCK *oncelock;
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;
42 };
43
44 int 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
49 int 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
54 int ossl_lib_ctx_unlock(OSSL_LIB_CTX *ctx)
55 {
56 return CRYPTO_THREAD_unlock(ossl_lib_ctx_get_concrete(ctx)->lock);
57 }
58
59 static int context_init(OSSL_LIB_CTX *ctx)
60 {
61 size_t i;
62 int exdata_done = 0;
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
72 for (i = 0; i < OSSL_LIB_CTX_MAX_INDEXES; i++) {
73 ctx->index_locks[i] = CRYPTO_THREAD_lock_new();
74 ctx->dyn_indexes[i] = -1;
75 if (ctx->index_locks[i] == NULL)
76 goto err;
77 }
78
79 /* OSSL_LIB_CTX is built on top of ex_data so we initialise that directly */
80 if (!ossl_do_ex_data_init(ctx))
81 goto err;
82 exdata_done = 1;
83
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);
87 goto err;
88 }
89
90 /* Everything depends on properties, so we also pre-initialise that */
91 if (!ossl_property_parse_init(ctx))
92 goto err;
93
94 return 1;
95 err:
96 if (exdata_done)
97 ossl_crypto_cleanup_all_ex_data_int(ctx);
98 CRYPTO_THREAD_lock_free(ctx->oncelock);
99 CRYPTO_THREAD_lock_free(ctx->lock);
100 ctx->lock = NULL;
101 return 0;
102 }
103
104 static int context_deinit(OSSL_LIB_CTX *ctx)
105 {
106 struct ossl_lib_ctx_onfree_list_st *tmp, *onfree;
107 int i;
108
109 if (ctx == NULL)
110 return 1;
111
112 ossl_ctx_thread_stop(ctx);
113
114 onfree = ctx->onfreelist;
115 while (onfree != NULL) {
116 onfree->fn(ctx);
117 tmp = onfree;
118 onfree = onfree->next;
119 OPENSSL_free(tmp);
120 }
121 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_OSSL_LIB_CTX, NULL, &ctx->data);
122 ossl_crypto_cleanup_all_ex_data_int(ctx);
123 for (i = 0; i < OSSL_LIB_CTX_MAX_INDEXES; i++)
124 CRYPTO_THREAD_lock_free(ctx->index_locks[i]);
125
126 CRYPTO_THREAD_lock_free(ctx->oncelock);
127 CRYPTO_THREAD_lock_free(ctx->lock);
128 ctx->lock = NULL;
129 return 1;
130 }
131
132 #ifndef FIPS_MODULE
133 /* The default default context */
134 static OSSL_LIB_CTX default_context_int;
135
136 static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT;
137 static CRYPTO_THREAD_LOCAL default_context_thread_local;
138
139 DEFINE_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
145 void ossl_lib_ctx_default_deinit(void)
146 {
147 context_deinit(&default_context_int);
148 }
149
150 static OSSL_LIB_CTX *get_thread_default_context(void)
151 {
152 if (!RUN_ONCE(&default_context_init, default_context_do_init))
153 return NULL;
154
155 return CRYPTO_THREAD_get_local(&default_context_thread_local);
156 }
157
158 static OSSL_LIB_CTX *get_default_context(void)
159 {
160 OSSL_LIB_CTX *current_defctx = get_thread_default_context();
161
162 if (current_defctx == NULL)
163 current_defctx = &default_context_int;
164 return current_defctx;
165 }
166
167 static int set_default_context(OSSL_LIB_CTX *defctx)
168 {
169 if (defctx == &default_context_int)
170 defctx = NULL;
171
172 return CRYPTO_THREAD_set_local(&default_context_thread_local, defctx);
173 }
174 #endif
175
176 OSSL_LIB_CTX *OSSL_LIB_CTX_new(void)
177 {
178 OSSL_LIB_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
179
180 if (ctx != NULL && !context_init(ctx)) {
181 OSSL_LIB_CTX_free(ctx);
182 ctx = NULL;
183 }
184 return ctx;
185 }
186
187 #ifndef FIPS_MODULE
188 OSSL_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
203 int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file)
204 {
205 return CONF_modules_load_file_ex(ctx, config_file, NULL, 0) > 0;
206 }
207 #endif
208
209 void OSSL_LIB_CTX_free(OSSL_LIB_CTX *ctx)
210 {
211 if (ossl_lib_ctx_is_default(ctx))
212 return;
213
214 context_deinit(ctx);
215 OPENSSL_free(ctx);
216 }
217
218 #ifndef FIPS_MODULE
219 OSSL_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
227 OSSL_LIB_CTX *OSSL_LIB_CTX_set0_default(OSSL_LIB_CTX *libctx)
228 {
229 OSSL_LIB_CTX *current_defctx;
230
231 if ((current_defctx = get_default_context()) != NULL) {
232 if (libctx != NULL)
233 set_default_context(libctx);
234 return current_defctx;
235 }
236
237 return NULL;
238 }
239 #endif
240
241 OSSL_LIB_CTX *ossl_lib_ctx_get_concrete(OSSL_LIB_CTX *ctx)
242 {
243 #ifndef FIPS_MODULE
244 if (ctx == NULL)
245 return get_default_context();
246 #endif
247 return ctx;
248 }
249
250 int ossl_lib_ctx_is_default(OSSL_LIB_CTX *ctx)
251 {
252 #ifndef FIPS_MODULE
253 if (ctx == NULL || ctx == get_default_context())
254 return 1;
255 #endif
256 return 0;
257 }
258
259 int ossl_lib_ctx_is_global_default(OSSL_LIB_CTX *ctx)
260 {
261 #ifndef FIPS_MODULE
262 if (ossl_lib_ctx_get_concrete(ctx) == &default_context_int)
263 return 1;
264 #endif
265 return 0;
266 }
267
268 static 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)
271 {
272 const OSSL_LIB_CTX_METHOD *meth = argp;
273 OSSL_LIB_CTX *ctx = ossl_crypto_ex_data_get_ossl_lib_ctx(ad);
274 void *ptr = meth->new_func(ctx);
275
276 if (ptr != NULL) {
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;
283 CRYPTO_set_ex_data(ad, index, ptr);
284 CRYPTO_THREAD_unlock(ctx->lock);
285 }
286 }
287 static void ossl_lib_ctx_generic_free(void *parent_ign, void *ptr,
288 CRYPTO_EX_DATA *ad, int index,
289 long argl_ign, void *argp)
290 {
291 const OSSL_LIB_CTX_METHOD *meth = argp;
292
293 meth->free_func(ptr);
294 }
295
296 static int ossl_lib_ctx_init_index(OSSL_LIB_CTX *ctx, int static_index,
297 const OSSL_LIB_CTX_METHOD *meth)
298 {
299 int idx;
300
301 ctx = ossl_lib_ctx_get_concrete(ctx);
302 if (ctx == NULL)
303 return 0;
304
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,
308 NULL, ossl_lib_ctx_generic_free,
309 meth->priority);
310 if (idx < 0)
311 return 0;
312
313 ctx->dyn_indexes[static_index] = idx;
314 return 1;
315 }
316
317 void *ossl_lib_ctx_get_data(OSSL_LIB_CTX *ctx, int index,
318 const OSSL_LIB_CTX_METHOD *meth)
319 {
320 void *data = NULL;
321 int dynidx;
322
323 ctx = ossl_lib_ctx_get_concrete(ctx);
324 if (ctx == NULL)
325 return NULL;
326
327 if (!CRYPTO_THREAD_read_lock(ctx->lock))
328 return NULL;
329 dynidx = ctx->dyn_indexes[index];
330 CRYPTO_THREAD_unlock(ctx->lock);
331
332 if (dynidx != -1) {
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 }
339 data = CRYPTO_get_ex_data(&ctx->data, dynidx);
340 CRYPTO_THREAD_unlock(ctx->lock);
341 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
342 return data;
343 }
344
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 }
351
352 dynidx = ctx->dyn_indexes[index];
353 if (dynidx != -1) {
354 data = CRYPTO_get_ex_data(&ctx->data, dynidx);
355 CRYPTO_THREAD_unlock(ctx->lock);
356 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
357 return data;
358 }
359
360 if (!ossl_lib_ctx_init_index(ctx, index, meth)) {
361 CRYPTO_THREAD_unlock(ctx->lock);
362 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
363 return NULL;
364 }
365
366 CRYPTO_THREAD_unlock(ctx->lock);
367
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])) {
380 if (!CRYPTO_THREAD_read_lock(ctx->lock))
381 goto end;
382 data = CRYPTO_get_ex_data(&ctx->data, ctx->dyn_indexes[index]);
383 CRYPTO_THREAD_unlock(ctx->lock);
384 }
385
386 end:
387 CRYPTO_THREAD_unlock(ctx->index_locks[index]);
388 return data;
389 }
390
391 OSSL_EX_DATA_GLOBAL *ossl_lib_ctx_get_ex_data_global(OSSL_LIB_CTX *ctx)
392 {
393 ctx = ossl_lib_ctx_get_concrete(ctx);
394 if (ctx == NULL)
395 return NULL;
396 return &ctx->global;
397 }
398
399 int ossl_lib_ctx_run_once(OSSL_LIB_CTX *ctx, unsigned int idx,
400 ossl_lib_ctx_run_once_fn run_once_fn)
401 {
402 int done = 0, ret = 0;
403
404 ctx = ossl_lib_ctx_get_concrete(ctx);
405 if (ctx == NULL)
406 return 0;
407
408 if (!CRYPTO_THREAD_read_lock(ctx->oncelock))
409 return 0;
410 done = ctx->run_once_done[idx];
411 if (done)
412 ret = ctx->run_once_ret[idx];
413 CRYPTO_THREAD_unlock(ctx->oncelock);
414
415 if (done)
416 return ret;
417
418 if (!CRYPTO_THREAD_write_lock(ctx->oncelock))
419 return 0;
420 if (ctx->run_once_done[idx]) {
421 ret = ctx->run_once_ret[idx];
422 CRYPTO_THREAD_unlock(ctx->oncelock);
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;
429 CRYPTO_THREAD_unlock(ctx->oncelock);
430
431 return ret;
432 }
433
434 int ossl_lib_ctx_onfree(OSSL_LIB_CTX *ctx, ossl_lib_ctx_onfree_fn onfreefn)
435 {
436 struct ossl_lib_ctx_onfree_list_st *newonfree
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 }
448
449 const 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 }