From: Matt Caswell Date: Fri, 24 May 2019 17:20:49 +0000 (+0100) Subject: Provide a version of ossl_init_thread_start that works in FIPS mode X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e41faf5784382a5d2bc23abebcf81b9f4708f6ec;p=openssl 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 (Merged from https://github.com/openssl/openssl/pull/9040) --- diff --git a/crypto/include/internal/cryptlib_int.h b/crypto/include/internal/cryptlib_int.h index e810ef02eb..0e7a0d41d2 100644 --- a/crypto/include/internal/cryptlib_int.h +++ b/crypto/include/internal/cryptlib_int.h @@ -16,6 +16,7 @@ int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn); int init_thread(void); void cleanup_thread(void); +void fips_thread_stop(OPENSSL_CTX *ctx); /* * OPENSSL_INIT flags. The primary list of these is in crypto.h. Flags below 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; diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 025e1acdfe..c40bb2601d 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -149,7 +149,8 @@ typedef struct ossl_ex_data_global_st { # define OPENSSL_CTX_DRBG_INDEX 5 # define OPENSSL_CTX_DRBG_NONCE_INDEX 6 # define OPENSSL_CTX_RAND_CRNGT_INDEX 7 -# define OPENSSL_CTX_MAX_INDEXES 8 +# define OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX 8 +# define OPENSSL_CTX_MAX_INDEXES 9 typedef struct openssl_ctx_method { void *(*new_func)(OPENSSL_CTX *ctx);