Commit be3b4641 authored by David Woodhouse's avatar David Woodhouse

Reinstate support for TPM2 'TSS2 KEY BLOB' support with GnuTLS

Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 9f93019d
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment