[openssl] master update

Matt Caswell matt at openssl.org
Thu May 20 08:49:52 UTC 2021


The branch master has been updated
       via  b195677073aa85cc72bd4b3289e7ecf47ae0e066 (commit)
       via  b1c053acdaaee5e653949932f9999370edfc64db (commit)
       via  366bf9aedbbf719097a891dbf675f46dab8c9276 (commit)
       via  18cb5c31e16ace483e09a3d72d47d675feb898b2 (commit)
       via  447588b69aa6ba46e61302570df9d2d2a57960ed (commit)
       via  ad8570a8b6b4ec27e92013653d4d36b0c1b36991 (commit)
       via  e2ed740ec4dcfd32723d849a146bfc126b95d16c (commit)
      from  87e4e9c473dd3305cb98b37c672edff8ddb436de (commit)


- Log -----------------------------------------------------------------
commit b195677073aa85cc72bd4b3289e7ecf47ae0e066
Author: Matt Caswell <matt at openssl.org>
Date:   Wed May 12 09:44:20 2021 +0100

    Update documentation for global properties mirroring
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15242)

commit b1c053acdaaee5e653949932f9999370edfc64db
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 11 16:50:27 2021 +0100

    Ensure mirroring of properties works for subsequent updates
    
    If the global properties are updated after a provider with a child libctx
    has already started we need to make sure those updates are mirrored in
    that child.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15242)

commit 366bf9aedbbf719097a891dbf675f46dab8c9276
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 11 16:49:45 2021 +0100

    Documentation updates for mirroring of global properties
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15242)

commit 18cb5c31e16ace483e09a3d72d47d675feb898b2
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 11 11:44:43 2021 +0100

    Test that properties are mirrored as we expect
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15242)

commit 447588b69aa6ba46e61302570df9d2d2a57960ed
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 7 17:59:47 2021 +0100

    Add a callback for providers to know about global properties changes
    
    Where a child libctx is in use it needs to know what the current global
    properties are.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15242)

commit ad8570a8b6b4ec27e92013653d4d36b0c1b36991
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 7 17:13:05 2021 +0100

    Add a test for converting a property list to a string
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15242)

commit e2ed740ec4dcfd32723d849a146bfc126b95d16c
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 7 16:42:53 2021 +0100

    Implement the ability to convert a PROPERTY_LIST to a string
    
    We have the ability to parse a string into a PROPERTY_LIST already. Now
    we have the ability to go the other way.
    
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15242)

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

Summary of changes:
 crypto/evp/evp_cnf.c                               |   2 +-
 crypto/evp/evp_fetch.c                             |  77 ++++++++++--
 crypto/property/property.c                         |  48 ++++++--
 crypto/property/property_local.h                   |   2 +
 crypto/property/property_parse.c                   | 130 +++++++++++++++++++++
 crypto/property/property_string.c                  |  44 +++++++
 crypto/provider_child.c                            |  10 ++
 crypto/provider_core.c                             |  40 ++++++-
 .../man3/ossl_global_properties_no_mirrored.pod    |  56 +++++++++
 doc/internal/man3/ossl_provider_new.pod            |  11 +-
 doc/man3/OSSL_LIB_CTX.pod                          |   6 +
 doc/man7/provider-base.pod                         |   9 +-
 include/crypto/evp.h                               |   3 +-
 include/internal/property.h                        |   7 ++
 include/internal/provider.h                        |   1 +
 include/openssl/core_dispatch.h                    |   1 +
 include/openssl/lhash.h.in                         |   7 ++
 test/p_test.c                                      |  28 +++++
 test/property_test.c                               |  56 +++++++++
 test/provider_internal_test.c                      |  14 ++-
 test/provider_test.c                               |  39 ++++++-
 21 files changed, 563 insertions(+), 28 deletions(-)
 create mode 100644 doc/internal/man3/ossl_global_properties_no_mirrored.pod

diff --git a/crypto/evp/evp_cnf.c b/crypto/evp/evp_cnf.c
index 145f52fe1d..c13652ca0f 100644
--- a/crypto/evp/evp_cnf.c
+++ b/crypto/evp/evp_cnf.c
@@ -51,7 +51,7 @@ static int alg_module_init(CONF_IMODULE *md, const CONF *cnf)
                 return 0;
             }
         } else if (strcmp(oval->name, "default_properties") == 0) {
-            if (!evp_set_default_properties_int(cnf->libctx, oval->value, 0)) {
+            if (!evp_set_default_properties_int(cnf->libctx, oval->value, 0, 0)) {
                 ERR_raise(ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE);
                 return 0;
             }
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
index 6c701bf1e2..e71d827d4b 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -384,24 +384,55 @@ int evp_method_store_flush(OSSL_LIB_CTX *libctx)
 
 static int evp_set_parsed_default_properties(OSSL_LIB_CTX *libctx,
                                              OSSL_PROPERTY_LIST *def_prop,
-                                             int loadconfig)
+                                             int loadconfig,
+                                             int mirrored)
 {
     OSSL_METHOD_STORE *store = get_evp_method_store(libctx);
     OSSL_PROPERTY_LIST **plp = ossl_ctx_global_properties(libctx, loadconfig);
 
-    if (plp != NULL) {
+    if (plp != NULL && store != NULL) {
+#ifndef FIPS_MODULE
+        char *propstr = NULL;
+        size_t strsz;
+
+        if (mirrored) {
+            if (ossl_global_properties_no_mirrored(libctx))
+                return 0;
+        } else {
+            /*
+             * These properties have been explicitly set on this libctx, so
+             * don't allow any mirroring from a parent libctx.
+             */
+            ossl_global_properties_stop_mirroring(libctx);
+        }
+
+        strsz = ossl_property_list_to_string(libctx, def_prop, NULL, 0);
+        if (strsz > 0)
+            propstr = OPENSSL_malloc(strsz);
+        if (propstr == NULL) {
+            ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        if (ossl_property_list_to_string(libctx, def_prop, propstr,
+                                         strsz) == 0) {
+            OPENSSL_free(propstr);
+            ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        ossl_provider_default_props_update(libctx, propstr);
+        OPENSSL_free(propstr);
+#endif
         ossl_property_free(*plp);
         *plp = def_prop;
         if (store != NULL)
             return ossl_method_store_flush_cache(store, 0);
-        return 1;
     }
     ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
     return 0;
 }
 
 int evp_set_default_properties_int(OSSL_LIB_CTX *libctx, const char *propq,
-                                   int loadconfig)
+                                   int loadconfig, int mirrored)
 {
     OSSL_PROPERTY_LIST *pl = NULL;
 
@@ -409,12 +440,16 @@ int evp_set_default_properties_int(OSSL_LIB_CTX *libctx, const char *propq,
         ERR_raise(ERR_LIB_EVP, EVP_R_DEFAULT_QUERY_PARSE_ERROR);
         return 0;
     }
-    return evp_set_parsed_default_properties(libctx, pl, loadconfig);
+    if (!evp_set_parsed_default_properties(libctx, pl, loadconfig, mirrored)) {
+        ossl_property_free(pl);
+        return 0;
+    }
+    return 1;
 }
 
 int EVP_set_default_properties(OSSL_LIB_CTX *libctx, const char *propq)
 {
-    return evp_set_default_properties_int(libctx, propq, 1);
+    return evp_set_default_properties_int(libctx, propq, 1, 0);
 }
 
 static int evp_default_properties_merge(OSSL_LIB_CTX *libctx, const char *propq)
@@ -436,7 +471,11 @@ static int evp_default_properties_merge(OSSL_LIB_CTX *libctx, const char *propq)
         ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
         return 0;
     }
-    return evp_set_parsed_default_properties(libctx, pl2, 0);
+    if (!evp_set_parsed_default_properties(libctx, pl2, 0, 0)) {
+        ossl_property_free(pl2);
+        return 0;
+    }
+    return 1;
 }
 
 static int evp_default_property_is_enabled(OSSL_LIB_CTX *libctx,
@@ -459,6 +498,30 @@ int EVP_default_properties_enable_fips(OSSL_LIB_CTX *libctx, int enable)
     return evp_default_properties_merge(libctx, query);
 }
 
+char *evp_get_global_properties_str(OSSL_LIB_CTX *libctx, int loadconfig)
+{
+    OSSL_PROPERTY_LIST **plp = ossl_ctx_global_properties(libctx, loadconfig);
+    char *propstr = NULL;
+    size_t sz;
+
+    sz = ossl_property_list_to_string(libctx, *plp, NULL, 0);
+    if (sz == 0) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
+        return NULL;
+    }
+
+    propstr = OPENSSL_malloc(sz);
+    if (propstr == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    if (ossl_property_list_to_string(libctx, *plp, propstr, sz) == 0) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
+        OPENSSL_free(propstr);
+        return NULL;
+    }
+    return propstr;
+}
 
 struct do_all_data_st {
     void (*user_fn)(void *method, void *arg);
diff --git a/crypto/property/property.c b/crypto/property/property.c
index da6bc84e27..a769a7307e 100644
--- a/crypto/property/property.c
+++ b/crypto/property/property.c
@@ -74,25 +74,31 @@ typedef struct {
 
 DEFINE_SPARSE_ARRAY_OF(ALGORITHM);
 
+typedef struct ossl_global_properties_st {
+    OSSL_PROPERTY_LIST *list;
+#ifndef FIPS_MODULE
+    unsigned int no_mirrored : 1;
+#endif
+} OSSL_GLOBAL_PROPERTIES;
+
 static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid);
 
 /* Global properties are stored per library context */
-static void ossl_ctx_global_properties_free(void *vstore)
+static void ossl_ctx_global_properties_free(void *vglobp)
 {
-    OSSL_PROPERTY_LIST **plp = vstore;
+    OSSL_GLOBAL_PROPERTIES *globp = vglobp;
 
-    if (plp != NULL) {
-        ossl_property_free(*plp);
-        OPENSSL_free(plp);
+    if (globp != NULL) {
+        ossl_property_free(globp->list);
+        OPENSSL_free(globp);
     }
 }
 
 static void *ossl_ctx_global_properties_new(OSSL_LIB_CTX *ctx)
 {
-    return OPENSSL_zalloc(sizeof(OSSL_PROPERTY_LIST **));
+    return OPENSSL_zalloc(sizeof(OSSL_GLOBAL_PROPERTIES));
 }
 
-
 static const OSSL_LIB_CTX_METHOD ossl_ctx_global_properties_method = {
     OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
     ossl_ctx_global_properties_new,
@@ -102,13 +108,37 @@ static const OSSL_LIB_CTX_METHOD ossl_ctx_global_properties_method = {
 OSSL_PROPERTY_LIST **ossl_ctx_global_properties(OSSL_LIB_CTX *libctx,
                                                 int loadconfig)
 {
+    OSSL_GLOBAL_PROPERTIES *globp;
+
 #ifndef FIPS_MODULE
     if (loadconfig && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))
         return NULL;
 #endif
-    return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
-                                 &ossl_ctx_global_properties_method);
+    globp = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
+                                  &ossl_ctx_global_properties_method);
+
+    return &globp->list;
+}
+
+#ifndef FIPS_MODULE
+int ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx)
+{
+    OSSL_GLOBAL_PROPERTIES *globp
+        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
+                                &ossl_ctx_global_properties_method);
+
+    return globp->no_mirrored ? 1 : 0;
+}
+
+void ossl_global_properties_stop_mirroring(OSSL_LIB_CTX *libctx)
+{
+    OSSL_GLOBAL_PROPERTIES *globp
+        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES,
+                                &ossl_ctx_global_properties_method);
+
+    globp->no_mirrored = 1;
 }
