]>
Commit | Line | Data |
---|---|---|
d64b6299 | 1 | /* |
33388b44 | 2 | * Copyright 2019-2020 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 | |
b8fe36fe | 15 | struct openssl_ctx_onfree_list_st { |
1aedc35f | 16 | openssl_ctx_onfree_fn *fn; |
b8fe36fe MC |
17 | struct openssl_ctx_onfree_list_st *next; |
18 | }; | |
19 | ||
d64b6299 RL |
20 | struct openssl_ctx_st { |
21 | CRYPTO_RWLOCK *lock; | |
22 | CRYPTO_EX_DATA data; | |
1aedc35f MC |
23 | |
24 | /* | |
25 | * For most data in the OPENSSL_CTX we just use ex_data to store it. But | |
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 */ | |
31 | int dyn_indexes[OPENSSL_CTX_MAX_INDEXES]; | |
32 | ||
770de346 MC |
33 | /* Keep a separate lock for each index */ |
34 | CRYPTO_RWLOCK *index_locks[OPENSSL_CTX_MAX_INDEXES]; | |
35 | ||
1aedc35f MC |
36 | CRYPTO_RWLOCK *oncelock; |
37 | int run_once_done[OPENSSL_CTX_MAX_RUN_ONCE]; | |
38 | int run_once_ret[OPENSSL_CTX_MAX_RUN_ONCE]; | |
b8fe36fe | 39 | struct openssl_ctx_onfree_list_st *onfreelist; |
d64b6299 RL |
40 | }; |
41 | ||
1aedc35f MC |
42 | #ifndef FIPS_MODE |
43 | static OPENSSL_CTX default_context_int; | |
1aedc35f MC |
44 | |
45 | /* Always points at default_context_int if it has been initialised */ | |
46 | static OPENSSL_CTX *default_context = NULL; | |
3593266d | 47 | #endif |
d64b6299 RL |
48 | |
49 | static int context_init(OPENSSL_CTX *ctx) | |
50 | { | |
1aedc35f | 51 | size_t i; |
505f4660 | 52 | int exdata_done = 0; |
1aedc35f MC |
53 | |
54 | ctx->lock = CRYPTO_THREAD_lock_new(); | |
55 | if (ctx->lock == NULL) | |
56 | return 0; | |
57 | ||
58 | ctx->oncelock = CRYPTO_THREAD_lock_new(); | |
59 | if (ctx->oncelock == NULL) | |
60 | goto err; | |
61 | ||
770de346 MC |
62 | for (i = 0; i < OPENSSL_CTX_MAX_INDEXES; i++) { |
63 | ctx->index_locks[i] = CRYPTO_THREAD_lock_new(); | |
1aedc35f | 64 | ctx->dyn_indexes[i] = -1; |
770de346 MC |
65 | if (ctx->index_locks[i] == NULL) |
66 | goto err; | |
67 | } | |
1aedc35f | 68 | |
505f4660 | 69 | /* OPENSSL_CTX is built on top of ex_data so we initialise that directly */ |
1aedc35f MC |
70 | if (!do_ex_data_init(ctx)) |
71 | goto err; | |
505f4660 | 72 | exdata_done = 1; |
1aedc35f MC |
73 | |
74 | if (!crypto_new_ex_data_ex(ctx, CRYPTO_EX_INDEX_OPENSSL_CTX, NULL, | |
75 | &ctx->data)) { | |
76 | crypto_cleanup_all_ex_data_int(ctx); | |
77 | goto err; | |
78 | } | |
79 | ||
505f4660 MC |
80 | /* Everything depends on properties, so we also pre-initialise that */ |
81 | if (!ossl_property_parse_init(ctx)) | |
82 | goto err; | |
83 | ||
1aedc35f MC |
84 | return 1; |
85 | err: | |
505f4660 MC |
86 | if (exdata_done) |
87 | crypto_cleanup_all_ex_data_int(ctx); | |
1aedc35f MC |
88 | CRYPTO_THREAD_lock_free(ctx->oncelock); |
89 | CRYPTO_THREAD_lock_free(ctx->lock); | |
90 | ctx->lock = NULL; | |
91 | return 0; | |
d64b6299 RL |
92 | } |
93 | ||
94 | static int context_deinit(OPENSSL_CTX *ctx) | |
95 | { | |
1aedc35f | 96 | struct openssl_ctx_onfree_list_st *tmp, *onfree; |
770de346 | 97 | int i; |
1aedc35f MC |
98 | |
99 | if (ctx == NULL) | |
100 | return 1; | |
b8fe36fe | 101 | |
da747958 MC |
102 | ossl_ctx_thread_stop(ctx); |
103 | ||
1aedc35f | 104 | onfree = ctx->onfreelist; |
b8fe36fe MC |
105 | while (onfree != NULL) { |
106 | onfree->fn(ctx); | |
107 | tmp = onfree; | |
108 | onfree = onfree->next; | |
109 | OPENSSL_free(tmp); | |
110 | } | |
d64b6299 | 111 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL, &ctx->data); |
1aedc35f | 112 | crypto_cleanup_all_ex_data_int(ctx); |
770de346 MC |
113 | for (i = 0; i < OPENSSL_CTX_MAX_INDEXES; i++) |
114 | CRYPTO_THREAD_lock_free(ctx->index_locks[i]); | |
115 | ||
1aedc35f | 116 | CRYPTO_THREAD_lock_free(ctx->oncelock); |
d64b6299 | 117 | CRYPTO_THREAD_lock_free(ctx->lock); |
1aedc35f | 118 | ctx->lock = NULL; |
d64b6299 RL |
119 | return 1; |
120 | } | |
121 | ||
1aedc35f MC |
122 | #ifndef FIPS_MODE |
123 | void openssl_ctx_default_deinit(void) | |
d64b6299 | 124 | { |
1aedc35f | 125 | context_deinit(default_context); |
d64b6299 | 126 | } |
1aedc35f MC |
127 | |
128 | static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT; | |
d64b6299 RL |
129 | DEFINE_RUN_ONCE_STATIC(do_default_context_init) |
130 | { | |
1aedc35f MC |
131 | if (context_init(&default_context_int)) |
132 | default_context = &default_context_int; | |
133 | ||
134 | return 1; | |
d64b6299 | 135 | } |
1aedc35f | 136 | #endif |
d64b6299 RL |
137 | |
138 | OPENSSL_CTX *OPENSSL_CTX_new(void) | |
139 | { | |
140 | OPENSSL_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); | |
141 | ||
142 | if (ctx != NULL && !context_init(ctx)) { | |
143 | OPENSSL_CTX_free(ctx); | |
144 | ctx = NULL; | |
145 | } | |
146 | return ctx; | |
147 | } | |
148 | ||
22e27978 SL |
149 | #ifndef FIPS_MODE |
150 | int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file) | |
151 | { | |
152 | return CONF_modules_load_file_with_libctx(ctx, config_file, NULL, 0) > 0; | |
153 | } | |
154 | #endif | |
155 | ||
d64b6299 RL |
156 | void OPENSSL_CTX_free(OPENSSL_CTX *ctx) |
157 | { | |
158 | if (ctx != NULL) | |
159 | context_deinit(ctx); | |
160 | OPENSSL_free(ctx); | |
161 | } | |
162 | ||
d4c051ce MC |
163 | OPENSSL_CTX *openssl_ctx_get_concrete(OPENSSL_CTX *ctx) |
164 | { | |
165 | #ifndef FIPS_MODE | |
166 | if (ctx == NULL) { | |
167 | if (!RUN_ONCE(&default_context_init, do_default_context_init)) | |
168 | return 0; | |
169 | return default_context; | |
170 | } | |
171 | #endif | |
172 | return ctx; | |
173 | } | |
174 | ||
6b1e5fa4 MC |
175 | int openssl_ctx_is_default(OPENSSL_CTX *ctx) |
176 | { | |
177 | #ifndef FIPS_MODE | |
178 | if (ctx == NULL || ctx == default_context) | |
179 | return 1; | |
180 | #endif | |
181 | return 0; | |
182 | } | |
183 | ||
d64b6299 RL |
184 | static void openssl_ctx_generic_new(void *parent_ign, void *ptr_ign, |
185 | CRYPTO_EX_DATA *ad, int index, | |
186 | long argl_ign, void *argp) | |
187 | { | |
188 | const OPENSSL_CTX_METHOD *meth = argp; | |
1aedc35f | 189 | void *ptr = meth->new_func(crypto_ex_data_get_openssl_ctx(ad)); |
d64b6299 RL |
190 | |
191 | if (ptr != NULL) | |
192 | CRYPTO_set_ex_data(ad, index, ptr); | |
193 | } | |
194 | static void openssl_ctx_generic_free(void *parent_ign, void *ptr, | |
195 | CRYPTO_EX_DATA *ad, int index, | |
196 | long argl_ign, void *argp) | |
197 | { | |
198 | const OPENSSL_CTX_METHOD *meth = argp; | |
199 | ||
200 | meth->free_func(ptr); | |
201 | } | |
1aedc35f MC |
202 | |
203 | /* Non-static so we can use it in context_internal_test */ | |
204 | static int openssl_ctx_init_index(OPENSSL_CTX *ctx, int static_index, | |
205 | const OPENSSL_CTX_METHOD *meth) | |
d64b6299 | 206 | { |
1aedc35f MC |
207 | int idx; |
208 | ||
d4c051ce | 209 | ctx = openssl_ctx_get_concrete(ctx); |
1aedc35f MC |
210 | if (ctx == NULL) |
211 | return 0; | |
212 | ||
213 | idx = crypto_get_ex_new_index_ex(ctx, CRYPTO_EX_INDEX_OPENSSL_CTX, 0, | |
214 | (void *)meth, | |
215 | openssl_ctx_generic_new, | |
216 | NULL, openssl_ctx_generic_free); | |
217 | if (idx < 0) | |
218 | return 0; | |
219 | ||
220 | ctx->dyn_indexes[static_index] = idx; | |
221 | return 1; | |
d64b6299 RL |
222 | } |
223 | ||
1aedc35f MC |
224 | void *openssl_ctx_get_data(OPENSSL_CTX *ctx, int index, |
225 | const OPENSSL_CTX_METHOD *meth) | |
d64b6299 RL |
226 | { |
227 | void *data = NULL; | |
770de346 | 228 | int dynidx; |
d64b6299 | 229 | |
d4c051ce | 230 | ctx = openssl_ctx_get_concrete(ctx); |
b8fe36fe MC |
231 | if (ctx == NULL) |
232 | return NULL; | |
d64b6299 RL |
233 | |
234 | CRYPTO_THREAD_read_lock(ctx->lock); | |
770de346 MC |
235 | dynidx = ctx->dyn_indexes[index]; |
236 | CRYPTO_THREAD_unlock(ctx->lock); | |
237 | ||
238 | if (dynidx != -1) { | |
239 | CRYPTO_THREAD_read_lock(ctx->index_locks[index]); | |
240 | data = CRYPTO_get_ex_data(&ctx->data, dynidx); | |
241 | CRYPTO_THREAD_unlock(ctx->index_locks[index]); | |
242 | return data; | |
243 | } | |
d64b6299 | 244 | |
770de346 MC |
245 | CRYPTO_THREAD_write_lock(ctx->index_locks[index]); |
246 | CRYPTO_THREAD_write_lock(ctx->lock); | |
247 | ||
248 | dynidx = ctx->dyn_indexes[index]; | |
249 | if (dynidx != -1) { | |
250 | CRYPTO_THREAD_unlock(ctx->lock); | |
251 | data = CRYPTO_get_ex_data(&ctx->data, dynidx); | |
252 | CRYPTO_THREAD_unlock(ctx->index_locks[index]); | |
253 | return data; | |
254 | } | |
255 | ||
256 | if (!openssl_ctx_init_index(ctx, index, meth)) { | |
1aedc35f | 257 | CRYPTO_THREAD_unlock(ctx->lock); |
770de346 | 258 | CRYPTO_THREAD_unlock(ctx->index_locks[index]); |
1aedc35f MC |
259 | return NULL; |
260 | } | |
261 | ||
770de346 MC |
262 | CRYPTO_THREAD_unlock(ctx->lock); |
263 | ||
d64b6299 RL |
264 | /* The alloc call ensures there's a value there */ |
265 | if (CRYPTO_alloc_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL, | |
1aedc35f MC |
266 | &ctx->data, ctx->dyn_indexes[index])) |
267 | data = CRYPTO_get_ex_data(&ctx->data, ctx->dyn_indexes[index]); | |
d64b6299 | 268 | |
770de346 | 269 | CRYPTO_THREAD_unlock(ctx->index_locks[index]); |
d64b6299 RL |
270 | |
271 | return data; | |
272 | } | |
273 | ||
1aedc35f MC |
274 | OSSL_EX_DATA_GLOBAL *openssl_ctx_get_ex_data_global(OPENSSL_CTX *ctx) |
275 | { | |
d4c051ce | 276 | ctx = openssl_ctx_get_concrete(ctx); |
1aedc35f MC |
277 | if (ctx == NULL) |
278 | return NULL; | |
279 | return &ctx->global; | |
280 | } | |
281 | ||
b8fe36fe MC |
282 | int openssl_ctx_run_once(OPENSSL_CTX *ctx, unsigned int idx, |
283 | openssl_ctx_run_once_fn run_once_fn) | |
284 | { | |
285 | int done = 0, ret = 0; | |
286 | ||
d4c051ce | 287 | ctx = openssl_ctx_get_concrete(ctx); |
b8fe36fe MC |
288 | if (ctx == NULL) |
289 | return 0; | |
290 | ||
1aedc35f | 291 | CRYPTO_THREAD_read_lock(ctx->oncelock); |
b8fe36fe MC |
292 | done = ctx->run_once_done[idx]; |
293 | if (done) | |
294 | ret = ctx->run_once_ret[idx]; | |
1aedc35f | 295 | CRYPTO_THREAD_unlock(ctx->oncelock); |
b8fe36fe MC |
296 | |
297 | if (done) | |
298 | return ret; | |
299 | ||
1aedc35f | 300 | CRYPTO_THREAD_write_lock(ctx->oncelock); |
b8fe36fe MC |
301 | if (ctx->run_once_done[idx]) { |
302 | ret = ctx->run_once_ret[idx]; | |
1aedc35f | 303 | CRYPTO_THREAD_unlock(ctx->oncelock); |
b8fe36fe MC |
304 | return ret; |
305 | } | |
306 | ||
307 | ret = run_once_fn(ctx); | |
308 | ctx->run_once_done[idx] = 1; | |
309 | ctx->run_once_ret[idx] = ret; | |
1aedc35f | 310 | CRYPTO_THREAD_unlock(ctx->oncelock); |
b8fe36fe MC |
311 | |
312 | return ret; | |
313 | } | |
314 | ||
315 | int openssl_ctx_onfree(OPENSSL_CTX *ctx, openssl_ctx_onfree_fn onfreefn) | |
316 | { | |
317 | struct openssl_ctx_onfree_list_st *newonfree | |
318 | = OPENSSL_malloc(sizeof(*newonfree)); | |
319 | ||
320 | if (newonfree == NULL) | |
321 | return 0; | |
322 | ||
323 | newonfree->fn = onfreefn; | |
324 | newonfree->next = ctx->onfreelist; | |
325 | ctx->onfreelist = newonfree; | |
326 | ||
327 | return 1; | |
328 | } |