@@ -821,6 +821,17 @@ if test "${with_crypto_library}" = "openssl"; then
AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [OpenSSL engine support available])
fi
+ have_openssl_provider="yes"
+ AC_CHECK_FUNCS(
+ [OSSL_PROVIDER_load]
+ ,
+ ,
+ [have_openssl_provider="no"; break]
+ )
+ if test "${have_openssl_provider}" = "yes"; then
+ AC_DEFINE([HAVE_XKEY_PROVIDER], [1], [External key loading provider can be used])
+ fi
+
AC_CHECK_FUNC(
[EVP_aes_256_gcm],
,
@@ -128,6 +128,7 @@ openvpn_SOURCES = \
tls_crypt.c tls_crypt.h \
tun.c tun.h \
vlan.c vlan.h \
+ xkey_provider.c xkey_common.h \
win32.h win32.c \
win32-util.h win32-util.c \
cryptoapi.h cryptoapi.c
new file mode 100644
@@ -0,0 +1,42 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2021 Selva Nair <selva.nair@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef XKEY_PUBLIC_H_
+#define XKEY_PUBLIC_H_
+
+#ifdef HAVE_XKEY_PROVIDER
+
+#include <openssl/provider.h>
+#include <openssl/core_dispatch.h>
+
+/**
+ * Initialization function for OpenVPN external key provider for OpenSSL
+ * Follows the signature of OSSL_PROVIDER init
+ */
+OSSL_provider_init_fn xkey_provider_init;
+
+#endif /* HAVE_XKEY_PROVIDER */
+
+#define XKEY_PROV_PROPS "provider=ovpn.xkey"
+
+#endif /* XKEY_PUBLIC_H_ */
new file mode 100644
@@ -0,0 +1,177 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2021 Selva Nair <selva.nair@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#ifdef HAVE_XKEY_PROVIDER
+
+#include "syshead.h"
+#include "error.h"
+#include "buffer.h"
+#include "xkey_common.h"
+
+#include <openssl/provider.h>
+#include <openssl/params.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_object.h>
+#include <openssl/core_names.h>
+#include <openssl/store.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+/* A descriptive name */
+static const char *provname = "OpenVPN External Key Provider";
+
+typedef struct
+{
+ const OSSL_CORE_HANDLE *core;
+ OSSL_PROVIDER *deflt; /* default provider that we load for delegating some ops */
+ OSSL_LIB_CTX *libctx; /* libctx of the core context in which we are running */
+} XKEY_PROVIDER_CTX;
+
+/* main provider interface */
+
+/* provider callbacks we implement */
+static OSSL_FUNC_provider_query_operation_fn query_operation;
+static OSSL_FUNC_provider_gettable_params_fn gettable_params;
+static OSSL_FUNC_provider_get_params_fn get_params;
+static OSSL_FUNC_provider_teardown_fn teardown;
+
+static const OSSL_ALGORITHM *
+query_operation(void *provctx, int op, int *no_store)
+{
+ dmsg(D_LOW, "In xkey provider query op with op = %d", op);
+
+ *no_store = 0;
+
+ switch (op)
+ {
+ case OSSL_OP_SIGNATURE:
+ return NULL;
+
+ case OSSL_OP_KEYMGMT:
+ return NULL;
+
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static const OSSL_PARAM *
+gettable_params(void *provctx)
+{
+ dmsg(D_LOW, "In xkey provider gettable_params");
+
+ static const OSSL_PARAM param_types[] = {
+ OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ return param_types;
+}
+static int
+get_params(void *provctx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+
+ dmsg(D_LOW, "In xkey provider get_params");
+
+ p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME);
+ if (p)
+ {
+ return (OSSL_PARAM_set_utf8_ptr(p, provname) != 0);
+ }
+
+ return 0;
+}
+
+static void
+teardown(void *provctx)
+{
+ dmsg(D_LOW, "In xkey provider teardown");
+
+ XKEY_PROVIDER_CTX *prov = provctx;
+ if (prov && prov->deflt)
+ {
+ OSSL_PROVIDER_unload(prov->deflt);
+ }
+ free(prov);
+}
+
+static const OSSL_DISPATCH dispatch_table[] = {
+ {OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))gettable_params},
+ {OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))get_params},
+ {OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))query_operation},
+ {OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))teardown},
+ {0, NULL}
+};
+
+int
+xkey_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in,
+ const OSSL_DISPATCH **out, void **provctx)
+{
+ XKEY_PROVIDER_CTX *prov;
+ OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL;
+
+ dmsg(D_LOW, "In xkey provider init");
+
+ prov = calloc(sizeof(*prov), 1);
+ if (!prov)
+ {
+ msg(M_NONFATAL, "xkey_provider_init: out of memory");
+ return 0;
+ }
+
+ /* get our libctx */
+ for (; in->function_id != 0; in++)
+ {
+ if (in->function_id == OSSL_FUNC_CORE_GET_LIBCTX)
+ {
+ c_get_libctx = OSSL_FUNC_core_get_libctx(in);
+ }
+ }
+
+ if (c_get_libctx)
+ {
+ prov->libctx = (OSSL_LIB_CTX *)c_get_libctx(handle);
+ }
+ prov->core = handle;
+
+ prov->deflt = OSSL_PROVIDER_load(prov->libctx, "default");
+ if (!prov->deflt)
+ {
+ msg(M_NONFATAL, "xkey_provider_init: default provider could not be loaded");
+ }
+
+ *out = dispatch_table;
+ *provctx = prov;
+
+ return 1;
+}
+
+#endif /* HAVE_XKEY_PROVIDER */