2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include <openssl/crypto.h>
11 #include <openssl/core_numbers.h>
12 #include "internal/cryptlib_int.h"
13 #include "internal/providercommon.h"
17 * Thread aware code may want to be told about thread stop events. We register
18 * to hear about those thread stop events when we see a new thread has started.
19 * We call the ossl_init_thread_start function to do that. In the FIPS provider
20 * we have our own copy of ossl_init_thread_start, which cascades notifications
21 * about threads stopping from libcrypto to all the code in the FIPS provider
22 * that needs to know about it.
24 * The FIPS provider tells libcrypto about which threads it is interested in
25 * by calling "c_thread_start" which is a function pointer created during
26 * provider initialisation (i.e. OSSL_init_provider).
28 extern OSSL_core_thread_start_fn *c_thread_start;
31 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
32 struct thread_event_handler_st {
34 OSSL_thread_stop_handler_fn handfn;
35 THREAD_EVENT_HANDLER *next;
38 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
40 static THREAD_EVENT_HANDLER **
41 init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
43 THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local);
47 && (hands = OPENSSL_zalloc(sizeof(*hands))) != NULL
48 && !CRYPTO_THREAD_set_local(local, hands)) {
53 CRYPTO_THREAD_set_local(local, NULL);
61 * Since per-thread-specific-data destructors are not universally
62 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
63 * is assumed to have destructor associated. And then an effort is made
64 * to call this single destructor on non-pthread platform[s].
66 * Initial value is "impossible". It is used as guard value to shortcut
67 * destructor for threads terminating before libcrypto is initialized or
68 * after it's de-initialized. Access to the key doesn't have to be
69 * serialized for the said threads, because they didn't use libcrypto
70 * and it doesn't matter if they pick "impossible" or derefernce real
71 * key value and pull NULL past initialization in the first thread that
72 * intends to use libcrypto.
76 CRYPTO_THREAD_LOCAL value;
77 } destructor_key = { -1 };
79 static void init_thread_destructor(void *hands)
81 init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands);
85 int ossl_init_thread(void)
87 if (!CRYPTO_THREAD_init_local(&destructor_key.value,
88 init_thread_destructor))
94 void ossl_cleanup_thread(void)
96 CRYPTO_THREAD_cleanup_local(&destructor_key.value);
97 destructor_key.sane = -1;
100 void OPENSSL_thread_stop_ex(OPENSSL_CTX *ctx)
102 ctx = openssl_ctx_get_concrete(ctx);
104 * TODO(3.0). It would be nice if we could figure out a way to do this on
105 * all threads that have used the OPENSSL_CTX when the OPENSSL_CTX is freed.
106 * This is currently not possible due to the use of thread local variables.
108 ossl_ctx_thread_stop(ctx);
111 void OPENSSL_thread_stop(void)
113 if (destructor_key.sane != -1) {
114 THREAD_EVENT_HANDLER **hands
115 = init_get_thread_local(&destructor_key.value, 0, 0);
116 init_thread_stop(NULL, hands);
121 void ossl_ctx_thread_stop(void *arg)
123 if (destructor_key.sane != -1) {
124 THREAD_EVENT_HANDLER **hands
125 = init_get_thread_local(&destructor_key.value, 0, 1);
126 init_thread_stop(arg, hands);
132 static void *thread_event_ossl_ctx_new(OPENSSL_CTX *libctx)
134 THREAD_EVENT_HANDLER **hands = NULL;
135 CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
140 if (!CRYPTO_THREAD_init_local(tlocal, NULL)) {
144 hands = OPENSSL_zalloc(sizeof(*hands));
148 if (!CRYPTO_THREAD_set_local(tlocal, hands))
154 OPENSSL_free(tlocal);
158 static void thread_event_ossl_ctx_free(void *tlocal)
160 OPENSSL_free(tlocal);
163 static const OPENSSL_CTX_METHOD thread_event_ossl_ctx_method = {
164 thread_event_ossl_ctx_new,
165 thread_event_ossl_ctx_free,
168 void ossl_ctx_thread_stop(void *arg)
170 THREAD_EVENT_HANDLER **hands;
171 OPENSSL_CTX *ctx = arg;
172 CRYPTO_THREAD_LOCAL *local
173 = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
174 &thread_event_ossl_ctx_method);
178 hands = init_get_thread_local(local, 0, 0);
179 init_thread_stop(arg, hands);
182 #endif /* FIPS_MODE */
185 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands)
187 THREAD_EVENT_HANDLER *curr, *prev = NULL;
189 /* Can't do much about this */
194 while (curr != NULL) {
195 if (arg != NULL && curr->arg != arg) {
199 curr->handfn(curr->arg);
208 int ossl_init_thread_start(void *arg, OSSL_thread_stop_handler_fn handfn)
210 THREAD_EVENT_HANDLER **hands;
211 THREAD_EVENT_HANDLER *hand;
213 OPENSSL_CTX *ctx = arg;
216 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
217 * of OPENSSL_CTX and thread. This is because in FIPS mode each OPENSSL_CTX
218 * gets informed about thread stop events individually.
220 CRYPTO_THREAD_LOCAL *local
221 = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
222 &thread_event_ossl_ctx_method);
225 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
226 * thread, but may hold multiple OPENSSL_CTXs. We only get told about
227 * thread stop events globally, so we have to ensure all affected
228 * OPENSSL_CTXs are informed.
230 CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
233 hands = init_get_thread_local(local, 1, 0);
238 if (*hands == NULL) {
240 * We've not yet registered any handlers for this thread. We need to get
241 * libcrypto to tell us about later thread stop events. c_thread_start
242 * is a callback to libcrypto defined in fipsprov.c
244 if (!c_thread_start(FIPS_get_provider(ctx), ossl_ctx_thread_stop))
249 hand = OPENSSL_malloc(sizeof(*hand));
253 hand->handfn = handfn;