[openssl] master update

Richard Levitte levitte at openssl.org
Tue Mar 19 13:07:03 UTC 2019


The branch master has been updated
       via  c41f3ae0d92a87b903a9ed585622adae06791676 (commit)
       via  e55008a9f2ae299374dcf868b660389e84dd2e0b (commit)
      from  6a6d9ecd1dff669c162e8ab940dac5db2e82679d (commit)


- Log -----------------------------------------------------------------
commit c41f3ae0d92a87b903a9ed585622adae06791676
Author: Richard Levitte <levitte at openssl.org>
Date:   Sun Mar 17 18:06:59 2019 +0100

    Replumbing: Add a mechanism to pre-populate the provider store
    
    OpenSSL will come with a set of well known providers, some of which
    need to be accessible from the start.  These are typically built in
    providers, or providers that will work as fallbacks.
    
    We do this when creating a new provider store, which means that this
    will happen in every library context, regardless of if it's the global
    default one, or an explicitely created one.
    
    We keep the data about the known providers we want to make accessible
    this way in crypto/provider_predefined.h, which may become generated.
    For now, though, we make it simple and edited manually.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8480)

commit e55008a9f2ae299374dcf868b660389e84dd2e0b
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Mar 14 10:53:27 2019 +0100

    Replumbing: add fallback provider capability
    
    To ensure that old applications aren't left without any provider, and
    at the same time not forcing any default provider on applications that
    know how to deal with them, we device the concept of fallback
    providers, which are automatically activated if no other provider is
    already activated.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8480)

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

Summary of changes:
 crypto/build.info                                  |   2 +-
 crypto/cpt_err.c                                   |   5 +
 crypto/err/openssl.txt                             |   3 +
 crypto/provider_core.c                             | 210 +++++++++++++++++----
 .../testutil/apps_mem.c => crypto/provider_local.h |  15 +-
 crypto/provider_predefined.c                       |  22 +++
 doc/internal/man3/ossl_provider_new.pod            |  26 ++-
 include/internal/provider.h                        |   1 +
 include/openssl/cryptoerr.h                        |   3 +
 9 files changed, 234 insertions(+), 53 deletions(-)
 copy test/testutil/apps_mem.c => crypto/provider_local.h (60%)
 create mode 100644 crypto/provider_predefined.c

diff --git a/crypto/build.info b/crypto/build.info
index 39cd91b..535fa35 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -9,7 +9,7 @@ SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 x509v3 conf \
 
 LIBS=../libcrypto
 # The Core
-SOURCE[../libcrypto]=provider_core.c core_fetch.c
+SOURCE[../libcrypto]=provider_core.c provider_predefined.c core_fetch.c
 
 # Central utilities
 SOURCE[../libcrypto]=\
diff --git a/crypto/cpt_err.c b/crypto/cpt_err.c
index bf7985c..3c3265d 100644
--- a/crypto/cpt_err.c
+++ b/crypto/cpt_err.c
@@ -57,6 +57,11 @@ static const ERR_STRING_DATA CRYPTO_str_functs[] = {
      "pkey_poly1305_init"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PKEY_SIPHASH_INIT, 0),
      "pkey_siphash_init"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PROVIDER_ACTIVATE, 0),
+     "provider_activate"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PROVIDER_NEW, 0), "provider_new"},
+    {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PROVIDER_STORE_NEW, 0),
+     "provider_store_new"},
     {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_SK_RESERVE, 0), "sk_reserve"},
     {0, NULL}
 };
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 4853a05..7309ed8 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -396,6 +396,9 @@ CRYPTO_F_OSSL_PROVIDER_NEW:131:ossl_provider_new
 CRYPTO_F_PKEY_HMAC_INIT:123:pkey_hmac_init
 CRYPTO_F_PKEY_POLY1305_INIT:124:pkey_poly1305_init
 CRYPTO_F_PKEY_SIPHASH_INIT:125:pkey_siphash_init
+CRYPTO_F_PROVIDER_ACTIVATE:134:provider_activate
+CRYPTO_F_PROVIDER_NEW:135:provider_new
+CRYPTO_F_PROVIDER_STORE_NEW:136:provider_store_new
 CRYPTO_F_SK_RESERVE:129:sk_reserve
 CT_F_CTLOG_NEW:117:CTLOG_new
 CT_F_CTLOG_NEW_FROM_BASE64:118:CTLOG_new_from_base64
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index 8af5b1f1..7a184a7 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -11,9 +11,14 @@
 #include <openssl/core_numbers.h>
 #include <openssl/opensslv.h>
 #include "internal/cryptlib.h"
