}
/* 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"));
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,
{ 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,
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"),
/* 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;
TPM2B_DIGEST ownerauth;
unsigned int need_userauth:1;
unsigned int need_ownerauth:1;
+ unsigned int legacy_srk:1;
unsigned int parent;
};
}
};
+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 = {
}
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) {
}
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;
}
vpninfo->tpm2->need_userauth = !emptyauth;
+ vpninfo->tpm2->legacy_srk = legacy;
switch(vpninfo->tpm2->pub.publicArea.type) {
case TPM2_ALG_RSA: return GNUTLS_PK_RSA;
TPM2B_PRIVATE priv;
char *parent_pass, *key_pass;
unsigned int need_userauth:1;
+ unsigned int legacy_srk:1;
unsigned int parent;
};
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;
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;
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,
}
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;
vpninfo->tpm2->parent = parent;
vpninfo->tpm2->need_userauth = !emptyauth;
+ vpninfo->tpm2->legacy_srk = legacy;
der = privdata->data;
dersize = privdata->size;