Replumbing: Add a mechanism to pre-populate the provider store
authorRichard Levitte <levitte@openssl.org>
Sun, 17 Mar 2019 17:06:59 +0000 (18:06 +0100)
committerRichard Levitte <levitte@openssl.org>
Tue, 19 Mar 2019 13:06:58 +0000 (14:06 +0100)
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@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/8480)

crypto/build.info
crypto/cpt_err.c
crypto/err/openssl.txt
crypto/provider_core.c
crypto/provider_local.h [new file with mode: 0644]
crypto/provider_predefined.c [new file with mode: 0644]
include/openssl/cryptoerr.h

index 39cd91ba507c7609e626b29b7a9808b0ac6fda7c..535fa35a10a24372277187d6bfc9141a28745990 100644 (file)
@@ -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]=\
index 88bee489f2bfb97bb24850a6803868a8e21c135b..3c3265dce5f788af8a05a708c249ecd19d67da43 100644 (file)
@@ -59,6 +59,9 @@ static const ERR_STRING_DATA CRYPTO_str_functs[] = {
      "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}
 };
index 9f84dbc99f54a335860ae1cbbee2dbed66af4e51..7309ed8fe4ba71128fcd08dbaa5b17cfa4ff2000 100644 (file)
@@ -397,6 +397,8 @@ 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
index c136e42e16e48161542c950db18d81bf83717359..7a184a7d67e8f207b35243ea1de3bf86d95b74ad 100644 (file)
 #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
@@ -78,6 +83,7 @@ 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
@@ -86,6 +92,28 @@ static void *provider_store_new(void)
         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;
 }
 
@@ -116,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;
@@ -151,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)
 {
@@ -168,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 */
diff --git a/crypto/provider_local.h b/crypto/provider_local.h
new file mode 100644 (file)
index 0000000..e4c649a
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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>
+
+struct predefined_providers_st {
+    const char *name;
+    OSSL_provider_init_fn *init;
+    unsigned int is_fallback:1;
+};
+
+extern const struct predefined_providers_st predefined_providers[];
diff --git a/crypto/provider_predefined.c b/crypto/provider_predefined.c
new file mode 100644 (file)
index 0000000..be21565
--- /dev/null
@@ -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 }
+};
index 42fd3b6544482b8b7350f3df6a66960cdacb0b02..b38b272a24af636af9ab66e753c643d73e64e0f9 100644 (file)
@@ -50,6 +50,8 @@ int ERR_load_CRYPTO_strings(void);
 # 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
 
 /*