]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Add shell of TPM2 support
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 27 Sep 2018 12:59:19 +0000 (14:59 +0200)
committerDavid Woodhouse <dwmw2@infradead.org>
Wed, 3 Oct 2018 07:38:03 +0000 (08:38 +0100)
This doesn't do anything useful at all yet. It would be nice if the two
available OpenSSL engines were actually compatible.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Makefile.am
configure.ac
gnutls.c
gnutls.h
gnutls_tpm2.c [new file with mode: 0644]
openconnect-internal.h

index fc36c590958356d8f70165df880ec377bcc3563e..545c8451cf81beee7ed9fa082756f48f11d15ee4 100644 (file)
@@ -31,7 +31,7 @@ library_srcs = ssl.c http.c http-auth.c auth-common.c library.c compat.c lzs.c m
 lib_srcs_cisco = auth.c cstp.c
 lib_srcs_juniper = oncp.c lzo.c auth-juniper.c
 lib_srcs_globalprotect = gpst.c auth-globalprotect.c
-lib_srcs_gnutls = gnutls.c gnutls_tpm.c
+lib_srcs_gnutls = gnutls.c gnutls_tpm.c gnutls_tpm2.c
 lib_srcs_openssl = openssl.c openssl-pkcs11.c
 lib_srcs_win32 = tun-win32.c sspi.c
 lib_srcs_posix = tun.c
index 7c136a6225a5337383a634cfab9223a6faff7ffe..55376d46e0c03884b56f691a1eec03ce5228d87f 100644 (file)
@@ -483,6 +483,14 @@ case "$ssl_library" in
        LIBS="$oldlibs"
        CFLAGS="$oldcflags"
 
+       tss2lib=
+       AC_MSG_CHECKING([for tss2 library])
+       AC_CHECK_LIB([tss], [TSS_Create], [tss2lib=tss2],
+                                  AC_CHECK_LIB([TSS_Create], [ibmtss], [tss2lib=ibmtss], []))
+       if test "%tss2lib" != ""; then
+           AC_CHECK_HEADER($tss2lib/tss.h, AC_DEFINE_UNQUOTED(HAVE_TSS2, $tss2lib, [TSS2 library]), [])
+       fi
+
        AC_DEFINE(OPENCONNECT_GNUTLS, 1, [Using GnuTLS])
        AC_SUBST(SSL_PC, [gnutls])
        AC_SUBST(SSL_LIBS, ['$(GNUTLS_LIBS)'])
index dc285570be892a96194f749e67128e08d4ba0f3a..c2ecc3476e91f5bfc987d89f058389887edf5088 100644 (file)
--- a/gnutls.c
+++ b/gnutls.c
@@ -561,7 +561,7 @@ static int get_cert_name(gnutls_x509_crt_t cert, char *name, size_t namelen)
        return 0;
 }
 
-#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined (HAVE_GNUTLS_SYSTEM_KEYS)
+#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_TSS2) || defined (HAVE_GNUTLS_SYSTEM_KEYS)
 /* We have to convert the array of X509 certificates to gnutls_pcert_st
    for ourselves. There's no function that takes a gnutls_privkey_t as
    the key and gnutls_x509_crt_t certificates. */
@@ -611,7 +611,7 @@ static int verify_signed_data(gnutls_pubkey_t pubkey, gnutls_privkey_t privkey,
 
        return gnutls_pubkey_verify_data2(pubkey, algo, 0, data, sig);
 }
-#endif /* (P11KIT || TROUSERS || SYSTEM_KEYS) */
+#endif /* (P11KIT || TROUSERS || TSS2 || SYSTEM_KEYS) */
 
 static int openssl_hash_password(struct openconnect_info *vpninfo, char *pass,
                                 gnutls_datum_t *key, gnutls_datum_t *salt)
@@ -901,7 +901,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
 {
        gnutls_datum_t fdata;
        gnutls_x509_privkey_t key = NULL;
-#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
+#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_TSS2) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
        gnutls_privkey_t pkey = NULL;
        gnutls_datum_t pkey_sig = {NULL, 0};
        void *dummy_hash_data = &load_certificate;
@@ -1319,6 +1319,21 @@ static int load_certificate(struct openconnect_info *vpninfo)
 #endif
        }
 