+#endif
 
 static int ossl_method_up_ref(METHOD *method)
 {
diff --git a/crypto/property/property_local.h b/crypto/property/property_local.h
index c744a5d3c3..8cc3a51270 100644
--- a/crypto/property/property_local.h
+++ b/crypto/property/property_local.h
@@ -16,8 +16,10 @@ typedef int OSSL_PROPERTY_IDX;
 /* Property string functions */
 OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
                                      int create);
+const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx);
 OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
                                       int create);
+const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx);
 
 /* Property list functions */
 void ossl_property_free(OSSL_PROPERTY_LIST *p);
diff --git a/crypto/property/property_parse.c b/crypto/property/property_parse.c
index dfae76518f..aab8cbe8a4 100644
--- a/crypto/property/property_parse.c
+++ b/crypto/property/property_parse.c
@@ -616,3 +616,133 @@ int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
 err:
     return 0;
 }
+
+static void put_char(char ch, char **buf, size_t *remain, size_t *needed)
+{
+    if (*remain == 0) {
+        ++*needed;
+        return;
+    }
+    if(*remain == 1)
+        **buf = '\0';
+    else
+        **buf = ch;
+    ++*buf;
+    ++*needed;
+    --*remain;
+}
+
+static void put_str(const char *str, char **buf, size_t *remain, size_t *needed)
+{
+    size_t olen, len;
+
+    len = olen = strlen(str);
+    *needed += len;
+
+    if (*remain == 0)
+        return;
+
+    if(*remain < len + 1)
+        len = *remain - 1;
+
+    if(len > 0) {
+        strncpy(*buf, str, len);
+        *buf += len;
+        *remain -= len;
+    }
+
+    if(len < olen && *remain == 1) {
+        **buf = '\0';
+        ++*buf;
+        --*remain;
+    }
+}
+
+static void put_num(int val, char **buf, size_t *remain, size_t *needed)
+{
+    int tmpval = val;
+    size_t len = 1;
+
+    for (; tmpval > 9; len++, tmpval /= 10);
+
+    *needed += len;
+
+    if (*remain == 0)
+        return;
+
+    BIO_snprintf(*buf, *remain, "%d", val);
+    if (*remain < len) {
+        *buf += *remain;
+        *remain = 0;
+    } else {
+        *buf += len;
+        *remain -= len;
+    }
+}
+
+size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
+                                    const OSSL_PROPERTY_LIST *list, char *buf,
+                                    size_t bufsize)
+{
+    int i;
+    const PROPERTY_DEFINITION *prop = NULL;
+    size_t needed = 0;
+    const char *val;
+
+    if (list == NULL) {
+        if (bufsize > 0)
+            *buf = '\0';
+        return 1;
+    }
+    if (list->n != 0)
+        prop = &list->properties[list->n - 1];
+    for (i = 0; i < list->n; i++, prop--) {
+        /* Skip invalid names */
+        if (prop->name_idx == 0)
+            continue;
+
+        if (needed > 0)
+            put_char(',', &buf, &bufsize, &needed);
+
+        if (prop->optional)
+            put_char('?', &buf, &bufsize, &needed);
+        else if (prop->oper == PROPERTY_OVERRIDE)
+            put_char('-', &buf, &bufsize, &needed);
+
+        val = ossl_property_name_str(ctx, prop->name_idx);
+        if (val == NULL)
+            return 0;
+        put_str(val, &buf, &bufsize, &needed);
+
+        switch (prop->oper) {
+            case PROPERTY_OPER_NE:
+                put_char('!', &buf, &bufsize, &needed);
+                /* fall through */
+            case PROPERTY_OPER_EQ:
+                put_char('=', &buf, &bufsize, &needed);
+                /* put value */
+                switch (prop->type) {
+                case PROPERTY_TYPE_STRING:
+                    val = ossl_property_value_str(ctx, prop->v.str_val);
+                    if (val == NULL)
+                        return 0;
+                    put_str(val, &buf, &bufsize, &needed);
+                    break;
+
+                case PROPERTY_TYPE_NUMBER:
+                    put_num(prop->v.int_val, &buf, &bufsize, &needed);
+                    break;
+
+                default:
+                    return 0;
+                }
+                break;
+            default:
+                /* do nothing */
+                break;
+        }
+    }
+
+    put_char('\0', &buf, &bufsize, &needed);
+    return needed;
+}
diff --git a/crypto/property/property_string.c b/crypto/property/property_string.c
index 9eb55cb461..06f58496db 100644
--- a/crypto/property/property_string.c
+++ b/crypto/property/property_string.c
@@ -162,6 +162,45 @@ OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
                                 s);
 }
 
