Add functions to see if a provider is available for use.
authorRichard Levitte <levitte@openssl.org>
Wed, 17 Jul 2019 09:29:04 +0000 (11:29 +0200)
committerRichard Levitte <levitte@openssl.org>
Fri, 26 Jul 2019 16:14:41 +0000 (18:14 +0200)
Public function OSSL_PROVIDER_available() takes a library context and
a provider name, and returns 1 if it's available for use, i.e. if it's
possible to fetch implementations from it, otherwise 0.

Internal function ossl_provider_activated() returns 1 if the given
OSSL_PROVIDER is activated, otherwise 0.

To make this possible, the activation of fallbacks got refactored out
to a separate function, which ended up simplifying the code.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9398)

CHANGES
crypto/provider.c
crypto/provider_core.c
doc/internal/man3/ossl_provider_new.pod
doc/man3/OSSL_PROVIDER.pod
include/internal/provider.h
include/internal/symhacks.h
include/openssl/provider.h
util/libcrypto.num

diff --git a/CHANGES b/CHANGES
index acaa099..80ad49e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,11 @@
 
  Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
 
+  *) Introduced a new function, OSSL_PROVIDER_available(), which can be used
+     to check if a named provider is loaded and available.  When called, it
+     will also activate all fallback providers if such are still present.
+     [Richard Levitte]
+
   *) Enforce a minimum DH modulus size of 512 bits.
      [Bernd Edlinger]
 
index f81260c..0250955 100644 (file)
@@ -35,6 +35,18 @@ int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov)
     return 1;
 }
 
+int OSSL_PROVIDER_available(OPENSSL_CTX *libctx, const char *name)
+{
+    OSSL_PROVIDER *prov = NULL;
+    int available = 0;
+
+    /* Find it or create it */
+    prov = ossl_provider_find(libctx, name);
+    available = ossl_provider_available(prov);
+    ossl_provider_free(prov);
+    return available;
+}
+
 const OSSL_PARAM *OSSL_PROVIDER_get_param_types(const OSSL_PROVIDER *prov)
 {
     return ossl_provider_get_param_types(prov);
index 0e86097..385a632 100644 (file)
@@ -572,67 +572,79 @@ static int provider_forall_loaded(struct provider_store_st *store,
     return ret;
 }
 
+/*
+ * This function only does something once when store->use_fallbacks == 1,
+ * and then sets store->use_fallbacks = 0, so the second call and so on is
+ * effectively a no-op.
+ */
+static void provider_activate_fallbacks(struct provider_store_st *store)
+{
+    if (store->use_fallbacks) {
+        int num_provs = sk_OSSL_PROVIDER_num(store->providers);
+        int activated_fallback_count = 0;
+        int i;
+
+        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 any attempt to use any of the
+             * fallback providers will fail anyway.
+             */
+            if (prov->flag_fallback) {
+                activated_fallback_count++;
+                provider_activate(prov);
+            }
+        }
+
+        /*
+         * 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.
+         */
+        if (activated_fallback_count > 0)
+            store->use_fallbacks = 0;
+    }
+}
+
 int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
                                 int (*cb)(OSSL_PROVIDER *provider,
                                           void *cbdata),
                                 void *cbdata)
 {
     int ret = 1;
-    int i;
     struct provider_store_st *store = get_provider_store(ctx);
 
     if (store != NULL) {
-        int found_activated = 0;
-
         CRYPTO_THREAD_read_lock(store->lock);
-        ret = provider_forall_loaded(store, &found_activated, cb, cbdata);
+
+        provider_activate_fallbacks(store);
 
         /*
-         * If there's nothing activated ever in this store, try to activate
-         * all fallbacks.
+         * Now, we sweep through all providers
          */
-        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);
-                }
-            }
+        ret = provider_forall_loaded(store, NULL, cb, cbdata);
 
-            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);
     }
 
     return ret;
 }
 
+int ossl_provider_available(OSSL_PROVIDER *prov)
+{
+    if (prov != NULL) {
+        CRYPTO_THREAD_read_lock(prov->store->lock);
+        provider_activate_fallbacks(prov->store);
+        CRYPTO_THREAD_unlock(prov->store->lock);
+
+        return prov->flag_initialized;
+    }
+    return 0;
+}
+
 /* Setters of Provider Object data */
 int ossl_provider_set_fallback(OSSL_PROVIDER *prov)
 {
index 426d953..255f194 100644 (file)
@@ -6,7 +6,7 @@ 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_activate,
+ossl_provider_activate, ossl_provider_available,
 ossl_provider_ctx,
 ossl_provider_forall_loaded,
 ossl_provider_name, ossl_provider_dso,
@@ -33,6 +33,8 @@ ossl_provider_get_params, ossl_provider_query_operation
 
  /* Load and initialize the Provider */
  int ossl_provider_activate(OSSL_PROVIDER *prov);
+ /* Check if provider is available */
+ int ossl_provider_available(OSSL_PROVIDER *prov);
 
  /* Return pointer to the provider's context */
  void *ossl_provider_ctx(const OSSL_PROVIDER *prov);
@@ -148,6 +150,10 @@ be located in that module, and called.
 
 =back
 
+ossl_provider_available() activates all fallbacks if no provider is
+activated yet, then checks if given provider object I<prov> is
+activated.
+
 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.
@@ -228,6 +234,9 @@ ossl_provider_free() doesn't return any value.
 ossl_provider_set_module_path(), ossl_provider_set_fallback() and
 ossl_provider_activate() return 1 on success, or 0 on error.
 
+ossl_provider_available() return 1 if the provider is available,
+otherwise 0.
+
 ossl_provider_name(), ossl_provider_dso(),
 ossl_provider_module_name(), and ossl_provider_module_path() return a
 pointer to their respective data if it's available, otherwise NULL
index 1453fcc..5608bf3 100644 (file)
@@ -3,6 +3,7 @@
 =head1 NAME
 
 OSSL_PROVIDER, OSSL_PROVIDER_load, OSSL_PROVIDER_unload,
+OSSL_PROVIDER_available,
 OSSL_PROVIDER_get_param_types, OSSL_PROVIDER_get_params,
 OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name - provider routines
 
@@ -12,13 +13,14 @@ OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name - provider routines
 
  typedef struct ossl_provider_st OSSL_PROVIDER;
 
- OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *, const char *name);
+ OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *libctx, const char *name);
  int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov);
