summaryrefslogtreecommitdiffstats
path: root/crypto/initthread.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2019-05-24 18:20:49 +0100
committerMatt Caswell <matt@openssl.org>2019-06-17 15:32:54 +0100
commite41faf5784382a5d2bc23abebcf81b9f4708f6ec (patch)
treed8fb927ed8a5e8576e96e600812f36b13511eee7 /crypto/initthread.c
parent72592b866492b84ba5ca1251d1a45875764c7b27 (diff)
Provide a version of ossl_init_thread_start that works in FIPS mode
This will need to be hooked up in a later commit with an event sent to the FIPS provider informing it of thread stop events. Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/9040)
Diffstat (limited to 'crypto/initthread.c')
-rw-r--r--crypto/initthread.c85
1 files changed, 74 insertions, 11 deletions
diff --git a/crypto/initthread.c b/crypto/initthread.c
index 6e56d47338..74a5f4815a 100644
--- a/crypto/initthread.c
+++ b/crypto/initthread.c
@@ -17,6 +17,9 @@ struct thread_event_handler_st {
THREAD_EVENT_HANDLER *next;
};
+static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands);
+
+#ifndef FIPS_MODE
/*
* Since per-thread-specific-data destructors are not universally
* available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
@@ -36,8 +39,6 @@ static union {
CRYPTO_THREAD_LOCAL value;
} destructor_key = { -1 };
-static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands);
-
static void ossl_init_thread_destructor(void *hands)
{
ossl_init_thread_stop((THREAD_EVENT_HANDLER **)hands);
@@ -78,6 +79,61 @@ static THREAD_EVENT_HANDLER **ossl_init_get_thread_local(int alloc)
return hands;
}
+void OPENSSL_thread_stop(void)
+{
+ if (destructor_key.sane != -1)
+ ossl_init_thread_stop(ossl_init_get_thread_local(0));
+}
+#else
+static void *thread_event_ossl_ctx_new(OPENSSL_CTX *libctx)
+{
+ THREAD_EVENT_HANDLER **hands = NULL;
+ CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(CRYPTO_THREAD_LOCAL));
+
+ if (tlocal == NULL)
+ return NULL;
+
+ hands = OPENSSL_zalloc(sizeof(*hands));
+ if (hands == NULL)
+ goto err;
+
+ if (!CRYPTO_THREAD_set_local(tlocal, hands))
+ goto err;
+
+ return tlocal;
+ err:
+ OPENSSL_free(hands);
+ OPENSSL_free(tlocal);
+ return NULL;
+}
+
+static void thread_event_ossl_ctx_free(void *vtlocal)
+{
+ CRYPTO_THREAD_LOCAL *tlocal = vtlocal;
+ THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(tlocal);
+
+ if (hands != NULL)
+ ossl_init_thread_stop(hands);
+
+ OPENSSL_free(tlocal);
+}
+
+static const OPENSSL_CTX_METHOD thread_event_ossl_ctx_method = {
+ thread_event_ossl_ctx_new,
+ thread_event_ossl_ctx_free,
+};
+
+void fips_thread_stop(OPENSSL_CTX *ctx)
+{
+ THREAD_EVENT_HANDLER **hands;
+
+ hands = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
+ &thread_event_ossl_ctx_method);
+ if (hands != NULL)
+ ossl_init_thread_stop(hands);
+}
+#endif /* FIPS_MODE */
+
static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands)
{
THREAD_EVENT_HANDLER *curr, *prev = NULL;
@@ -97,21 +153,28 @@ static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands)
OPENSSL_free(hands);
}
-void OPENSSL_thread_stop(void)
-{
- if (destructor_key.sane != -1)
- ossl_init_thread_stop(ossl_init_get_thread_local(0));
-}
-
int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn)
{
THREAD_EVENT_HANDLER **hands;
THREAD_EVENT_HANDLER *hand;
- if (!OPENSSL_init_crypto(0, NULL))
- return 0;
-
+#ifdef FIPS_MODE
+ /*
+ * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
+ * of OPENSSL_CTX and thread. This is because in FIPS mode each OPENSSL_CTX
+ * gets informed about thread stop events individually.
+ */
+ hands = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
+ &thread_event_ossl_ctx_method);
+#else
+ /*
+ * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
+ * thread, but may hold multiple OPENSSL_CTXs. We only get told about
+ * thread stop events globally, so we have to ensure all affected
+ * OPENSSL_CTXs are informed.
+ */
hands = ossl_init_get_thread_local(1);
+#endif
if (hands == NULL)
return 0;