[openssl] master update

Matt Caswell matt at openssl.org
Tue May 11 14:15:08 UTC 2021


The branch master has been updated
       via  b8be229dab036b26de8830444bf2beb82e71f50e (commit)
       via  c1fb5e072fdeffc5b686e265283f0b31b1c37c3b (commit)
       via  878be71c2d284d1fc4d591fdbbfb14eed63da10f (commit)
       via  fb9b3a7bce236c96d8db37e52db83997b4cb18db (commit)
       via  abaa2dd2981ba3c15456016c6248f539242cfb49 (commit)
       via  8c627075656cf2709680eeb5aa1826f00db2e483 (commit)
       via  3b85bcfa14988cb383d94e5dee16645ce1ad39ed (commit)
       via  7b88c184b66c0d7cfb1f76422448af6a636eea8c (commit)
       via  5442611dffed2c345ef83d494f2ef7ffb9cf3883 (commit)
       via  d0efad482f7d72db3d52bdb0380bd019e6d59de8 (commit)
       via  f12a5690de906c05031f0195b6dec6925ff27231 (commit)
       via  a16d21744df686a7c005d1f129915d9083476e14 (commit)
       via  d07af736de592602f2831f8559d0302cb116e190 (commit)
      from  56784203ec2e4c8d94fccb25b956e21331b800b1 (commit)


- Log -----------------------------------------------------------------
commit b8be229dab036b26de8830444bf2beb82e71f50e
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 7 11:18:57 2021 +0100

    Update FIPS checksums
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit c1fb5e072fdeffc5b686e265283f0b31b1c37c3b
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 7 11:03:59 2021 +0100

    Exclude child provider code from the FIPS module
    
    We don't need the child provider code in the FIPS module so we exclude
    it.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit 878be71c2d284d1fc4d591fdbbfb14eed63da10f
Author: Matt Caswell <matt at openssl.org>
Date:   Wed May 5 14:43:19 2021 +0100

    Update documentation following addition of OSSL_LIB_CTX_new_child()
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit fb9b3a7bce236c96d8db37e52db83997b4cb18db
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 4 17:38:10 2021 +0100

    Add additional testing of child libctx/providers
    
    Add a case where a provider explicitly loads a provider into a child
    libctx where it does not already exist.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit abaa2dd2981ba3c15456016c6248f539242cfb49
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 4 16:23:31 2021 +0100

    Don't convert pre-existing providers into children
    
    If a provider explicitly loads another provider into a child libctx where
    it wasn't previously loaded then we don't start treating it like a child
    if the parent libctx subsequently loads the same provider.
    
    Fixes #14925
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit 8c627075656cf2709680eeb5aa1826f00db2e483
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 29 16:37:42 2021 +0100

    Add support for child provider to up_ref/free their parent
    
    If the ref counts on a child provider change, then this needs to be
    reflected in the parent so we add callbacks to do this.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit 3b85bcfa14988cb383d94e5dee16645ce1ad39ed
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 26 16:00:04 2021 +0100

    Add a test to check that child provider callbacks are working
    
    Write a test to confirm that if a provider is unloaded/loaded into a
    libctx then it is similarly unloaded/loaded from any child libctxs.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit 7b88c184b66c0d7cfb1f76422448af6a636eea8c
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Apr 23 12:08:27 2021 +0100

    Register callbacks with core for child provider creation/deletion
    
    By adding callbacks to the core this will enable (in future commits) the
    ability to add/remove child providers as the providers are added/removed
    from the parent libctx.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit 5442611dffed2c345ef83d494f2ef7ffb9cf3883
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 22 15:58:50 2021 +0100

    Add a test for OSSL_LIB_CTX_new_child()
    
    Check that we can create such a libctx and usable providers are loaded
    into it.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit d0efad482f7d72db3d52bdb0380bd019e6d59de8
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 22 08:31:08 2021 +0100

    Modify the legacy provider to use OSSL_LIB_CTX_new_child()
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit f12a5690de906c05031f0195b6dec6925ff27231
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Apr 21 16:51:41 2021 +0100

    Add the concept of a child OSSL_LIB_CTX
    
    Add a child OSSL_LIB_CTX that will mirror the providers loaded into the
    parent libctx. This is useful for providers that want to use algorithms
    from other providers and just need to inherit the providers used by the
    application.
    
    Fixes #14925
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit a16d21744df686a7c005d1f129915d9083476e14
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 26 11:35:17 2021 +0100

    Add the ability for ex_data to have a priority
    
    Where an object has multiple ex_data associated with it, then we free that
    ex_data in order of priority (high priority first).
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

commit d07af736de592602f2831f8559d0302cb116e190
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 22 09:43:22 2021 +0100

    Only load the config file into the default libctx if necessary
    
    There is no need to load providers from the config file into the default
    libctx, if the current libctx that we are using isn't the default libctx.
    This avoids some deadlock situations.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14991)

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

Summary of changes:
 crypto/bio/bss_core.c                       |   1 +
 crypto/build.info                           |   2 +-
 crypto/context.c                            |  34 ++-
 crypto/core_namemap.c                       |   1 +
 crypto/encode_decode/decoder_meth.c         |   1 +
 crypto/encode_decode/encoder_meth.c         |   1 +
 crypto/evp/evp_fetch.c                      |   2 +
 crypto/ex_data.c                            |  62 +++--
 crypto/initthread.c                         |   1 +
 crypto/property/defn_cache.c                |   1 +
 crypto/property/property.c                  |   1 +
 crypto/property/property_string.c           |   1 +
 crypto/provider.c                           |   7 +-
 crypto/provider_child.c                     | 330 ++++++++++++++++++++++
 crypto/provider_conf.c                      |   4 +-
 crypto/provider_core.c                      | 409 ++++++++++++++++++++++++++--
 crypto/rand/rand_lib.c                      |   1 +
 crypto/self_test_core.c                     |   1 +
 crypto/store/store_meth.c                   |   1 +
 doc/internal/man3/ossl_lib_ctx_get_data.pod |  14 +-
 doc/internal/man3/ossl_provider_new.pod     |  53 +++-
 doc/man3/OSSL_LIB_CTX.pod                   |  56 +++-
 doc/man3/OSSL_PROVIDER.pod                  |  10 +-
 doc/man7/provider-base.pod                  |  54 ++++
 include/internal/core.h                     |   1 +
 include/internal/cryptlib.h                 |  12 +-
 include/internal/provider.h                 |  19 +-
 include/openssl/core_dispatch.h             |  27 ++
 include/openssl/crypto.h.in                 |   6 +-
 include/openssl/provider.h                  |   1 +
 providers/fips-sources.checksums            |  26 +-
 providers/fips.checksum                     |   2 +-
 providers/fips/fipsprov.c                   |   1 +
 providers/implementations/rands/crngt.c     |   1 +
 providers/implementations/rands/drbg.c      |   1 +
 providers/legacyprov.c                      |   7 +-
 test/bio_core_test.c                        |   2 +-
 test/context_internal_test.c                |   1 +
 test/p_test.c                               |  80 +++++-
 test/provider_internal_test.c               |   2 +-
 test/provider_test.c                        | 158 ++++++++++-
 test/recipes/04-test_provider.t             |   7 +-
 util/libcrypto.num                          |   2 +
 43 files changed, 1298 insertions(+), 106 deletions(-)
 create mode 100644 crypto/provider_child.c

diff --git a/crypto/bio/bss_core.c b/crypto/bio/bss_core.c
index 2baabe614e..89b1ef7395 100644
--- a/crypto/bio/bss_core.c
+++ b/crypto/bio/bss_core.c
@@ -30,6 +30,7 @@ static void *bio_core_globals_new(OSSL_LIB_CTX *ctx)
 }
 
 static const OSSL_LIB_CTX_METHOD bio_core_globals_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     bio_core_globals_new,
     bio_core_globals_free,
 };
diff --git a/crypto/build.info b/crypto/build.info
index ffcc2b0183..ed4581eef5 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -99,7 +99,7 @@ $UTIL_COMMON=\
 SOURCE[../libcrypto]=$UTIL_COMMON \
         mem.c mem_sec.c \
         cversion.c info.c cpt_err.c ebcdic.c uid.c o_time.c o_dir.c \
-        o_fopen.c getenv.c o_init.c init.c trace.c provider.c \
+        o_fopen.c getenv.c o_init.c init.c trace.c provider.c provider_child.c \
         punycode.c
 SOURCE[../providers/libfips.a]=$UTIL_COMMON
 
diff --git a/crypto/context.c b/crypto/context.c
index 4ea949970a..1e0dfa8e01 100644
--- a/crypto/context.c
+++ b/crypto/context.c
@@ -13,6 +13,7 @@
 #include "internal/property.h"
 #include "internal/core.h"
 #include "internal/bio.h"
+#include "internal/provider.h"
 
 struct ossl_lib_ctx_onfree_list_st {
     ossl_lib_ctx_onfree_fn *fn;
@@ -39,6 +40,7 @@ struct ossl_lib_ctx_st {
     int run_once_done[OSSL_LIB_CTX_MAX_RUN_ONCE];
     int run_once_ret[OSSL_LIB_CTX_MAX_RUN_ONCE];
     struct ossl_lib_ctx_onfree_list_st *onfreelist;
+    unsigned int ischild:1;
 };
 
 int ossl_lib_ctx_write_lock(OSSL_LIB_CTX *ctx)
@@ -56,6 +58,15 @@ int ossl_lib_ctx_unlock(OSSL_LIB_CTX *ctx)
     return CRYPTO_THREAD_unlock(ossl_lib_ctx_get_concrete(ctx)->lock);
 }
 
+int ossl_lib_ctx_is_child(OSSL_LIB_CTX *ctx)
+{
+    ctx = ossl_lib_ctx_get_concrete(ctx);
+
+    if (ctx == NULL)
+        return 0;
+    return ctx->ischild;
+}
+
 static int context_init(OSSL_LIB_CTX *ctx)
 {
     size_t i;
@@ -185,7 +196,8 @@ OSSL_LIB_CTX *OSSL_LIB_CTX_new(void)
 }
 
 #ifndef FIPS_MODULE
-OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_DISPATCH *in)
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_CORE_HANDLE *handle,
+                                             const OSSL_DISPATCH *in)
 {
     OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new();
 
@@ -200,6 +212,23 @@ OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_DISPATCH *in)
     return ctx;
 }
 
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_child(const OSSL_CORE_HANDLE *handle,
+                                     const OSSL_DISPATCH *in)
+{
+    OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new_from_dispatch(handle, in);
+
+    if (ctx == NULL)
+        return NULL;
+
+    if (!ossl_provider_init_as_child(ctx, handle, in)) {
+        OSSL_LIB_CTX_free(ctx);
+        return NULL;
+    }
+    ctx->ischild = 1;
+
+    return ctx;
+}
+
 int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file)
 {
     return CONF_modules_load_file_ex(ctx, config_file, NULL, 0) > 0;
@@ -305,7 +334,8 @@ static int ossl_lib_ctx_init_index(OSSL_LIB_CTX *ctx, int static_index,
     idx = ossl_crypto_get_ex_new_index_ex(ctx, CRYPTO_EX_INDEX_OSSL_LIB_CTX, 0,
                                           (void *)meth,
                                           ossl_lib_ctx_generic_new,
-                                          NULL, ossl_lib_ctx_generic_free);
+                                          NULL, ossl_lib_ctx_generic_free,
+                                          meth->priority);
     if (idx < 0)
         return 0;
 
diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c
index 1009fb1e94..5bb0f09ec7 100644
--- a/crypto/core_namemap.c
+++ b/crypto/core_namemap.c
@@ -87,6 +87,7 @@ static void stored_namemap_free(void *vnamemap)
 }
 
 static const OSSL_LIB_CTX_METHOD stored_namemap_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     stored_namemap_new,
     stored_namemap_free,
 };
diff --git a/crypto/encode_decode/decoder_meth.c b/crypto/encode_decode/decoder_meth.c
index 7f8a365b66..7a271f7408 100644
--- a/crypto/encode_decode/decoder_meth.c
+++ b/crypto/encode_decode/decoder_meth.c
@@ -76,6 +76,7 @@ static void *decoder_store_new(OSSL_LIB_CTX *ctx)
 
 
 static const OSSL_LIB_CTX_METHOD decoder_store_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     decoder_store_new,
     decoder_store_free,
 };
diff --git a/crypto/encode_decode/encoder_meth.c b/crypto/encode_decode/encoder_meth.c
index de0a66578c..bb319460b9 100644
--- a/crypto/encode_decode/encoder_meth.c
+++ b/crypto/encode_decode/encoder_meth.c
@@ -76,6 +76,7 @@ static void *encoder_store_new(OSSL_LIB_CTX *ctx)
 
 
 static const OSSL_LIB_CTX_METHOD encoder_store_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     encoder_store_new,
     encoder_store_free,
 };
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
index 266f657ff2..6c701bf1e2 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -35,6 +35,8 @@ static void *evp_method_store_new(OSSL_LIB_CTX *ctx)
 
 
 static const OSSL_LIB_CTX_METHOD evp_method_store_method = {
+    /* We want evp_method_store to be cleaned up before the provider store */
+    OSSL_LIB_CTX_METHOD_PRIORITY_2,
     evp_method_store_new,
     evp_method_store_free,
 };
diff --git a/crypto/ex_data.c b/crypto/ex_data.c
index 4a0efbdb18..40223f06e4 100644
--- a/crypto/ex_data.c
+++ b/crypto/ex_data.c
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <stdlib.h>
 #include "crypto/cryptlib.h"
 #include "internal/thread_once.h"
 
