Skip to content
Permalink
Browse files
Reinstate support for TPM2 'TSS2 KEY BLOB' support with GnuTLS
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
dwmw2 committed Oct 12, 2018
1 parent 9f93019 commit be3b46410b5b67e081cbc640c8a2873f635012d4
Showing with 85 additions and 17 deletions.
  1. +2 −1 gnutls.c
  2. +2 −1 gnutls.h
  3. +30 −8 gnutls_tpm2.c
  4. +40 −2 gnutls_tpm2_esys.c
  5. +11 −5 gnutls_tpm2_ibm.c
@@ -1320,7 +1320,8 @@ static int load_certificate(struct openconnect_info *vpninfo)
}

/* Is it a PEM file with a TPM key blob? */
if (strstr((char *)fdata.data, "-----BEGIN TSS2 PRIVATE KEY-----")) {
if (strstr((char *)fdata.data, "-----BEGIN TSS2 PRIVATE KEY-----") ||
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"));
@@ -32,7 +32,8 @@ 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);
unsigned int parent, int emptyauth, int legacy,
gnutls_datum_t *privdata, gnutls_datum_t *pubdata);

int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
void *_vpninfo, unsigned int flags,
@@ -51,6 +51,21 @@ const asn1_static_node tpmkey_asn1_tab[] = {
{ NULL, 0, NULL }
};

const asn1_static_node tpmkey_asn1_tab_old[] = {
{ "TPMKey", 536875024, NULL },
{ NULL, 1073741836, NULL },
{ "TPMKey", 536870917, NULL },
{ "type", 1073741836, NULL },
{ "emptyAuth", 1610637316, NULL },
{ NULL, 2056, "0"},
{ "parent", 1610637315, NULL },
{ NULL, 2056, "1"},
{ "pubkey", 1610637319, NULL },
{ NULL, 2056, "2"},
{ "privkey", 7, NULL },
{ NULL, 0, NULL }
};


#if GNUTLS_VERSION_NUMBER < 0x030600
static int tpm2_rsa_sign_fn(gnutls_privkey_t key, void *_vpninfo,
@@ -168,16 +183,22 @@ int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
int emptyauth = 0;
unsigned int parent;
int err, ret = -EINVAL;
const asn1_static_node *asn1tab;

err = gnutls_pem_base64_decode_alloc("TSS2 PRIVATE KEY", fdata, &asn1);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Error decoding TSS2 key blob: %s\n"),
gnutls_strerror(err));
return -EINVAL;
if (!err) {
asn1tab = tpmkey_asn1_tab;
} else {
if (gnutls_pem_base64_decode_alloc("TSS2 KEY BLOB", fdata, &asn1)) {
/* Report the first error */
vpn_progress(vpninfo, PRG_ERR,
_("Error decoding TSS2 key blob: %s\n"),
gnutls_strerror(err));
return -EINVAL;
}
asn1tab = tpmkey_asn1_tab_old;
}

err = asn1_array2tree(tpmkey_asn1_tab, &tpmkey_def, NULL);
err = asn1_array2tree(asn1tab, &tpmkey_def, NULL);
if (err != ASN1_SUCCESS) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to create ASN.1 type for TPM2: %s\n"),
@@ -243,7 +264,8 @@ int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,