+#include "internal/nelem.h"
 #include "internal/thread_once.h"
 #include "internal/provider.h"
 #include "internal/refcount.h"
+#include "provider_local.h"
+
+static OSSL_PROVIDER *provider_new(const char *name,
+                                   OSSL_provider_init_fn *init_function);
 
 /*-
  * Provider Object structure
@@ -25,6 +30,7 @@ struct provider_store_st;        /* Forward declaration */
 struct ossl_provider_st {
     /* Flag bits */
     unsigned int flag_initialized:1;
+    unsigned int flag_fallback:1;
 
     /* OpenSSL library side data */
     CRYPTO_REF_COUNT refcnt;
@@ -32,6 +38,7 @@ struct ossl_provider_st {
     char *name;
     DSO *module;
     OSSL_provider_init_fn *init_function;
+    struct provider_store_st *store; /* The store this instance belongs to */
 
     /* Provider side functions */
     OSSL_provider_teardown_fn *teardown;
@@ -58,6 +65,7 @@ static int ossl_provider_cmp(const OSSL_PROVIDER * const *a,
 struct provider_store_st {
     STACK_OF(OSSL_PROVIDER) *providers;
     CRYPTO_RWLOCK *lock;
+    unsigned int use_fallbacks:1;
 };
 static int provider_store_index = -1;
 
@@ -75,13 +83,37 @@ static void provider_store_free(void *vstore)
 static void *provider_store_new(void)
 {
     struct provider_store_st *store = OPENSSL_zalloc(sizeof(*store));
+    const struct predefined_providers_st *p = NULL;
 
     if (store == NULL
         || (store->providers = sk_OSSL_PROVIDER_new(ossl_provider_cmp)) == NULL
         || (store->lock = CRYPTO_THREAD_lock_new()) == NULL) {
         provider_store_free(store);
-        store = NULL;
+        return NULL;
     }
+    store->use_fallbacks = 1;
+
+    for (p = predefined_providers; p->name != NULL; p++) {
+        OSSL_PROVIDER *prov = NULL;
+
+        /*
+         * We use the internal constructor directly here,
+         * otherwise we get a call loop
+         */
+        prov = provider_new(p->name, p->init);
+
+        if (prov == NULL
+            || sk_OSSL_PROVIDER_push(store->providers, prov) == 0) {
+            ossl_provider_free(prov);
+            provider_store_free(store);
+            CRYPTOerr(CRYPTO_F_PROVIDER_STORE_NEW, ERR_R_INTERNAL_ERROR);
+            return NULL;
+        }
+        prov->store = store;
+        if(p->is_fallback)
+            ossl_provider_set_fallback(prov);
+    }
+
     return store;
 }
 
@@ -112,20 +144,6 @@ static struct provider_store_st *get_provider_store(OPENSSL_CTX *libctx)
     return store;
 }
 
-/*-
- * Provider Object methods
- * =======================
- */
-
-int ossl_provider_upref(OSSL_PROVIDER *prov)
-{
-    int ref = 0;
-
-    CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock);
-    return ref;
-}
-
-/* Finder, constructor and destructor */
 OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name)
 {
     struct provider_store_st *store = NULL;
@@ -147,6 +165,39 @@ OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name)
     return prov;
 }
 
+/*-
+ * Provider Object methods
+ * =======================
+ */
+
+static OSSL_PROVIDER *provider_new(const char *name,
+                                   OSSL_provider_init_fn *init_function)
+{
+    OSSL_PROVIDER *prov = NULL;
+
+    if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL
+#ifndef HAVE_ATOMICS
+        || (prov->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL
+#endif
+        || !ossl_provider_upref(prov) /* +1 One reference to be returned */
+        || (prov->name = OPENSSL_strdup(name)) == NULL) {
+        ossl_provider_free(prov);
+        CRYPTOerr(CRYPTO_F_PROVIDER_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    prov->init_function = init_function;
+    return prov;
+}
+
+int ossl_provider_upref(OSSL_PROVIDER *prov)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock);
+    return ref;
+}
+
 OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
                                  OSSL_provider_init_fn *init_function)
 {
@@ -164,18 +215,9 @@ OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
         return NULL;
     }
 
