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