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)
This commit is contained in:
Matt Caswell 2019-05-24 18:20:49 +01:00
parent 72592b8664
commit e41faf5784
3 changed files with 77 additions and 12 deletions

View file

@ -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

View file

@ -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;

View file

@ -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);