-    if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL
-#ifndef HAVE_ATOMICS
-        || (prov->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL
-#endif
-        || !ossl_provider_upref(prov) /* +1 One reference to be returned */
-        || (prov->name = OPENSSL_strdup(name)) == NULL) {
-        ossl_provider_free(prov);
-        CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW, ERR_R_MALLOC_FAILURE);
+    /* provider_new() generates an error, so no need here */
+    if ((prov = provider_new(name, init_function)) == NULL)
         return NULL;
-    }
-
-    prov->init_function = init_function;
 
     CRYPTO_THREAD_write_lock(store->lock);
     if (!ossl_provider_upref(prov)) { /* +1 One reference for the store */
@@ -185,6 +227,8 @@ OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
         ossl_provider_free(prov); /* -1 Store reference */
         ossl_provider_free(prov); /* -1 Reference that was to be returned */
         prov = NULL;
+    } else {
+        prov->store = store;
     }
     CRYPTO_THREAD_unlock(store->lock);
 
@@ -207,11 +251,13 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
         CRYPTO_DOWN_REF(&prov->refcnt, &ref, prov->refcnt_lock);
 
         /*
-         * When the refcount drops down to one, there is only one reference,
-         * the store.
+         * When the refcount drops below two, the store is the only
+         * possible reference, or it has already been taken away from
+         * the store (this may happen if a provider was activated
+         * because it's a fallback, but isn't currently used)
          * When that happens, the provider is inactivated.
          */
