]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Initialize the xkey provider and use it in SSL context
authorSelva Nair <selva.nair@gmail.com>
Tue, 14 Dec 2021 16:59:15 +0000 (11:59 -0500)
committerGert Doering <gert@greenie.muc.de>
Thu, 20 Jan 2022 14:19:03 +0000 (15:19 +0100)
- Add function to check when external key is in use

- Load xkey provider into a custom library context when required

- Use the custom libctx in SSL CTX when external key is in use

As no keys are yet loaded through the provider,
no functionality gets delegated to it as yet.

v2 changes: Provider loading is reworked to activate only when external
            keys are in use
            This was 2/9 in v1

Signed-off-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <20211214165928.30676-6-selva.nair@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg23432.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/openssl_compat.h
src/openvpn/options.c
src/openvpn/options.h
src/openvpn/ssl.c
src/openvpn/ssl.h
src/openvpn/ssl_mbedtls.c
src/openvpn/ssl_openssl.c
src/openvpn/xkey_common.h

index 7a323be52295f97d1667cb1929f956a83c3c8fd7..f702afde2b2f31f44ac9b2ba41b3f78978929fb3 100644 (file)
@@ -760,6 +760,14 @@ int EVP_PKEY_get_group_name(EVP_PKEY *pkey, char *gname, size_t gname_sz,
 #define EVP_CIPHER_get0_name EVP_CIPHER_name
 #define EVP_CIPHER_CTX_get_mode EVP_CIPHER_CTX_mode
 
+/** Reduce SSL_CTX_new_ex() to SSL_CTX_new() for OpenSSL < 3 */
+#define SSL_CTX_new_ex(libctx, propq, method)                \
+        SSL_CTX_new((method))
+
+/* Some safe typedefs to avoid too many ifdefs */
+typedef void OSSL_LIB_CTX;
+typedef void OSSL_PROVIDER;
+
 /* Mimics the functions but only when the default context without
  * options is chosen */
 static inline const EVP_CIPHER *
index bf8e77590222df3b4190b34ccb0e908504d51fd8..aafec1a29397427627b99e0d975c4177eec8c8a3 100644 (file)
@@ -5286,6 +5286,22 @@ show_compression_warning(struct compress_options *info)
 }
 #endif
 
+bool key_is_external(const struct options *options)
+{
+    bool ret = false;
+#ifdef ENABLE_MANAGEMENT
+    ret = ret || (options->management_flags & MF_EXTERNAL_KEY);
+#endif
+#ifdef ENABLE_PKCS11
+    ret = ret || (options->pkcs11_providers[0] != NULL);
+#endif
+#ifdef ENABLE_CRYPTOAPI
+    ret = ret || options->cryptoapi_cert;
+#endif
+
+    return ret;
+}
+
 static void
 add_option(struct options *options,
            char *p[],
index d4f41cd712b23243f7e2158462ae7ae40deeb7d0..8dc063432260fb549b950c42a49674a209befcda 100644 (file)
@@ -862,4 +862,6 @@ void options_string_import(struct options *options,
                            unsigned int *option_types_found,
                            struct env_set *es);
 
+bool key_is_external(const struct options *options);
+
 #endif /* ifndef OPTIONS_H */
index db0e728184fd84ad723ab324487386200fb28455..891355fb61e2c87008fc673bdedb37ddc89d5458 100644 (file)
@@ -604,6 +604,11 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx, bool in_ch
 
     tls_clear_error();
 
+    if (key_is_external(options))
+    {
+        load_xkey_provider();
+    }
+
     if (options->tls_server)
     {
         tls_ctx_server_new(new_ctx);
index b14453fe2815cb8f06aeaed094994b5563c3c23c..784ddd323b98a0e41d10eb9ec6989e0defd50b29 100644 (file)
@@ -627,4 +627,10 @@ show_available_tls_ciphers(const char *cipher_list,
 bool
 tls_session_generate_data_channel_keys(struct tls_session *session);
 
+/**
+ * Load ovpn.xkey provider used for external key signing
+ */
+void
+load_xkey_provider(void);
+
 #endif /* ifndef OPENVPN_SSL_H */
index 5624c5142b779860532a59786936994f5fbcae67..403499d1ab677edf09f8d23c72a31e1ee68e5572 100644 (file)
@@ -1549,4 +1549,10 @@ get_ssl_library_version(void)
     return mbedtls_version;
 }
 
+void
+load_xkey_provider(void)
+{
+    return; /* no external key provider in mbedTLS build */
+}
+
 #endif /* defined(ENABLE_CRYPTO_MBEDTLS) */
index 724664bb93db73b04f8c697045701b3456ac32fe..bdaa7a2bfe4d5389334258889bf3eef09251d2e4 100644 (file)
@@ -45,6 +45,7 @@
 #include "ssl_common.h"
 #include "base64.h"
 #include "openssl_compat.h"
+#include "xkey_common.h"
 
 #ifdef ENABLE_CRYPTOAPI
 #include "cryptoapi.h"
 #include <openssl/applink.c>
 #endif
 
+static OSSL_LIB_CTX *tls_libctx;
+
+static void unload_xkey_provider(void);
+
 /*
  * Allocate space in SSL objects in which to store a struct tls_session
  * pointer back to parent.
@@ -113,7 +118,7 @@ tls_ctx_server_new(struct tls_root_ctx *ctx)
 {
     ASSERT(NULL != ctx);
 
-    ctx->ctx = SSL_CTX_new(SSLv23_server_method());
+    ctx->ctx = SSL_CTX_new_ex(tls_libctx, NULL, SSLv23_server_method());
 
     if (ctx->ctx == NULL)
     {
@@ -131,7 +136,7 @@ tls_ctx_client_new(struct tls_root_ctx *ctx)
 {
     ASSERT(NULL != ctx);
 
-    ctx->ctx = SSL_CTX_new(SSLv23_client_method());
+    ctx->ctx = SSL_CTX_new_ex(tls_libctx, NULL, SSLv23_client_method());
 
     if (ctx->ctx == NULL)
     {
@@ -150,6 +155,7 @@ tls_ctx_free(struct tls_root_ctx *ctx)
     ASSERT(NULL != ctx);
     SSL_CTX_free(ctx->ctx);
     ctx->ctx = NULL;
+    unload_xkey_provider(); /* in case it is loaded */
 }
 
 bool
@@ -2284,4 +2290,87 @@ get_ssl_library_version(void)
     return OpenSSL_version(OPENSSL_VERSION);
 }
 
