[openssl] master update

Matt Caswell matt at openssl.org
Thu May 2 21:46:13 UTC 2019


The branch master has been updated
       via  25b25b0f80f2b3f0c5449a6d5a8e7639187f9bf3 (commit)
       via  65a1e917a6be8c5a776a593b7bed9a52c950c71b (commit)
       via  1aedc35fd6c2f40f269c88b2f7d5a617172b47c5 (commit)
       via  b8fe36fee000970dcb7cd363f31445969cfbf677 (commit)
      from  61783db5b5c4c5edbdb47d6a7d0393782e72685d (commit)


- Log -----------------------------------------------------------------
commit 25b25b0f80f2b3f0c5449a6d5a8e7639187f9bf3
Author: Matt Caswell <matt at openssl.org>
Date:   Thu May 2 14:32:44 2019 +0100

    Update internal documentation after global data move to OPENSSL_CTX
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8857)

commit 65a1e917a6be8c5a776a593b7bed9a52c950c71b
Author: Matt Caswell <matt at openssl.org>
Date:   Thu May 2 13:42:31 2019 +0100

    Add some TODO notes into init.c
    
    We should be seeking to move the OPENSSL_init_crypto and OPENSSL_cleanup
    processing into OPENSSL_CTX instead.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8857)

commit 1aedc35fd6c2f40f269c88b2f7d5a617172b47c5
Author: Matt Caswell <matt at openssl.org>
Date:   Wed May 1 11:02:43 2019 +0100

    Instead of global data store it in an OPENSSL_CTX
    
    Various core and property related code files used global data. We should
    store all of that in an OPENSSL_CTX instead.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8857)

commit b8fe36fee000970dcb7cd363f31445969cfbf677
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Apr 30 15:15:48 2019 +0100

    Add support for openssl_ctx_run_once and openssl_ctx_onfree
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8857)

-----------------------------------------------------------------------

Summary of changes:
 crypto/context.c                            | 212 +++++++++++++++++++++++++---
 crypto/core_fetch.c                         |   2 +-
 crypto/cpt_err.c                            |   8 +-
 crypto/err/openssl.txt                      |   2 +
 crypto/evp/evp_fetch.c                      |  32 +----
 crypto/ex_data.c                            | 164 ++++++++++++---------
 crypto/init.c                               |  17 ++-
 crypto/property/defn_cache.c                |  41 ++++--
 crypto/property/property.c                  |  50 +++----
 crypto/property/property_lcl.h              |  25 ++--
 crypto/property/property_parse.c            |  46 +++---
 crypto/property/property_string.c           |  97 +++++++++----
 crypto/provider_core.c                      |  18 +--
 doc/internal/man3/OSSL_METHOD_STORE.pod     |  14 +-
 doc/internal/man3/openssl_ctx_get_data.pod  |  90 ++++++++----
 doc/internal/man3/ossl_method_construct.pod |   5 +-
 include/internal/core.h                     |   2 +-
 include/internal/cryptlib.h                 |  72 +++++++++-
 include/internal/property.h                 |   5 +-
 include/openssl/crypto.h                    |   1 +
 include/openssl/cryptoerr.h                 |   4 +-
 test/build.info                             |   2 +-
 test/context_internal_test.c                |  20 +--
 test/property_test.c                        |  72 +++++-----
 24 files changed, 658 insertions(+), 343 deletions(-)

diff --git a/crypto/context.c b/crypto/context.c
index 752711b..be2d348 100644
--- a/crypto/context.c
+++ b/crypto/context.c
@@ -10,38 +10,106 @@
 #include "internal/cryptlib.h"
 #include "internal/thread_once.h"
 
+struct openssl_ctx_onfree_list_st {
+    openssl_ctx_onfree_fn *fn;
+    struct openssl_ctx_onfree_list_st *next;
+};
+
 struct openssl_ctx_st {
     CRYPTO_RWLOCK *lock;
     CRYPTO_EX_DATA data;
+
+    /*
+     * For most data in the OPENSSL_CTX we just use ex_data to store it. But
+     * that doesn't work for ex_data itself - so we store that directly.
+     */
+    OSSL_EX_DATA_GLOBAL global;
+
+    /* Map internal static indexes to dynamically created indexes */
+    int dyn_indexes[OPENSSL_CTX_MAX_INDEXES];
+
+    CRYPTO_RWLOCK *oncelock;
+    int run_once_done[OPENSSL_CTX_MAX_RUN_ONCE];
+    int run_once_ret[OPENSSL_CTX_MAX_RUN_ONCE];
+    struct openssl_ctx_onfree_list_st *onfreelist;
 };
 
-static OPENSSL_CTX default_context;
+#ifndef FIPS_MODE
+static OPENSSL_CTX default_context_int;
+#endif
+
+/* Always points at default_context_int if it has been initialised */
+static OPENSSL_CTX *default_context = NULL;
 
 static int context_init(OPENSSL_CTX *ctx)
 {
-    return (ctx->lock = CRYPTO_THREAD_lock_new()) != NULL
-        && CRYPTO_new_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL,
-                              &ctx->data);
+    size_t i;
+
+    ctx->lock = CRYPTO_THREAD_lock_new();
+    if (ctx->lock == NULL)
+        return 0;
+
+    ctx->oncelock = CRYPTO_THREAD_lock_new();
+    if (ctx->oncelock == NULL)
+        goto err;
+
+    for (i = 0; i < OPENSSL_CTX_MAX_INDEXES; i++)
+        ctx->dyn_indexes[i] = -1;
+
+    if (!do_ex_data_init(ctx))
+        goto err;
+
+    if (!crypto_new_ex_data_ex(ctx, CRYPTO_EX_INDEX_OPENSSL_CTX, NULL,
+                               &ctx->data)) {
+        crypto_cleanup_all_ex_data_int(ctx);
+        goto err;
+    }
+
+    return 1;
+ err:
+    CRYPTO_THREAD_lock_free(ctx->oncelock);
+    CRYPTO_THREAD_lock_free(ctx->lock);
+    ctx->lock = NULL;
+    return 0;
 }
 
 static int context_deinit(OPENSSL_CTX *ctx)
 {
+    struct openssl_ctx_onfree_list_st *tmp, *onfree;
+
+    if (ctx == NULL)
+        return 1;
+
+    onfree = ctx->onfreelist;
+    while (onfree != NULL) {
+        onfree->fn(ctx);
+        tmp = onfree;
+        onfree = onfree->next;
+        OPENSSL_free(tmp);
+    }
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL, &ctx->data);
+    crypto_cleanup_all_ex_data_int(ctx);
+    CRYPTO_THREAD_lock_free(ctx->oncelock);
     CRYPTO_THREAD_lock_free(ctx->lock);
+    ctx->lock = NULL;
     return 1;
 }
 
-static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT;
-static void do_default_context_deinit(void)
+#ifndef FIPS_MODE
+void openssl_ctx_default_deinit(void)
 {
-    context_deinit(&default_context);
+    context_deinit(default_context);
 }
+
+static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(do_default_context_init)
 {
-    return OPENSSL_init_crypto(0, NULL)
-        && context_init(&default_context)
-        && OPENSSL_atexit(do_default_context_deinit);
+    if (context_init(&default_context_int))
+        default_context = &default_context_int;
+
+    return 1;
 }
+#endif
 
 OPENSSL_CTX *OPENSSL_CTX_new(void)
 {
@@ -66,7 +134,7 @@ static void openssl_ctx_generic_new(void *parent_ign, void *ptr_ign,
                                     long argl_ign, void *argp)
 {
     const OPENSSL_CTX_METHOD *meth = argp;
-    void *ptr = meth->new_func();
+    void *ptr = meth->new_func(crypto_ex_data_get_openssl_ctx(ad));
 
     if (ptr != NULL)
         CRYPTO_set_ex_data(ad, index, ptr);
@@ -79,32 +147,136 @@ static void openssl_ctx_generic_free(void *parent_ign, void *ptr,
 
     meth->free_func(ptr);
 }
-int openssl_ctx_new_index(const OPENSSL_CTX_METHOD *meth)
+
+/* Non-static so we can use it in context_internal_test */
+static int openssl_ctx_init_index(OPENSSL_CTX *ctx, int static_index,
+                                  const OPENSSL_CTX_METHOD *meth)
 {
-    return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_OPENSSL_CTX, 0, (void *)meth,
-                                   openssl_ctx_generic_new, NULL,
-                                   openssl_ctx_generic_free);
+    int idx;
+
+#ifndef FIPS_MODE
+    if (ctx == NULL) {
+        if (!RUN_ONCE(&default_context_init, do_default_context_init))
+            return 0;
+        ctx = default_context;
+    }
+#endif
+    if (ctx == NULL)
+        return 0;
+
+    idx = crypto_get_ex_new_index_ex(ctx, CRYPTO_EX_INDEX_OPENSSL_CTX, 0,
+                                     (void *)meth,
+                                     openssl_ctx_generic_new,
+                                     NULL, openssl_ctx_generic_free);
+    if (idx < 0)
+        return 0;
+
+    ctx->dyn_indexes[static_index] = idx;
+    return 1;
 }
 
-void *openssl_ctx_get_data(OPENSSL_CTX *ctx, int index)
+void *openssl_ctx_get_data(OPENSSL_CTX *ctx, int index,
+                           const OPENSSL_CTX_METHOD *meth)
 {
     void *data = NULL;
 
+#ifndef FIPS_MODE
     if (ctx == NULL) {
         if (!RUN_ONCE(&default_context_init, do_default_context_init))
-            return 0;
-        ctx = &default_context;
+            return NULL;
+        ctx = default_context;
     }
+#endif
+    if (ctx == NULL)
+        return NULL;
 
     CRYPTO_THREAD_read_lock(ctx->lock);
 
+    if (ctx->dyn_indexes[index] == -1
+            && !openssl_ctx_init_index(ctx, index, meth)) {
+        CRYPTO_THREAD_unlock(ctx->lock);
+        return NULL;
+    }
+
     /* The alloc call ensures there's a value there */
     if (CRYPTO_alloc_ex_data(CRYPTO_EX_INDEX_OPENSSL_CTX, NULL,
-                             &ctx->data, index))
-        data = CRYPTO_get_ex_data(&ctx->data, index);
+                             &ctx->data, ctx->dyn_indexes[index]))
+        data = CRYPTO_get_ex_data(&ctx->data, ctx->dyn_indexes[index]);
 
     CRYPTO_THREAD_unlock(ctx->lock);
 
     return data;
 }
 
