]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Reinstate support for TPM2 'TSS2 KEY BLOB' support with GnuTLS
authorDavid Woodhouse <dwmw2@infradead.org>
Fri, 12 Oct 2018 19:25:35 +0000 (12:25 -0700)
committerDavid Woodhouse <dwmw2@infradead.org>
Fri, 12 Oct 2018 19:25:35 +0000 (12:25 -0700)
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
gnutls.c
gnutls.h
gnutls_tpm2.c
gnutls_tpm2_esys.c
gnutls_tpm2_ibm.c

index b3b61a897b8202775e253cac2155f6a5d3b78adf..b8bd8b6b148f0e8711a57fb2eafecca21dd36fbc 100644 (file)
--- a/gnutls.c
+++ b/gnutls.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"));
index cd79f4098edc08fc4083f89c3b080c56bee9e489..b25a15ae12c4829faf6d75c2a0e3e2bf4721baea 100644 (file)
--- a/gnutls.h
+++ b/gnutls.h
@@ -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,
index abca9c4fa58d0626142f1f9fa787d9eb748c401b..90fc178607f45fa125357ecef5c0fa73d812b0cb 100644 (file)
@@ -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;
 
index 149c7d03b43225855d0dc4e546f35cc474f04882..282dcd25b094f1ba88ddc8d7be2fdc8fab8cb7a4 100644 (file)
@@ -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;
index e5cc28a25914001cbe6247137c2a96f2772c2283..a7584532f42fad2e621fecaea7003e81090c693b 100644 (file)
@@ -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;