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 ossl_init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
40 static THREAD_EVENT_HANDLER **
41 ossl_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 ossl_init_thread_destructor(void *hands)
81 ossl_init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands);
87 if (!CRYPTO_THREAD_init_local(&destructor_key.value,
88 ossl_init_thread_destructor))
94 void cleanup_thread(void)
96 CRYPTO_THREAD_cleanup_local(&destructor_key.value);
97 destructor_key.sane = -1;
100 void OPENSSL_thread_stop(void)
102 if (destructor_key.sane != -1) {
103 THREAD_EVENT_HANDLER **hands
104 = ossl_init_get_thread_local(&destructor_key.value, 0, 0);
105 ossl_init_thread_stop(NULL, hands);
110 void ossl_ctx_thread_stop(void *arg)
112 if (destructor_key.sane != -1) {
113 THREAD_EVENT_HANDLER **hands
114 = ossl_init_get_thread_local(&destructor_key.value, 0, 1);
115 ossl_init_thread_stop(arg, hands);
121 static void *thread_event_ossl_ctx_new(OPENSSL_CTX *libctx)
123 THREAD_EVENT_HANDLER **hands = NULL;
124 CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
129 if (!CRYPTO_THREAD_init_local(tlocal, NULL)) {
133 hands = OPENSSL_zalloc(sizeof(*hands));
137 if (!CRYPTO_THREAD_set_local(tlocal, hands))
143 OPENSSL_free(tlocal);
147 static void thread_event_ossl_ctx_free(void *tlocal)
149 OPENSSL_free(tlocal);
152 static const OPENSSL_CTX_METHOD thread_event_ossl_ctx_method = {
153 thread_event_ossl_ctx_new,
154 thread_event_ossl_ctx_free,
157 void ossl_ctx_thread_stop(void *arg)
159 THREAD_EVENT_HANDLER **hands;
160 OPENSSL_CTX *ctx = arg;
161 CRYPTO_THREAD_LOCAL *local
162 = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
163 &thread_event_ossl_ctx_method);
167 hands = ossl_init_get_thread_local(local, 0, 0);
168 ossl_init_thread_stop(arg, hands);
171 #endif /* FIPS_MODE */
174 static void ossl_init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands)
176 THREAD_EVENT_HANDLER *curr, *prev = NULL;
178 /* Can't do much about this */
183 while (curr != NULL) {
184 if (arg != NULL && curr->arg != arg) {
188 curr->handfn(curr->arg);
197 int ossl_init_thread_start(void *arg, OSSL_thread_stop_handler_fn handfn)
199 THREAD_EVENT_HANDLER **hands;
200 THREAD_EVENT_HANDLER *hand;
202 OPENSSL_CTX *ctx = arg;
205 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
206 * of OPENSSL_CTX and thread. This is because in FIPS mode each OPENSSL_CTX
207 * gets informed about thread stop events individually.
209 CRYPTO_THREAD_LOCAL *local
210 = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
211 &thread_event_ossl_ctx_method);
214 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
215 * thread, but may hold multiple OPENSSL_CTXs. We only get told about
216 * thread stop events globally, so we have to ensure all affected
217 * OPENSSL_CTXs are informed.
219 CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
222 hands = ossl_init_get_thread_local(local, 1, 0);
227 if (*hands == NULL) {
229 * We've not yet registered any handlers for this thread. We need to get
230 * libcrypto to tell us about later thread stop events. c_thread_start
231 * is a callback to libcrypto defined in fipsprov.c
233 if (!c_thread_start(FIPS_get_provider(ctx), ossl_ctx_thread_stop))
238 hand = OPENSSL_malloc(sizeof(*hand));
242 hand->handfn = handfn;