+OSSL_EX_DATA_GLOBAL *openssl_ctx_get_ex_data_global(OPENSSL_CTX *ctx)
+{
+    /*
+     * The default context code is not needed in FIPS_MODE and ctx should never
+     * be NULL in the FIPS provider. However we compile this code out to ensure
+     * we fail immediately if ctx == NULL in FIPS_MODE
+     */
+#ifndef FIPS_MODE
+    if (ctx == NULL) {
+        if (!RUN_ONCE(&default_context_init, do_default_context_init))
+            return NULL;
+        ctx = default_context;
+    }
+#endif
+    if (ctx == NULL)
+        return NULL;
+    return &ctx->global;
+}
+
+int openssl_ctx_run_once(OPENSSL_CTX *ctx, unsigned int idx,
+                         openssl_ctx_run_once_fn run_once_fn)
+{
+    int done = 0, ret = 0;
+
+#ifndef FIPS_MODE
+    if (ctx == NULL) {
+        if (!RUN_ONCE(&default_context_init, do_default_context_init))
+            return 0;
+        ctx = default_context;
+    }
+#endif
+    if (ctx == NULL)
+        return 0;
+
+    CRYPTO_THREAD_read_lock(ctx->oncelock);
+    done = ctx->run_once_done[idx];
+    if (done)
+        ret = ctx->run_once_ret[idx];
+    CRYPTO_THREAD_unlock(ctx->oncelock);
+
+    if (done)
+        return ret;
+
+    CRYPTO_THREAD_write_lock(ctx->oncelock);
+    if (ctx->run_once_done[idx]) {
+        ret = ctx->run_once_ret[idx];
+        CRYPTO_THREAD_unlock(ctx->oncelock);
+        return ret;
+    }
+
+    ret = run_once_fn(ctx);
+    ctx->run_once_done[idx] = 1;
+    ctx->run_once_ret[idx] = ret;
+    CRYPTO_THREAD_unlock(ctx->oncelock);
+
+    return ret;
+}
+
+int openssl_ctx_onfree(OPENSSL_CTX *ctx, openssl_ctx_onfree_fn onfreefn)
+{
+    struct openssl_ctx_onfree_list_st *newonfree
+        = OPENSSL_malloc(sizeof(*newonfree));
+
+    if (newonfree == NULL)
+        return 0;
+
+    newonfree->fn = onfreefn;
+    newonfree->next = ctx->onfreelist;
+    ctx->onfreelist = newonfree;
+
+    return 1;
+}
diff --git a/crypto/core_fetch.c b/crypto/core_fetch.c
index 2c4b0d7..6c4ed6a 100644
--- a/crypto/core_fetch.c
+++ b/crypto/core_fetch.c
@@ -86,7 +86,7 @@ void *ossl_method_construct(OPENSSL_CTX *libctx, int operation_id,
          * We have a temporary store to be able to easily search among new
          * items, or items that should find themselves in the global store.
          */
-        if ((cbdata.store = mcm->alloc_tmp_store()) == NULL)
+        if ((cbdata.store = mcm->alloc_tmp_store(libctx)) == NULL)
             goto fin;
 
         cbdata.libctx = libctx;
diff --git a/crypto/cpt_err.c b/crypto/cpt_err.c
index 8c38692..25bb813 100644
--- a/crypto/cpt_err.c
+++ b/crypto/cpt_err.c
@@ -21,9 +21,13 @@ static const ERR_STRING_DATA CRYPTO_str_functs[] = {
      "CRYPTO_free_ex_data"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, 0),
      "CRYPTO_get_ex_new_index"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX, 0),
+     "CRYPTO_get_ex_new_index_ex"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_MEMDUP, 0), "CRYPTO_memdup"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_NEW_EX_DATA, 0),
      "CRYPTO_new_ex_data"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_NEW_EX_DATA_EX, 0),
+     "crypto_new_ex_data_ex"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_OCB128_COPY_CTX, 0),
      "CRYPTO_ocb128_copy_ctx"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_OCB128_INIT, 0),
@@ -46,10 +50,10 @@ static const ERR_STRING_DATA CRYPTO_str_functs[] = {
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OPENSSL_SK_DEEP_COPY, 0),
      "OPENSSL_sk_deep_copy"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OPENSSL_SK_DUP, 0), "OPENSSL_sk_dup"},
-    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN, 0),
-     "OSSL_PROVIDER_add_builtin"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_ACTIVATE, 0),
      "ossl_provider_activate"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN, 0),
+     "OSSL_PROVIDER_add_builtin"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_ADD_PARAMETER, 0),
      "ossl_provider_add_parameter"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_OSSL_PROVIDER_NEW, 0),
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 5c444f5..225fe21 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -374,8 +374,10 @@ CRYPTO_F_CMAC_CTX_NEW:120:CMAC_CTX_new
 CRYPTO_F_CRYPTO_DUP_EX_DATA:110:CRYPTO_dup_ex_data
 CRYPTO_F_CRYPTO_FREE_EX_DATA:111:CRYPTO_free_ex_data
 CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX:100:CRYPTO_get_ex_new_index
+CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX:141:crypto_get_ex_new_index_ex
 CRYPTO_F_CRYPTO_MEMDUP:115:CRYPTO_memdup
 CRYPTO_F_CRYPTO_NEW_EX_DATA:112:CRYPTO_new_ex_data
+CRYPTO_F_CRYPTO_NEW_EX_DATA_EX:142:crypto_new_ex_data_ex
 CRYPTO_F_CRYPTO_OCB128_COPY_CTX:121:CRYPTO_ocb128_copy_ctx
 CRYPTO_F_CRYPTO_OCB128_INIT:122:CRYPTO_ocb128_init
 CRYPTO_F_CRYPTO_SET_EX_DATA:102:CRYPTO_set_ex_data
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
index c054f31..d2c0b62 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -19,17 +19,14 @@
 #include "internal/evp_int.h"    /* evp_locl.h needs it */
 #include "evp_locl.h"
 
-/* The OpenSSL library context index for the default method store */
-static int default_method_store_index = -1;
-
 static void default_method_store_free(void *vstore)
 {
     ossl_method_store_free(vstore);
 }
 
-static void *default_method_store_new(void)
+static void *default_method_store_new(OPENSSL_CTX *ctx)
 {
-    return ossl_method_store_new();
+    return ossl_method_store_new(ctx);
 }
 
 
@@ -38,21 +35,6 @@ static const OPENSSL_CTX_METHOD default_method_store_method = {
     default_method_store_free,
 };
 
-static int default_method_store_init(void)
-{
-    default_method_store_index =
-        openssl_ctx_new_index(&default_method_store_method);
-
-    return default_method_store_index != -1;
-}
-
-static CRYPTO_ONCE default_method_store_init_flag = CRYPTO_ONCE_STATIC_INIT;
-DEFINE_RUN_ONCE_STATIC(do_default_method_store_init)
-{
-    return OPENSSL_init_crypto(0, NULL)
-        && default_method_store_init();
-}
-
 /* Data to be passed through ossl_method_construct() */
 struct method_data_st {
     const char *name;
@@ -68,9 +50,9 @@ struct method_data_st {
 /*
  * Generic routines to fetch / create EVP methods with ossl_method_construct()
  */
-static void *alloc_tmp_method_store(void)
+static void *alloc_tmp_method_store(OPENSSL_CTX *ctx)
 {
-    return ossl_method_store_new();
+    return ossl_method_store_new(ctx);
 }
 
  static void dealloc_tmp_method_store(void *store)
@@ -81,10 +63,8 @@ static void *alloc_tmp_method_store(void)
 
 static OSSL_METHOD_STORE *get_default_method_store(OPENSSL_CTX *libctx)
 {
-    if (!RUN_ONCE(&default_method_store_init_flag,
-                  do_default_method_store_init))
-        return NULL;
-    return openssl_ctx_get_data(libctx, default_method_store_index);
+    return openssl_ctx_get_data(libctx, OPENSSL_CTX_DEFAULT_METHOD_STORE_INDEX,
+                                &default_method_store_method);
 }
 
 static void *get_method_from_store(OPENSSL_CTX *libctx, void *store,
diff --git a/crypto/ex_data.c b/crypto/ex_data.c
index 5f83191..d9dd3d2 100644
--- a/crypto/ex_data.c
+++ b/crypto/ex_data.c
@@ -10,58 +10,33 @@
 #include "internal/cryptlib_int.h"
 #include "internal/thread_once.h"
 
-/*
- * Each structure type (sometimes called a class), that supports
- * exdata has a stack of callbacks for each instance.
- */
-struct ex_callback_st {
-    long argl;                  /* Arbitrary long */
-    void *argp;                 /* Arbitrary void * */
-    CRYPTO_EX_new *new_func;
-    CRYPTO_EX_free *free_func;
-    CRYPTO_EX_dup *dup_func;
-};
-
-/*
- * The state for each class.  This could just be a typedef, but
- * a structure allows future changes.
- */
-typedef struct ex_callbacks_st {
-    STACK_OF(EX_CALLBACK) *meth;
-} EX_CALLBACKS;
-
-static EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT];
-
-static CRYPTO_RWLOCK *ex_data_lock = NULL;
-static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT;
-
-DEFINE_RUN_ONCE_STATIC(do_ex_data_init)
+int do_ex_data_init(OPENSSL_CTX *ctx)
 {
-    if (!OPENSSL_init_crypto(0, NULL))
+    OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
+
+    if (global == NULL)
         return 0;
-    ex_data_lock = CRYPTO_THREAD_lock_new();
-    return ex_data_lock != NULL;
+
+    global->ex_data_lock = CRYPTO_THREAD_lock_new();
+    return global->ex_data_lock != NULL;
 }
 
 /*
  * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
  * a given class.  On success, *holds the lock.*
  */
-static EX_CALLBACKS *get_and_lock(int class_index)
+static EX_CALLBACKS *get_and_lock(OPENSSL_CTX *ctx, int class_index)
 {
     EX_CALLBACKS *ip;
+    OSSL_EX_DATA_GLOBAL *global = NULL;
 
     if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
         CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_PASSED_INVALID_ARGUMENT);
         return NULL;
     }
 
-    if (!RUN_ONCE(&ex_data_init, do_ex_data_init)) {
-        CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE);
-        return NULL;
-    }
-
-    if (ex_data_lock == NULL) {
+    global = openssl_ctx_get_ex_data_global(ctx);
+    if (global->ex_data_lock == NULL) {
         /*
          * This can happen in normal operation when using CRYPTO_mem_leaks().
          * The CRYPTO_mem_leaks() function calls OPENSSL_cleanup() which cleans
@@ -74,8 +49,8 @@ static EX_CALLBACKS *get_and_lock(int class_index)
          return NULL;
     }
 
-    ip = &ex_data[class_index];
-    CRYPTO_THREAD_write_lock(ex_data_lock);
+    ip = &global->ex_data[class_index];
+    CRYPTO_THREAD_write_lock(global->ex_data_lock);
     return ip;
 }
 
@@ -90,19 +65,23 @@ static void cleanup_cb(EX_CALLBACK *funcs)
  * called under potential race-conditions anyway (it's for program shutdown
  * after all).
  */
-void crypto_cleanup_all_ex_data_int(void)
+void crypto_cleanup_all_ex_data_int(OPENSSL_CTX *ctx)
 {
     int i;
+    OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
+
+    if (global == NULL)
+        return;
 
     for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
-        EX_CALLBACKS *ip = &ex_data[i];
+        EX_CALLBACKS *ip = &global->ex_data[i];
 
         sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
         ip->meth = NULL;
     }
 
-    CRYPTO_THREAD_lock_free(ex_data_lock);
-    ex_data_lock = NULL;
+    CRYPTO_THREAD_lock_free(global->ex_data_lock);
+    global->ex_data_lock = NULL;
 }
 
 
@@ -127,12 +106,17 @@ static int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
     return 1;
 }
 