/* 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);
ret = install_tpm2_key(vpninfo, pkey, pkey_sig, parent, emptyauth,
asn1tab == tpmkey_asn1_tab_old, &privdata, &pubdata);
if (ret < 0)
goto out_tpmkey;

@@ -66,6 +66,7 @@ struct oc_tpm2_ctx {
TPM2B_DIGEST ownerauth;
unsigned int need_userauth:1;
unsigned int need_ownerauth:1;
unsigned int legacy_srk:1;
unsigned int parent;
};

@@ -106,6 +107,41 @@ static TPM2B_PUBLIC primaryTemplate = {
}
};

static TPM2B_PUBLIC primaryTemplate_legacy = {
.publicArea = {
.type = TPM2_ALG_ECC,
.nameAlg = TPM2_ALG_SHA256,
.objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
TPMA_OBJECT_RESTRICTED |
TPMA_OBJECT_DECRYPT |
TPMA_OBJECT_NODA |
TPMA_OBJECT_SENSITIVEDATAORIGIN),
.authPolicy = {
.size = 0,
},
.parameters.eccDetail = {
.symmetric = {
.algorithm = TPM2_ALG_AES,
.keyBits.aes = 128,
.mode.aes = TPM2_ALG_CFB,
},
.scheme = {
.scheme = TPM2_ALG_NULL,
.details = {}
},
.curveID = TPM2_ECC_NIST_P256,
.kdf = {
.scheme = TPM2_ALG_NULL,
.details = {}
},
},
.unique.ecc = {
.x.size = 0,
.y.size = 0
}
}
};

static TPM2B_SENSITIVE_CREATE primarySensitive = {
.sensitive = {
.userAuth = {
@@ -175,7 +211,8 @@ static int init_tpm2_primary(struct openconnect_info *vpninfo,
}
r = Esys_CreatePrimary(ctx, hierarchy,
ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
&primarySensitive, &primaryTemplate,
&primarySensitive,
vpninfo->tpm2->legacy_srk ? &primaryTemplate_legacy : &primaryTemplate,
&allOutsideInfo, &allCreationPCR,
primaryHandle, NULL, NULL, NULL, NULL);
if (r == KEY_AUTH_FAILED) {
@@ -480,7 +517,7 @@ int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
}

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)
unsigned int parent, int emptyauth, int legacy, gnutls_datum_t *privdata, gnutls_datum_t *pubdata)
{
TSS2_RC r;

@@ -517,6 +554,7 @@ int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, g
}

vpninfo->tpm2->need_userauth = !emptyauth;
vpninfo->tpm2->legacy_srk = legacy;

switch(vpninfo->tpm2->pub.publicArea.type) {
case TPM2_ALG_RSA: return GNUTLS_PK_RSA;
@@ -40,6 +40,7 @@ struct oc_tpm2_ctx {
TPM2B_PRIVATE priv;
char *parent_pass, *key_pass;
unsigned int need_userauth:1;
unsigned int legacy_srk:1;
unsigned int parent;
};

@@ -188,7 +189,8 @@ static void tpm2_flush_srk(TSS_CONTEXT *tssContext, TPM_HANDLE hSRK)


static TPM_RC tpm2_load_srk(TSS_CONTEXT *tssContext, TPM_HANDLE *h,
const char *auth, TPM_HANDLE hierarchy)
const char *auth, TPM_HANDLE hierarchy,
int legacy_srk)
{
TPM_RC rc;
CreatePrimary_In in;
@@ -215,13 +217,15 @@ static TPM_RC tpm2_load_srk(TSS_CONTEXT *tssContext, TPM_HANDLE *h,
in.inPublic.publicArea.type = TPM_ALG_ECC;
in.inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
in.inPublic.publicArea.objectAttributes.val =
TPMA_OBJECT_FIXEDPARENT |
TPMA_OBJECT_FIXEDTPM |
TPMA_OBJECT_NODA |
TPMA_OBJECT_SENSITIVEDATAORIGIN |
TPMA_OBJECT_USERWITHAUTH |
TPMA_OBJECT_DECRYPT |
TPMA_OBJECT_RESTRICTED;
if (!legacy_srk)
in.inPublic.publicArea.objectAttributes.val |=
TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_FIXEDTPM;

in.inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
in.inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
in.inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
@@ -295,7 +299,7 @@ static TPM_HANDLE tpm2_load_key(struct openconnect_info *vpninfo, TSS_CONTEXT **
in.parentHandle = vpninfo->tpm2->parent;
} else {
reauth_srk:
rc = tpm2_load_srk(tssContext, &in.parentHandle, pass, vpninfo->tpm2->parent);
rc = tpm2_load_srk(tssContext, &in.parentHandle, pass, vpninfo->tpm2->parent, vpninfo->tpm2->legacy_srk);
if (rc == KEY_AUTH_FAILED) {
free_pass(&pass);
if (!request_passphrase(vpninfo, "openconnect_tpm2_hierarchy", &pass,
@@ -511,7 +515,8 @@ int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
}

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)
unsigned int parent, int emptyauth, int legacy,
gnutls_datum_t *privdata, gnutls_datum_t *pubdata)
{
TPM_RC rc;
BYTE *der;
@@ -531,6 +536,7 @@ int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, g

vpninfo->tpm2->parent = parent;
vpninfo->tpm2->need_userauth = !emptyauth;
vpninfo->tpm2->legacy_srk = legacy;

der = privdata->data;
dersize = privdata->size;

0 comments on commit be3b464

Please sign in to comment.