-        if (ref == 1 && prov->flag_initialized) {
+        if (ref < 2 && prov->flag_initialized) {
             if (prov->teardown != NULL)
                 prov->teardown();
             prov->flag_initialized = 0;
@@ -246,7 +292,12 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
  */
 static const OSSL_DISPATCH *core_dispatch; /* Define further down */
 
-int ossl_provider_activate(OSSL_PROVIDER *prov)
+/*
+ * Internal version that doesn't affect the store flags, and thereby avoid
+ * locking.  Direct callers must remember to set the store flags when
+ * appropriate
+ */
+static int provider_activate(OSSL_PROVIDER *prov)
 {
     const OSSL_DISPATCH *provider_dispatch = NULL;
 
@@ -295,7 +346,7 @@ int ossl_provider_activate(OSSL_PROVIDER *prov)
 
     if (prov->init_function == NULL
         || !prov->init_function(prov, core_dispatch, &provider_dispatch)) {
-        CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_ACTIVATE, ERR_R_INIT_FAIL);
+        CRYPTOerr(CRYPTO_F_PROVIDER_ACTIVATE, ERR_R_INIT_FAIL);
         ERR_add_error_data(2, "name=", prov->name);
         DSO_free(prov->module);
         prov->module = NULL;
@@ -329,6 +380,46 @@ int ossl_provider_activate(OSSL_PROVIDER *prov)
     return 1;
 }
 
+int ossl_provider_activate(OSSL_PROVIDER *prov)
+{
+    if (provider_activate(prov)) {
+        CRYPTO_THREAD_write_lock(prov->store->lock);
+        prov->store->use_fallbacks = 0;
+        CRYPTO_THREAD_unlock(prov->store->lock);
+        return 1;
+    }
+
+    return 0;
+}
+
+
+static int provider_forall_loaded(struct provider_store_st *store,
+                                  int *found_activated,
+                                  int (*cb)(OSSL_PROVIDER *provider,
+                                            void *cbdata),
+                                  void *cbdata)
+{
+    int i;
+    int ret = 1;
+    int num_provs = sk_OSSL_PROVIDER_num(store->providers);
+
+    if (found_activated != NULL)
+        *found_activated = 0;
+    for (i = 0; i < num_provs; i++) {
+        OSSL_PROVIDER *prov =
+            sk_OSSL_PROVIDER_value(store->providers, i);
+
+        if (prov->flag_initialized) {
+            if (found_activated != NULL)
+                *found_activated = 1;
+            if (!(ret = cb(prov, cbdata)))
+                break;
+        }
+    }
+
+    return ret;
+}
+
 int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
                                 int (*cb)(OSSL_PROVIDER *provider,
                                           void *cbdata),
@@ -339,13 +430,50 @@ int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
     struct provider_store_st *store = get_provider_store(ctx);
 
     if (store != NULL) {
+        int found_activated = 0;
+
         CRYPTO_THREAD_read_lock(store->lock);
-        for (i = 0; i < sk_OSSL_PROVIDER_num(store->providers); i++) {
-            OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i);
+        ret = provider_forall_loaded(store, &found_activated, cb, cbdata);
 
-            if (prov->flag_initialized
-                && !(ret = cb(prov, cbdata)))
-                break;
+        /*
+         * If there's nothing activated ever in this store, try to activate
+         * all fallbacks.
+         */
+        if (!found_activated && store->use_fallbacks) {
+            int num_provs = sk_OSSL_PROVIDER_num(store->providers);
+            int activated_fallback_count = 0;
+
+            for (i = 0; i < num_provs; i++) {
+                OSSL_PROVIDER *prov =
+                    sk_OSSL_PROVIDER_value(store->providers, i);
+
+                /*
+                 * Note that we don't care if the activation succeeds or
+                 * not.  If it doesn't succeed, then the next loop will
+                 * fail anyway.
+                 */
+                if (prov->flag_fallback) {
+                    activated_fallback_count++;
+                    provider_activate(prov);
+                }
+            }
+
+            if (activated_fallback_count > 0) {
+                /*
+                 * We assume that all fallbacks have been added to the store
+                 * before any fallback is activated.
+                 * TODO: We may have to reconsider this, IF we find ourselves
+                 * adding fallbacks after any previous fallback has been
+                 * activated.
+                 */
+                store->use_fallbacks = 0;
+
+                /*
+                 * Now that we've activated available fallbacks, try a
+                 * second sweep
+                 */
+                ret = provider_forall_loaded(store, NULL, cb, cbdata);
+            }
         }
         CRYPTO_THREAD_unlock(store->lock);
     }
@@ -353,6 +481,16 @@ int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
     return ret;
 }
 
+/* Setters of Provider Object data */
+int ossl_provider_set_fallback(OSSL_PROVIDER *prov)
+{
+    if (prov == NULL)
+        return 0;
+
+    prov->flag_fallback = 1;
+    return 1;
+}
+
 /* Getters of Provider Object data */
 const char *ossl_provider_name(OSSL_PROVIDER *prov)
 {
diff --git a/test/testutil/apps_mem.c b/crypto/provider_local.h
similarity index 60%
copy from test/testutil/apps_mem.c
copy to crypto/provider_local.h
index fa60bc6..e4c649a 100644
--- a/test/testutil/apps_mem.c
+++ b/crypto/provider_local.h
@@ -7,13 +7,12 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include "apps.h"
+#include <openssl/core.h>
 
-/* shim that avoids sucking in too much from apps/apps.c */
+struct predefined_providers_st {
+    const char *name;
+    OSSL_provider_init_fn *init;
+    unsigned int is_fallback:1;
+};
 
-void* app_malloc(int sz, const char *what)
-{
-    void *vp = OPENSSL_malloc(sz);
-
-    return vp;
-}
+extern const struct predefined_providers_st predefined_providers[];
diff --git a/crypto/provider_predefined.c b/crypto/provider_predefined.c
new file mode 100644
index 0000000..be21565
--- /dev/null
+++ b/crypto/provider_predefined.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019 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 <openssl/core.h>
+#include "provider_local.h"
+
+#if 0                            /* Until it exists for real */
+OSSL_provider_init_fn ossl_default_provider_init;
+#endif
+
+const struct predefined_providers_st predefined_providers[] = {
+#if 0                            /* Until it exists for real */
+    { "default", ossl_default_provider_init, 1 },
+#endif
+    { NULL, NULL, 0 }
+};
diff --git a/doc/internal/man3/ossl_provider_new.pod b/doc/internal/man3/ossl_provider_new.pod
index 7633e0e..aa984c9 100644
--- a/doc/internal/man3/ossl_provider_new.pod
+++ b/doc/internal/man3/ossl_provider_new.pod
@@ -4,7 +4,8 @@
 
 ossl_provider_find, ossl_provider_new, ossl_provider_upref,
 ossl_provider_free, ossl_provider_add_module_location,
-ossl_provider_activate, ossl_provider_forall_loaded,
+ossl_provider_set_fallback, ossl_provider_activate,
+ossl_provider_forall_loaded,
 ossl_provider_name, ossl_provider_dso,
 ossl_provider_module_name, ossl_provider_module_path,
 ossl_provider_teardown, ossl_provider_get_param_types,
@@ -23,6 +24,7 @@ ossl_provider_get_params, ossl_provider_query_operation
 
  /* Setters */
  int ossl_provider_add_module_location(OSSL_PROVIDER *prov, const char *loc);
+ int ossl_provider_set_fallback(OSSL_PROVIDER *prov);
 
  /* Load and initialize the Provider */
  int ossl_provider_activate(OSSL_PROVIDER *prov);
@@ -71,7 +73,7 @@ times as ossl_provider_activate() has.
 
 ossl_provider_find() finds an existing I<provider object> in the
 I<provider object> store by C<name>.
-The I<provider object> it finds gets it's reference count
+The I<provider object> it finds gets its reference count
 incremented.
 
 ossl_provider_new() creates a new I<provider object> and stores it in
@@ -84,14 +86,20 @@ To indicate a built-in provider, the C<init_function> argument must
 point at the provider initialization function for that provider.
 
 ossl_provider_free() decrements a I<provider object>'s reference
-counter; if it drops to one, the I<provider object> will be
-inactivated (it's teardown function is called) but kept in the store;
-if it drops down to zero, the associated module will be unloaded if
-one was loaded, and the I<provider object> will be freed.
+counter; if it drops below 2, the I<provider object> is assumed to
+have fallen out of use and will be inactivated (its teardown function
+is called); if it drops down to zero, the I<provider object> is
+assumed to have been taken out of the store, and the associated module
+will be unloaded if one was loaded, and the I<provider object> will be
+freed.
 
 ossl_provider_add_module_location() adds a location to look for a
 provider module.
 
+ossl_provider_set_fallback() marks an available provider as fallback.
+Note that after this call, the I<provider object> pointer that was
+used can simply be dropped, but not freed.
+
 ossl_provider_activate() "activates" the provider for the given
 I<provider object>.
 What "activates" means depends on what type of I<provider object> it
@@ -115,6 +123,8 @@ be located in that module, and called.
 
 ossl_provider_forall_loaded() iterates over all the currently
 "activated" providers, and calls C<cb> for each of them.
+If no providers have been "activated" yet, it tries to activate all
+available fallback providers and tries another iteration.
 
 ossl_provider_name() returns the name that was given with
 ossl_provider_new().
@@ -178,8 +188,8 @@ it has been incremented.
 
 ossl_provider_free() doesn't return any value.
 
-ossl_provider_add_module_location() and ossl_provider_activate()
-return 1 on success, or 0 on error.
+ossl_provider_add_module_location(), ossl_provider_set_fallback() and
+ossl_provider_activate() return 1 on success, or 0 on error.
 
 ossl_provider_name(), ossl_provider_dso(),
 ossl_provider_module_name(), and ossl_provider_module_path() return a
diff --git a/include/internal/provider.h b/include/internal/provider.h
index ac70fcc..8af20a7 100644
--- a/include/internal/provider.h
+++ b/include/internal/provider.h
@@ -34,6 +34,7 @@ void ossl_provider_free(OSSL_PROVIDER *prov);
 
 /* Setters */
 int ossl_provider_add_module_location(OSSL_PROVIDER *prov, const char *loc);
+int ossl_provider_set_fallback(OSSL_PROVIDER *prov);
 
 /*
  * Activate the Provider
diff --git a/include/openssl/cryptoerr.h b/include/openssl/cryptoerr.h
index c27f05c..b38b272 100644
--- a/include/openssl/cryptoerr.h
+++ b/include/openssl/cryptoerr.h
@@ -49,6 +49,9 @@ int ERR_load_CRYPTO_strings(void);
 # define CRYPTO_F_PKEY_HMAC_INIT                          123
 # define CRYPTO_F_PKEY_POLY1305_INIT                      124
 # define CRYPTO_F_PKEY_SIPHASH_INIT                       125
+# define CRYPTO_F_PROVIDER_ACTIVATE                       134
+# define CRYPTO_F_PROVIDER_NEW                            135
+# define CRYPTO_F_PROVIDER_STORE_NEW                      136
 # define CRYPTO_F_SK_RESERVE                              129
 
 /*


More information about the openssl-commits mailing list