-int CRYPTO_free_ex_index(int class_index, int idx)
+int crypto_free_ex_index_ex(OPENSSL_CTX *ctx, int class_index, int idx)
 {
-    EX_CALLBACKS *ip = get_and_lock(class_index);
+    EX_CALLBACKS *ip = get_and_lock(ctx, class_index);
     EX_CALLBACK *a;
     int toret = 0;
+    OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
+
+    if (global == NULL)
+        goto err;
 
+    ip = get_and_lock(ctx, class_index);
     if (ip == NULL)
         return 0;
     if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
@@ -145,21 +129,32 @@ int CRYPTO_free_ex_index(int class_index, int idx)
     a->free_func = dummy_free;
     toret = 1;
 err:
-    CRYPTO_THREAD_unlock(ex_data_lock);
+    CRYPTO_THREAD_unlock(global->ex_data_lock);
     return toret;
 }
 
+int CRYPTO_free_ex_index(int class_index, int idx)
+{
+    return crypto_free_ex_index_ex(NULL, class_index, idx);
+}
+
 /*
  * Register a new index.
  */
-int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
-                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
-                            CRYPTO_EX_free *free_func)
+int crypto_get_ex_new_index_ex(OPENSSL_CTX *ctx, int class_index, long argl,
+                               void *argp, CRYPTO_EX_new *new_func,
+                               CRYPTO_EX_dup *dup_func,
+                               CRYPTO_EX_free *free_func)
 {
     int toret = -1;
     EX_CALLBACK *a;
-    EX_CALLBACKS *ip = get_and_lock(class_index);
+    EX_CALLBACKS *ip;
+    OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
 
+    if (global == NULL)
+        goto err;
+
+    ip = get_and_lock(ctx, class_index);
     if (ip == NULL)
         return -1;
 
@@ -169,14 +164,14 @@ int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
          * "app_data" routines use ex_data index zero.  See RT 3710. */
         if (ip->meth == NULL
             || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
-            CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
+            CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX, ERR_R_MALLOC_FAILURE);
             goto err;
         }
     }
 
     a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
     if (a == NULL) {
-        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
+        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX, ERR_R_MALLOC_FAILURE);
         goto err;
     }
     a->argl = argl;
@@ -186,7 +181,7 @@ int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
     a->free_func = free_func;
 
     if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
-        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
+        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX, ERR_R_MALLOC_FAILURE);
         OPENSSL_free(a);
         goto err;
     }
@@ -194,10 +189,18 @@ int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
     (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
 
  err:
-    CRYPTO_THREAD_unlock(ex_data_lock);
+    CRYPTO_THREAD_unlock(global->ex_data_lock);
     return toret;
 }
 
+int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
+                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
+                            CRYPTO_EX_free *free_func)
+{
+    return crypto_get_ex_new_index_ex(NULL, class_index, argl, argp, new_func,
+                                      dup_func, free_func);
+}
+
 /*
  * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
  * calling new() callbacks for each index in the class used by this variable
@@ -205,17 +208,24 @@ int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
  * in the lock, then using them outside the lock. Note this only applies
  * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
  */
-int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
+int crypto_new_ex_data_ex(OPENSSL_CTX *ctx, int class_index, void *obj,
+                          CRYPTO_EX_DATA *ad)
 {
     int mx, i;
     void *ptr;
     EX_CALLBACK **storage = NULL;
     EX_CALLBACK *stack[10];
-    EX_CALLBACKS *ip = get_and_lock(class_index);
+    EX_CALLBACKS *ip;
+    OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
+
+    if (global == NULL)
+        return 0;
 
+    ip = get_and_lock(ctx, class_index);
     if (ip == NULL)
         return 0;
 
+    ad->ctx = ctx;
     ad->sk = NULL;
 
     mx = sk_EX_CALLBACK_num(ip->meth);
@@ -228,10 +238,10 @@ int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
             for (i = 0; i < mx; i++)
                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
     }
-    CRYPTO_THREAD_unlock(ex_data_lock);
+    CRYPTO_THREAD_unlock(global->ex_data_lock);
 
     if (mx > 0 && storage == NULL) {
-        CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
+        CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA_EX, ERR_R_MALLOC_FAILURE);
         return 0;
     }
     for (i = 0; i < mx; i++) {
@@ -246,6 +256,11 @@ int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
     return 1;
 }
 
+int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
+{
+    return crypto_new_ex_data_ex(NULL, class_index, obj, ad);
+}
+
 /*
  * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
  * for each index in the class used by this variable
@@ -259,11 +274,16 @@ int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
     EX_CALLBACK **storage = NULL;
     EX_CALLBACKS *ip;
     int toret = 0;
+    OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(from->ctx);
+
+    if (global == NULL)
+        return 0;
 
+    to->ctx = from->ctx;
     if (from->sk == NULL)
         /* Nothing to copy over */
         return 1;
-    if ((ip = get_and_lock(class_index)) == NULL)
+    if ((ip = get_and_lock(from->ctx, class_index)) == NULL)
         return 0;
 
     mx = sk_EX_CALLBACK_num(ip->meth);
@@ -279,7 +299,7 @@ int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
             for (i = 0; i < mx; i++)
                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
     }
-    CRYPTO_THREAD_unlock(ex_data_lock);
+    CRYPTO_THREAD_unlock(global->ex_data_lock);
 
     if (mx == 0)
         return 1;
@@ -325,8 +345,12 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
     EX_CALLBACK *f;
     EX_CALLBACK *stack[10];
     EX_CALLBACK **storage = NULL;
+    OSSL_EX_DATA_GLOBAL *global;
 
-    if ((ip = get_and_lock(class_index)) == NULL)
+    if ((ip = get_and_lock(ad->ctx, class_index)) == NULL)
+        goto err;
+    global = openssl_ctx_get_ex_data_global(ad->ctx);
+    if (global == NULL)
         goto err;
 
     mx = sk_EX_CALLBACK_num(ip->meth);
@@ -339,15 +363,15 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
             for (i = 0; i < mx; i++)
                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
     }