+struct find_str_st {
+    const char *str;
+    OSSL_PROPERTY_IDX idx;
+};
+
+static void find_str_fn(PROPERTY_STRING *prop, void *vfindstr)
+{
+    struct find_str_st *findstr = vfindstr;
+
+    if (prop->idx == findstr->idx)
+        findstr->str = prop->s;
+}
+
+static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx,
+                                     OSSL_PROPERTY_IDX idx)
+{
+    struct find_str_st findstr;
+    PROPERTY_STRING_DATA *propdata
+        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
+                                &property_string_data_method);
+
+    if (propdata == NULL)
+        return NULL;
+
+    findstr.str = NULL;
+    findstr.idx = idx;
+
+    lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names
+                                      : propdata->prop_values,
+                                 find_str_fn, &findstr);
+
+    return findstr.str;
+}
+
+const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
+{
+    return ossl_property_str(1, ctx, idx);
+}
+
 OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
                                       int create)
 {
@@ -175,3 +214,8 @@ OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
                                 create ? &propdata->prop_value_idx : NULL,
                                 s);
 }
+
+const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
+{
+    return ossl_property_str(0, ctx, idx);
+}
diff --git a/crypto/provider_child.c b/crypto/provider_child.c
index 14d0054624..7ab161b795 100644
--- a/crypto/provider_child.c
+++ b/crypto/provider_child.c
@@ -12,8 +12,10 @@
 #include <openssl/core_dispatch.h>
 #include <openssl/core_names.h>
 #include <openssl/provider.h>
+#include <openssl/evp.h>
 #include "internal/provider.h"
 #include "internal/cryptlib.h"
+#include "crypto/evp.h"
 
 DEFINE_STACK_OF(OSSL_PROVIDER)
 
@@ -198,6 +200,13 @@ static int provider_remove_child_cb(const OSSL_CORE_HANDLE *prov, void *cbdata)
     return 1;
 }
 
+static int provider_global_props_cb(const char *props, void *cbdata)
+{
+    OSSL_LIB_CTX *ctx = cbdata;
+
+    return evp_set_default_properties_int(ctx, props, 0, 1);
+}
+
 int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx,
                                 const OSSL_CORE_HANDLE *handle,
                                 const OSSL_DISPATCH *in)
