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