-    CRYPTO_THREAD_unlock(ex_data_lock);
+    CRYPTO_THREAD_unlock(global->ex_data_lock);
 
     for (i = 0; i < mx; i++) {
         if (storage != NULL)
             f = storage[i];
         else {
-            CRYPTO_THREAD_write_lock(ex_data_lock);
+            CRYPTO_THREAD_write_lock(global->ex_data_lock);
             f = sk_EX_CALLBACK_value(ip->meth, i);
-            CRYPTO_THREAD_unlock(ex_data_lock);
+            CRYPTO_THREAD_unlock(global->ex_data_lock);
         }
         if (f != NULL && f->free_func != NULL) {
             ptr = CRYPTO_get_ex_data(ad, i);
@@ -360,6 +384,7 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
  err:
     sk_void_free(ad->sk);
     ad->sk = NULL;
+    ad->ctx = NULL;
 }
 
 /*
@@ -372,6 +397,10 @@ int CRYPTO_alloc_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad,
     EX_CALLBACK *f;
     EX_CALLBACKS *ip;
     void *curval;
+    OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ad->ctx);
+
+    if (global == NULL)
+        return 0;
 
     curval = CRYPTO_get_ex_data(ad, idx);
 
@@ -379,11 +408,11 @@ int CRYPTO_alloc_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad,
     if (curval != NULL)
         return 1;
 
-    ip = get_and_lock(class_index);
+    ip = get_and_lock(ad->ctx, class_index);
     if (ip == NULL)
         return 0;
     f = sk_EX_CALLBACK_value(ip->meth, idx);
-    CRYPTO_THREAD_unlock(ex_data_lock);
+    CRYPTO_THREAD_unlock(global->ex_data_lock);
 
     /*
      * This should end up calling CRYPTO_set_ex_data(), which allocates
@@ -432,3 +461,8 @@ void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
         return NULL;
     return sk_void_value(ad->sk, idx);
 }
+
+OPENSSL_CTX *crypto_ex_data_get_openssl_ctx(const CRYPTO_EX_DATA *ad)
+{
+    return ad->ctx;
+}
diff --git a/crypto/init.c b/crypto/init.c
index 43fe1a6..d2048ea 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -468,6 +468,11 @@ void OPENSSL_cleanup(void)
     OPENSSL_INIT_STOP *currhandler, *lasthandler;
     CRYPTO_THREAD_LOCAL key;
 
+    /*
+     * TODO(3.0): This function needs looking at with a view to moving most/all
+     * of this into onfree handlers in OPENSSL_CTX.
+     */
+
     /* If we've not been inited then no need to deinit */
     if (!base_inited)
         return;
@@ -526,7 +531,7 @@ void OPENSSL_cleanup(void)
      * - rand_cleanup_int could call an ENGINE's RAND cleanup function so
      * must be called before engine_cleanup_int()
      * - ENGINEs use CRYPTO_EX_DATA and therefore, must be cleaned up
-     * before the ex data handlers are wiped in CRYPTO_cleanup_all_ex_data().
+     * before the ex data handlers are wiped during default openssl_ctx deinit.
      * - conf_modules_free_int() can end up in ENGINE code so must be called
      * before engine_cleanup_int()
      * - ENGINEs and additional EVP algorithms might use added OIDs names so
@@ -540,6 +545,7 @@ void OPENSSL_cleanup(void)
 
     OSSL_TRACE(INIT, "OPENSSL_cleanup: conf_modules_free_int()\n");
     conf_modules_free_int();
+
 #ifndef OPENSSL_NO_ENGINE
     OSSL_TRACE(INIT, "OPENSSL_cleanup: engine_cleanup_int()\n");
     engine_cleanup_int();
@@ -547,8 +553,8 @@ void OPENSSL_cleanup(void)
     OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_store_cleanup_int()\n");
     ossl_store_cleanup_int();
 
-    OSSL_TRACE(INIT, "OPENSSL_cleanup: crypto_cleanup_all_ex_data_int()\n");
-    crypto_cleanup_all_ex_data_int();
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: openssl_ctx_default_deinit()\n");
+    openssl_ctx_default_deinit();
 
     OSSL_TRACE(INIT, "OPENSSL_cleanup: bio_cleanup()\n");
     bio_cleanup();
@@ -578,6 +584,11 @@ void OPENSSL_cleanup(void)
  */
 int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
 {
+    /*
+     * TODO(3.0): This function needs looking at with a view to moving most/all
+     * of this into OPENSSL_CTX.
+     */
+
     if (stopped) {
         if (!(opts & OPENSSL_INIT_BASE_ONLY))
             CRYPTOerr(CRYPTO_F_OPENSSL_INIT_CRYPTO, ERR_R_INIT_FAIL);
diff --git a/crypto/property/defn_cache.c b/crypto/property/defn_cache.c
index df87c19..aec05c1 100644
--- a/crypto/property/defn_cache.c
+++ b/crypto/property/defn_cache.c
@@ -29,8 +29,6 @@ typedef struct {
 
 DEFINE_LHASH_OF(PROPERTY_DEFN_ELEM);
 
-static LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns = NULL;
-
 static unsigned long property_defn_hash(const PROPERTY_DEFN_ELEM *a)
 {
     return OPENSSL_LH_strhash(a->prop);
@@ -48,35 +46,52 @@ static void property_defn_free(PROPERTY_DEFN_ELEM *elem)
     OPENSSL_free(elem);
 }
 
-int ossl_prop_defn_init(void)
+static void property_defns_free(void *vproperty_defns)
 {
-    property_defns = lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash,
-                                               &property_defn_cmp);
-    return property_defns != NULL;
-}
+    LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns = vproperty_defns;
 
-void ossl_prop_defn_cleanup(void)
-{
     if (property_defns != NULL) {
-        lh_PROPERTY_DEFN_ELEM_doall(property_defns, &property_defn_free);
+        lh_PROPERTY_DEFN_ELEM_doall(property_defns,
+                                    &property_defn_free);
         lh_PROPERTY_DEFN_ELEM_free(property_defns);
-        property_defns = NULL;
     }
 }
 
-OSSL_PROPERTY_LIST *ossl_prop_defn_get(const char *prop)
+static void *property_defns_new(OPENSSL_CTX *ctx) {
+    return lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash, &property_defn_cmp);
+}
+
+static const OPENSSL_CTX_METHOD property_defns_method = {
+    property_defns_new,
+    property_defns_free,
+};
+
+OSSL_PROPERTY_LIST *ossl_prop_defn_get(OPENSSL_CTX *ctx, const char *prop)
 {
     PROPERTY_DEFN_ELEM elem, *r;
+    LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns;
+
+    property_defns = openssl_ctx_get_data(ctx, OPENSSL_CTX_PROPERTY_DEFN_INDEX,
+                                          &property_defns_method);
+    if (property_defns == NULL)
+        return NULL;
 
     elem.prop = prop;
     r = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem);
     return r != NULL ? r->defn : NULL;
 }
 
-int ossl_prop_defn_set(const char *prop, OSSL_PROPERTY_LIST *pl)
+int ossl_prop_defn_set(OPENSSL_CTX *ctx, const char *prop,
+                       OSSL_PROPERTY_LIST *pl)
 {
     PROPERTY_DEFN_ELEM elem, *old, *p = NULL;
     size_t len;
+    LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns;
+
+    property_defns = openssl_ctx_get_data(ctx, OPENSSL_CTX_PROPERTY_DEFN_INDEX,
+                                          &property_defns_method);
+    if (property_defns == NULL)
+        return 0;
 
     if (prop == NULL)
         return 1;
diff --git a/crypto/property/property.c b/crypto/property/property.c
index a2122dc..930c89b 100644
--- a/crypto/property/property.c
+++ b/crypto/property/property.c
@@ -47,6 +47,7 @@ typedef struct {
 } ALGORITHM;
 
 struct ossl_method_store_st {
+    OPENSSL_CTX *ctx;
     size_t nelem;
     SPARSE_ARRAY_OF(ALGORITHM) *algs;
     OSSL_PROPERTY_LIST *global_properties;
@@ -82,29 +83,10 @@ int ossl_property_unlock(OSSL_METHOD_STORE *p)
     return p != 0 ? CRYPTO_THREAD_unlock(p->lock) : 0;
 }
 
-int ossl_method_store_init(void)
+static openssl_ctx_run_once_fn do_method_store_init;
+int do_method_store_init(OPENSSL_CTX *ctx)
 {
-    if (ossl_property_string_init()
-            && ossl_prop_defn_init()
-            && ossl_property_parse_init())
-        return 1;
-
-    ossl_method_store_cleanup();
-    return 0;
-}
-
-void ossl_method_store_cleanup(void)
-{
-    ossl_property_string_cleanup();
-    ossl_prop_defn_cleanup();
-}
-
-static CRYPTO_ONCE method_store_init_flag = CRYPTO_ONCE_STATIC_INIT;
-DEFINE_RUN_ONCE_STATIC(do_method_store_init)
-{
-    return OPENSSL_init_crypto(0, NULL)
-        && ossl_method_store_init()
-        && OPENSSL_atexit(&ossl_method_store_cleanup);
+    return ossl_property_parse_init(ctx);
 }
 
 static unsigned long query_hash(const QUERY *a)
@@ -141,15 +123,22 @@ static void alg_cleanup(ossl_uintmax_t idx, ALGORITHM *a)
     }
 }
 