@@ -265,6 +274,7 @@ int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx,
     if (!gbl->c_provider_register_child_cb(gbl->handle,
                                            provider_create_child_cb,
                                            provider_remove_child_cb,
+                                           provider_global_props_cb,
                                            ctx))
         return 0;
 
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index 9d5248de0d..512a16ee66 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -46,7 +46,8 @@ DEFINE_STACK_OF(INFOPAIR)
 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);
+    int (*remove_cb)(const OSSL_CORE_HANDLE *provider, void *cbdata);
+    int (*global_props_cb)(const char *props, void *cbdata);
     void *cbdata;
 } OSSL_PROVIDER_CHILD_CB;
 DEFINE_STACK_OF(OSSL_PROVIDER_CHILD_CB)
@@ -1363,13 +1364,40 @@ int ossl_provider_convert_to_child(OSSL_PROVIDER *prov,
     return 1;
 }
 
+int ossl_provider_default_props_update(OSSL_LIB_CTX *libctx, const char *props)
+{
+#ifndef FIPS_MODULE
+    struct provider_store_st *store = NULL;
+    int i, max;
+    OSSL_PROVIDER_CHILD_CB *child_cb;
+
+    if ((store = get_provider_store(libctx)) == NULL)
+        return 0;
+
+    if (!CRYPTO_THREAD_read_lock(store->lock))
+        return 0;
+
+    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);
+        child_cb->global_props_cb(props, child_cb->cbdata);
+    }
+
+    CRYPTO_THREAD_unlock(store->lock);
+#endif
+    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)(
+                                           int (*remove_cb)(
                                                const OSSL_CORE_HANDLE *provider,
                                                void *cbdata),
+                                           int (*global_props_cb)(
+                                               const char *props,
+                                               void *cbdata),
                                            void *cbdata)
 {
     /*
@@ -1382,6 +1410,7 @@ static int ossl_provider_register_child_cb(const OSSL_CORE_HANDLE *handle,
     struct provider_store_st *store = NULL;
     int ret = 0, i, max;
     OSSL_PROVIDER_CHILD_CB *child_cb;
+    char *propsstr = NULL;
 
     if ((store = get_provider_store(libctx)) == NULL)
         return 0;
@@ -1392,12 +1421,19 @@ static int ossl_provider_register_child_cb(const OSSL_CORE_HANDLE *handle,
     child_cb->prov = thisprov;
     child_cb->create_cb = create_cb;
     child_cb->remove_cb = remove_cb;
+    child_cb->global_props_cb = global_props_cb;
     child_cb->cbdata = cbdata;
 
     if (!CRYPTO_THREAD_write_lock(store->lock)) {
         OPENSSL_free(child_cb);
         return 0;
     }
+    propsstr = evp_get_global_properties_str(libctx, 0);
+
+    if (propsstr != NULL) {
+        global_props_cb(propsstr, cbdata);
+        OPENSSL_free(propsstr);
+    }
     max = sk_OSSL_PROVIDER_num(store->providers);
     for (i = 0; i < max; i++) {
         prov = sk_OSSL_PROVIDER_value(store->providers, i);
diff --git a/doc/internal/man3/ossl_global_properties_no_mirrored.pod b/doc/internal/man3/ossl_global_properties_no_mirrored.pod
new file mode 100644
index 0000000000..6c39ccbc0f
--- /dev/null
+++ b/doc/internal/man3/ossl_global_properties_no_mirrored.pod
@@ -0,0 +1,56 @@
+=pod
+
+=head1 NAME
+
+ossl_property_list_to_string, ossl_global_properties_no_mirrored
+- internal property routines
+
+=head1 SYNOPSIS
+
+ #include "internal/property.h"
+
+ size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
+                                     const OSSL_PROPERTY_LIST *list, char *buf,
+                                     size_t bufsize);
+
+ int ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx);
+ void ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx);
+
+
+=head1 DESCRIPTION
+
+ossl_property_list_to_string() takes a given OSSL_PROPERTY_LIST in I<list> and
+converts it to a string. If I<buf> is non NULL then the string will be stored
+in I<buf>. The size of the buffer is provided in I<bufsize>. If I<bufsize> is
+too short then the string will be truncated. If I<buf> is NULL then the length
+of the string is still calculated and returned. If the property list has no
+properties in it then the empty string will be stored in I<buf>.
+
+ossl_global_properties_no_mirrored() checks whether mirroring of global
+properties from a parent library context is allowed for the current library
+context.
+
+ossl_global_properties_no_mirrored() prevents future mirroring of global
+properties from a parent library context for the current library context.
+
+=head1 RETURN VALUES
+
+ossl_property_list_to_string() returns the length of the string, or 0 on error.
+
+ossl_global_properties_no_mirrored() returns 1 if mirroring of global properties
+is not allowed, or 0 otherwise.
+
+=head1 HISTORY
+
+The functions described here were all added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/internal/man3/ossl_provider_new.pod b/doc/internal/man3/ossl_provider_new.pod
index 7ab60eb3a5..ed2d6993b3 100644
--- a/doc/internal/man3/ossl_provider_new.pod
+++ b/doc/internal/man3/ossl_provider_new.pod
@@ -7,7 +7,7 @@ ossl_provider_free,
 ossl_provider_set_fallback, ossl_provider_set_module_path,
 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_default_props_update, ossl_provider_get0_dispatch,
 ossl_provider_init_as_child,
 ossl_provider_activate, ossl_provider_deactivate, ossl_provider_available,
 ossl_provider_ctx,
@@ -46,6 +46,8 @@ ossl_provider_get_capabilities
  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);
+ int ossl_provider_default_props_update(OSSL_LIB_CTX *libctx,
+                                        const char *props);
 
  /*
   * Activate the Provider
@@ -193,6 +195,10 @@ 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_default_props_update() is responsible for informing any child
+providers of an update to the default properties. The new properties are
+supplied in the I<props> string.
+
 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.
@@ -339,7 +345,8 @@ called for any activated providers.
 
 ossl_provider_set_module_path(), ossl_provider_set_fallback(),
 ossl_provider_activate(), ossl_provider_activate_leave_fallbacks() and
-ossl_provider_deactivate() return 1 on success, or 0 on error.
+ossl_provider_deactivate(), ossl_provider_default_props_update() return 1 on
+success, or 0 on error.
 
 ossl_provider_available() return 1 if the provider is available,
 otherwise 0.
diff --git a/doc/man3/OSSL_LIB_CTX.pod b/doc/man3/OSSL_LIB_CTX.pod
index 57037e2ba6..d51816ead7 100644
--- a/doc/man3/OSSL_LIB_CTX.pod
+++ b/doc/man3/OSSL_LIB_CTX.pod
@@ -69,6 +69,12 @@ 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.
 
+In addition to providers, a child library context will also mirror the default
+properties (set via L<EVP_set_default_properties(3)>) from the parent library
+context. If L<EVP_set_default_properties(3)> is called directly on a child
+library context then the new properties will override anything from the parent
+library context and mirroring of the properties will stop.
+
 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
diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod
index 19cd4e445b..10ad301fb4 100644
--- a/doc/man7/provider-base.pod
+++ b/doc/man7/provider-base.pod
@@ -89,6 +89,7 @@ provider-base
                                       void *cbdata),
                      int (*remove_cb)(const OSSL_CORE_HANDLE *provider,
                                       void *cbdata),
+                     int (*global_props_cb)(const char *props, void *cbdata),
                      void *cbdata);
  void provider_deregister_child_cb(const OSSL_CORE_HANDLE *handle);
  const char *provider_name(const OSSL_CORE_HANDLE *prov);
@@ -289,12 +290,16 @@ 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.
+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.
+return 1 on success or 0 on failure.
+
+I<global_props_cb> is a callback that will be called when the global properties
+from the parent library context are changed. 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
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index 96a109e38b..92a9f0fc29 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -886,7 +886,8 @@ int evp_pkey_ctx_use_cached_data(EVP_PKEY_CTX *ctx);
 
 int evp_method_store_flush(OSSL_LIB_CTX *libctx);
 int evp_set_default_properties_int(OSSL_LIB_CTX *libctx, const char *propq,
-                                   int loadconfig);
+                                   int loadconfig, int mirrored);
+char *evp_get_global_properties_str(OSSL_LIB_CTX *libctx, int loadconfig);
 
 void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force);
 
diff --git a/include/internal/property.h b/include/internal/property.h
index 58ceddbb76..856cd740ad 100644
--- a/include/internal/property.h
+++ b/include/internal/property.h
@@ -64,4 +64,11 @@ __owur int ossl_method_store_flush_cache(OSSL_METHOD_STORE *store, int all);
 OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
                                         const OSSL_PROPERTY_LIST *b);
 
+size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
+                                    const OSSL_PROPERTY_LIST *list, char *buf,
+                                    size_t bufsize);
+
+int ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx);
+void ossl_global_properties_stop_mirroring(OSSL_LIB_CTX *libctx);
+
 #endif
diff --git a/include/internal/provider.h b/include/internal/provider.h
index 020cbc8a9e..df20c76f90 100644
--- a/include/internal/provider.h
+++ b/include/internal/provider.h
@@ -50,6 +50,7 @@ int ossl_provider_convert_to_child(OSSL_PROVIDER *prov,
 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);
+int ossl_provider_default_props_update(OSSL_LIB_CTX *libctx, const char *props);
 
 /* Disable fallback loading */
 int ossl_provider_disable_fallback_loading(OSSL_LIB_CTX *libctx);
diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h
index 5c453eaac0..458cbb1c9e 100644
--- a/include/openssl/core_dispatch.h
+++ b/include/openssl/core_dispatch.h
@@ -196,6 +196,7 @@ 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),
+                     int (*global_props_cb)(const char *props, void *cbdata),
                      void *cbdata))
 OSSL_CORE_MAKE_FUNC(void, provider_deregister_child_cb,
                     (const OSSL_CORE_HANDLE *handle))