@@ -141,7 +142,8 @@ int ossl_crypto_get_ex_new_index_ex(OSSL_LIB_CTX *ctx, int class_index,
                                     long argl, void *argp,
                                     CRYPTO_EX_new *new_func,
                                     CRYPTO_EX_dup *dup_func,
-                                    CRYPTO_EX_free *free_func)
+                                    CRYPTO_EX_free *free_func,
+                                    int priority)
 {
     int toret = -1;
     EX_CALLBACK *a;
@@ -176,6 +178,7 @@ int ossl_crypto_get_ex_new_index_ex(OSSL_LIB_CTX *ctx, int class_index,
     a->new_func = new_func;
     a->dup_func = dup_func;
     a->free_func = free_func;
+    a->priority = priority;
 
     if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
         ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
@@ -195,7 +198,7 @@ int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
                             CRYPTO_EX_free *free_func)
 {
     return ossl_crypto_get_ex_new_index_ex(NULL, class_index, argl, argp,
-                                           new_func, dup_func, free_func);
+                                           new_func, dup_func, free_func, 0);
 }
 
 /*
@@ -331,6 +334,27 @@ int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
     return toret;
 }
 
+struct ex_callback_entry {
+    const EX_CALLBACK *excb;
+    int index;
+};
+
+static int ex_callback_compare(const void *a, const void *b)
+{
+    const struct ex_callback_entry *ap = (const struct ex_callback_entry *)a;
+    const struct ex_callback_entry *bp = (const struct ex_callback_entry *)b;
+
+    if (ap->excb == bp->excb)
+        return 0;
+
+    if (ap->excb == NULL)
+        return 1;
+    if (bp->excb == NULL)
+        return -1;
+    if (ap->excb->priority == bp->excb->priority)
+        return 0;
+    return ap->excb->priority > bp->excb->priority ? -1 : 1;
+}
 
 /*
  * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
@@ -341,9 +365,9 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
     int mx, i;
     EX_CALLBACKS *ip;
     void *ptr;
-    EX_CALLBACK *f;
-    EX_CALLBACK *stack[10];
-    EX_CALLBACK **storage = NULL;
+    const EX_CALLBACK *f;
+    struct ex_callback_entry stack[10];
+    struct ex_callback_entry *storage = NULL;
     OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ad->ctx);
 
     if (global == NULL)
@@ -360,23 +384,23 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
         else
             storage = OPENSSL_malloc(sizeof(*storage) * mx);
         if (storage != NULL)
-            for (i = 0; i < mx; i++)
-                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
+            for (i = 0; i < mx; i++) {
+                storage[i].excb = sk_EX_CALLBACK_value(ip->meth, i);
+                storage[i].index = i;
+            }
     }
     CRYPTO_THREAD_unlock(global->ex_data_lock);
 
-    for (i = 0; i < mx; i++) {
-        if (storage != NULL)
-            f = storage[i];
-        else {
-            if (!CRYPTO_THREAD_write_lock(global->ex_data_lock))
-                continue;
-            f = sk_EX_CALLBACK_value(ip->meth, i);
-            CRYPTO_THREAD_unlock(global->ex_data_lock);
-        }
-        if (f != NULL && f->free_func != NULL) {
-            ptr = CRYPTO_get_ex_data(ad, i);
-            f->free_func(obj, ptr, ad, i, f->argl, f->argp);
+    if (storage != NULL) {
+        /* Sort according to priority. High priority first */
+        qsort(storage, mx, sizeof(*storage), ex_callback_compare);
+        for (i = 0; i < mx; i++) {
+            f = storage[i].excb;
+
+            if (f != NULL && f->free_func != NULL) {
+                ptr = CRYPTO_get_ex_data(ad, storage[i].index);
+                f->free_func(obj, ptr, ad, storage[i].index, f->argl, f->argp);
+            }
         }
     }
 
diff --git a/crypto/initthread.c b/crypto/initthread.c
index 0740668071..fec3213047 100644
--- a/crypto/initthread.c
+++ b/crypto/initthread.c
@@ -278,6 +278,7 @@ static void thread_event_ossl_ctx_free(void *tlocal)
 }
 
 static const OSSL_LIB_CTX_METHOD thread_event_ossl_ctx_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     thread_event_ossl_ctx_new,
     thread_event_ossl_ctx_free,
 };
diff --git a/crypto/property/defn_cache.c b/crypto/property/defn_cache.c
index 6c6503bdcc..8007599526 100644
--- a/crypto/property/defn_cache.c
+++ b/crypto/property/defn_cache.c
@@ -63,6 +63,7 @@ static void *property_defns_new(OSSL_LIB_CTX *ctx) {
 }
 
 static const OSSL_LIB_CTX_METHOD property_defns_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     property_defns_new,
     property_defns_free,
 };
diff --git a/crypto/property/property.c b/crypto/property/property.c
index 2b841a2204..da6bc84e27 100644
--- a/crypto/property/property.c
+++ b/crypto/property/property.c
@@ -94,6 +94,7 @@ static void *ossl_ctx_global_properties_new(OSSL_LIB_CTX *ctx)
 
 
 static const OSSL_LIB_CTX_METHOD ossl_ctx_global_properties_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     ossl_ctx_global_properties_new,
     ossl_ctx_global_properties_free,
 };
diff --git a/crypto/property/property_string.c b/crypto/property/property_string.c
index 90bb322faa..9eb55cb461 100644
--- a/crypto/property/property_string.c
+++ b/crypto/property/property_string.c
@@ -105,6 +105,7 @@ err:
 }
 
 static const OSSL_LIB_CTX_METHOD property_string_data_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     property_string_data_new,
     property_string_data_free,
 };
diff --git a/crypto/provider.c b/crypto/provider.c
index bdff44afb9..766086a47b 100644
--- a/crypto/provider.c
+++ b/crypto/provider.c
@@ -23,7 +23,7 @@ OSSL_PROVIDER *OSSL_PROVIDER_try_load(OSSL_LIB_CTX *libctx, const char *name,
         && (prov = ossl_provider_new(libctx, name, NULL, 0)) == NULL)
         return NULL;
 
-    if (!ossl_provider_activate(prov, retain_fallbacks)) {
+    if (!ossl_provider_activate(prov, retain_fallbacks, 1)) {
         ossl_provider_free(prov);
         return NULL;
     }
@@ -88,6 +88,11 @@ void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov)
     return ossl_provider_prov_ctx(prov);
 }
 
+const OSSL_DISPATCH *OSSL_PROVIDER_get0_dispatch(const OSSL_PROVIDER *prov)
+{
+    return ossl_provider_get0_dispatch(prov);
+}
+
 int OSSL_PROVIDER_self_test(const OSSL_PROVIDER *prov)
 {
     return ossl_provider_self_test(prov);
diff --git a/crypto/provider_child.c b/crypto/provider_child.c
new file mode 100644
index 0000000000..0ca61c0686
--- /dev/null
+++ b/crypto/provider_child.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <assert.h>
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/provider.h>
+#include "internal/provider.h"
+#include "internal/cryptlib.h"
+
+DEFINE_STACK_OF(OSSL_PROVIDER)
+
+struct child_prov_globals {
+    const OSSL_CORE_HANDLE *handle;
+    const OSSL_CORE_HANDLE *curr_prov;
+    unsigned int isinited:1;
+    CRYPTO_RWLOCK *lock;
+    OSSL_FUNC_core_get_libctx_fn *c_get_libctx;
+    OSSL_FUNC_provider_register_child_cb_fn *c_provider_register_child_cb;
+    OSSL_FUNC_provider_deregister_child_cb_fn *c_provider_deregister_child_cb;
+    OSSL_FUNC_provider_name_fn *c_prov_name;
+    OSSL_FUNC_provider_get0_provider_ctx_fn *c_prov_get0_provider_ctx;
+    OSSL_FUNC_provider_get0_dispatch_fn *c_prov_get0_dispatch;
+    OSSL_FUNC_provider_up_ref_fn *c_prov_up_ref;
+    OSSL_FUNC_provider_free_fn *c_prov_free;
+};
+
+static void *child_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx)
+{
+    return OPENSSL_zalloc(sizeof(struct child_prov_globals));
+}
+
+static void child_prov_ossl_ctx_free(void *vgbl)
+{
+    struct child_prov_globals *gbl = vgbl;
+
+    gbl->c_provider_deregister_child_cb(gbl->handle);
+    CRYPTO_THREAD_lock_free(gbl->lock);
+    OPENSSL_free(gbl);
+}
+
+static const OSSL_LIB_CTX_METHOD child_prov_ossl_ctx_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
+    child_prov_ossl_ctx_new,
+    child_prov_ossl_ctx_free,
+};
+
+static OSSL_provider_init_fn ossl_child_provider_init;
+
+static int ossl_child_provider_init(const OSSL_CORE_HANDLE *handle,
+                                    const OSSL_DISPATCH *in,
+                                    const OSSL_DISPATCH **out,
+                                    void **provctx)
+{
+    OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL;
+    OSSL_LIB_CTX *ctx;
+    struct child_prov_globals *gbl;
+
+    for (; in->function_id != 0; in++) {
+        switch (in->function_id) {
+        case OSSL_FUNC_CORE_GET_LIBCTX:
+            c_get_libctx = OSSL_FUNC_core_get_libctx(in);
+            break;
+        default:
+            /* Just ignore anything we don't understand */
+            break;
+        }
+    }
+
+    if (c_get_libctx == NULL)
+        return 0;
+
+    /*
+     * We need an OSSL_LIB_CTX but c_get_libctx returns OPENSSL_CORE_CTX. We are
+     * a built-in provider and so we can get away with this cast. Normal
+     * providers can't do this.
+     */
+    ctx = (OSSL_LIB_CTX *)c_get_libctx(handle);
+
+    gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+                                &child_prov_ossl_ctx_method);
+    if (gbl == NULL)
+        return 0;
+
+    *provctx = gbl->c_prov_get0_provider_ctx(gbl->curr_prov);
+    *out = gbl->c_prov_get0_dispatch(gbl->curr_prov);
+
+    return 1;
+}
+
+static int provider_create_child_cb(const OSSL_CORE_HANDLE *prov, void *cbdata)
+{
+    OSSL_LIB_CTX *ctx = cbdata;
+    struct child_prov_globals *gbl;
+    const char *provname;
+    OSSL_PROVIDER *cprov;
+    int ret = 0;
+
+    gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+                                &child_prov_ossl_ctx_method);
+    if (gbl == NULL)
+        return 0;
+
+    /*
+     * If !gbl->isinited, then we are still initing and we already hold the
+     * lock - so don't take it again.
+     */
+    if (gbl->isinited && !CRYPTO_THREAD_write_lock(gbl->lock))
+        return 0;
+
+    provname = gbl->c_prov_name(prov);
+
+    /*
+     * We're operating under a lock so we can store the "current" provider in
+     * the global data.
+     */
+    gbl->curr_prov = prov;
+
+    if ((cprov = ossl_provider_find(ctx, provname, 1)) != NULL) {
+        /*
+        * We free the newly created ref. We rely on the provider sticking around
+        * in the provider store.
+        */
+        ossl_provider_free(cprov);
+
+        /*
+         * The provider already exists. It could be an unused built-in, or a
+         * previously created child, or it could have been explicitly loaded. If
+         * explicitly loaded it cannot be converted to a child and we ignore it
+         * - i.e. we don't start treating it like a child.
+         */
+        if (!ossl_provider_convert_to_child(cprov, prov,
+                                            ossl_child_provider_init))
+            goto err;
+    } else {
+        /*
+         * Create it - passing 1 as final param so we don't try and recursively
+         * init children
+         */
+        if ((cprov = ossl_provider_new(ctx, provname, ossl_child_provider_init,
+                                       1)) == NULL)
+            goto err;
+
+        /*
+        * We free the newly created ref. We rely on the provider sticking around
+        * in the provider store.
+        */
+        ossl_provider_free(cprov);
+
+        if (!ossl_provider_activate(cprov, 0, 0))
+            goto err;
+
+        if (!ossl_provider_set_child(cprov, prov)) {
+            ossl_provider_deactivate(cprov);
+            goto err;
+        }
+    }
+
+    ret = 1;
+ err:
+    if (gbl->isinited)
+        CRYPTO_THREAD_unlock(gbl->lock);
+    return ret;
+}
+
+static int provider_remove_child_cb(const OSSL_CORE_HANDLE *prov, void *cbdata)
+{
+    OSSL_LIB_CTX *ctx = cbdata;
+    struct child_prov_globals *gbl;
+    const char *provname;
+    OSSL_PROVIDER *cprov;
+
+    gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+                                &child_prov_ossl_ctx_method);
+    if (gbl == NULL)
+        return 0;
+
+    provname = gbl->c_prov_name(prov);
+    cprov = ossl_provider_find(ctx, provname, 1);
+    if (cprov == NULL)
+        return 0;
+    /*
+     * ossl_provider_find ups the ref count, so we free it again here. We can
+     * rely on the provider store reference count.
+     */
+    ossl_provider_free(cprov);
+    if (ossl_provider_is_child(cprov)
+            && !ossl_provider_deactivate(cprov))
+        return 0;
+
+    return 1;
+}
+
+int ossl_provider_init_child_providers(OSSL_LIB_CTX *ctx)
+{
+    struct child_prov_globals *gbl;
+
+    /* Should never happen */
+    if (ctx == NULL)
+        return 0;
+
+    gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+                                &child_prov_ossl_ctx_method);
+    if (gbl == NULL)
+        return 0;
+
+    if (!CRYPTO_THREAD_read_lock(gbl->lock))
+        return 0;
+    if (gbl->isinited) {
+        CRYPTO_THREAD_unlock(gbl->lock);
+        return 1;
+    }
+    CRYPTO_THREAD_unlock(gbl->lock);
+
+    if (!CRYPTO_THREAD_write_lock(gbl->lock))
+        return 0;
+    if (!gbl->isinited) {
+        if (!gbl->c_provider_register_child_cb(gbl->handle,
+                                               provider_create_child_cb,
+                                               provider_remove_child_cb,
+                                               ctx)) {
+            CRYPTO_THREAD_unlock(gbl->lock);
+            return 0;
+        }
+        gbl->isinited = 1;
+    }
+    CRYPTO_THREAD_unlock(gbl->lock);
+
+    return 1;
+}
+
+int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx,
+                                const OSSL_CORE_HANDLE *handle,
+                                const OSSL_DISPATCH *in)
+{
+    struct child_prov_globals *gbl;
+
+    if (ctx == NULL)
+        return 0;
+
+    gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+                                &child_prov_ossl_ctx_method);
+    if (gbl == NULL)
+        return 0;
+
+    gbl->handle = handle;
+    for (; in->function_id != 0; in++) {
+        switch (in->function_id) {
+        case OSSL_FUNC_CORE_GET_LIBCTX:
+            gbl->c_get_libctx = OSSL_FUNC_core_get_libctx(in);
+            break;
+        case OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB:
+            gbl->c_provider_register_child_cb
+                = OSSL_FUNC_provider_register_child_cb(in);
+            break;
+        case OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB:
+            gbl->c_provider_deregister_child_cb
+                = OSSL_FUNC_provider_deregister_child_cb(in);
+            break;
+        case OSSL_FUNC_PROVIDER_NAME:
+            gbl->c_prov_name = OSSL_FUNC_provider_name(in);
+            break;
+        case OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX:
+            gbl->c_prov_get0_provider_ctx
+                = OSSL_FUNC_provider_get0_provider_ctx(in);
+            break;
+        case OSSL_FUNC_PROVIDER_GET0_DISPATCH:
+            gbl->c_prov_get0_dispatch = OSSL_FUNC_provider_get0_dispatch(in);
+            break;
+        case OSSL_FUNC_PROVIDER_UP_REF:
+            gbl->c_prov_up_ref
+                = OSSL_FUNC_provider_up_ref(in);
+            break;
+        case OSSL_FUNC_PROVIDER_FREE:
+            gbl->c_prov_free = OSSL_FUNC_provider_free(in);
+            break;
+        default:
+            /* Just ignore anything we don't understand */
+            break;
+        }
+    }
+
+    if (gbl->c_get_libctx == NULL
+            || gbl->c_provider_register_child_cb == NULL
+            || gbl->c_prov_name == NULL
+            || gbl->c_prov_get0_provider_ctx == NULL
+            || gbl->c_prov_get0_dispatch == NULL
+            || gbl->c_prov_up_ref == NULL
+            || gbl->c_prov_free == NULL)
+        return 0;
+
+    gbl->lock = CRYPTO_THREAD_lock_new();
+    if (gbl->lock == NULL)
+        return 0;
+
+    return 1;
+}
+
+int ossl_provider_up_ref_parent(OSSL_PROVIDER *prov, int activate)
+{
+    struct child_prov_globals *gbl;
+
+    gbl = ossl_lib_ctx_get_data(ossl_provider_libctx(prov),
+                                OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+                                &child_prov_ossl_ctx_method);
+    if (gbl == NULL)
+        return 0;
+
+    return gbl->c_prov_up_ref(ossl_provider_get_parent(prov), activate);
+}
+
+int ossl_provider_free_parent(OSSL_PROVIDER *prov, int deactivate)
+{
+    struct child_prov_globals *gbl;
+
+    gbl = ossl_lib_ctx_get_data(ossl_provider_libctx(prov),
+                                OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+                                &child_prov_ossl_ctx_method);
+    if (gbl == NULL)
+        return 0;
+
+    return gbl->c_prov_free(ossl_provider_get_parent(prov), deactivate);
+}
diff --git a/crypto/provider_conf.c b/crypto/provider_conf.c
index a04a7aa553..5725ef3c63 100644
--- a/crypto/provider_conf.c
+++ b/crypto/provider_conf.c
@@ -45,6 +45,8 @@ static void prov_conf_ossl_ctx_free(void *vpcgbl)
 }
 
 static const OSSL_LIB_CTX_METHOD provider_conf_ossl_ctx_method = {
+    /* Must be freed before the provider store is freed */
+    OSSL_LIB_CTX_METHOD_PRIORITY_2,
     prov_conf_ossl_ctx_new,
     prov_conf_ossl_ctx_free,
 };