+       /* Is it a PEM file with a TPM key blob? */
+       if (strstr((char *)fdata.data, "-----BEGIN TSS2 KEY BLOB-----")) {
+#ifndef HAVE_TSS2
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("This version of OpenConnect was built without TPM2 support\n"));
+               return -EINVAL;
+#else
+               ret = load_tpm2_key(vpninfo, &fdata, &pkey, &pkey_sig);
+               if (ret)
+                       goto out;
+
+               goto match_cert;
+#endif
+       }
+
        /* OK, try other PEM files... */
        gnutls_x509_privkey_init(&key);
        if ((pem_header = strstr((char *)fdata.data, "-----BEGIN RSA PRIVATE KEY-----")) ||
@@ -1462,7 +1477,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
           enabled we'll fall straight through the bit at match_cert: below, and go
           directly to the bit where it prints the 'no match found' error and exits. */
 
-#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
+#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_TSS2) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
  match_cert:
        /* If we have a privkey from PKCS#11 or TPM, we can't do the simple comparison
           of key ID that we do for software keys to find which certificate is a
@@ -1516,7 +1531,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
                }
                gnutls_free(pkey_sig.data);
        }
-#endif /* P11KIT || TROUSERS || SYSTEM_KEYS */
+#endif /* P11KIT || TROUSERS || TSS2 || SYSTEM_KEYS */
 
        /* We shouldn't reach this. It means that we didn't find *any* matching cert */
        vpn_progress(vpninfo, PRG_ERR,
@@ -1693,7 +1708,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
           key and certs. GnuTLS makes us do this differently for X509 privkeys
           vs. TPM/PKCS#11 "generic" privkeys, and the latter is particularly
           'fun' for GnuTLS 2.12... */
-#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
+#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_TSS2) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
        if (pkey) {
                err = assign_privkey(vpninfo, pkey,
                                     supporting_certs,
@@ -1704,7 +1719,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
                                        of extra_certs[] may have been zeroed. */
                }
        } else
-#endif /* P11KIT || TROUSERS */
+#endif /* P11KIT || TROUSERS || TSS2 || SYSTEM_KEYS  */
                err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
                                                      supporting_certs,
                                                      nr_supporting_certs, key);
@@ -1741,7 +1756,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
        }
        gnutls_free(extra_certs);
 
-#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
+#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_TSS2) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
        if (pkey)
                gnutls_privkey_deinit(pkey);
        /* If we support arbitrary privkeys, we might have abused fdata.data
@@ -2315,6 +2330,9 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
                vpninfo->https_cred = NULL;
 #ifdef HAVE_TROUSERS
                release_tpm1_ctx(vpninfo);
+#endif
+#ifdef HAVE_TSS2
+               release_tpm2_ctx(vpninfo);
 #endif
        }
 }
index 93ad42dca70a90502da28336f1f5c724d1e6d9db..5d6e227776cda59dfb1f89c3c9d03ebbbd95b5e0 100644 (file)
--- a/gnutls.h
+++ b/gnutls.h
@@ -28,6 +28,10 @@ int load_tpm1_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
                  gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig);
 void release_tpm1_ctx(struct openconnect_info *info);
 
+int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
+                gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig);
+void release_tpm2_ctx(struct openconnect_info *info);
+
 char *get_gnutls_cipher(gnutls_session_t session);
 
 #endif /* __OPENCONNECT_GNUTLS_H__ */
diff --git a/gnutls_tpm2.c b/gnutls_tpm2.c
new file mode 100644 (file)
index 0000000..f7ef826
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * OpenConnect (SSL + DTLS) VPN client
+ *
+ * Copyright © 2018 David Woodhouse.
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1, 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
+ * Lesser General Public License for more details.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <gnutls/gnutls.h>
+#include "openconnect-internal.h"
+
+#include "gnutls.h"
+
+#ifdef HAVE_TSS2
+#define TSSINCLUDE(x) < HAVE_TSS2/x >
+#include TSSINCLUDE(tss.h)
+
+struct oc_tpm2_ctx {
+};
+
+int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
+                 gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig)
+{
+       gnutls_datum_t asn1;
+       int err;
+
+       err = gnutls_pem_base64_decode_alloc("TSS2 KEY BLOB", fdata, &asn1);
+       if (err) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Error decoding TSS2 key blob: %s\n"),
+                            gnutls_strerror(err));
+               return -EINVAL;
+       }
+       free(asn1.data);
+       vpn_progress(vpninfo, PRG_ERR,
+                    _("TPM2 not really implemented yet\n"));
+       return -EINVAL;
+}
+
+void release_tpm2_ctx(struct openconnect_info *vpninfo)
+{
+       if (vpninfo->tpm2)
+               free(vpninfo->tpm2);
+       vpninfo->tpm2 = NULL;
+}
+#endif /* HAVE_TSS2 */
index 63547a4a83506dd568189ec73d3ea47fe60b55e6..2fac50bc65615d393a8390b9c8d7b378e4bfc541 100644 (file)
@@ -346,6 +346,7 @@ struct esp {
 
 struct oc_pcsc_ctx;
 struct oc_tpm1_ctx;
+struct oc_tpm2_ctx;
 
 struct openconnect_info {
        const struct vpn_proto *proto;
@@ -503,6 +504,9 @@ struct openconnect_info {
 #ifdef HAVE_TROUSERS
        struct oc_tpm1_ctx *tpm1;
 #endif
+#ifdef HAVE_TSS2
+       struct oc_tpm2_ctx *tpm2;
+#endif
 #endif /* OPENCONNECT_GNUTLS */
        struct pin_cache *pin_cache;
        struct keepalive_info ssl_times;