diff --git a/include/openssl/lhash.h.in b/include/openssl/lhash.h.in
index 571dce43ea..04f6c45736 100644
--- a/include/openssl/lhash.h.in
+++ b/include/openssl/lhash.h.in
@@ -226,6 +226,13 @@ void OPENSSL_LH_node_usage_stats_bio(const OPENSSL_LHASH *lh, BIO *out);
     { \
         OPENSSL_LH_doall((OPENSSL_LHASH *)lh, (OPENSSL_LH_DOALL_FUNC)doall); \
     } \
+    static ossl_unused ossl_inline void lh_##type##_doall_arg(LHASH_OF(type) *lh, \
+                                                              void (*doallarg)(type *, void *), \
+                                                              void *arg) \
+    { \
+        OPENSSL_LH_doall_arg((OPENSSL_LHASH *)lh, \
+                             (OPENSSL_LH_DOALL_FUNCARG)doallarg, arg); \
+    } \
     LHASH_OF(type)
 
 #define IMPLEMENT_LHASH_DOALL_ARG_CONST(type, argtype) \
diff --git a/test/p_test.c b/test/p_test.c
index 22bf8648fe..80f0784dd9 100644
--- a/test/p_test.c
+++ b/test/p_test.c
@@ -183,6 +183,22 @@ static int p_get_params(void *provctx, OSSL_PARAM params[])
             } else {
                 ok = 0;
             }