@@ -162,7 +164,7 @@ static int provider_conf_load(OSSL_LIB_CTX *libctx, const char *name,
     ok = provider_conf_params(prov, NULL, value, cnf);
 
     if (ok && activate) {
-        if (!ossl_provider_activate(prov, 0)) {
+        if (!ossl_provider_activate(prov, 0, 1)) {
             ok = 0;
         } else {
             if (pcgbl->activated_providers == NULL)
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index c419e6f644..f0b429d986 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -22,6 +22,7 @@
 #include "internal/provider.h"
 #include "internal/refcount.h"
 #include "internal/bio.h"
+#include "internal/core.h"
 #include "provider_local.h"
 #ifndef FIPS_MODULE
 # include <openssl/self_test.h>
@@ -41,6 +42,16 @@ typedef struct {
 } INFOPAIR;
 DEFINE_STACK_OF(INFOPAIR)
 
+#ifndef FIPS_MODULE
+typedef struct {
+    OSSL_PROVIDER *prov;
+    int (*create_cb)(const OSSL_CORE_HANDLE *provider, void *cbdata);
+    void (*remove_cb)(const OSSL_CORE_HANDLE *provider, void *cbdata);
+    void *cbdata;
+} OSSL_PROVIDER_CHILD_CB;
+DEFINE_STACK_OF(OSSL_PROVIDER_CHILD_CB)
+#endif
+
 struct provider_store_st;        /* Forward declaration */
 
 struct ossl_provider_st {
@@ -48,6 +59,9 @@ struct ossl_provider_st {
     unsigned int flag_initialized:1;
     unsigned int flag_activated:1;
     unsigned int flag_fallback:1; /* Can be used as fallback */
+#ifndef FIPS_MODULE
+    unsigned int flag_couldbechild:1;
+#endif
 
     /* Getting and setting the flags require synchronization */
     CRYPTO_RWLOCK *flag_lock;
@@ -91,8 +105,15 @@ struct ossl_provider_st {
     size_t operation_bits_sz;
     CRYPTO_RWLOCK *opbits_lock;
 
+#ifndef FIPS_MODULE
+    /* Whether this provider is the child of some other provider */
+    const OSSL_CORE_HANDLE *handle;
+    unsigned int ischild:1;
+#endif
+
     /* Provider side data */
     void *provctx;
+    const OSSL_DISPATCH *dispatch;
 };
 DEFINE_STACK_OF(OSSL_PROVIDER)
 
@@ -111,7 +132,9 @@ static int ossl_provider_cmp(const OSSL_PROVIDER * const *a,
  */
 
 struct provider_store_st {
+    OSSL_LIB_CTX *libctx;
     STACK_OF(OSSL_PROVIDER) *providers;
+    STACK_OF(OSSL_PROVIDER_CHILD_CB) *child_cbs;
     CRYPTO_RWLOCK *default_path_lock;
     CRYPTO_RWLOCK *lock;
     char *default_path;
@@ -132,6 +155,13 @@ static void provider_deactivate_free(OSSL_PROVIDER *prov)
     ossl_provider_free(prov);
 }
 
+#ifndef FIPS_MODULE
+static void ossl_provider_child_cb_free(OSSL_PROVIDER_CHILD_CB *cb)
+{
+    OPENSSL_free(cb);
+}
+#endif
+
 static void provider_store_free(void *vstore)
 {
     struct provider_store_st *store = vstore;
@@ -141,6 +171,10 @@ static void provider_store_free(void *vstore)
     store->freeing = 1;
     OPENSSL_free(store->default_path);
     sk_OSSL_PROVIDER_pop_free(store->providers, provider_deactivate_free);
+#ifndef FIPS_MODULE
+    sk_OSSL_PROVIDER_CHILD_CB_pop_free(store->child_cbs,
+                                       ossl_provider_child_cb_free);
+#endif
     CRYPTO_THREAD_lock_free(store->default_path_lock);
     CRYPTO_THREAD_lock_free(store->lock);
     OPENSSL_free(store);
@@ -154,10 +188,14 @@ static void *provider_store_new(OSSL_LIB_CTX *ctx)
     if (store == NULL
         || (store->providers = sk_OSSL_PROVIDER_new(ossl_provider_cmp)) == NULL
         || (store->default_path_lock = CRYPTO_THREAD_lock_new()) == NULL
+#ifndef FIPS_MODULE
+        || (store->child_cbs = sk_OSSL_PROVIDER_CHILD_CB_new_null()) == NULL
+#endif
         || (store->lock = CRYPTO_THREAD_lock_new()) == NULL) {
         provider_store_free(store);
         return NULL;
     }
+    store->libctx = ctx;
     store->use_fallbacks = 1;
 
     for (p = ossl_predefined_providers; p->name != NULL; p++) {
@@ -189,6 +227,8 @@ static void *provider_store_new(OSSL_LIB_CTX *ctx)
 }
 
 static const OSSL_LIB_CTX_METHOD provider_store_method = {
+    /* Needs to be freed before the child provider data is freed */
+    OSSL_LIB_CTX_METHOD_PRIORITY_1,
     provider_store_new,
     provider_store_free,
 };
@@ -233,8 +273,13 @@ OSSL_PROVIDER *ossl_provider_find(OSSL_LIB_CTX *libctx, const char *name,
          * Make sure any providers are loaded from config before we try to find
          * them.
          */
-        if (!noconfig)
-            OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+        if (!noconfig) {
+            if (ossl_lib_ctx_is_default(libctx))
+                OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+            if (ossl_lib_ctx_is_child(libctx)
+                    && !ossl_provider_init_child_providers(libctx))
+                return NULL;
+        }
 #endif
 
         tmpl.name = (char *)name;
@@ -274,6 +319,9 @@ static OSSL_PROVIDER *provider_new(const char *name,
     }
 
     prov->init_function = init_function;
+#ifndef FIPS_MODULE
+    prov->flag_couldbechild = 1;
+#endif
     return prov;
 }
 
@@ -283,9 +331,38 @@ int ossl_provider_up_ref(OSSL_PROVIDER *prov)
 
     if (CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock) <= 0)
         return 0;
+
+#ifndef FIPS_MODULE
+    if (prov->ischild) {
+        if (!ossl_provider_up_ref_parent(prov, 0)) {
+            ossl_provider_free(prov);
+            return 0;
+        }
+    }
+#endif
+
     return ref;
 }
 
+#ifndef FIPS_MODULE
+static int provider_up_ref_intern(OSSL_PROVIDER *prov, int activate)
+{
+    if (activate)
+        return ossl_provider_activate(prov, 0, 1);
+
+    return ossl_provider_up_ref(prov);
+}
+
+static int provider_free_intern(OSSL_PROVIDER *prov, int deactivate)
+{
+    if (deactivate)
+        return ossl_provider_deactivate(prov);
+
+    ossl_provider_free(prov);
+    return 1;
+}
+#endif
+
 OSSL_PROVIDER *ossl_provider_new(OSSL_LIB_CTX *libctx, const char *name,
                                  OSSL_provider_init_fn *init_function,
                                  int noconfig)
@@ -361,8 +438,7 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
          */
         if (ref == 0) {
             if (prov->flag_initialized) {
-                if (prov->teardown != NULL)
-                    prov->teardown(prov->provctx);
+                ossl_provider_teardown(prov);
 #ifndef OPENSSL_NO_ERR
 # ifndef FIPS_MODULE
                 if (prov->error_strings != NULL) {
@@ -397,6 +473,11 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
 #endif
             OPENSSL_free(prov);
         }
+#ifndef FIPS_MODULE
+        else if (prov->ischild) {
+            ossl_provider_free_parent(prov, 0);
+        }
+#endif
     }
 }
 
@@ -580,6 +661,10 @@ static int provider_init(OSSL_PROVIDER *prov, int flag_lock)
         goto end;
     }
     prov->provctx = tmp_provctx;
+    prov->dispatch = provider_dispatch;
+#ifndef FIPS_MODULE
+    prov->flag_couldbechild = 0;
+#endif
 
     for (; provider_dispatch->function_id != 0; provider_dispatch++) {
         switch (provider_dispatch->function_id) {
@@ -685,17 +770,49 @@ static int provider_init(OSSL_PROVIDER *prov, int flag_lock)
 static int provider_deactivate(OSSL_PROVIDER *prov)
 {
     int count;
+    struct provider_store_st *store;
 
     if (!ossl_assert(prov != NULL))
         return -1;
 
-    if (!CRYPTO_THREAD_write_lock(prov->flag_lock))
+    store = get_provider_store(prov->libctx);
+    if (store == NULL)
+        return -1;
+
+    if (!CRYPTO_THREAD_read_lock(store->lock))
         return -1;
+    if (!CRYPTO_THREAD_write_lock(prov->flag_lock)) {
+        CRYPTO_THREAD_unlock(store->lock);
+        return -1;
+    }
 
-    if ((count = --prov->activatecnt) < 1)
+#ifndef FIPS_MODULE
+    if (prov->activatecnt == 2 && prov->ischild) {
+        /*
+         * We have had a direct activation in this child libctx so we need to
+         * now down the ref count in the parent provider.
+         */
+        ossl_provider_free_parent(prov, 1);
+    }
+#endif
+
+    if ((count = --prov->activatecnt) < 1) {
         prov->flag_activated = 0;
+#ifndef FIPS_MODULE
+        {
+            int i, max = sk_OSSL_PROVIDER_CHILD_CB_num(store->child_cbs);
+            OSSL_PROVIDER_CHILD_CB *child_cb;
+
+            for (i = 0; i < max; i++) {
+                child_cb = sk_OSSL_PROVIDER_CHILD_CB_value(store->child_cbs, i);
+                child_cb->remove_cb((OSSL_CORE_HANDLE *)prov, child_cb->cbdata);
+            }
+        }
+#endif
+    }
 
     CRYPTO_THREAD_unlock(prov->flag_lock);
+    CRYPTO_THREAD_unlock(store->lock);
 
     /* We don't deinit here, that's done in ossl_provider_free() */
     return count;
@@ -705,22 +822,64 @@ static int provider_deactivate(OSSL_PROVIDER *prov)
  * Activate a provider.
  * Return -1 on failure and the activation count on success
  */
-static int provider_activate(OSSL_PROVIDER *prov, int flag_lock)
+static int provider_activate(OSSL_PROVIDER *prov, int lock, int upcalls)
 {
-    int count;
+    int count = -1;
 
-    if (provider_init(prov, flag_lock)) {
-        if (flag_lock && !CRYPTO_THREAD_write_lock(prov->flag_lock))
+    if (provider_init(prov, lock)) {
+        int ret = 1;
+        struct provider_store_st *store;
+
+        store = get_provider_store(prov->libctx);
+        if (store == NULL)
             return -1;
-        count = ++prov->activatecnt;
-        prov->flag_activated = 1;
-        if (flag_lock)
-            CRYPTO_THREAD_unlock(prov->flag_lock);
 
-        return count;
+        if (lock && !CRYPTO_THREAD_read_lock(store->lock))
+            return -1;
+
+        if (lock && !CRYPTO_THREAD_write_lock(prov->flag_lock)) {
+            CRYPTO_THREAD_unlock(store->lock);
+            return -1;
+        }
+
+#ifndef FIPS_MODULE
+        if (prov->ischild && upcalls)
+            ret = ossl_provider_up_ref_parent(prov, 1);
+#endif
+
+        if (ret) {
+            count = ++prov->activatecnt;
+            prov->flag_activated = 1;
+
+#ifndef FIPS_MODULE
+            if (prov->activatecnt == 1) {
+                OSSL_PROVIDER_CHILD_CB *child_cb;
+                int i, max;
+
+                max = sk_OSSL_PROVIDER_CHILD_CB_num(store->child_cbs);
+                for (i = 0; i < max; i++) {
+                    /*
+                     * This is newly activated (activatecnt == 1), so we need to
+                     * create child providers as necessary.
+                     */
+                    child_cb = sk_OSSL_PROVIDER_CHILD_CB_value(store->child_cbs,
+                                                               i);
+                    ret &= child_cb->create_cb((OSSL_CORE_HANDLE *)prov,
+                                               child_cb->cbdata);
+                }
+            }
+#endif
+        }
+
+        if (lock) {
+            CRYPTO_THREAD_unlock(prov->flag_lock);
+            CRYPTO_THREAD_unlock(store->lock);
+        }
+        if (!ret)
+            return -1;
     }
 
-    return -1;
+    return count;
 }
 
 static int provider_flush_store_cache(const OSSL_PROVIDER *prov)
@@ -741,13 +900,14 @@ static int provider_flush_store_cache(const OSSL_PROVIDER *prov)
     return 1;
 }
 
-int ossl_provider_activate(OSSL_PROVIDER *prov, int retain_fallbacks)
+int ossl_provider_activate(OSSL_PROVIDER *prov, int retain_fallbacks,
+                           int upcalls)
 {
     int count;
 
     if (prov == NULL)
         return 0;
-    if ((count = provider_activate(prov, 1)) > 0) {
+    if ((count = provider_activate(prov, 1, upcalls)) > 0) {
         if (!retain_fallbacks) {
             if (!CRYPTO_THREAD_write_lock(prov->store->lock)) {
                 provider_deactivate(prov);
@@ -808,9 +968,12 @@ static void provider_activate_fallbacks(struct provider_store_st *store)
         OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i);
 
         if (ossl_provider_up_ref(prov)) {
-            if (prov->flag_fallback) {
-                if (provider_activate(prov, 1) > 0)
-                    activated_fallback_count++;
+            if (CRYPTO_THREAD_write_lock(prov->flag_lock)) {
+                if (prov->flag_fallback) {
+                    if (provider_activate(prov, 0, 0) > 0)
+                        activated_fallback_count++;
+                }
+                CRYPTO_THREAD_unlock(prov->flag_lock);
             }
             ossl_provider_free(prov);
         }
@@ -842,7 +1005,11 @@ int ossl_provider_doall_activated(OSSL_LIB_CTX *ctx,
      * Make sure any providers are loaded from config before we try to use
      * them.
      */
-    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+    if (ossl_lib_ctx_is_default(ctx))
+        OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+    if (ossl_lib_ctx_is_child(ctx)
+            && !ossl_provider_init_child_providers(ctx))
+        return 0;
 #endif
 
     if (store == NULL)
@@ -879,7 +1046,7 @@ int ossl_provider_doall_activated(OSSL_LIB_CTX *ctx,
              * It's already activated, but we up the activated count to ensure
              * it remains activated until after we've called the user callback.
              */
-            if (provider_activate(prov, 0) < 0) {
+            if (provider_activate(prov, 0, 1) < 0) {
                 ossl_provider_free(prov);
                 CRYPTO_THREAD_unlock(prov->flag_lock);
                 goto err_unlock;
@@ -988,6 +1155,14 @@ void *ossl_provider_prov_ctx(const OSSL_PROVIDER *prov)
     return NULL;
 }
 
+const OSSL_DISPATCH *ossl_provider_get0_dispatch(const OSSL_PROVIDER *prov)
+{
+    if (prov != NULL)
+        return prov->dispatch;
+
+    return NULL;
+}
+
 OSSL_LIB_CTX *ossl_provider_libctx(const OSSL_PROVIDER *prov)
 {
     return prov != NULL ? prov->libctx : NULL;
@@ -996,7 +1171,11 @@ OSSL_LIB_CTX *ossl_provider_libctx(const OSSL_PROVIDER *prov)
 /* Wrappers around calls to the provider */
 void ossl_provider_teardown(const OSSL_PROVIDER *prov)
 {
-    if (prov->teardown != NULL)
+    if (prov->teardown != NULL
+#ifndef FIPS_MODULE
+            && !prov->ischild
+#endif
+       )
         prov->teardown(prov->provctx);
 }
 
@@ -1131,6 +1310,171 @@ int ossl_provider_test_operation_bit(OSSL_PROVIDER *provider, size_t bitnum,
     return 1;
 }
 
+#ifndef FIPS_MODULE
+const OSSL_CORE_HANDLE *ossl_provider_get_parent(OSSL_PROVIDER *prov)
+{
+    return prov->handle;
+}
+
+int ossl_provider_is_child(const OSSL_PROVIDER *prov)
+{
+    return prov->ischild;
+}
+
+int ossl_provider_set_child(OSSL_PROVIDER *prov, const OSSL_CORE_HANDLE *handle)
+{
+    prov->handle = handle;
+    prov->ischild = 1;
+
+    return 1;
+}
+
+int ossl_provider_convert_to_child(OSSL_PROVIDER *prov,
+                                   const OSSL_CORE_HANDLE *handle,
+                                   OSSL_provider_init_fn *init_function)
+{
+    int flush = 0;
+
+    if (!CRYPTO_THREAD_write_lock(prov->store->lock))
+        return 0;
+    if (!CRYPTO_THREAD_write_lock(prov->flag_lock)) {
+        CRYPTO_THREAD_unlock(prov->store->lock);
+        return 0;
+    }
+    /*
+     * The provider could be in one of three states: (1) Already a child,
+     * (2) Not a child (but eligible to be one), or (3) Not a child (not
+     * eligible to be one).
+     */
+    if (prov->flag_couldbechild) {
+        ossl_provider_set_child(prov, handle);
+        prov->init_function = init_function;
+    }
+    if (prov->ischild && provider_activate(prov, 0, 0)) {
+        flush = 1;
+        prov->store->use_fallbacks = 0;
+    }
+
+    CRYPTO_THREAD_unlock(prov->flag_lock);
+    CRYPTO_THREAD_unlock(prov->store->lock);
+
+    if (flush)
+        provider_flush_store_cache(prov);
+
+    /*
+     * We report success whether or not the provider was eligible for conversion
+     * to a child. If its not elgibile then it has already been loaded as a non
+     * child provider and we should keep it like that.
+     */
+    return 1;
+}
+
+static int ossl_provider_register_child_cb(const OSSL_CORE_HANDLE *handle,
+                                           int (*create_cb)(
+                                               const OSSL_CORE_HANDLE *provider,
+                                               void *cbdata),
+                                           void (*remove_cb)(
+                                               const OSSL_CORE_HANDLE *provider,
+                                               void *cbdata),
+                                           void *cbdata)
+{
+    /*
+     * This is really an OSSL_PROVIDER that we created and cast to
+     * OSSL_CORE_HANDLE originally. Therefore it is safe to cast it back.
+     */
+    OSSL_PROVIDER *thisprov = (OSSL_PROVIDER *)handle;
+    OSSL_PROVIDER *prov;
+    OSSL_LIB_CTX *libctx = thisprov->libctx;
+    struct provider_store_st *store = NULL;
+    int ret = 0, i, max;
+    OSSL_PROVIDER_CHILD_CB *child_cb;
+
+    if ((store = get_provider_store(libctx)) == NULL)
+        return 0;
+
+    child_cb = OPENSSL_malloc(sizeof(*child_cb));
+    if (child_cb == NULL)
+        return 0;
+    child_cb->prov = thisprov;
+    child_cb->create_cb = create_cb;
+    child_cb->remove_cb = remove_cb;
+    child_cb->cbdata = cbdata;
+
+    if (!CRYPTO_THREAD_write_lock(store->lock)) {
+        OPENSSL_free(child_cb);
+        return 0;
+    }
+    max = sk_OSSL_PROVIDER_num(store->providers);
+    for (i = 0; i < max; i++) {
+        prov = sk_OSSL_PROVIDER_value(store->providers, i);
+        /*
+         * We require register_child_cb to be called during a provider init
+         * function. The currently initing provider will never be activated yet
+         * and we we should not attempt to aquire the flag_lock for it.
+         */
+        if (prov == thisprov)
+            continue;
+        if (!CRYPTO_THREAD_read_lock(prov->flag_lock))
+            break;
+        /*
+         * We hold the lock while calling the user callback. This means that the
+         * user callback must be short and simple and not do anything likely to
+         * cause a deadlock.
+         */
+        if (prov->flag_activated
+                && !create_cb((OSSL_CORE_HANDLE *)prov, cbdata))
+            break;
+        CRYPTO_THREAD_unlock(prov->flag_lock);
+    }
+    if (i == max) {
+        /* Success */
+        ret = sk_OSSL_PROVIDER_CHILD_CB_push(store->child_cbs, child_cb);
+    }
+    if (i != max || ret <= 0) {
+        /* Failed during creation. Remove everything we just added */
+        for (; i >= 0; i--) {
+            prov = sk_OSSL_PROVIDER_value(store->providers, i);
+            remove_cb((OSSL_CORE_HANDLE *)prov, cbdata);
+        }
+        OPENSSL_free(child_cb);
+        ret = 0;
+    }
+    CRYPTO_THREAD_unlock(store->lock);
+
+    return ret;
+}
+
+static void ossl_provider_deregister_child_cb(const OSSL_CORE_HANDLE *handle)
+{
+    /*
+     * This is really an OSSL_PROVIDER that we created and cast to
+     * OSSL_CORE_HANDLE originally. Therefore it is safe to cast it back.
+     */
+    OSSL_PROVIDER *thisprov = (OSSL_PROVIDER *)handle;
+    OSSL_LIB_CTX *libctx = thisprov->libctx;
+    struct provider_store_st *store = NULL;
+    int i, max;
+    OSSL_PROVIDER_CHILD_CB *child_cb;
+
+    if ((store = get_provider_store(libctx)) == NULL)
+        return;
+
+    if (!CRYPTO_THREAD_write_lock(store->lock))
+        return;
+    max = sk_OSSL_PROVIDER_CHILD_CB_num(store->child_cbs);
+    for (i = 0; i < max; i++) {
+        child_cb = sk_OSSL_PROVIDER_CHILD_CB_value(store->child_cbs, i);
+        if (child_cb->prov == thisprov) {
+            /* Found an entry */
+            sk_OSSL_PROVIDER_CHILD_CB_delete(store->child_cbs, i);
+            OPENSSL_free(child_cb);
+            break;
+        }
+    }
+    CRYPTO_THREAD_unlock(store->lock);
+}
+#endif
+
 /*-
  * Core functions for the provider
  * ===============================
@@ -1348,7 +1692,22 @@ static const OSSL_DISPATCH core_dispatch_[] = {
     { OSSL_FUNC_CRYPTO_SECURE_ALLOCATED,
         (void (*)(void))CRYPTO_secure_allocated },
     { OSSL_FUNC_OPENSSL_CLEANSE, (void (*)(void))OPENSSL_cleanse },
-
+#ifndef FIPS_MODULE
+    { OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB,
+        (void (*)(void))ossl_provider_register_child_cb },
+    { OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB,
+        (void (*)(void))ossl_provider_deregister_child_cb },
+    { OSSL_FUNC_PROVIDER_NAME,
+        (void (*)(void))OSSL_PROVIDER_name },
+    { OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX,
+        (void (*)(void))OSSL_PROVIDER_get0_provider_ctx },
+    { OSSL_FUNC_PROVIDER_GET0_DISPATCH,
+        (void (*)(void))OSSL_PROVIDER_get0_dispatch },
+    { OSSL_FUNC_PROVIDER_UP_REF,
+        (void (*)(void))provider_up_ref_intern },
+    { OSSL_FUNC_PROVIDER_FREE,
+        (void (*)(void))provider_free_intern },
+#endif
     { 0, NULL }
 };
 static const OSSL_DISPATCH *core_dispatch = core_dispatch_;
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index f6c5bc15ee..bdf5f71f44 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -486,6 +486,7 @@ static void rand_ossl_ctx_free(void *vdgbl)
 }
 
 static const OSSL_LIB_CTX_METHOD rand_drbg_ossl_ctx_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     rand_ossl_ctx_new,
     rand_ossl_ctx_free,
 };
diff --git a/crypto/self_test_core.c b/crypto/self_test_core.c
index a4f6c9ab2a..341af7b194 100644
--- a/crypto/self_test_core.c
+++ b/crypto/self_test_core.c
@@ -46,6 +46,7 @@ static void self_test_set_callback_free(void *stcb)
 }
 
 static const OSSL_LIB_CTX_METHOD self_test_set_callback_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     self_test_set_callback_new,
     self_test_set_callback_free,
 };
diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c
index a2ab341fe9..7bf0a329ce 100644
--- a/crypto/store/store_meth.c
+++ b/crypto/store/store_meth.c
@@ -81,6 +81,7 @@ static void *loader_store_new(OSSL_LIB_CTX *ctx)
 
 
 static const OSSL_LIB_CTX_METHOD loader_store_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     loader_store_new,
     loader_store_free,
 };
diff --git a/doc/internal/man3/ossl_lib_ctx_get_data.pod b/doc/internal/man3/ossl_lib_ctx_get_data.pod
index b79e93d848..6b80aa011e 100644
--- a/doc/internal/man3/ossl_lib_ctx_get_data.pod
+++ b/doc/internal/man3/ossl_lib_ctx_get_data.pod
@@ -2,7 +2,8 @@
 
 =head1 NAME
 
-ossl_lib_ctx_get_data, ossl_lib_ctx_run_once, ossl_lib_ctx_onfree
+ossl_lib_ctx_get_data, ossl_lib_ctx_run_once, ossl_lib_ctx_onfree,
+ossl_lib_ctx_is_child
 - internal OSSL_LIB_CTX routines
 
 =head1 SYNOPSIS
@@ -11,6 +12,7 @@ ossl_lib_ctx_get_data, ossl_lib_ctx_run_once, ossl_lib_ctx_onfree
  #include "internal/cryptlib.h"
 
  typedef struct ossl_lib_ctx_method {
+     int priority;
      void *(*new_func)(OSSL_LIB_CTX *ctx);
      void (*free_func)(void *);
  } OSSL_LIB_CTX_METHOD;
@@ -22,6 +24,8 @@ ossl_lib_ctx_get_data, ossl_lib_ctx_run_once, ossl_lib_ctx_onfree
                            ossl_lib_ctx_run_once_fn run_once_fn);
  int ossl_lib_ctx_onfree(OSSL_LIB_CTX *ctx, ossl_lib_ctx_onfree_fn onfreefn);
 
+ int ossl_lib_ctx_is_child(OSSL_LIB_CTX *ctx);
+
 =head1 DESCRIPTION
 
 Internally, the OpenSSL library context B<OSSL_LIB_CTX> is implemented
@@ -53,6 +57,9 @@ using ossl_lib_ctx_onfree. This associates an "on free" routine I<onfreefn> with
 the library context I<ctx>. When I<ctx> is freed all associated "on free"
 routines are called.
 
+ossl_lib_ctx_is_child() returns 1 if this library context is a child and 0
+otherwise.
+
 =head1 RETURN VALUES
 
 ossl_lib_ctx_get_data() returns a pointer on success, or NULL on
@@ -86,8 +93,13 @@ and a destructor to an index.
  /*
   * Include a reference to this in the methods table in context.c 
   * OSSL_LIB_CTX_FOO_INDEX should be added to internal/cryptlib.h
+  * Priorities can be OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
+  * OSSL_LIB_CTX_METHOD_PRIORITY_1, OSSL_LIB_CTX_METHOD_PRIORITY_2, etc.
+  * Default priority is low (0). The higher the priority the earlier the
+  * method's destructor will be called when the library context is cleaned up.
   */
  const OSSL_LIB_CTX_METHOD foo_method = {
+     OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
      foo_new,
      foo_free
  };
diff --git a/doc/internal/man3/ossl_provider_new.pod b/doc/internal/man3/ossl_provider_new.pod
index e83869a9de..ff347bad3f 100644
--- a/doc/internal/man3/ossl_provider_new.pod
+++ b/doc/internal/man3/ossl_provider_new.pod
@@ -5,7 +5,10 @@
 ossl_provider_find, ossl_provider_new, ossl_provider_up_ref,
 ossl_provider_free,
 ossl_provider_set_fallback, ossl_provider_set_module_path,
-ossl_provider_add_parameter,
+ossl_provider_add_parameter, ossl_provider_set_child, ossl_provider_get_parent,
+ossl_provider_up_ref_parent, ossl_provider_free_parent,
+ossl_provider_get0_dispatch, ossl_provider_init_child_providers,
+ossl_provider_init_as_child,
 ossl_provider_activate, ossl_provider_deactivate, ossl_provider_available,
 ossl_provider_ctx,
 ossl_provider_doall_activated,
@@ -37,11 +40,19 @@ ossl_provider_get_capabilities
  int ossl_provider_add_parameter(OSSL_PROVIDER *prov, const char *name,
                                  const char *value);
 
+ /* Child Providers */
+ int ossl_provider_set_child(OSSL_PROVIDER *prov,
+                             const OSSL_CORE_HANDLE *handle);
+ const OSSL_CORE_HANDLE *ossl_provider_get_parent(OSSL_PROVIDER *prov);
+ int ossl_provider_up_ref_parent(OSSL_PROVIDER *prov, int activate);
+ int ossl_provider_free_parent(OSSL_PROVIDER *prov, int deactivate);
+
  /*
   * Activate the Provider
   * If the Provider is a module, the module will be loaded
   */
- int ossl_provider_activate(OSSL_PROVIDER *prov, int retain_fallbacks);
+ int ossl_provider_activate(OSSL_PROVIDER *prov, int retain_fallbacks,
+                            int upcalls);
  int ossl_provider_deactivate(OSSL_PROVIDER *prov);
  /* Check if provider is available (activated) */
  int ossl_provider_available(OSSL_PROVIDER *prov);
@@ -49,6 +60,8 @@ ossl_provider_get_capabilities
  /* Return pointer to the provider's context */
  void *ossl_provider_ctx(const OSSL_PROVIDER *prov);
 
+ const OSSL_DISPATCH *ossl_provider_get0_dispatch(const OSSL_PROVIDER *prov);
+
  /* Iterate over all loaded providers */
  int ossl_provider_doall_activated(OSSL_LIB_CTX *,
                                    int (*cb)(OSSL_PROVIDER *provider,
@@ -82,6 +95,12 @@ ossl_provider_get_capabilities
                                       int *result);
  int ossl_provider_clear_all_operation_bits(OSSL_LIB_CTX *libctx);
 
+ int ossl_provider_init_child_providers(OSSL_LIB_CTX *ctx);
+ int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx,
+                                 const OSSL_CORE_HANDLE *handle,
+                                 const OSSL_DISPATCH *in);
+
+
 =head1 DESCRIPTION
 
 I<OSSL_PROVIDER> is a type that holds all the necessary information
@@ -162,6 +181,19 @@ provider will use the name to find the value it wants.
 Only text parameters can be given, and it's up to the provider to
 interpret them.
 
+ossl_provider_set_child() marks this provider as a child of a provider in the
+parent library context. I<handle> is the B<OSSL_CORE_HANDLE> object passed to
+the provider's B<OSSL_provider_init> function.
+
+ossl_provider_get_parent() obtains the handle on the parent provider.
+
+ossl_provider_up_ref_parent() increases the reference count on the parent
+provider. If I<activate> is nonzero then the parent provider is also activated.
+
+ossl_provider_free_parent() decreases the reference count on the parent
+provider. If I<deactivate> is nonzero then the parent provider is also
+deactivated.
+
 ossl_provider_activate() "activates" the provider for the given
 provider object I<prov> by incrementing its activation count, flagging
 it as activated, and initializing it if it isn't already initialized.
@@ -184,7 +216,9 @@ be located in that module, and called.
 =back
 
 If I<retain_fallbacks> is zero, fallbacks are disabled.  If it is nonzero,
-fallbacks are left unchanged.
+fallbacks are left unchanged. If I<upcalls> is nonzero then, if this is a child
+provider, upcalls to the parent libctx will be made to inform it of an
+up-ref.
 
 ossl_provider_deactivate() "deactivates" the provider for the given
 provider object I<prov> by decrementing its activation count.  When
@@ -198,6 +232,10 @@ ossl_provider_ctx() returns a context created by the provider.
 Outside of the provider, it's completely opaque, but it needs to be
 passed back to some of the provider functions.
 
+ossl_provider_get0_dispatch() returns the dispatch table that the provider
+initially returned in the I<out> parameter of its B<OSSL_provider_init>
+function.
+
 ossl_provider_doall_activated() iterates over all the currently
 "activated" providers, and calls I<cb> for each of them.
 If no providers have been "activated" yet, it tries to activate all
@@ -253,6 +291,15 @@ I<*result> to 1 or 0 accorddingly.
 ossl_provider_clear_all_operation_bits() clears all of the operation bits
 to (0) for all providers in the library context I<libctx>.
 
+ossl_provider_init_child_providers() registers the callbacks required to
+receive notifications about loading and unloading of providers in the parent
+library context.
+
+ossl_provider_init_as_child() stores in the library context I<ctx> references to
+the necessary upcalls for managing child providers. The I<handle> and I<in>
+parameters are the B<OSSL_CORE_HANDLE> and B<OSSL_DISPATCH> pointers that were
+passed to the provider's B<OSSL_provider_init> function.
+
 =head1 NOTES
 
 Locating a provider module happens as follows:
diff --git a/doc/man3/OSSL_LIB_CTX.pod b/doc/man3/OSSL_LIB_CTX.pod
index 9796c8575c..57037e2ba6 100644
--- a/doc/man3/OSSL_LIB_CTX.pod
+++ b/doc/man3/OSSL_LIB_CTX.pod
@@ -3,8 +3,8 @@
 =head1 NAME
 
 OSSL_LIB_CTX, OSSL_LIB_CTX_new, OSSL_LIB_CTX_new_from_dispatch,
-OSSL_LIB_CTX_free, OSSL_LIB_CTX_load_config, OSSL_LIB_CTX_get0_global_default,
-OSSL_LIB_CTX_set0_default
+OSSL_LIB_CTX_new_child, OSSL_LIB_CTX_free, OSSL_LIB_CTX_load_config,
+OSSL_LIB_CTX_get0_global_default, OSSL_LIB_CTX_set0_default
 - OpenSSL library context
 
 =head1 SYNOPSIS
@@ -14,7 +14,10 @@ OSSL_LIB_CTX_set0_default
  typedef struct ossl_lib_ctx_st OSSL_LIB_CTX;
 
  OSSL_LIB_CTX *OSSL_LIB_CTX_new(void);
- OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_DISPATCH *in);
+ OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_CORE_HANDLE *handle,
+                                              const OSSL_DISPATCH *in);
+ OSSL_LIB_CTX *OSSL_LIB_CTX_new_child(const OSSL_CORE_HANDLE *handle,
+                                      const OSSL_DISPATCH *in);
  int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file);
  void OSSL_LIB_CTX_free(OSSL_LIB_CTX *ctx);
  OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void);
@@ -36,10 +39,49 @@ OSSL_LIB_CTX_new() creates a new OpenSSL library context.
 
 OSSL_LIB_CTX_new_from_dispatch() creates a new OpenSSL library context
 initialised to use callbacks from the OSSL_DISPATCH structure. This is primarily
-useful for provider authors. The dispatch structure passed should be the same
-one as passed to a provider's OSSL_provider_init function in the I<in> argument.
-Some OpenSSL functions, such as L<BIO_new_from_core_bio(3)>, require the library
-context to be created in this way in order to work.
+useful for provider authors. The I<handle> and dispatch structure arguments
+passed should be the same ones as passed to a provider's
+OSSL_provider_init function. Some OpenSSL functions, such as
+L<BIO_new_from_core_bio(3)>, require the library context to be created in this
+way in order to work.
+
+OSSL_LIB_CTX_new_child() is only useful to provider authors and does the same
+thing as OSSL_LIB_CTX_new_from_dispatch() except that it additionally links the
+new library context to the application library context. The new library context
+is a full library context in its own right, but will have all the same providers
+available to it that are available in the application library context (without
+having to reload them). If the application loads or unloads providers from the
+application library context then this will be automatically mirrored in the
+child library context.
+
+In addition providers that are not loaded in the parent library context can be
+explicitly loaded into the child library context independently from the parent
+library context. Providers loaded independently in this way will not be mirrored
+in the parent library context and will not be affected if the parent library
+context subsequently loads the same provider.
+
+A provider may call the function L<OSSL_PROVIDER_load(3)> with the child library
+context as required. If the provider already exists due to it being mirrored
+from the parent library context then it will remain available and its reference
+count will be increased. If L<OSSL_PROVIDER_load(3)> is called in this way then
+L<OSSL_PROVIDER_unload(3)> should be subsequently called to decrement the
+reference count. L<OSSL_PROVIDER_unload(3)> must not be called for a provider in
+the child library context that did not have an earlier L<OSSL_PROVIDER_load(3)>
+call for that provider in that child library context.
+
+OSSL_LIB_CTX_new_child() must only be called from within the scope of a
+provider's B<OSSL_provider_init> function (see L<provider-base(7)>). Calling it
+outside of that function may succeed but may not correctly mirror all providers
+and is considered undefined behaviour. When called from within the scope of a
+provider's B<OSSL_provider_init> function the currently initialising provider is
+not yet available in the application's library context and therefore will
+similarly not yet be available in the newly constructed child library context.
+As soon as the B<OSSL_provider_init> function returns then the new provider is
+available in the application's library context and will be similarly mirrored in
+the child library context. Since the current provider is still initialising
+the provider should not attempt to perform fetches, or call any function that
+performs a fetch using the child library context until after the initialisation
+function has completed.
 
 OSSL_LIB_CTX_load_config() loads a configuration file using the given C<ctx>.
 This can be used to associate a library context with providers that are loaded
diff --git a/doc/man3/OSSL_PROVIDER.pod b/doc/man3/OSSL_PROVIDER.pod
index d5317ee3f5..391084e68e 100644
--- a/doc/man3/OSSL_PROVIDER.pod
+++ b/doc/man3/OSSL_PROVIDER.pod
@@ -7,8 +7,9 @@ OSSL_PROVIDER, OSSL_PROVIDER_load, OSSL_PROVIDER_try_load, OSSL_PROVIDER_unload,
 OSSL_PROVIDER_available, OSSL_PROVIDER_do_all,
 OSSL_PROVIDER_gettable_params, OSSL_PROVIDER_get_params,
 OSSL_PROVIDER_query_operation, OSSL_PROVIDER_unquery_operation,
-OSSL_PROVIDER_get0_provider_ctx, OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name,
-OSSL_PROVIDER_get_capabilities, OSSL_PROVIDER_self_test
+OSSL_PROVIDER_get0_provider_ctx, OSSL_PROVIDER_get0_dispatch,
+OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name, OSSL_PROVIDER_get_capabilities,
+OSSL_PROVIDER_self_test
 - provider routines
 
 =head1 SYNOPSIS
@@ -39,6 +40,7 @@ OSSL_PROVIDER_get_capabilities, OSSL_PROVIDER_self_test
                                       int operation_id,
                                       const OSSL_ALGORITHM *algs);
  void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov);
+ const OSSL_DISPATCH *OSSL_PROVIDER_get0_dispatch(const OSSL_PROVIDER *prov);
 
  int OSSL_PROVIDER_add_builtin(OSSL_LIB_CTX *libctx, const char *name,
                                ossl_provider_init_fn *init_fn);
@@ -130,6 +132,10 @@ OSSL_PROVIDER_get0_provider_ctx() returns the provider context for the given
 provider. The provider context is an opaque handle set by the provider itself
 and is passed back to the provider by libcrypto in various function calls.
 
+OSSL_PROVIDER_get0_dispatch() returns the provider's dispatch table as it was
+returned in the I<out> parameter from the provider's init function. See
+L<provider-base(7)>.
+
 If it is permissible to cache references to this array then I<*no_store> is set
 to 0 or 1 otherwise. If the array is not cacheable then it is assumed to
 have a short lifetime.
diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod
index c07f9fddf6..fe48beb1d1 100644
--- a/doc/man7/provider-base.pod
+++ b/doc/man7/provider-base.pod
@@ -80,6 +80,21 @@ provider-base
  void cleanup_nonce(const OSSL_CORE_HANDLE *handle,
                     unsigned char *buf, size_t len);
 
+ /* Functions for querying the providers in the application library context */
+ int provider_register_child_cb(const OSSL_CORE_HANDLE *handle,
+                     int (*create_cb)(const OSSL_CORE_HANDLE *provider,
+                                      void *cbdata),
+                     int (*remove_cb)(const OSSL_CORE_HANDLE *provider,
+                                      void *cbdata),
+                     void *cbdata);
+ void provider_deregister_child_cb(const OSSL_CORE_HANDLE *handle);
+ const char *provider_name(const OSSL_CORE_HANDLE *prov);
+ void *provider_get0_provider_ctx(const OSSL_CORE_HANDLE *prov);
+ const OSSL_DISPATCH *provider_get0_dispatch(const OSSL_CORE_HANDLE *prov);
+ int provider_up_ref(const OSSL_CORE_HANDLE *prov, int activate);
+ int provider_free(const OSSL_CORE_HANDLE *prov, int deactivate);
+
+
  /* Functions offered by the provider to libcrypto */
  void provider_teardown(void *provctx);
  const OSSL_ITEM *provider_gettable_params(void *provctx);
@@ -260,6 +275,45 @@ cleanup_nonce() is used to clean up and free the buffer returned by
 get_nonce().  The nonce pointer returned by get_nonce() is passed in
 B<buf> and its length in B<len>.
 
+provider_register_child_cb() registers callbacks for being informed about the
+loading and unloading of providers in the application's library context.
+I<handle> is this provider's handle and I<cbdata> is this provider's data
+that will be passed back to the callbacks. It returns 1 on success or 0
+otherwise.
+
+I<create_cb> is a callback that will be called when a new provider is loaded
+into the application's library context. It is also called for any providers that
+are already loaded at the point that this callback is registered. The callback
+is passed the handle being used for the new provider being loadded and this
+provider's data in I<cbdata>. It should return 1 on success  or 0 on failure.
+
+I<remove_cb> is a callback that will be called when a new provider is unloaded
+from the application's library context. It is passed the handle being used for
+the provider being unloaded and this provider's data in I<cbdata>. It should
+return 1 on success  or 0 on failure.
+
+provider_deregister_child_cb() unregisters callbacks previously registered via
+provider_register_child_cb(). If provider_register_child_cb() has been called
+then provider_deregister_child_cb() should be called at or before the point that
+this provider's teardown function is called.
+
+provider_name() returns a string giving the name of the provider identified by
+I<handle>.
+
+provider_get0_provider_ctx() returns the provider context that is associated
+with the provider identified by I<prov>.
+
+provider_get0_dispatch() gets the dispatch table registered by the provider
+identified by I<prov> when it initialised.
+
+provider_up_ref() increments the reference count on the provider I<prov>. If
+I<activate> is nonzero then the provider is also loaded if it is not already
+loaded. It returns 1 on success or 0 on failure.
+
+provider_free() decrements the reference count on the provider I<prov>. If
+I<deactivate> is nonzero then the provider is also unloaded if it is not
+already loaded. It returns 1 on success or 0 on failure.
+
 =head2 Provider functions
 
 provider_teardown() is called when a provider is shut down and removed
diff --git a/include/internal/core.h b/include/internal/core.h
index 68b3943679..091b4b2d04 100644
--- a/include/internal/core.h
+++ b/include/internal/core.h
@@ -64,5 +64,6 @@ char *ossl_algorithm_get1_first_name(const OSSL_ALGORITHM *algo);
 __owur int ossl_lib_ctx_write_lock(OSSL_LIB_CTX *ctx);
 __owur int ossl_lib_ctx_read_lock(OSSL_LIB_CTX *ctx);
 int ossl_lib_ctx_unlock(OSSL_LIB_CTX *ctx);
+int ossl_lib_ctx_is_child(OSSL_LIB_CTX *ctx);
 
 #endif
diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h
index d583153b89..d943419a52 100644
--- a/include/internal/cryptlib.h
+++ b/include/internal/cryptlib.h
@@ -120,6 +120,7 @@ size_t OPENSSL_instrument_bus2(unsigned int *, size_t, size_t);
 struct ex_callback_st {
     long argl;                  /* Arbitrary long */
     void *argp;                 /* Arbitrary void * */
+    int priority;               /* Priority ordering for freeing */
     CRYPTO_EX_new *new_func;
     CRYPTO_EX_free *free_func;
     CRYPTO_EX_dup *dup_func;
@@ -164,9 +165,15 @@ typedef struct ossl_ex_data_global_st {
 # define OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX      15
 # define OSSL_LIB_CTX_PROVIDER_CONF_INDEX           16
 # define OSSL_LIB_CTX_BIO_CORE_INDEX                17
-# define OSSL_LIB_CTX_MAX_INDEXES                   18
+# define OSSL_LIB_CTX_CHILD_PROVIDER_INDEX          18
+# define OSSL_LIB_CTX_MAX_INDEXES                   19
+
+# define OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY       0
+# define OSSL_LIB_CTX_METHOD_PRIORITY_1             1
+# define OSSL_LIB_CTX_METHOD_PRIORITY_2             2
 
 typedef struct ossl_lib_ctx_method {
+    int priority;
     void *(*new_func)(OSSL_LIB_CTX *ctx);
     void (*free_func)(void *);
 } OSSL_LIB_CTX_METHOD;
@@ -196,7 +203,8 @@ int ossl_crypto_get_ex_new_index_ex(OSSL_LIB_CTX *ctx, int class_index,
                                     long argl, void *argp,
                                     CRYPTO_EX_new *new_func,
                                     CRYPTO_EX_dup *dup_func,
-                                    CRYPTO_EX_free *free_func);
+                                    CRYPTO_EX_free *free_func,
+                                    int priority);
 int ossl_crypto_free_ex_index_ex(OSSL_LIB_CTX *ctx, int class_index, int idx);
 
 /* Function for simple binary search */
diff --git a/include/internal/provider.h b/include/internal/provider.h
index 64fe2f1178..5b0af7a335 100644
--- a/include/internal/provider.h
+++ b/include/internal/provider.h
@@ -42,6 +42,15 @@ int ossl_provider_set_module_path(OSSL_PROVIDER *prov, const char *module_path);
 int ossl_provider_add_parameter(OSSL_PROVIDER *prov, const char *name,
                                 const char *value);
 
+int ossl_provider_is_child(const OSSL_PROVIDER *prov);
+int ossl_provider_set_child(OSSL_PROVIDER *prov, const OSSL_CORE_HANDLE *handle);
+int ossl_provider_convert_to_child(OSSL_PROVIDER *prov,
+                                   const OSSL_CORE_HANDLE *handle,
+                                   OSSL_provider_init_fn *init_function);
+const OSSL_CORE_HANDLE *ossl_provider_get_parent(OSSL_PROVIDER *prov);
+int ossl_provider_up_ref_parent(OSSL_PROVIDER *prov, int activate);
+int ossl_provider_free_parent(OSSL_PROVIDER *prov, int deactivate);
+
 /* Disable fallback loading */
 int ossl_provider_disable_fallback_loading(OSSL_LIB_CTX *libctx);
 
@@ -49,7 +58,8 @@ int ossl_provider_disable_fallback_loading(OSSL_LIB_CTX *libctx);
  * Activate the Provider
  * If the Provider is a module, the module will be loaded
  */
-int ossl_provider_activate(OSSL_PROVIDER *prov, int retain_fallbacks);
+int ossl_provider_activate(OSSL_PROVIDER *prov, int retain_fallbacks,
+                           int upcalls);
 int ossl_provider_deactivate(OSSL_PROVIDER *prov);
 /* Check if the provider is available (activated) */
 int ossl_provider_available(OSSL_PROVIDER *prov);
@@ -69,6 +79,7 @@ const DSO *ossl_provider_dso(const OSSL_PROVIDER *prov);
 const char *ossl_provider_module_name(const OSSL_PROVIDER *prov);
 const char *ossl_provider_module_path(const OSSL_PROVIDER *prov);
 void *ossl_provider_prov_ctx(const OSSL_PROVIDER *prov);
+const OSSL_DISPATCH *ossl_provider_get0_dispatch(const OSSL_PROVIDER *prov);
 OSSL_LIB_CTX *ossl_provider_libctx(const OSSL_PROVIDER *prov);
 
 /* Thin wrappers around calls to the provider */
@@ -96,6 +107,12 @@ int ossl_provider_clear_all_operation_bits(OSSL_LIB_CTX *libctx);
 /* Configuration */
 void ossl_provider_add_conf_module(void);
 
+/* Child providers */
+int ossl_provider_init_child_providers(OSSL_LIB_CTX *ctx);
+int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx,
+                                const OSSL_CORE_HANDLE *handle,
+                                const OSSL_DISPATCH *in);
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h
index d088a66f30..5c453eaac0 100644
--- a/include/openssl/core_dispatch.h
+++ b/include/openssl/core_dispatch.h
@@ -183,6 +183,33 @@ OSSL_CORE_MAKE_FUNC(size_t, get_nonce, (const OSSL_CORE_HANDLE *handle,
 OSSL_CORE_MAKE_FUNC(void, cleanup_nonce, (const OSSL_CORE_HANDLE *handle,
                                           unsigned char *buf, size_t len))
 
+/* Functions to access the core's providers */
+#define OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB   105
+#define OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB 106
+#define OSSL_FUNC_PROVIDER_NAME                107
+#define OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX   108
+#define OSSL_FUNC_PROVIDER_GET0_DISPATCH       109
+#define OSSL_FUNC_PROVIDER_UP_REF              110
+#define OSSL_FUNC_PROVIDER_FREE                111
+
+OSSL_CORE_MAKE_FUNC(int, provider_register_child_cb,
+                    (const OSSL_CORE_HANDLE *handle,
+                     int (*create_cb)(const OSSL_CORE_HANDLE *provider, void *cbdata),
+                     int (*remove_cb)(const OSSL_CORE_HANDLE *provider, void *cbdata),
+                     void *cbdata))
+OSSL_CORE_MAKE_FUNC(void, provider_deregister_child_cb,
+                    (const OSSL_CORE_HANDLE *handle))
+OSSL_CORE_MAKE_FUNC(const char *, provider_name,
+                    (const OSSL_CORE_HANDLE *prov))
+OSSL_CORE_MAKE_FUNC(void *, provider_get0_provider_ctx,
+                    (const OSSL_CORE_HANDLE *prov))
+OSSL_CORE_MAKE_FUNC(const OSSL_DISPATCH *, provider_get0_dispatch,
+                    (const OSSL_CORE_HANDLE *prov))
+OSSL_CORE_MAKE_FUNC(int, provider_up_ref,
+                    (const OSSL_CORE_HANDLE *prov, int activate))
+OSSL_CORE_MAKE_FUNC(int, provider_free,
+                    (const OSSL_CORE_HANDLE *prov, int deactivate))
+
 /* Functions provided by the provider to the Core, reserved numbers 1024-1535 */
 # define OSSL_FUNC_PROVIDER_TEARDOWN           1024
 OSSL_CORE_MAKE_FUNC(void,provider_teardown,(void *provctx))
diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in
index e868172acc..724e2ca5da 100644
--- a/include/openssl/crypto.h.in
+++ b/include/openssl/crypto.h.in
@@ -37,6 +37,7 @@ use OpenSSL::stackhash qw(generate_stack_macros);
 # include <openssl/types.h>
 # include <openssl/opensslconf.h>
 # include <openssl/cryptoerr.h>
+# include <openssl/core.h>
 
 # ifdef CHARSET_EBCDIC
 #  include <openssl/ebcdic.h>
@@ -517,7 +518,10 @@ CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void);
 int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b);
 
 OSSL_LIB_CTX *OSSL_LIB_CTX_new(void);
-OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_DISPATCH *in);
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_CORE_HANDLE *handle,
+                                             const OSSL_DISPATCH *in);
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_child(const OSSL_CORE_HANDLE *handle,
+                                     const OSSL_DISPATCH *in);
 int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file);
 void OSSL_LIB_CTX_free(OSSL_LIB_CTX *);
 OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void);
diff --git a/include/openssl/provider.h b/include/openssl/provider.h
index 56b430710f..e66d5324af 100644
--- a/include/openssl/provider.h
+++ b/include/openssl/provider.h
@@ -44,6 +44,7 @@ const OSSL_ALGORITHM *OSSL_PROVIDER_query_operation(const OSSL_PROVIDER *prov,
 void OSSL_PROVIDER_unquery_operation(const OSSL_PROVIDER *prov,
                                      int operation_id, const OSSL_ALGORITHM *algs);
 void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov);
+const OSSL_DISPATCH *OSSL_PROVIDER_get0_dispatch(const OSSL_PROVIDER *prov);
 
 /* Add a built in providers */
 int OSSL_PROVIDER_add_builtin(OSSL_LIB_CTX *, const char *name,
diff --git a/providers/fips-sources.checksums b/providers/fips-sources.checksums
index a406564162..72d4f9cf28 100644
--- a/providers/fips-sources.checksums
+++ b/providers/fips-sources.checksums
@@ -97,10 +97,10 @@ ae840ec19a4e86f2b3a65f4d0c878c3885bac6ca6b24ab8c03b73c45c12e4d05  crypto/bn/rsaz
 834db8ff36006e5cb53e09ca6c44290124bd23692f4341ea6563b66fcade4cea  crypto/bsearch.c
 c39334b70e1394e43f378ae8d31b6e6dc125e4d9181e6536d38e649c4eaadb75  crypto/buffer/buffer.c
 35e3ad090adedc8e5873e2831bf713e1f52846b4cbdd232e01692ebe35318c3c  crypto/cmac/cmac.c
-f63058e3d3df38f44856f062b7e67d58681488dbe7f27d90979cc4afdfe4a395  crypto/context.c
+b352903e60908dc7287051983e2068508715b4d9f3f46575540295010908bfa0  crypto/context.c
 0a27ead487bd4775cece449dab53ca5aa9d1997012c85b1dcd2178d3b851dd94  crypto/core_algorithm.c
 2185a7d136ee77725fc1b8a6b401bebceeeddc067eea0482e0ab2916ce550e78  crypto/core_fetch.c
-66d5fa1814ec1c80c1635dad5d4311722d20890afe44133f958a4be4447b8252  crypto/core_namemap.c
+9e0912561955172067e70ebb1913c4d9de35de612789e91f7f61180ca03b4ad8  crypto/core_namemap.c
 469e2f53b5f76cd487a60d3d4c44c8fc3a6c4d08405597ba664661ba485508d3  crypto/cpuid.c
 7c5237bdc26eca21d4ccb25f13569e217103fe21574157b813c2aecd05983472  crypto/cryptlib.c
 53529f4e0575dd83b45a53e852fcec512ada53dd6979268e473885f139b8e0b9  crypto/ctype.c
@@ -169,7 +169,7 @@ fa39906519062932adafb63cbf05b5dfa7563673576d421c80ec6b889d024e84  crypto/ec/ecp_
 e819c499207dd2ee5457cd9411c6089e13476bedf41de2aa67e10b13810ff0e5  crypto/evp/digest.c
 5e2c5d865029ae86855f15e162360d091f28ca0d4c67260700c90aa25faf308b  crypto/evp/ec_support.c
 c146c0a8a06e3c558207c1c76039dd2a61a2160cc243e9e3de2e290bc6e1b2d0  crypto/evp/evp_enc.c
-9b4956b5c28db987001b33421aacf3b9f352181f874c768ad1b034e083483561  crypto/evp/evp_fetch.c
+4518be2a70f28492668fe1ad6464593ff0db227ab75536bc5dc5a9c0da135800  crypto/evp/evp_fetch.c
 ce97d3bbaa68d2c3aae7f2c4d8709396ec2f0f131abf2c2584e523585ec89c02  crypto/evp/evp_lib.c
 af0245f7a849997921c0719df339469427656821416b402754fc1f5f5e2da291  crypto/evp/evp_rand.c
 c0f87865be8dab6ea909fd976e5a46e4e8343b18403090c4a59b2af90f9a1329  crypto/evp/evp_utils.c
@@ -187,7 +187,7 @@ b7e9ce6e8a35e0fc5b4eb4c047cda1e811b757669dbfafa71e743d85e07817a4  crypto/evp/pme
 ff8a5ff024c228fe714e4cf758260cf9e9c992a9311acb5f96b0f2ed6af1a814  crypto/evp/pmeth_gn.c
 b360a72944bcb8f8ae8bd28d9b8a4a6aa4f39d1402295f84af243d14c3f1898c  crypto/evp/pmeth_lib.c
 52d8ea3b8b3ef52b58306b0fbd4557d682ba69a5384672ba7e1682c9a853f417  crypto/evp/signature.c
-e0a58ecf268c6bec531898d8fe6b148601b0bed8324fa8d5668de643c027606b  crypto/ex_data.c
+b06cb8fd4bd95aae1f66e1e145269c82169257f1a60ef0f78f80a3d4c5131fac  crypto/ex_data.c
 ae496cbb92b8664bb729997a241d12cc515a3944d66fe87b0c6e24f1011e061f  crypto/ffc/ffc_backend.c
 ead786b4f5689ab69d6cca5d49e513e0f90cb558b67e6c5898255f2671f1393d  crypto/ffc/ffc_dh.c
 8390c3015b5bb7f65a5cde533390788e7e61e381823c58c2e7caf8e50ca63a3b  crypto/ffc/ffc_key_generate.c
@@ -196,7 +196,7 @@ a87945698684673832fbedb4d01e2f11df58f43f79605a9e6d7136bb15b02e52  crypto/ffc/ffc
 887357f0422954f2ecb855d468ad2456a76372dc401301ba284c0fd8c6b5092e  crypto/ffc/ffc_params_generate.c
 73dac805abab36cd9df53a421221c71d06a366a4ce479fa788be777f11b47159  crypto/ffc/ffc_params_validate.c
 c193773792bec29c791e84d150ffe5ef25f53cb02e23f0e12e9000234b4322e5  crypto/hmac/hmac.c
-7000ba81f54c1d516a536bc6e96ad3729e3b5b15740006c2e22f0b76606042d6  crypto/initthread.c
+271083f71a1ce24988a0932f73c0221260591823afd495bf2ae8d11e8469b659  crypto/initthread.c
 c6c83f826eb6465f2a1b186ea692ff6fe32dbfb821d18d254625b69083d68fb0  crypto/lhash/lhash.c
 f866aafae928db1b439ac950dc90744a2397dfe222672fe68b3798396190c8b0  crypto/mem_clr.c
 183bdca6f855182d7d2c78a5c961b34283f85ea69ac828b700605ee82546397d  crypto/modes/asm/aes-gcm-armv8_64.pl
@@ -228,13 +228,13 @@ c2fe815fb3fd5efe9a6544cae55f9469063a0f6fb728361737b927f6182ae0bb  crypto/param_b
 1164175c2259bc104ec315d39a4f80fa67604f40e55036044d18ccf94da71a76  crypto/params_dup.c
 d0f6af3e89a693f0327e1bf073666cbec6786220ef3b3688ef0be9539d5ab6bf  crypto/params_from_text.c
 0dd202ec1def47c12852a8ae4bfaadb74f7fe968d68def631fe3ac671aac943f  crypto/passphrase.c
-098d0722daac442b8b6a6fc0aa6c4a4c49f9329426c3e2db9ebf71fe32376e4c  crypto/property/defn_cache.c
-87cb2235e335046e04a563551cceb452e2eaf338123f482e76a037e4ffae0902  crypto/property/property.c
+2140778d5f35e503e22b173736e18ff84406f6657463e8ff9e7b91a78aa686d3  crypto/property/defn_cache.c
+85b314961fa249dcaa2847294d1903447a3f5f73c0dd5ab10f7cd9641c925219  crypto/property/property.c
 51bc907d992893f03f35774178d2c8dc98cf3cf9503ff839ee1561640e6b274a  crypto/property/property_parse.c
-4941717698573a86d589fbec5002471cb4011e9a1840111a3ddccecc861a3af5  crypto/property/property_string.c
-8bf84eeb85a16128170eb295c77245c8ba4ecf25fa4d2be907a612245e4b8b24  crypto/provider_core.c
+e703fec7e28de11c89e131503eb75095472e8c03563105ca8767c34db22a105c  crypto/property/property_string.c
+c9d4d0adb3313c5c90c7db9bce9af59d02efc5fe8181c18a778625b1cc296d6f  crypto/provider_core.c
 3ebbf42baa3722f86298960c7b14b49cefc25c38fce326a0c4666546539da231  crypto/provider_predefined.c
-4fec006dc82d1bc5c03aa1b6d011b670bed67fad12b73823eb6767afc4f241f3  crypto/rand/rand_lib.c
+14341361b4308fe1528b11a9f88edff037b10b51e9e7aa29b70b43a4e3be3d59  crypto/rand/rand_lib.c
 f19876a1ff4ab97f22a926cc59c9ced0cdde69ad2c45ecf546d91104ec5b0dde  crypto/rand/rand_meth.c
 a6841319cb6e9970a3c3f8adb619086310e4b56d1f52448ef2e2caaeface4146  crypto/rsa/rsa_backend.c
 38a102cd1da1f6ca5a46e6a22f018237964336274385f5c70cbedcaa6997647e  crypto/rsa/rsa_chk.c
@@ -325,7 +325,7 @@ d447cd774869da68a2cc0bbb19c547ee6ed4858c7aee1f3d5bba7796f97823a9  providers/comm
 eec462d685dd3b4764b076a3c18ecd9dd254350a0b78ddc2f8a60587829e1ce3  providers/common/provider_util.c
 494723d55bc6ecdb70f59499a2c42260cabc5fa30681ac3b48267dfa242158b3  providers/common/securitycheck.c
 50a0e01e877ae818cf874f4515a130db0e869d4e9e8ce882bff1255695aba789  providers/common/securitycheck_fips.c
-fd92f958755683dda449a45f82ecdff342574a9536f6e8727decf5be9a5b747a  providers/fips/fipsprov.c
+5c31ba4eedb31e2509288be50280e0df58faa86fe4b5e99a1167a53fd6f3bd0f  providers/fips/fipsprov.c
 c69e60c29711d55cd5672dab9ff051f3c093d54e63a0ec575baa899e6bbf9c2b  providers/fips/self_test.c
 fb56f801613642f6b497803890b528a643024e3cdb5bd5dd619a2981afb2f3b0  providers/fips/self_test_kats.c
 08b287621158afb67e61e52fc34efbb9f9fe22ee6709c7ed6c937d5feb2b7fd8  providers/implementations/asymciphers/rsa_enc.c
@@ -382,8 +382,8 @@ c48eb00f0de1c28baaa3cf7c0e85d4d2a20592783aa545f8934da487c05a3e87  providers/impl
 f51b074d55028d3e24656da348d21ca79f6680fdb30383d936251f1b3467caab  providers/implementations/macs/gmac_prov.c
 35505704fda658c0911f95974913c1f2dd75c8f91c5d2ec597c70c52624bdfdf  providers/implementations/macs/hmac_prov.c
 e42823cce1d08d9cb6cb32cc6b913241573c2cbbd856ff77a331b0956ee5aa02  providers/implementations/macs/kmac_prov.c
-dcc1afbe2965de7c5ac0a17ab1b19b8ed512049376833cb410db30f8dc4e2064  providers/implementations/rands/crngt.c
-c7a811a8b2911ec76faf985145a445b81d19c57f5457dad203b39f1da48e6c1b  providers/implementations/rands/drbg.c
+bf30274dd6b528ae913984775bd8f29c6c48c0ef06d464d0f738217727b7aa5c  providers/implementations/rands/crngt.c
+080afdc1704ad2a53cfbd54060b8b4f86a110ce48663fe86f2480d05aff00a15  providers/implementations/rands/drbg.c
 3dc5f082235664ee02b827760bdf1c1dcd90d058b9664994751f7606009556ed  providers/implementations/rands/drbg_ctr.c
 c36937930bcaecd6d5131d0317b9162a96cc956df164848dc53f423af838d04a  providers/implementations/rands/drbg_hash.c
 531c0ce4212570474b59a1b039e61a97ee5504e56e2f10de1f36578f1bca79d3  providers/implementations/rands/drbg_hmac.c
diff --git a/providers/fips.checksum b/providers/fips.checksum
index d34f8d6298..a02e185df1 100644
--- a/providers/fips.checksum
+++ b/providers/fips.checksum
@@ -1 +1 @@
-d5397de128260293373b9e70152a07e990cf4f98accfe9c69b78aefc782e2e96  providers/fips-sources.checksums
+25ebfe80438755a6a997fd7b76a2d30725c7be0ae73b9378d0daf5e444453afa  providers/fips-sources.checksums
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index 841c80bab7..7998d55d9a 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -96,6 +96,7 @@ static void fips_prov_ossl_ctx_free(void *fgbl)
 }
 
 static const OSSL_LIB_CTX_METHOD fips_prov_ossl_ctx_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     fips_prov_ossl_ctx_new,
     fips_prov_ossl_ctx_free,
 };
diff --git a/providers/implementations/rands/crngt.c b/providers/implementations/rands/crngt.c
index f1b31df101..87902c995c 100644
--- a/providers/implementations/rands/crngt.c
+++ b/providers/implementations/rands/crngt.c
@@ -83,6 +83,7 @@ static void *rand_crng_ossl_ctx_new(OSSL_LIB_CTX *ctx)
 }
 
 static const OSSL_LIB_CTX_METHOD rand_crng_ossl_ctx_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     rand_crng_ossl_ctx_new,
     rand_crng_ossl_ctx_free,
 };
diff --git a/providers/implementations/rands/drbg.c b/providers/implementations/rands/drbg.c
index 461d641273..81343fbd52 100644
--- a/providers/implementations/rands/drbg.c
+++ b/providers/implementations/rands/drbg.c
@@ -303,6 +303,7 @@ static void prov_drbg_nonce_ossl_ctx_free(void *vdngbl)
 }
 
 static const OSSL_LIB_CTX_METHOD drbg_nonce_ossl_ctx_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     prov_drbg_nonce_ossl_ctx_new,
     prov_drbg_nonce_ossl_ctx_free,
 };
diff --git a/providers/legacyprov.c b/providers/legacyprov.c
index 852f6a4e91..1f137a721f 100644
--- a/providers/legacyprov.c
+++ b/providers/legacyprov.c
@@ -178,13 +178,8 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
 {
     OSSL_LIB_CTX *libctx = NULL;
 
-    /*
-     * We do not need to use any up-calls provided by libcrypto, so we ignore
-     * the "in" dispatch table.
-     */
-
     if ((*provctx = ossl_prov_ctx_new()) == NULL
-        || (libctx = OSSL_LIB_CTX_new()) == NULL) {
+        || (libctx = OSSL_LIB_CTX_new_child(handle, in)) == NULL) {
         OSSL_LIB_CTX_free(libctx);
         legacy_teardown(*provctx);
         *provctx = NULL;
diff --git a/test/bio_core_test.c b/test/bio_core_test.c
index 9ec8af9b8f..ae326cef92 100644
--- a/test/bio_core_test.c
+++ b/test/bio_core_test.c
@@ -55,7 +55,7 @@ static const OSSL_DISPATCH biocbs[] = {
 static int test_bio_core(void)
 {
     BIO *cbio = NULL, *cbiobad = NULL;
-    OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new_from_dispatch(biocbs);
+    OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new_from_dispatch(NULL, biocbs);
     int testresult = 0;
     OSSL_CORE_BIO corebio;
     const char *msg = "Hello world";
diff --git a/test/context_internal_test.c b/test/context_internal_test.c
index 46afd9f521..4c02f601cc 100644
--- a/test/context_internal_test.c
+++ b/test/context_internal_test.c
@@ -39,6 +39,7 @@ static void foo_free(void *ptr)
     OPENSSL_free(ptr);
 }
 static const OSSL_LIB_CTX_METHOD foo_method = {
+    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     foo_new,
     foo_free
 };
diff --git a/test/p_test.c b/test/p_test.c
index 6f55abda01..8c7bdaf7b8 100644
--- a/test/p_test.c
+++ b/test/p_test.c
@@ -30,11 +30,16 @@
 #include <openssl/core.h>
 #include <openssl/core_dispatch.h>
 #include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/crypto.h>
+#include <openssl/provider.h>
 
 typedef struct p_test_ctx {
     char *thisfile;
     char *thisfunc;
     const OSSL_CORE_HANDLE *handle;
+    OSSL_LIB_CTX *libctx;
+    OSSL_PROVIDER *deflt;
 } P_TEST_CTX;
 
 static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL;
@@ -46,6 +51,7 @@ static OSSL_FUNC_core_vset_error_fn *c_vset_error;
 /* Tell the core what params we provide and what type they are */
 static const OSSL_PARAM p_param_types[] = {
     { "greeting", OSSL_PARAM_UTF8_STRING, NULL, 0, 0 },
+    { "digest-check", OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0},
     { NULL, 0, NULL, 0, 0 }
 };
 
@@ -109,6 +115,47 @@ static int p_get_params(void *provctx, OSSL_PARAM params[])
                 strcpy(p->data, buf);
             else
                 ok = 0;
+        } else if (strcmp(p->key, "digest-check") == 0) {
+            unsigned int digestsuccess = 0;
+
+            /*
+             * Test we can use an algorithm from another provider. We're using
+             * legacy to check that legacy is actually available and we haven't
+             * just fallen back to default.
+             */
+#ifdef PROVIDER_INIT_FUNCTION_NAME
+            EVP_MD *md4 = EVP_MD_fetch(ctx->libctx, "MD4", NULL);
+            EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
+            const char *msg = "Hello world";
+            unsigned char out[16];
+
+            /*
+             * We should have the default provider available that we loaded
+             * ourselves, and the base and legacy providers which we inherit
+             * from the parent libctx. We should also have "this" provider
+             * available.
+             */
+            if (OSSL_PROVIDER_available(ctx->libctx, "default")
+                    && OSSL_PROVIDER_available(ctx->libctx, "base")
+                    && OSSL_PROVIDER_available(ctx->libctx, "legacy")
+                    && OSSL_PROVIDER_available(ctx->libctx, "p_test")
+                    && md4 != NULL
+                    && mdctx != NULL) {
+                if (EVP_DigestInit_ex(mdctx, md4, NULL)
+                        && EVP_DigestUpdate(mdctx, (const unsigned char *)msg,
+                                            strlen(msg))
+                        &&EVP_DigestFinal(mdctx, out, NULL))
+                    digestsuccess = 1;
+            }
+            EVP_MD_CTX_free(mdctx);
+            EVP_MD_free(md4);
+#endif
+            if (p->data_size >= sizeof(digestsuccess)) {
+                *(unsigned int *)p->data = digestsuccess;
+                p->return_size = sizeof(digestsuccess);
+            } else {
+                ok = 0;
+            }
         }
     }
     return ok;
@@ -130,6 +177,8 @@ static const OSSL_ITEM *p_get_reason_strings(void *_)
 {
     static const OSSL_ITEM reason_strings[] = {
         {1, "dummy reason string"},
+        {2, "Can't create child library context"},
+        {3, "Can't load default provider"},
         {0, NULL}
     };
 
@@ -146,11 +195,12 @@ static const OSSL_DISPATCH p_test_table[] = {
 };
 
 int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
-                       const OSSL_DISPATCH *in,
+                       const OSSL_DISPATCH *oin,
                        const OSSL_DISPATCH **out,
                        void **provctx)
 {
     P_TEST_CTX *ctx;
+    const OSSL_DISPATCH *in = oin;
 
     for (; in->function_id != 0; in++) {
         switch (in->function_id) {
@@ -191,6 +241,30 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
     ctx->thisfile = strdup(OPENSSL_FILE);
     ctx->thisfunc = strdup(OPENSSL_FUNC);
     ctx->handle = handle;
+#ifdef PROVIDER_INIT_FUNCTION_NAME
+    /* We only do this if we are linked with libcrypto */
+    ctx->libctx = OSSL_LIB_CTX_new_child(handle, oin);
+    if (ctx->libctx == NULL) {
+        /* We set error "2" for a failure to create the child libctx*/
+        p_set_error(ERR_LIB_PROV, 2, ctx->thisfile, OPENSSL_LINE, ctx->thisfunc,
+                    NULL);
+        p_teardown(ctx);
+        return 0;
+    }
+    /*
+     * "default" has not been loaded into the parent libctx. We should be able
+     * to explicitly load it as a non-child provider.
+     */
+    ctx->deflt = OSSL_PROVIDER_load(ctx->libctx, "default");
+    if (ctx->deflt == NULL
+            || !OSSL_PROVIDER_available(ctx->libctx, "default")) {
+        /* We set error "3" for a failure to load the default provider */
+        p_set_error(ERR_LIB_PROV, 3, ctx->thisfile, OPENSSL_LINE, ctx->thisfunc,
+                    NULL);
+        p_teardown(ctx);
+        return 0;
+    }
+#endif
 
     /*
      * Set a spurious error to check error handling works correctly. This will
@@ -207,6 +281,10 @@ static void p_teardown(void *provctx)
 {
     P_TEST_CTX *ctx = (P_TEST_CTX *)provctx;
 
+#ifdef PROVIDER_INIT_FUNCTION_NAME
+    OSSL_PROVIDER_unload(ctx->deflt);
+    OSSL_LIB_CTX_free(ctx->libctx);
+#endif
     free(ctx->thisfile);
     free(ctx->thisfunc);
     free(ctx);
diff --git a/test/provider_internal_test.c b/test/provider_internal_test.c
index 7bf2b8e272..2341dd3dac 100644
--- a/test/provider_internal_test.c
+++ b/test/provider_internal_test.c
@@ -26,7 +26,7 @@ static int test_provider(OSSL_PROVIDER *prov, const char *expected_greeting)
     int ret = 0;
 
     ret =
-        TEST_true(ossl_provider_activate(prov, 0))
+        TEST_true(ossl_provider_activate(prov, 0, 1))
         && TEST_true(ossl_provider_get_params(prov, greeting_request))
         && TEST_ptr(greeting = greeting_request[0].data)
         && TEST_size_t_gt(greeting_request[0].data_size, 0)
diff --git a/test/provider_test.c b/test/provider_test.c
index d89611b9b2..4d8dbaee6f 100644
--- a/test/provider_test.c
+++ b/test/provider_test.c
@@ -19,26 +19,88 @@ static OSSL_PARAM greeting_request[] = {
     { NULL, 0, NULL, 0, 0 }
 };
 
-static int test_provider(OSSL_LIB_CTX **libctx, const char *name)
+static unsigned int digestsuccess = 0;
+static OSSL_PARAM digest_check[] = {
+    { "digest-check", OSSL_PARAM_UNSIGNED_INTEGER, &digestsuccess,
+      sizeof(digestsuccess) },
+    { NULL, 0, NULL, 0, 0 }
+};
+
+static int test_provider(OSSL_LIB_CTX **libctx, const char *name,
+                         OSSL_PROVIDER *legacy)
 {
     OSSL_PROVIDER *prov = NULL;
     const char *greeting = NULL;
     char expected_greeting[256];
     int ok = 0;
     long err;
+    int dolegacycheck = (legacy != NULL);
+    OSSL_PROVIDER *deflt = NULL, *base = NULL;
 
     BIO_snprintf(expected_greeting, sizeof(expected_greeting),
                  "Hello OpenSSL %.20s, greetings from %s!",
                  OPENSSL_VERSION_STR, name);
 
-    if (!TEST_ptr(prov = OSSL_PROVIDER_load(*libctx, name))
-            || !TEST_true(OSSL_PROVIDER_get_params(prov, greeting_request))
+    /*
+        * Check that it is possible to have a built-in provider mirrored in
+        * a child lib ctx.
+        */
+    if (!TEST_ptr(base = OSSL_PROVIDER_load(*libctx, "base")))
+        goto err;
+    if (!TEST_ptr(prov = OSSL_PROVIDER_load(*libctx, name)))
+        goto err;
+    if (dolegacycheck) {
+        if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
+                || !TEST_true(digestsuccess))
+            goto err;
+    }
+    if (!TEST_true(OSSL_PROVIDER_get_params(prov, greeting_request))
             || !TEST_ptr(greeting = greeting_request[0].data)
             || !TEST_size_t_gt(greeting_request[0].data_size, 0)
-            || !TEST_str_eq(greeting, expected_greeting)
-            || !TEST_true(OSSL_PROVIDER_unload(prov)))
+            || !TEST_str_eq(greeting, expected_greeting))
+        goto err;
+
+    /* Make sure we got the error we were expecting */
+    err = ERR_peek_last_error();
+    if (!TEST_int_gt(err, 0)
+            || !TEST_int_eq(ERR_GET_REASON(err), 1))
         goto err;
 
+    OSSL_PROVIDER_unload(legacy);
+    legacy = NULL;
+
+    if (dolegacycheck) {
+        /* Legacy provider should also be unloaded from child libctx */
+        if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
+                || !TEST_false(digestsuccess))
+            goto err;
+        /*
+         * Loading the legacy provider again should make it available again in
+         * the child libctx. Loading and unloading the default provider should
+         * have no impact on the child because the child loads it explicitly
+         * before this point.
+         */
+        legacy = OSSL_PROVIDER_load(*libctx, "legacy");
+        deflt = OSSL_PROVIDER_load(*libctx, "default");
+        if (!TEST_ptr(deflt)
+                || !TEST_true(OSSL_PROVIDER_available(*libctx, "default")))
+            goto err;
+        OSSL_PROVIDER_unload(deflt);
+        deflt = NULL;
+        if (!TEST_ptr(legacy)
+                || !TEST_false(OSSL_PROVIDER_available(*libctx, "default"))
+                || !TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
+                || !TEST_true(digestsuccess))
+        goto err;
+        OSSL_PROVIDER_unload(legacy);
+        legacy = NULL;
+    }
+
+    if (!TEST_true(OSSL_PROVIDER_unload(base)))
+        goto err;
+    base = NULL;
+    if (!TEST_true(OSSL_PROVIDER_unload(prov)))
+        goto err;
     prov = NULL;
 
     /*
@@ -48,16 +110,14 @@ static int test_provider(OSSL_LIB_CTX **libctx, const char *name)
     OSSL_LIB_CTX_free(*libctx);
     *libctx = NULL;
 
-    /* Make sure we got the error we were expecting */
-    err = ERR_peek_last_error();
-    if (!TEST_int_gt(err, 0)
-            || !TEST_int_eq(ERR_GET_REASON(err), 1))
-        goto err;
-
     /* We print out all the data to make sure it can still be accessed */
     ERR_print_errors_fp(stderr);
     ok = 1;
  err:
+    OSSL_PROVIDER_unload(base);
+    OSSL_PROVIDER_unload(deflt);
+    OSSL_PROVIDER_unload(legacy);
+    legacy = NULL;
     OSSL_PROVIDER_unload(prov);
     OSSL_LIB_CTX_free(*libctx);
     *libctx = NULL;
@@ -74,13 +134,42 @@ static int test_builtin_provider(void)
         TEST_ptr(libctx)
         && TEST_true(OSSL_PROVIDER_add_builtin(libctx, name,
                                                PROVIDER_INIT_FUNCTION_NAME))
-        && test_provider(&libctx, name);
+        && test_provider(&libctx, name, NULL);
 
     OSSL_LIB_CTX_free(libctx);
 
     return ok;
 }
 
+/* Test relies on fetching the MD4 digest from the legacy provider */
+#ifndef OPENSSL_NO_MD4
+static int test_builtin_provider_with_child(void)
+{
+    OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+    const char *name = "p_test";
+    OSSL_PROVIDER *legacy;
+
+    if (!TEST_ptr(libctx))
+        return 0;
+
+    legacy = OSSL_PROVIDER_load(libctx, "legacy");
+    if (legacy == NULL) {
+        /*
+         * In this case we assume we've been built with "no-legacy" and skip
+         * this test (there is no OPENSSL_NO_LEGACY)
+         */
+        return 1;
+    }
+
+    if (!TEST_true(OSSL_PROVIDER_add_builtin(libctx, name,
+                                             PROVIDER_INIT_FUNCTION_NAME)))
+        return 0;
+
+    /* test_provider will free libctx and unload legacy as part of the test */
+    return test_provider(&libctx, name, legacy);
+}
+#endif
+
 #ifndef NO_PROVIDER_MODULE
 static int test_loaded_provider(void)
 {
@@ -91,15 +180,54 @@ static int test_loaded_provider(void)
         return 0;
 
     /* test_provider will free libctx as part of the test */
-    return test_provider(&libctx, name);
+    return test_provider(&libctx, name, NULL);
 }
 #endif
 
+typedef enum OPTION_choice {
+    OPT_ERR = -1,
+    OPT_EOF = 0,
+    OPT_LOADED,
+    OPT_TEST_ENUM
+} OPTION_CHOICE;
+
+const OPTIONS *test_get_options(void)
+{
+    static const OPTIONS test_options[] = {
+        OPT_TEST_OPTIONS_DEFAULT_USAGE,
+        { "loaded", OPT_LOADED, '-', "Run test with a loaded provider" },
+        { NULL }
+    };
+    return test_options;
+}
+
 int setup_tests(void)
 {
-    ADD_TEST(test_builtin_provider);
+    OPTION_CHOICE o;
+    int loaded = 0;
+
+    while ((o = opt_next()) != OPT_EOF) {
+        switch (o) {
+        case OPT_TEST_CASES:
+            break;
+        case OPT_LOADED:
+            loaded = 1;
+            break;
+        default:
+            return 0;
+        }
+    }
+
+    if (!loaded) {
+        ADD_TEST(test_builtin_provider);
+#ifndef OPENSSL_NO_MD4
+        ADD_TEST(test_builtin_provider_with_child);
+#endif
+    }
 #ifndef NO_PROVIDER_MODULE
-    ADD_TEST(test_loaded_provider);
+    else {
+        ADD_TEST(test_loaded_provider);
+    }
 #endif
     return 1;
 }
diff --git a/test/recipes/04-test_provider.t b/test/recipes/04-test_provider.t
index 9195a424cd..44274f8f07 100644
--- a/test/recipes/04-test_provider.t
+++ b/test/recipes/04-test_provider.t
@@ -8,11 +8,14 @@
 
 use strict;
 use OpenSSL::Test qw(:DEFAULT bldtop_dir);
-use OpenSSL::Test::Simple;
 use OpenSSL::Test::Utils;
 
 setup("test_provider");
 
+plan tests => 2;
+
+ok(run(test(['provider_test'])), "provider_test");
+
 $ENV{"OPENSSL_MODULES"} = bldtop_dir("test");
 
-simple_test("test_provider", "provider_test");
+ok(run(test(['provider_test', '-loaded'])), "provider_test -loaded");
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 1820baf4ad..a99b5aa047 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5402,3 +5402,5 @@ BIO_new_from_core_bio                   ?	3_0_0	EXIST::FUNCTION:
 BIO_new_ex                              ?	3_0_0	EXIST::FUNCTION:
 BIO_s_core                              ?	3_0_0	EXIST::FUNCTION:
 OSSL_LIB_CTX_new_from_dispatch          ?	3_0_0	EXIST::FUNCTION:
+OSSL_LIB_CTX_new_child                  ?	3_0_0	EXIST::FUNCTION:
+OSSL_PROVIDER_get0_dispatch             ?	3_0_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list