-OSSL_METHOD_STORE *ossl_method_store_new(void)
+/*
+ * The OPENSSL_CTX param here allows access to underlying property data needed
+ * for computation
+ */
+OSSL_METHOD_STORE *ossl_method_store_new(OPENSSL_CTX *ctx)
 {
     OSSL_METHOD_STORE *res;
 
-    if (!RUN_ONCE(&method_store_init_flag, do_method_store_init))
-        return 0;
+    if (!openssl_ctx_run_once(ctx,
+                              OPENSSL_CTX_METHOD_STORE_RUN_ONCE_INDEX,
+                              do_method_store_init))
+        return NULL;
 
     res = OPENSSL_zalloc(sizeof(*res));
     if (res != NULL) {
+        res->ctx = ctx;
         if ((res->algs = ossl_sa_ALGORITHM_new()) == NULL) {
             OPENSSL_free(res);
             return NULL;
@@ -212,10 +201,11 @@ int ossl_method_store_add(OSSL_METHOD_STORE *store,
      */
     ossl_property_write_lock(store);
     ossl_method_cache_flush(store, nid);
-    if ((impl->properties = ossl_prop_defn_get(properties)) == NULL) {
-        if ((impl->properties = ossl_parse_property(properties)) == NULL)
+    if ((impl->properties = ossl_prop_defn_get(store->ctx, properties)) == NULL) {
+        impl->properties = ossl_parse_property(store->ctx, properties);
+        if (impl->properties == NULL)
             goto err;
-        ossl_prop_defn_set(properties, impl->properties);
+        ossl_prop_defn_set(store->ctx, properties, impl->properties);
     }
 
     alg = ossl_method_store_retrieve(store, nid);
@@ -310,7 +300,7 @@ int ossl_method_store_fetch(OSSL_METHOD_STORE *store, int nid,
         }
         goto fin;
     }
-    pq = ossl_parse_query(prop_query);
+    pq = ossl_parse_query(store->ctx, prop_query);
     if (pq == NULL)
         goto fin;
     if (store->global_properties != NULL) {
@@ -350,7 +340,7 @@ int ossl_method_store_set_global_properties(OSSL_METHOD_STORE *store,
         ossl_property_unlock(store);
         return 1;
     }
-    store->global_properties = ossl_parse_query(prop_query);
+    store->global_properties = ossl_parse_query(store->ctx, prop_query);
     ret = store->global_properties != NULL;
     ossl_property_unlock(store);
     return ret;
diff --git a/crypto/property/property_lcl.h b/crypto/property/property_lcl.h
index faf3fe1..304dc22 100644
--- a/crypto/property/property_lcl.h
+++ b/crypto/property/property_lcl.h
@@ -14,18 +14,14 @@
 typedef struct ossl_property_list_st OSSL_PROPERTY_LIST;
 typedef int OSSL_PROPERTY_IDX;
 
-/* Initialisation and finalisation for subsystem */
-int ossl_method_store_init(void);
-void ossl_method_store_cleanup(void);
-
 /* Property string functions */
-OSSL_PROPERTY_IDX ossl_property_name(const char *s, int create);
-OSSL_PROPERTY_IDX ossl_property_value(const char *s, int create);
-int ossl_property_string_init(void);
-void ossl_property_string_cleanup(void);
+OSSL_PROPERTY_IDX ossl_property_name(OPENSSL_CTX *ctx, const char *s,
+                                     int create);
+OSSL_PROPERTY_IDX ossl_property_value(OPENSSL_CTX *ctx, const char *s,
+                                      int create);
 
 /* Property list functions */
-int ossl_property_parse_init(void);
+int ossl_property_parse_init(OPENSSL_CTX *ctx);
 void ossl_property_free(OSSL_PROPERTY_LIST *p);
 int ossl_property_match(const OSSL_PROPERTY_LIST *query,
                         const OSSL_PROPERTY_LIST *defn);
@@ -33,16 +29,15 @@ OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
                                         const OSSL_PROPERTY_LIST *b);
 
 /* Property definition functions */
-OSSL_PROPERTY_LIST *ossl_parse_property(const char *s);
+OSSL_PROPERTY_LIST *ossl_parse_property(OPENSSL_CTX *ctx, const char *s);
 
 /* Property query functions */
-OSSL_PROPERTY_LIST *ossl_parse_query(const char *s);
+OSSL_PROPERTY_LIST *ossl_parse_query(OPENSSL_CTX *ctx, const char *s);
 
 /* Property definition cache functions */
-int ossl_prop_defn_init(void);
-void ossl_prop_defn_cleanup(void);
-OSSL_PROPERTY_LIST *ossl_prop_defn_get(const char *prop);
-int ossl_prop_defn_set(const char *prop, OSSL_PROPERTY_LIST *pl);
+OSSL_PROPERTY_LIST *ossl_prop_defn_get(OPENSSL_CTX *ctx, const char *prop);
+int ossl_prop_defn_set(OPENSSL_CTX *ctx, const char *prop,
+                       OSSL_PROPERTY_LIST *pl);
 
 /* Property cache lock / unlock */
 int ossl_property_write_lock(OSSL_METHOD_STORE *);
diff --git a/crypto/property/property_parse.c b/crypto/property/property_parse.c
index faaaee8..efc459a 100644
--- a/crypto/property/property_parse.c
+++ b/crypto/property/property_parse.c
@@ -78,7 +78,8 @@ static int match(const char *t[], const char m[], size_t m_len)
     return 0;
 }
 
-static int parse_name(const char *t[], int create, OSSL_PROPERTY_IDX *idx)
+static int parse_name(OPENSSL_CTX *ctx, const char *t[], int create,
+                      OSSL_PROPERTY_IDX *idx)
 {
     char name[100];
     int err = 0;
@@ -109,7 +110,7 @@ static int parse_name(const char *t[], int create, OSSL_PROPERTY_IDX *idx)
     name[i] = '\0';
     *t = skip_space(s);
     if (!err) {
-        *idx = ossl_property_name(name, user_name && create);
+        *idx = ossl_property_name(ctx, name, user_name && create);
         return 1;
     }
     PROPerr(PROP_F_PARSE_NAME, PROP_R_NAME_TOO_LONG);
@@ -180,8 +181,8 @@ static int parse_oct(const char *t[], PROPERTY_DEFINITION *res)
     return 1;
 }
 
-static int parse_string(const char *t[], char delim, PROPERTY_DEFINITION *res,
-                        const int create)
+static int parse_string(OPENSSL_CTX *ctx, const char *t[], char delim,
+                        PROPERTY_DEFINITION *res, const int create)
 {
     char v[1000];
     const char *s = *t;
@@ -205,13 +206,13 @@ static int parse_string(const char *t[], char delim, PROPERTY_DEFINITION *res,
     if (err)
         PROPerr(PROP_F_PARSE_STRING, PROP_R_STRING_TOO_LONG);
     else
-        res->v.str_val = ossl_property_value(v, create);
+        res->v.str_val = ossl_property_value(ctx, v, create);
     res->type = PROPERTY_TYPE_STRING;
     return !err;
 }
 
-static int parse_unquoted(const char *t[], PROPERTY_DEFINITION *res,
-                          const int create)
+static int parse_unquoted(OPENSSL_CTX *ctx, const char *t[],
+                          PROPERTY_DEFINITION *res, const int create)
 {
     char v[1000];
     const char *s = *t;
@@ -236,19 +237,20 @@ static int parse_unquoted(const char *t[], PROPERTY_DEFINITION *res,
     if (err)
         PROPerr(PROP_F_PARSE_UNQUOTED, PROP_R_STRING_TOO_LONG);
     else
-        res->v.str_val = ossl_property_value(v, create);
+        res->v.str_val = ossl_property_value(ctx, v, create);
     res->type = PROPERTY_TYPE_STRING;
     return !err;
 }
 
-static int parse_value(const char *t[], PROPERTY_DEFINITION *res, int create)
+static int parse_value(OPENSSL_CTX *ctx, const char *t[],
+                       PROPERTY_DEFINITION *res, int create)
 {
     const char *s = *t;
     int r = 0;
 
     if (*s == '"' || *s == '\'') {
         s++;
-        r = parse_string(&s, s[-1], res, create);
+        r = parse_string(ctx, &s, s[-1], res, create);
     } else if (*s == '+') {
         s++;
         r = parse_number(&s, res);
@@ -265,7 +267,7 @@ static int parse_value(const char *t[], PROPERTY_DEFINITION *res, int create)
     } else if (ossl_isdigit(*s)) {
         return parse_number(t, res);
     } else if (ossl_isalpha(*s))
-        return parse_unquoted(t, res, create);
+        return parse_unquoted(ctx, t, res, create);
     if (r)
         *t = s;
     return r;
@@ -312,7 +314,7 @@ static OSSL_PROPERTY_LIST *stack_to_property_list(STACK_OF(PROPERTY_DEFINITION)
     return r;
 }
 
-OSSL_PROPERTY_LIST *ossl_parse_property(const char *defn)
+OSSL_PROPERTY_LIST *ossl_parse_property(OPENSSL_CTX *ctx, const char *defn)
 {
     PROPERTY_DEFINITION *prop = NULL;
     OSSL_PROPERTY_LIST *res = NULL;
@@ -330,7 +332,7 @@ OSSL_PROPERTY_LIST *ossl_parse_property(const char *defn)
         if (prop == NULL)
             goto err;
         memset(&prop->v, 0, sizeof(prop->v));
-        if (!parse_name(&s, 1, &prop->name_idx))
+        if (!parse_name(ctx, &s, 1, &prop->name_idx))
             goto err;
         prop->oper = PROPERTY_OPER_EQ;
         if (prop->name_idx == 0) {
@@ -338,7 +340,7 @@ OSSL_PROPERTY_LIST *ossl_parse_property(const char *defn)
             goto err;
         }
         if (match_ch(&s, '=')) {
-            if (!parse_value(&s, prop, 1)) {
+            if (!parse_value(ctx, &s, prop, 1)) {
                 PROPerr(PROP_F_OSSL_PARSE_PROPERTY, PROP_R_NO_VALUE);
                 goto err;
             }
@@ -365,7 +367,7 @@ err:
     return res;
 }
 
-OSSL_PROPERTY_LIST *ossl_parse_query(const char *s)
+OSSL_PROPERTY_LIST *ossl_parse_query(OPENSSL_CTX *ctx, const char *s)
 {
     STACK_OF(PROPERTY_DEFINITION) *sk;
     OSSL_PROPERTY_LIST *res = NULL;
@@ -385,11 +387,11 @@ OSSL_PROPERTY_LIST *ossl_parse_query(const char *s)
 
         if (match_ch(&s, '-')) {
             prop->oper = PROPERTY_OVERRIDE;
-            if (!parse_name(&s, 0, &prop->name_idx))
+            if (!parse_name(ctx, &s, 0, &prop->name_idx))
                 goto err;
             goto skip_value;
         }
-        if (!parse_name(&s, 0, &prop->name_idx))
+        if (!parse_name(ctx, &s, 0, &prop->name_idx))
             goto err;
 
         if (match_ch(&s, '=')) {
@@ -403,7 +405,7 @@ OSSL_PROPERTY_LIST *ossl_parse_query(const char *s)
             prop->v.str_val = ossl_property_true;
             goto skip_value;
         }
-        if (!parse_value(&s, prop, 0))
+        if (!parse_value(ctx, &s, prop, 0))
             prop->type = PROPERTY_TYPE_VALUE_UNDEFINED;
 
 skip_value:
@@ -519,7 +521,7 @@ OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
     return r;
 }
 
-int ossl_property_parse_init(void)
+int ossl_property_parse_init(OPENSSL_CTX *ctx)
 {
     static const char *const predefined_names[] = {
         "default",      /* Being provided by the default built-in provider */
@@ -532,12 +534,12 @@ int ossl_property_parse_init(void)
     size_t i;
 
     for (i = 0; i < OSSL_NELEM(predefined_names); i++)
-        if (ossl_property_name(predefined_names[i], 1) == 0)
+        if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
             goto err;
 
     /* Pre-populate the two Boolean values */
-    if ((ossl_property_true = ossl_property_value("yes", 1)) == 0
-        || (ossl_property_false = ossl_property_value("no", 1)) == 0)
+    if ((ossl_property_true = ossl_property_value(ctx, "yes", 1)) == 0
+        || (ossl_property_false = ossl_property_value(ctx, "no", 1)) == 0)
         goto err;
 
     return 1;
diff --git a/crypto/property/property_string.c b/crypto/property/property_string.c
index 7f6e30e..dcf5dcc 100644
--- a/crypto/property/property_string.c
+++ b/crypto/property/property_string.c
@@ -34,10 +34,12 @@ typedef struct {
 DEFINE_LHASH_OF(PROPERTY_STRING);
 typedef LHASH_OF(PROPERTY_STRING) PROP_TABLE;
 
-static PROP_TABLE *prop_names;
-static PROP_TABLE *prop_values;
-static OSSL_PROPERTY_IDX prop_name_idx = 0;
-static OSSL_PROPERTY_IDX prop_value_idx = 0;
+typedef struct {
+    PROP_TABLE *prop_names;
+    PROP_TABLE *prop_values;
+    OSSL_PROPERTY_IDX prop_name_idx;
+    OSSL_PROPERTY_IDX prop_value_idx;
+} PROPERTY_STRING_DATA;
 
 static unsigned long property_hash(const PROPERTY_STRING *a)
 {
@@ -65,6 +67,48 @@ static void property_table_free(PROP_TABLE **pt)
     }
 }
 
+static void property_string_data_free(void *vpropdata)
+{
+    PROPERTY_STRING_DATA *propdata = vpropdata;
+
+    if (propdata == NULL)
+        return;
+
+    property_table_free(&propdata->prop_names);
+    property_table_free(&propdata->prop_values);
+    propdata->prop_name_idx = propdata->prop_value_idx = 0;
+
+    OPENSSL_free(propdata);
+}
+
+static void *property_string_data_new(OPENSSL_CTX *ctx) {
+    PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata));
+
+    if (propdata == NULL)
+        return NULL;
+
+    propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash,
+                                                  &property_cmp);
+    if (propdata->prop_names == NULL)
+        goto err;
+
+    propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash,
+                                                   &property_cmp);
+    if (propdata->prop_values == NULL)
+        goto err;
+
+    return propdata;
+
+err:
+    property_string_data_free(propdata);
+    return NULL;
+}
+
+static const OPENSSL_CTX_METHOD property_string_data_method = {
+    property_string_data_new,
+    property_string_data_free,
+};
+
 static PROPERTY_STRING *new_property_string(const char *s,
                                             OSSL_PROPERTY_IDX *pidx)
 {
@@ -103,35 +147,30 @@ static OSSL_PROPERTY_IDX ossl_property_string(PROP_TABLE *t,
     return ps != NULL ? ps->idx : 0;
 }
 
-OSSL_PROPERTY_IDX ossl_property_name(const char *s, int create)
+OSSL_PROPERTY_IDX ossl_property_name(OPENSSL_CTX *ctx, const char *s,
+                                     int create)
 {
-    return ossl_property_string(prop_names, create ? &prop_name_idx : NULL, s);
-}
-
-OSSL_PROPERTY_IDX ossl_property_value(const char *s, int create)
-{
-    return ossl_property_string(prop_values, create ? &prop_value_idx : NULL, s);
-}
+    PROPERTY_STRING_DATA *propdata
+        = openssl_ctx_get_data(ctx, OPENSSL_CTX_PROPERTY_STRING_INDEX,
+                               &property_string_data_method);
 
-int ossl_property_string_init(void)
-{
-    prop_names = lh_PROPERTY_STRING_new(&property_hash, &property_cmp);
-    if (prop_names == NULL)
+    if (propdata == NULL)
         return 0;
-
-    prop_values = lh_PROPERTY_STRING_new(&property_hash, &property_cmp);
-    if (prop_values == NULL)
-        goto err;
-    return 1;
-
-err:
-    ossl_property_string_cleanup();
-    return 0;
+    return ossl_property_string(propdata->prop_names,
+                                create ? &propdata->prop_name_idx : NULL,
+                                s);
 }
 
-void ossl_property_string_cleanup(void)
+OSSL_PROPERTY_IDX ossl_property_value(OPENSSL_CTX *ctx, const char *s,
+                                      int create)
 {
-    property_table_free(&prop_names);
-    property_table_free(&prop_values);
-    prop_name_idx = prop_value_idx = 0;
+    PROPERTY_STRING_DATA *propdata
+        = openssl_ctx_get_data(ctx, OPENSSL_CTX_PROPERTY_STRING_INDEX,
+                               &property_string_data_method);
+
+    if (propdata == NULL)
+        return 0;
+    return ossl_property_string(propdata->prop_values,
+                                create ? &propdata->prop_value_idx : NULL,
+                                s);
 }
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index 2d74f6d..36af527 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -79,7 +79,6 @@ struct provider_store_st {
     CRYPTO_RWLOCK *lock;
     unsigned int use_fallbacks:1;
 };
-static int provider_store_index = -1;
 
 static void provider_store_free(void *vstore)
 {
@@ -92,7 +91,7 @@ static void provider_store_free(void *vstore)
     OPENSSL_free(store);
 }
 
-static void *provider_store_new(void)
+static void *provider_store_new(OPENSSL_CTX *ctx)
 {
     struct provider_store_st *store = OPENSSL_zalloc(sizeof(*store));
     const struct predefined_providers_st *p = NULL;
@@ -134,23 +133,12 @@ static const OPENSSL_CTX_METHOD provider_store_method = {
     provider_store_free,
 };
 
-static CRYPTO_ONCE provider_store_init_flag = CRYPTO_ONCE_STATIC_INIT;
-DEFINE_RUN_ONCE_STATIC(do_provider_store_init)
-{
-    return OPENSSL_init_crypto(0, NULL)
-        && (provider_store_index =
-            openssl_ctx_new_index(&provider_store_method)) != -1;
-}
-
-
 static struct provider_store_st *get_provider_store(OPENSSL_CTX *libctx)
 {
     struct provider_store_st *store = NULL;
 
-    if (!RUN_ONCE(&provider_store_init_flag, do_provider_store_init))
-        return NULL;
-
-    store = openssl_ctx_get_data(libctx, provider_store_index);
+    store = openssl_ctx_get_data(libctx, OPENSSL_CTX_PROVIDER_STORE_INDEX,
+                                 &provider_store_method);
     if (store == NULL)
         CRYPTOerr(CRYPTO_F_GET_PROVIDER_STORE, ERR_R_INTERNAL_ERROR);
     return store;
diff --git a/doc/internal/man3/OSSL_METHOD_STORE.pod b/doc/internal/man3/OSSL_METHOD_STORE.pod
index 25cf56e..f95d397 100644
--- a/doc/internal/man3/OSSL_METHOD_STORE.pod
+++ b/doc/internal/man3/OSSL_METHOD_STORE.pod
@@ -15,10 +15,10 @@ ossl_method_store_cache_get, ossl_method_store_cache_set
 
  typedef struct ossl_method_store_st OSSL_METHOD_STORE;
 
- OSSL_METHOD_STORE *ossl_method_store_new(void);
+ OSSL_METHOD_STORE *ossl_method_store_new(OPENSSL_CTX *ctx);
  void ossl_method_store_free(OSSL_METHOD_STORE *store);
- int ossl_method_store_init(void);
- void ossl_method_store_cleanup(void);
+ int ossl_method_store_init(OPENSSL_CTX *ctx);
+ void ossl_method_store_cleanup(OPENSSL_CTX *ctx);
  int ossl_method_store_add(OSSL_METHOD_STORE *store,
                            int nid, const char *properties,
                            void *method, void (*method_destruct)(void *));
@@ -51,12 +51,14 @@ separately (see L</Cache Functions> below).
 
 =head2 Store Functions
 
-ossl_method_store_init() initialises the method store subsystem.
+ossl_method_store_init() initialises the method store subsystem in the scope of
+the library context B<ctx>.
 
 ossl_method_store_cleanup() cleans up and shuts down the implementation method
-store subsystem.
+store subsystem in the scope of the library context B<ctx>.
 
-ossl_method_store_new() create a new empty method store.
+ossl_method_store_new() create a new empty method store using the supplied
+B<ctx> to allow access to the required underlying property data.
 
 ossl_method_store_free() frees resources allocated to B<store>.
 
diff --git a/doc/internal/man3/openssl_ctx_get_data.pod b/doc/internal/man3/openssl_ctx_get_data.pod
index db066ad..d9b3f5d 100644
--- a/doc/internal/man3/openssl_ctx_get_data.pod
+++ b/doc/internal/man3/openssl_ctx_get_data.pod
@@ -2,7 +2,8 @@
 
 =head1 NAME
 
-openssl_ctx_new_index, openssl_ctx_get_data - internal OPENSSL_CTX routines
+openssl_ctx_get_data, openssl_ctx_run_once, openssl_ctx_onfree
+- internal OPENSSL_CTX routines
 
 =head1 SYNOPSIS
 
@@ -10,12 +11,16 @@ openssl_ctx_new_index, openssl_ctx_get_data - internal OPENSSL_CTX routines
  #include "internal/cryptlib.h"
 
  typedef struct openssl_ctx_method {
-     void *(*new_func)(void);
+     void *(*new_func)(OPENSSL_CTX *ctx);
      void (*free_func)(void *);
  } OPENSSL_CTX_METHOD;
 
- int openssl_ctx_new_index(const OPENSSL_CTX_METHOD *meth);
- void *openssl_ctx_get_data(OPENSSL_CTX *ctx, int index);
+ void *openssl_ctx_get_data(OPENSSL_CTX *ctx, int index,
+                            const OPENSSL_CTX_METHOD *meth);
+
+ int openssl_ctx_run_once(OPENSSL_CTX *ctx, unsigned int idx,
+                          openssl_ctx_run_once_fn run_once_fn);
+ int openssl_ctx_onfree(OPENSSL_CTX *ctx, openssl_ctx_onfree_fn onfreefn);
 
 =head1 DESCRIPTION
 
@@ -23,26 +28,32 @@ Internally, the OpenSSL library context C<OPENSSL_CTX> is implemented
 as a C<CRYPTO_EX_DATA>, which allows data from diverse parts of the
 library to be added and removed dynamically.
 Each such data item must have a corresponding CRYPTO_EX_DATA index
-associated with it.
+associated with it. Unlike normal CRYPTO_EX_DATA objects we use static indexes
+to identify data items. These are mapped transparetnly to CRYPTO_EX_DATA dynamic
+indexes internally to the implementation.
 See the example further down to see how that's done.
 
-openssl_ctx_new_index() allocates a new library context index, and
-associates it with the functions given through C<meth>.
-The functions given through that method are used to create or free
-items that are stored at that index whenever a library context is
-created or freed, meaning that the code that use a data item of that
+openssl_ctx_get_data() is used to retrieve a pointer to the data in
+the library context C<ctx> associated with the given C<index>. An
+OPENSSL_CTX_METHOD must be defined and given in the C<meth> parameter. The index
+for it should be defined in cryptlib.h. The functions through the method are
+used to create or free items that are stored at that index whenever a library
+context is created or freed, meaning that the code that use a data item of that
 index doesn't have to worry about that, just use the data available.
 
 Deallocation of an index happens automatically when the library
 context is freed.
 
-openssl_ctx_get_data() is used to retrieve a pointer to the data in
-the library context C<ctx> associated with the given C<index>.
+openssl_ctx_run_once is used to run some initialisation routine C<run_once_fn>
+exactly once per library context C<ctx> object. Each initialisation routine
+should be allocate a unique run once index in cryptlib.h.
 
-=head1 RETURN VALUES
+Any resources allocated via a run once initialisation routine can be cleaned up
+using openssl_ctx_onfree. This associates an "on free" routine C<onfreefn> with
+the library context C<ctx>. When C<ctx> is freed all associated "on free"
+routines are called.
 
-openssl_ctx_new_index() returns -1 on error, otherwise the allocated
-index number.
+=head1 RETURN VALUES
 
 openssl_ctx_get_data() returns a pointer on success, or C<NULL> on
 failure.
@@ -53,17 +64,14 @@ failure.
 
 For a type C<FOO> that should end up in the OpenSSL library context, a
 small bit of initialization is needed, i.e. to associate a constructor
-and a destructor to a new index.
-
- /* The index will always be entirely global, and dynamically allocated */
- static int foo_index = -1;
+and a destructor to an index.
 
  typedef struct foo_st {
      int i;
      void *data;
  } FOO;
 
- static void *foo_new(void)
+ static void *foo_new(OPENSSL_CTX *ctx)
  {
      FOO *ptr = OPENSSL_zalloc(sizeof(*foo));
      if (ptr != NULL)
@@ -74,27 +82,49 @@ and a destructor to a new index.
  {
      OPENSSL_free(ptr);
  }
- static const OPENSSL_CTX_METHOD foo_method = {
+
+ /*
+  * Include a reference to this in the methods table in context.c 
+  * OPENSSL_CTX_FOO_INDEX should be added to internal/cryptlib.h
+  */
+ const OPENSSL_CTX_METHOD foo_method = {
      foo_new,
      foo_free
  };
 
- static int foo_init(void)
- {
-     foo_index = openssl_ctx_new_index(foo_method);
-
-     return foo_index != -1;
- }
-
 =head2 Usage
 
 To get and use the data stored in the library context, simply do this:
 
  /*
   * ctx is received from a caller,
-  * foo_index comes from the example above
   */
- FOO *data = openssl_ctx_get_data(ctx, foo_index);
+ FOO *data = openssl_ctx_get_data(ctx, OPENSSL_CTX_FOO_INDEX, &foo_method);
+
+=head2 Run Once
+
+ void foo_cleanup(OPENSSL_CTX *ctx)
+ {
+     /* Free foo resources associated with ctx */
+ }
+
+ static openssl_ctx_run_once_fn do_foo_init;
+ static int do_foo_init(OPENSSL_CTX *ctx)
+ {
+     /* Allocate and initialise some foo resources and associated with ctx */
+     return openssl_ctx_onfree(ctx, &foo_cleanup)
+ }
+
+ int foo_some_function(OPENSSL_CTX *ctx)
+ {
+    if (!openssl_ctx_run_once(ctx,
+                              OPENSSL_CTX_FOO_RUN_ONCE_INDEX,
+                              do_foo_init))
+        return 0;
+
+    /* Do some work using foo resources in ctx */
+ }
+
 
 =head1 SEE ALSO
 
diff --git a/doc/internal/man3/ossl_method_construct.pod b/doc/internal/man3/ossl_method_construct.pod
index 7b682dd..47f4a24 100644
--- a/doc/internal/man3/ossl_method_construct.pod
+++ b/doc/internal/man3/ossl_method_construct.pod
@@ -11,7 +11,7 @@ OSSL_METHOD_CONSTRUCT_METHOD, ossl_method_construct
 
  struct ossl_method_construct_method_st {
      /* Create store */
-     void *(*alloc_tmp_store)(void);
+     void *(*alloc_tmp_store)(OPENSSL_CTX *ctx);
      /* Remove a store */
      void (*dealloc_tmp_store)(void *store);
      /* Get an already existing method from a store */
@@ -33,6 +33,7 @@ OSSL_METHOD_CONSTRUCT_METHOD, ossl_method_construct
                              int force_cache,
                              OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data);
 
+
 =head1 DESCRIPTION
 
 All libcrypto sub-systems that want to create their own methods based
@@ -65,7 +66,7 @@ function pointers:
 
 =item alloc_tmp_store()
 
-Create a temporary method store.
+Create a temporary method store in the scope of the library context C<ctx>.
 This store is used to temporarily store methods for easier lookup, for
 when the provider doesn't want its dispatch table stored in a longer
 term cache.
diff --git a/include/internal/core.h b/include/internal/core.h
index 06a0775..ddafaee 100644
--- a/include/internal/core.h
+++ b/include/internal/core.h
@@ -28,7 +28,7 @@
  */
 typedef struct ossl_method_construct_method_st {
     /* Create store */
-    void *(*alloc_tmp_store)(void);
+    void *(*alloc_tmp_store)(OPENSSL_CTX *ctx);
     /* Remove a store */
     void (*dealloc_tmp_store)(void *store);
     /* Get an already existing method from a store */
diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h
index e791245..df23f57 100644
--- a/include/internal/cryptlib.h
+++ b/include/internal/cryptlib.h
@@ -88,7 +88,8 @@ DEFINE_LHASH_OF(MEM);
 void OPENSSL_cpuid_setup(void);
 extern unsigned int OPENSSL_ia32cap_P[];
 void OPENSSL_showfatal(const char *fmta, ...);
-void crypto_cleanup_all_ex_data_int(void);
+int do_ex_data_init(OPENSSL_CTX *ctx);
+void crypto_cleanup_all_ex_data_int(OPENSSL_CTX *ctx);
 int openssl_init_fork_handlers(void);
 
 char *ossl_safe_getenv(const char *name);
@@ -105,13 +106,72 @@ uint32_t OPENSSL_rdtsc(void);
 size_t OPENSSL_instrument_bus(unsigned int *, size_t);
 size_t OPENSSL_instrument_bus2(unsigned int *, size_t, size_t);
 
+/* ex_data structures */
+
+/*
+ * Each structure type (sometimes called a class), that supports
+ * exdata has a stack of callbacks for each instance.
+ */
+struct ex_callback_st {
+    long argl;                  /* Arbitrary long */
+    void *argp;                 /* Arbitrary void * */
+    CRYPTO_EX_new *new_func;
+    CRYPTO_EX_free *free_func;
+    CRYPTO_EX_dup *dup_func;
+};
+
+/*
+ * The state for each class.  This could just be a typedef, but
+ * a structure allows future changes.
+ */
+typedef struct ex_callbacks_st {
+    STACK_OF(EX_CALLBACK) *meth;
+} EX_CALLBACKS;
+
+typedef struct ossl_ex_data_global_st {
+    CRYPTO_RWLOCK *ex_data_lock;
+    EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT];
+} OSSL_EX_DATA_GLOBAL;
+
+
+/* OPENSSL_CTX */
+
+# define OPENSSL_CTX_PROVIDER_STORE_RUN_ONCE_INDEX          0
+# define OPENSSL_CTX_DEFAULT_METHOD_STORE_RUN_ONCE_INDEX    1
+# define OPENSSL_CTX_METHOD_STORE_RUN_ONCE_INDEX            2
+# define OPENSSL_CTX_MAX_RUN_ONCE                           3
+
+# define OPENSSL_CTX_DEFAULT_METHOD_STORE_INDEX     0
+# define OPENSSL_CTX_PROVIDER_STORE_INDEX           1
+# define OPENSSL_CTX_PROPERTY_DEFN_INDEX            2
+# define OPENSSL_CTX_PROPERTY_STRING_INDEX          3
+# define OPENSSL_CTX_MAX_INDEXES                    4
+
 typedef struct openssl_ctx_method {
-    void *(*new_func)(void);
+    void *(*new_func)(OPENSSL_CTX *ctx);
     void (*free_func)(void *);
 } OPENSSL_CTX_METHOD;
-/* For each type of data to store in the context, an index must be created */
-int openssl_ctx_new_index(const OPENSSL_CTX_METHOD *);
-/* Functions to retrieve pointers to data by index */
-void *openssl_ctx_get_data(OPENSSL_CTX *, int /* index */);
 
+/* Functions to retrieve pointers to data by index */
+void *openssl_ctx_get_data(OPENSSL_CTX *, int /* index */,
+                           const OPENSSL_CTX_METHOD * ctx);
+
+void openssl_ctx_default_deinit(void);
+OSSL_EX_DATA_GLOBAL *openssl_ctx_get_ex_data_global(OPENSSL_CTX *ctx);
+typedef int (openssl_ctx_run_once_fn)(OPENSSL_CTX *ctx);
+typedef void (openssl_ctx_onfree_fn)(OPENSSL_CTX *ctx);
+
+int openssl_ctx_run_once(OPENSSL_CTX *ctx, unsigned int idx,
+                         openssl_ctx_run_once_fn run_once_fn);
+int openssl_ctx_onfree(OPENSSL_CTX *ctx, openssl_ctx_onfree_fn onfreefn);
+
+OPENSSL_CTX *crypto_ex_data_get_openssl_ctx(const CRYPTO_EX_DATA *ad);
+int crypto_new_ex_data_ex(OPENSSL_CTX *ctx, int class_index, void *obj,
+                          CRYPTO_EX_DATA *ad);
+int crypto_get_ex_new_index_ex(OPENSSL_CTX *ctx, int class_index,
+                               long argl, void *argp,
+                               CRYPTO_EX_new *new_func,
+                               CRYPTO_EX_dup *dup_func,
+                               CRYPTO_EX_free *free_func);
+int crypto_free_ex_index_ex(OPENSSL_CTX *ctx, int class_index, int idx);
 #endif
diff --git a/include/internal/property.h b/include/internal/property.h
index 82b3a33..d143263 100644
--- a/include/internal/property.h
+++ b/include/internal/property.h
@@ -11,10 +11,12 @@
 #ifndef HEADER_PROPERTY_H
 # define HEADER_PROPERTY_H
 
+#include "internal/cryptlib.h"
+
 typedef struct ossl_method_store_st OSSL_METHOD_STORE;
 
 /* Implementation store functions */
-OSSL_METHOD_STORE *ossl_method_store_new(void);
+OSSL_METHOD_STORE *ossl_method_store_new(OPENSSL_CTX *ctx);
 void ossl_method_store_free(OSSL_METHOD_STORE *store);
 int ossl_method_store_add(OSSL_METHOD_STORE *store, int nid,
                           const char *properties, void *implementation,
@@ -31,5 +33,4 @@ int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, int nid,
                                 const char *prop_query, void **result);
 int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, int nid,
                                 const char *prop_query, void *result);
-
 #endif
diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h
index a7e78e4..7d9532f 100644
--- a/include/openssl/crypto.h
+++ b/include/openssl/crypto.h
@@ -84,6 +84,7 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock);
 # define CRYPTO_MEM_CHECK_DISABLE 0x3   /* Control only */
 
 struct crypto_ex_data_st {
+    OPENSSL_CTX *ctx;
     STACK_OF(void) *sk;
 };
 DEFINE_STACK_OF(void)
diff --git a/include/openssl/cryptoerr.h b/include/openssl/cryptoerr.h
index ff5767a..b9eb62c 100644
--- a/include/openssl/cryptoerr.h
+++ b/include/openssl/cryptoerr.h
@@ -27,8 +27,10 @@ int ERR_load_CRYPTO_strings(void);
 # define CRYPTO_F_CRYPTO_DUP_EX_DATA                      110
 # define CRYPTO_F_CRYPTO_FREE_EX_DATA                     111
 # define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX                 100
+# define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX              141
 # define CRYPTO_F_CRYPTO_MEMDUP                           115
 # define CRYPTO_F_CRYPTO_NEW_EX_DATA                      112
+# define CRYPTO_F_CRYPTO_NEW_EX_DATA_EX                   142
 # define CRYPTO_F_CRYPTO_OCB128_COPY_CTX                  121
 # define CRYPTO_F_CRYPTO_OCB128_INIT                      122
 # define CRYPTO_F_CRYPTO_SET_EX_DATA                      102
@@ -43,8 +45,8 @@ int ERR_load_CRYPTO_strings(void);
 # define CRYPTO_F_OPENSSL_LH_NEW                          126
 # define CRYPTO_F_OPENSSL_SK_DEEP_COPY                    127
 # define CRYPTO_F_OPENSSL_SK_DUP                          128
-# define CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN               132
 # define CRYPTO_F_OSSL_PROVIDER_ACTIVATE                  130
+# define CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN               132
 # define CRYPTO_F_OSSL_PROVIDER_ADD_PARAMETER             139
 # define CRYPTO_F_OSSL_PROVIDER_NEW                       131
 # define CRYPTO_F_OSSL_PROVIDER_SET_MODULE_PATH           140
diff --git a/test/build.info b/test/build.info
index ded3bd7..2800c71 100644
--- a/test/build.info
+++ b/test/build.info
@@ -503,7 +503,7 @@ IF[{- !$disabled{tests} -}]
     DEPEND[wpackettest]=../libcrypto ../libssl.a libtestutil.a
 
     SOURCE[property_test]=property_test.c
-    INCLUDE[property_test]=../include ../apps/include
+    INCLUDE[property_test]=.. ../include ../apps/include
     DEPEND[property_test]=../libcrypto.a libtestutil.a
 
     SOURCE[ctype_internal_test]=ctype_internal_test.c
diff --git a/test/context_internal_test.c b/test/context_internal_test.c
index aca3db3..6c675bc 100644
--- a/test/context_internal_test.c
+++ b/test/context_internal_test.c
@@ -22,15 +22,12 @@
  * BEGIN EXAMPLE
  */
 
-/* The index will always be entirely global, and dynamically allocated */
-static int foo_index = -1;
-
 typedef struct foo_st {
     int i;
     void *data;
 } FOO;
 
-static void *foo_new(void)
+static void *foo_new(OPENSSL_CTX *ctx)
 {
     FOO *ptr = OPENSSL_zalloc(sizeof(*ptr));
     if (ptr != NULL)
@@ -46,14 +43,6 @@ static const OPENSSL_CTX_METHOD foo_method = {
     foo_free
 };
 
-static int foo_init(void)
-{
-    if (foo_index == -1)
-        foo_index = openssl_ctx_new_index(&foo_method);
-
-    return foo_index != -1;
-}
-
 /*
  * END EXAMPLE
  * ======================================================================
@@ -63,9 +52,7 @@ static int test_context(OPENSSL_CTX *ctx)
 {
     FOO *data = NULL;
 
-    return
-        TEST_true(foo_init())
-        && TEST_ptr(data = openssl_ctx_get_data(ctx, foo_index))
+    return TEST_ptr(data = openssl_ctx_get_data(ctx, 0, &foo_method))
         /* OPENSSL_zalloc in foo_new() initialized it to zero */
         && TEST_int_eq(data->i, 42);
 }
@@ -74,8 +61,7 @@ static int test_app_context(void)
 {
     OPENSSL_CTX *ctx = NULL;
     int result =
-        TEST_true(foo_init())
-        && TEST_ptr(ctx = OPENSSL_CTX_new())
+        TEST_ptr(ctx = OPENSSL_CTX_new())
         && test_context(ctx);
 
     OPENSSL_CTX_free(ctx);
diff --git a/test/property_test.c b/test/property_test.c
index ee94252..7ec40d6 100644
--- a/test/property_test.c
+++ b/test/property_test.c
@@ -21,7 +21,7 @@ static int add_property_names(const char *n, ...)
 
     va_start(args, n);
     do {
-        if (!TEST_int_ne(ossl_property_name(n, 1), 0))
+        if (!TEST_int_ne(ossl_property_name(NULL, n, 1), 0))
             res = 0;
     } while ((n = va_arg(args, const char *)) != NULL);
     va_end(args);
@@ -34,24 +34,24 @@ static int test_property_string(void)
     int res = 0;
     OSSL_PROPERTY_IDX i, j;
 
-    if (TEST_ptr(store = ossl_method_store_new())
-        && TEST_int_eq(ossl_property_name("fnord", 0), 0)
-        && TEST_int_ne(ossl_property_name("fnord", 1), 0)
-        && TEST_int_ne(ossl_property_name("name", 1), 0)
+    if (TEST_ptr(store = ossl_method_store_new(NULL))
+        && TEST_int_eq(ossl_property_name(NULL, "fnord", 0), 0)
+        && TEST_int_ne(ossl_property_name(NULL, "fnord", 1), 0)
+        && TEST_int_ne(ossl_property_name(NULL, "name", 1), 0)
         /* Property value checks */
-        && TEST_int_eq(ossl_property_value("fnord", 0), 0)
-        && TEST_int_ne(i = ossl_property_value("no", 0), 0)
-        && TEST_int_ne(j = ossl_property_value("yes", 0), 0)
+        && TEST_int_eq(ossl_property_value(NULL, "fnord", 0), 0)
+        && TEST_int_ne(i = ossl_property_value(NULL, "no", 0), 0)
+        && TEST_int_ne(j = ossl_property_value(NULL, "yes", 0), 0)
         && TEST_int_ne(i, j)
-        && TEST_int_eq(ossl_property_value("yes", 1), j)
-        && TEST_int_eq(ossl_property_value("no", 1), i)
-        && TEST_int_ne(i = ossl_property_value("illuminati", 1), 0)
-        && TEST_int_eq(j = ossl_property_value("fnord", 1), i + 1)
-        && TEST_int_eq(ossl_property_value("fnord", 1), j)
+        && TEST_int_eq(ossl_property_value(NULL, "yes", 1), j)
+        && TEST_int_eq(ossl_property_value(NULL, "no", 1), i)
+        && TEST_int_ne(i = ossl_property_value(NULL, "illuminati", 1), 0)
+        && TEST_int_eq(j = ossl_property_value(NULL, "fnord", 1), i + 1)
+        && TEST_int_eq(ossl_property_value(NULL, "fnord", 1), j)
         /* Check name and values are distinct */
-        && TEST_int_eq(ossl_property_value("cold", 0), 0)
-        && TEST_int_ne(ossl_property_name("fnord", 0),
-                       ossl_property_value("fnord", 0)))
+        && TEST_int_eq(ossl_property_value(NULL, "cold", 0), 0)
+        && TEST_int_ne(ossl_property_name(NULL, "fnord", 0),
+                       ossl_property_value(NULL, "fnord", 0)))
         res = 1;
     ossl_method_store_free(store);
     return res;
@@ -95,11 +95,11 @@ static int test_property_parse(int n)
     OSSL_PROPERTY_LIST *p = NULL, *q = NULL;
     int r = 0;
 
-    if (TEST_ptr(store = ossl_method_store_new())
+    if (TEST_ptr(store = ossl_method_store_new(NULL))
         && add_property_names("sky", "groan", "cold", "today", "tomorrow", "n",
                               NULL)
-        && TEST_ptr(p = ossl_parse_property(parser_tests[n].defn))
-        && TEST_ptr(q = ossl_parse_query(parser_tests[n].query))
+        && TEST_ptr(p = ossl_parse_property(NULL, parser_tests[n].defn))
+        && TEST_ptr(q = ossl_parse_query(NULL, parser_tests[n].query))
         && TEST_int_eq(ossl_property_match(q, p), parser_tests[n].e))
         r = 1;
     ossl_property_free(p);
@@ -141,12 +141,12 @@ static int test_property_merge(int n)
     OSSL_PROPERTY_LIST *q_combined = NULL, *prop = NULL;
     int r = 0;
 
-    if (TEST_ptr(store = ossl_method_store_new())
+    if (TEST_ptr(store = ossl_method_store_new(NULL))
         && add_property_names("colour", "urn", "clouds", "pot", "day", "night",
                               NULL)
-        && TEST_ptr(prop = ossl_parse_property(merge_tests[n].prop))
-        && TEST_ptr(q_global = ossl_parse_query(merge_tests[n].q_global))
-        && TEST_ptr(q_local = ossl_parse_query(merge_tests[n].q_local))
+        && TEST_ptr(prop = ossl_parse_property(NULL, merge_tests[n].prop))
+        && TEST_ptr(q_global = ossl_parse_query(NULL, merge_tests[n].q_global))
+        && TEST_ptr(q_local = ossl_parse_query(NULL, merge_tests[n].q_local))
         && TEST_ptr(q_combined = ossl_property_merge(q_local, q_global))
         && TEST_true(ossl_property_match(q_combined, prop)))
         r = 1;
@@ -164,15 +164,15 @@ static int test_property_defn_cache(void)
     OSSL_PROPERTY_LIST *red, *blue;
     int r = 0;
 
-    if (TEST_ptr(store = ossl_method_store_new())
+    if (TEST_ptr(store = ossl_method_store_new(NULL))
         && add_property_names("red", "blue", NULL)
-        && TEST_ptr(red = ossl_parse_property("red"))
-        && TEST_ptr(blue = ossl_parse_property("blue"))
+        && TEST_ptr(red = ossl_parse_property(NULL, "red"))
+        && TEST_ptr(blue = ossl_parse_property(NULL, "blue"))
         && TEST_ptr_ne(red, blue)
-        && TEST_true(ossl_prop_defn_set("red", red))
-        && TEST_true(ossl_prop_defn_set("blue", blue))
-        && TEST_ptr_eq(ossl_prop_defn_get("red"), red)
-        && TEST_ptr_eq(ossl_prop_defn_get("blue"), blue))
+        && TEST_true(ossl_prop_defn_set(NULL, "red", red))
+        && TEST_true(ossl_prop_defn_set(NULL, "blue", blue))
+        && TEST_ptr_eq(ossl_prop_defn_get(NULL, "red"), red)
+        && TEST_ptr_eq(ossl_prop_defn_get(NULL, "blue"), blue))
         r = 1;
     ossl_method_store_free(store);
     return r;
@@ -196,10 +196,10 @@ static int test_definition_compares(int n)
     OSSL_PROPERTY_LIST *d = NULL, *q = NULL;
     int r;
 
-    r = TEST_ptr(store = ossl_method_store_new())
+    r = TEST_ptr(store = ossl_method_store_new(NULL))
         && add_property_names("alpha", "omega", NULL)
-        && TEST_ptr(d = ossl_parse_property(definition_tests[n].defn))
-        && TEST_ptr(q = ossl_parse_query(definition_tests[n].query))
+        && TEST_ptr(d = ossl_parse_property(NULL, definition_tests[n].defn))
+        && TEST_ptr(q = ossl_parse_query(NULL, definition_tests[n].query))
         && TEST_int_eq(ossl_property_match(q, d), definition_tests[n].e);
 
     ossl_property_free(d);
@@ -224,7 +224,7 @@ static int test_register_deregister(void)
     int ret = 0;
     OSSL_METHOD_STORE *store;
 
-    if (!TEST_ptr(store = ossl_method_store_new())
+    if (!TEST_ptr(store = ossl_method_store_new(NULL))
         || !add_property_names("position", NULL))
         goto err;
 
@@ -291,7 +291,7 @@ static int test_property(void)
     int ret = 0;
     void *result;
 
-    if (!TEST_ptr(store = ossl_method_store_new())
+    if (!TEST_ptr(store = ossl_method_store_new(NULL))
         || !add_property_names("fast", "colour", "sky", "furry", NULL))
         goto err;
 
@@ -329,7 +329,7 @@ static int test_query_cache_stochastic(void)
     int errors = 0;
     int v[10001];
 
-    if (!TEST_ptr(store = ossl_method_store_new())
+    if (!TEST_ptr(store = ossl_method_store_new(NULL))
         || !add_property_names("n", NULL))
         goto err;
 


More information about the openssl-commits mailing list