+        } else if (strcmp(p->key, "stop-property-mirror") == 0) {
+            /*
+             * Setting the default properties explicitly should stop mirroring
+             * of properties from the parent libctx.
+             */
+            unsigned int stopsuccess = 0;
+
+#ifdef PROVIDER_INIT_FUNCTION_NAME
+            stopsuccess = EVP_set_default_properties(ctx->libctx, NULL);
+#endif
+            if (p->data_size >= sizeof(stopsuccess)) {
+                *(unsigned int *)p->data = stopsuccess;
+                p->return_size = sizeof(stopsuccess);
+            } else {
+                ok = 0;
+            }
         }
     }
     return ok;
@@ -266,6 +282,18 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
         p_teardown(ctx);
         return 0;
     }
+    /*
+     * The default provider is loaded - but the default properties should not
+     * allow its use.
+     */
+    {
+        EVP_MD *sha256 = EVP_MD_fetch(ctx->libctx, "SHA2-256", NULL);
+        if (sha256 != NULL) {
+            EVP_MD_free(sha256);
+            p_teardown(ctx);
+            return 0;
+        }
+    }
 #endif
 
     /*
diff --git a/test/property_test.c b/test/property_test.c
index 3682474bd2..94540bc776 100644
--- a/test/property_test.c
+++ b/test/property_test.c
@@ -435,6 +435,61 @@ err:
     return ret;
 }
 
+static int test_property_list_to_string(void)
+{
+    OSSL_PROPERTY_LIST *pl = NULL;
+    int ret = 0;
+    struct props_list_str {
+        const char *in;
+        const char *out;
+    } props[] = {
+        { "fips=yes", "fips=yes" },
+        { "fips!=yes", "fips!=yes" },
+        { "fips = yes", "fips=yes" },
+        { "fips", "fips=yes" },
+        { "fips=no", "fips=no" },
+        { "-fips", "-fips" },
+        { "?fips=yes", "?fips=yes" },
+        { "fips=yes,provider=fips", "fips=yes,provider=fips" },
+        { "fips = yes , provider = fips", "fips=yes,provider=fips" },
+        { "fips=yes,provider!=fips", "fips=yes,provider!=fips" },
+        { "fips=yes,?provider=fips", "fips=yes,?provider=fips" },
+        { "fips=yes,-provider", "fips=yes,-provider" },
+          /* foo is an unknown internal name */
+        { "foo=yes,fips=yes", "fips=yes"},
+        { "", "" },
+        { NULL, "" }
+    };
+    size_t i, bufsize;
+    char *buf = NULL;
+
+    for (i = 0; i < OSSL_NELEM(props); i++) {
+        if (props[i].in != NULL
+                && !TEST_ptr(pl = ossl_parse_query(NULL, props[i].in, 1)))
+            goto err;
+        bufsize = ossl_property_list_to_string(NULL, pl, NULL, 0);
+        if (!TEST_size_t_gt(bufsize, 0))
+            goto err;
+        buf = OPENSSL_malloc(bufsize);
+        if (!TEST_ptr(buf)
+                || !TEST_size_t_eq(ossl_property_list_to_string(NULL, pl, buf,
+                                                                bufsize),
+                                   bufsize)
+                || !TEST_str_eq(props[i].out, buf)
+                || !TEST_size_t_eq(bufsize, strlen(props[i].out) + 1))
+            goto err;
+        OPENSSL_free(buf);
+        buf = NULL;
+        ossl_property_free(pl);
+        pl = NULL;
+    }
+
+    ret = 1;
+ err:
+    OPENSSL_free(buf);
+    ossl_property_free(pl);
+    return ret;
+}
 
 int setup_tests(void)
 {
@@ -448,5 +503,6 @@ int setup_tests(void)
     ADD_TEST(test_property);
     ADD_TEST(test_query_cache_stochastic);
     ADD_TEST(test_fips_mode);
+    ADD_TEST(test_property_list_to_string);
     return 1;
 }