+
+/** Some helper routines for provider load/unload */
+#ifdef HAVE_XKEY_PROVIDER
+static int
+provider_load(OSSL_PROVIDER *prov, void *dest_libctx)
+{
+    const char *name = OSSL_PROVIDER_get0_name(prov);
+    OSSL_PROVIDER_load(dest_libctx, name);
+    return 1;
+}
+
+static int
+provider_unload(OSSL_PROVIDER *prov, void *unused)
+{
+    (void) unused;
+    OSSL_PROVIDER_unload(prov);
+    return 1;
+}
+#endif /* HAVE_XKEY_PROVIDER */
+
+/**
+ * Setup ovpn.xey provider for signing with external keys.
+ * It is loaded into a custom library context so as not to pollute
+ * the default context. Alternatively we could override any
+ * system-wide property query set on the default context. But we
+ * want to avoid that.
+ */
+void
+load_xkey_provider(void)
+{
+#ifdef HAVE_XKEY_PROVIDER
+
+    /* Make a new library context for use in TLS context */
+    if (!tls_libctx)
+    {
+        tls_libctx = OSSL_LIB_CTX_new();
+        check_malloc_return(tls_libctx);
+
+        /* Load all providers in default LIBCTX into this libctx.
+         * OpenSSL has a child libctx functionality to automate this,
+         * but currently that is usable only from within providers.
+         * So we do something close to it manually here.
+         */
+        OSSL_PROVIDER_do_all(NULL, provider_load, tls_libctx);
+    }
+
+    if (!OSSL_PROVIDER_available(tls_libctx, "ovpn.xkey"))
+    {
+        OSSL_PROVIDER_add_builtin(tls_libctx, "ovpn.xkey", xkey_provider_init);
+        if (!OSSL_PROVIDER_load(tls_libctx, "ovpn.xkey"))
+        {
+            msg(M_NONFATAL, "ERROR: failed loading external key provider: "
+                            "Signing with external keys will not work.");
+        }
+    }
+
+    /* We only implement minimal functionality in ovpn.xkey, so we do not want
+     * methods in xkey to be picked unless absolutely required (i.e, when the key
+     * is external). Ensure this by setting a default propquery for the custom
+     * libctx that unprefers, but does not forbid, ovpn.xkey. See also man page
+     * of "property" in OpenSSL 3.0.
+     */
+    EVP_set_default_properties(tls_libctx, "?provider!=ovpn.xkey");
+
+#endif /* HAVE_XKEY_PROVIDER */
+}
+
+/**
+ * Undo steps in load_xkey_provider
+ */
+static void
+unload_xkey_provider(void)
+{
+#ifdef HAVE_XKEY_PROVIDER
+    if (tls_libctx)
+    {
+        OSSL_PROVIDER_do_all(tls_libctx, provider_unload, NULL);
+        OSSL_LIB_CTX_free(tls_libctx);
+    }
+#endif /* HAVE_XKEY_PROVIDER */
+    tls_libctx = NULL;
+}
+
 #endif /* defined(ENABLE_CRYPTO_OPENSSL) */
index db58d07755319e7ab94d6e5316edc22dd504ce1d..f46bacd214d16068e24311d370212df1bfd7cba7 100644 (file)
@@ -28,7 +28,6 @@
 #include <openssl/opensslv.h>
 #if OPENSSL_VERSION_NUMBER >= 0x30000010L && !defined(DISABLE_XKEY_PROVIDER)
 #define HAVE_XKEY_PROVIDER 1
-
 #include <openssl/provider.h>
 #include <openssl/core_dispatch.h>