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 "internal/cryptlib_int.h"
13 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
14 struct thread_event_handler_st {
16 ossl_thread_stop_handler_fn handfn;
17 THREAD_EVENT_HANDLER *next;
20 static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands);
24 * Since per-thread-specific-data destructors are not universally
25 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
26 * is assumed to have destructor associated. And then an effort is made
27 * to call this single destructor on non-pthread platform[s].
29 * Initial value is "impossible". It is used as guard value to shortcut
30 * destructor for threads terminating before libcrypto is initialized or
31 * after it's de-initialized. Access to the key doesn't have to be
32 * serialized for the said threads, because they didn't use libcrypto
33 * and it doesn't matter if they pick "impossible" or derefernce real
34 * key value and pull NULL past initialization in the first thread that
35 * intends to use libcrypto.
39 CRYPTO_THREAD_LOCAL value;
40 } destructor_key = { -1 };
42 static void ossl_init_thread_destructor(void *hands)
44 ossl_init_thread_stop((THREAD_EVENT_HANDLER **)hands);
50 if (!CRYPTO_THREAD_init_local(&destructor_key.value,
51 ossl_init_thread_destructor))
57 void cleanup_thread(void)
59 CRYPTO_THREAD_cleanup_local(&destructor_key.value);
60 destructor_key.sane = -1;
63 static THREAD_EVENT_HANDLER **ossl_init_get_thread_local(int alloc)
65 THREAD_EVENT_HANDLER **hands =
66 CRYPTO_THREAD_get_local(&destructor_key.value);
70 && (hands = OPENSSL_zalloc(sizeof(*hands))) != NULL
71 && !CRYPTO_THREAD_set_local(&destructor_key.value, hands)) {
76 CRYPTO_THREAD_set_local(&destructor_key.value, NULL);
82 void OPENSSL_thread_stop(void)
84 if (destructor_key.sane != -1)
85 ossl_init_thread_stop(ossl_init_get_thread_local(0));
88 static void *thread_event_ossl_ctx_new(OPENSSL_CTX *libctx)
90 THREAD_EVENT_HANDLER **hands = NULL;
91 CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(CRYPTO_THREAD_LOCAL));
96 hands = OPENSSL_zalloc(sizeof(*hands));
100 if (!CRYPTO_THREAD_set_local(tlocal, hands))
106 OPENSSL_free(tlocal);
110 static void thread_event_ossl_ctx_free(void *vtlocal)
112 CRYPTO_THREAD_LOCAL *tlocal = vtlocal;
113 THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(tlocal);
116 ossl_init_thread_stop(hands);
118 OPENSSL_free(tlocal);
121 static const OPENSSL_CTX_METHOD thread_event_ossl_ctx_method = {
122 thread_event_ossl_ctx_new,
123 thread_event_ossl_ctx_free,
126 void fips_thread_stop(OPENSSL_CTX *ctx)
128 THREAD_EVENT_HANDLER **hands;
130 hands = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
131 &thread_event_ossl_ctx_method);
133 ossl_init_thread_stop(hands);
135 #endif /* FIPS_MODE */
137 static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands)
139 THREAD_EVENT_HANDLER *curr, *prev = NULL;
141 /* Can't do much about this */
146 while (curr != NULL) {
147 curr->handfn(curr->ctx);
156 int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn)
158 THREAD_EVENT_HANDLER **hands;
159 THREAD_EVENT_HANDLER *hand;
163 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
164 * of OPENSSL_CTX and thread. This is because in FIPS mode each OPENSSL_CTX
165 * gets informed about thread stop events individually.
167 hands = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
168 &thread_event_ossl_ctx_method);
171 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
172 * thread, but may hold multiple OPENSSL_CTXs. We only get told about
173 * thread stop events globally, so we have to ensure all affected
174 * OPENSSL_CTXs are informed.
176 hands = ossl_init_get_thread_local(1);
182 hand = OPENSSL_malloc(sizeof(*hand));
186 hand->handfn = handfn;