diff --git a/test/provider_internal_test.c b/test/provider_internal_test.c
index 2341dd3dac..6c295451c1 100644
--- a/test/provider_internal_test.c
+++ b/test/provider_internal_test.c
@@ -53,11 +53,23 @@ static int test_builtin_provider(void)
 {
     const char *name = "p_test_builtin";
     OSSL_PROVIDER *prov = NULL;
+    int ret;
 
-    return
+    /*
+     * We set properties that we know the providers we are using don't have.
+     * This should mean that the p_test provider will fail any fetches - which
+     * is something we test inside the provider.
+     */
+    EVP_set_default_properties(NULL, "fips=yes");
+
+    ret =
         TEST_ptr(prov =
                  ossl_provider_new(NULL, name, PROVIDER_INIT_FUNCTION_NAME, 0))
         && test_provider(prov, expected_greeting1(name));
+
+    EVP_set_default_properties(NULL, "");
+
+    return ret;
 }
 
 #ifndef NO_PROVIDER_MODULE
diff --git a/test/provider_test.c b/test/provider_test.c
index 4d8dbaee6f..807b8fcf22 100644
--- a/test/provider_test.c
+++ b/test/provider_test.c
@@ -26,6 +26,13 @@ static OSSL_PARAM digest_check[] = {
     { NULL, 0, NULL, 0, 0 }
 };
 
+static unsigned int stopsuccess = 0;
+static OSSL_PARAM stop_property_mirror[] = {
+    { "stop-property-mirror", OSSL_PARAM_UNSIGNED_INTEGER, &stopsuccess,
+      sizeof(stopsuccess) },
+    { NULL, 0, NULL, 0, 0 }
+};
+
 static int test_provider(OSSL_LIB_CTX **libctx, const char *name,
                          OSSL_PROVIDER *legacy)
 {
@@ -41,18 +48,44 @@ static int test_provider(OSSL_LIB_CTX **libctx, const char *name,
                  "Hello OpenSSL %.20s, greetings from %s!",
                  OPENSSL_VERSION_STR, name);
 
+
     /*
-        * Check that it is possible to have a built-in provider mirrored in
-        * a child lib ctx.
-        */
+     * We set properties that we know the providers we are using don't have.
+     * This should mean that the p_test provider will fail any fetches - which
+     * is something we test inside the provider.
+     */
+    EVP_set_default_properties(*libctx, "fips=yes");
+    /*
+     * 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;
+
+    /*
+     * Once the provider is loaded we clear the default properties and fetches
+     * should start working again.
+     */
+    EVP_set_default_properties(*libctx, "");
     if (dolegacycheck) {
         if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
                 || !TEST_true(digestsuccess))
             goto err;
+
+        /*
+         * Check that a provider can prevent property mirroring if it sets its
+         * own properties explicitly
+         */
+        if (!TEST_true(OSSL_PROVIDER_get_params(prov, stop_property_mirror))
+                || !TEST_true(stopsuccess))
+            goto err;
+        EVP_set_default_properties(*libctx, "fips=yes");
+        if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check))
+                || !TEST_true(digestsuccess))
+            goto err;
+        EVP_set_default_properties(*libctx, "");
     }
     if (!TEST_true(OSSL_PROVIDER_get_params(prov, greeting_request))
             || !TEST_ptr(greeting = greeting_request[0].data)


More information about the openssl-commits mailing list