+ int OSSL_PROVIDER_available(OPENSSL_CTX *libctx, const char *name);
 
  const OSSL_PARAM *OSSL_PROVIDER_get_param_types(OSSL_PROVIDER *prov);
  int OSSL_PROVIDER_get_params(OSSL_PROVIDER *prov, OSSL_PARAM params[]);
 
- int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *, const char *name,
+ int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *libctx, const char *name,
                                ossl_provider_init_fn *init_fn);
 
  const char *OSSL_PROVIDER_name(const OSSL_PROVIDER *prov);
@@ -32,6 +34,9 @@ A provider can be built in to the application or the OpenSSL
 libraries, or can be a loadable module.
 The functions described here handle both forms.
 
+Some of these functions operate within a library context, please see
+L<OPENSSL_CTX(3)> for further details.
+
 =head2 Functions
 
 OSSL_PROVIDER_add_builtin() is used to add a built in provider to
@@ -49,6 +54,9 @@ OSSL_PROVIDER_unload() unloads the given provider.
 For a provider added with OSSL_PROVIDER_add_builtin(), this simply
 runs its teardown function.
 
+OSSL_PROVIDER_available() checks if a named provider is available
+for use.
+
 OSSL_PROVIDER_get_param_types() is used to get a provider parameter
 descriptor set as a constant B<OSSL_PARAM> array.
 See L<OSSL_PARAM(3)> for more information.
@@ -69,6 +77,9 @@ success, or B<NULL> on error.
 
 OSSL_PROVIDER_unload() returns 1 on success, or 0 on error.
 
+OSSL_PROVIDER_available() returns 1 if the named provider is available,
+otherwise 0.
+
 OSSL_PROVIDER_get_param_types() returns a pointer to an array
 of constant B<OSSL_PARAM>, or NULL if none is provided.
 
@@ -95,7 +106,7 @@ its build number.
 
 =head1 SEE ALSO
 
-L<openssl-core.h(7)>, L<provider(7)>
+L<openssl-core.h(7)>, L<OPENSSL_CTX(3)>, L<provider(7)>
 
 =head1 HISTORY
 
index fbc60fc..aa18764 100644 (file)
@@ -44,6 +44,8 @@ int ossl_provider_add_parameter(OSSL_PROVIDER *prov, const char *name,
  * Inactivation is done by freeing the Provider
  */
 int ossl_provider_activate(OSSL_PROVIDER *prov);
+/* Check if the provider is available */
+int ossl_provider_available(OSSL_PROVIDER *prov);
 
 /* Return pointer to the provider's context */
 void *ossl_provider_ctx(const OSSL_PROVIDER *prov);
index 2b09604..6e8f78e 100644 (file)
@@ -14,6 +14,9 @@
 
 # if defined(OPENSSL_SYS_VMS)
 
+/* ossl_provider_available vs OSSL_PROVIDER_available */
+#  undef ossl_provider_available
+#  define ossl_provider_available                 ossl_int_prov_available
 /* ossl_provider_get_param_types vs OSSL_PROVIDER_get_param_types */
 #  undef ossl_provider_get_param_types
 #  define ossl_provider_get_param_types           ossl_int_prov_get_param_types
index 68d5d10..d5a6292 100644 (file)
@@ -19,6 +19,7 @@ extern "C" {
 /* Load and unload a provider */
 OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *, const char *name);
 int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov);
+int OSSL_PROVIDER_available(OPENSSL_CTX *, const char *name);
 
 const OSSL_PARAM *OSSL_PROVIDER_get_param_types(const OSSL_PROVIDER *prov);
 int OSSL_PROVIDER_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]);
index 1533a88..8146248 100644 (file)
@@ -4699,3 +4699,4 @@ OSSL_PROVIDER_name                      4804      3_0_0   EXIST::FUNCTION:
 EVP_CIPHER_do_all_ex                    4805   3_0_0   EXIST::FUNCTION:
 EVP_MD_do_all_ex                        4806   3_0_0   EXIST::FUNCTION:
 EVP_KEYEXCH_provider                    4807   3_0_0   EXIST::FUNCTION:
+OSSL_PROVIDER_available                 4808   3_0_0   EXIST::FUNCTION: