Skip to content

Commit

Permalink
First pass at proper TPM2 support for GnuTLS using tss2-esys
Browse files Browse the repository at this point in the history
Various caveats, including the complete lack of authentication, lack
of EC and policy support, hard-coded use of PKCS#1 padding, etc.

But hey, it works for my test case.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
dwmw2 committed Oct 8, 2018
1 parent e1f2bb7 commit b7b29a5
Show file tree
Hide file tree
Showing 5 changed files with 429 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Expand Up @@ -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 gnutls_tpm2.c
lib_srcs_gnutls = gnutls.c gnutls_tpm.c gnutls_tpm2.c gnutls_tpm2_esys.c
lib_srcs_openssl = openssl.c openssl-pkcs11.c
lib_srcs_win32 = tun-win32.c sspi.c
lib_srcs_posix = tun.c
Expand Down
18 changes: 3 additions & 15 deletions configure.ac
Expand Up @@ -483,24 +483,12 @@ case "$ssl_library" in
LIBS="$oldlibs"
CFLAGS="$oldcflags"

tss2lib=
AC_CHECK_LIB([tss], [TSS_Create], [tss2inc=tss2
tss2lib=tss],
AC_CHECK_LIB([TSS_Create], [ibmtss], [tss2inc=ibmtss
tss2lib=ibmtss], []))
if test "$tss2lib" != ""; then
PKG_CHECK_MODULES(TASN1, libtasn1, [], [tss2lib=])
fi
if test "$tss2lib" != ""; then
AC_CHECK_HEADER($tss2inc/tss.h,
[AC_DEFINE_UNQUOTED(HAVE_TSS2, $tss2inc, [TSS2 library])
AC_SUBST(TSS2_LIBS, [-l$tss2lib])], [])
fi
PKG_CHECK_MODULES(TPM2, [libtasn1 tss2-esys], [AC_DEFINE(HAVE_TSS2, 1, [Have TSS2])], [:])

AC_DEFINE(OPENCONNECT_GNUTLS, 1, [Using GnuTLS])
AC_SUBST(SSL_PC, [gnutls])
AC_SUBST(SSL_LIBS, ['$(GNUTLS_LIBS) $(TASN1_LIBS) $(TSS2_LIBS)'])
AC_SUBST(SSL_CFLAGS, ['$(GNUTLS_CFLAGS) $(TASN1_CFLAGS)'])
AC_SUBST(SSL_LIBS, ['$(GNUTLS_LIBS) $(TPM2_LIBS)'])
AC_SUBST(SSL_CFLAGS, ['$(GNUTLS_CFLAGS) $(TPM2_CFLAGS)'])
;;

*)
Expand Down
3 changes: 3 additions & 0 deletions gnutls.h
Expand Up @@ -31,6 +31,9 @@ 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);
int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig,
unsigned int parent, int emptyauth, gnutls_datum_t *privdata, gnutls_datum_t *pubdata);


char *get_gnutls_cipher(gnutls_session_t session);

Expand Down
59 changes: 42 additions & 17 deletions gnutls_tpm2.c
Expand Up @@ -26,13 +26,10 @@
#include "gnutls.h"

#ifdef HAVE_TSS2
#define TSSINCLUDE(x) < HAVE_TSS2/x >
#include TSSINCLUDE(tss.h)

struct oc_tpm2_ctx {
};
#include <libtasn1.h>


const asn1_static_node tpmkey_asn1_tab[] = {
{ "TPMKey", 536875024, NULL },
{ NULL, 1073741836, NULL },
Expand All @@ -48,16 +45,38 @@ const asn1_static_node tpmkey_asn1_tab[] = {
{ NULL, 0, NULL }
};


static int decode_data(ASN1_TYPE n, gnutls_datum_t *r)
{
ASN1_DATA_NODE d;
int len, lenlen;

if (!n)
return -EINVAL;

if (asn1_read_node_value(n, &d) != ASN1_SUCCESS)
return -EINVAL;

len = asn1_get_length_der(d.value, d.value_len, &lenlen);
if (len < 0)
return -EINVAL;

r->data = (unsigned char *)d.value + lenlen;
r->size = len;

return 0;
}

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;
gnutls_datum_t asn1, pubdata, privdata;
ASN1_TYPE tpmkey_def = ASN1_TYPE_EMPTY, tpmkey = ASN1_TYPE_EMPTY;
char value_buf[16];
int value_buflen;
int emptyauth = 0;
unsigned int parent;
int err, ret = -EINVAL;

err = gnutls_pem_base64_decode_alloc("TSS2 KEY BLOB", fdata, &asn1);
if (err) {
Expand All @@ -83,7 +102,6 @@ int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
asn1_strerror(err));
goto out_tpmkey;
}
asn1_print_structure(stdout, tpmkey, "", ASN1_PRINT_ALL);

value_buflen = sizeof(value_buf);
err = asn1_read_value(tpmkey, "type", value_buf, &value_buflen);
Expand All @@ -109,7 +127,7 @@ int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
value_buflen = 4;
err = asn1_read_value(tpmkey, "parent", value_buf, &value_buflen);
if (err == ASN1_ELEMENT_NOT_FOUND)
parent = TPM_RH_OWNER;
parent = 0x40000001; // RH_OWNER
else if (err != ASN1_SUCCESS) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse TPM2 key parent: %s\n"),
Expand All @@ -122,25 +140,32 @@ int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
for (i = 0; i < value_buflen; i++)
parent |= value_buf[value_buflen - i - 1] << (8 * i);
}

if (decode_data(asn1_find_node(tpmkey, "pubkey"), &pubdata) < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse TPM2 pubkey element\n"));
goto out_tpmkey;
}
if (decode_data(asn1_find_node(tpmkey, "privkey"), &privdata) < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse TPM2 privkey element\n"));
goto out_tpmkey;
}

vpn_progress(vpninfo, PRG_DEBUG,
_("Parsed TPM2 key with parent %x, emptyauth %d\n"),
parent, emptyauth);

vpn_progress(vpninfo, PRG_ERR,
_("TPM2 not really implemented yet\n"));
/* Now we've extracted what we need from the ASN.1, invoke the
* actual TPM2 code (whichever implementation we end up with */
ret = install_tpm2_key(vpninfo, pkey, pkey_sig, parent, emptyauth, &privdata, &pubdata);

out_tpmkey:
asn1_delete_structure(&tpmkey);
asn1_delete_structure(&tpmkey_def);
out_asn1:
free(asn1.data);
return -EINVAL;
return ret;
}

void release_tpm2_ctx(struct openconnect_info *vpninfo)
{
if (vpninfo->tpm2)
free(vpninfo->tpm2);
vpninfo->tpm2 = NULL;
}
#endif /* HAVE_TSS2 */

0 comments on commit b7b29a5

Please sign in to comment.