]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
First cut at IBM TSS support, mostly copied from James's tpm2 engine.
authorDavid Woodhouse <dwmw2@infradead.org>
Wed, 10 Oct 2018 22:19:33 +0000 (15:19 -0700)
committerDavid Woodhouse <dwmw2@infradead.org>
Thu, 11 Oct 2018 01:14:17 +0000 (18:14 -0700)
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
configure.ac
gnutls_tpm2_esys.c
gnutls_tpm2_ibm.c
www/building.xml
www/tpm.xml

index ff2a7d825a1e280958f0937465cf6ad2a730ab1f..cbe6d9e0b779bac40ab24daa54197631c067d0ba 100644 (file)
@@ -492,7 +492,7 @@ case "$ssl_library" in
                              AC_SUBST(TPM2_LIBS, ['$(TASN1_LIBS) $(TSS2_ESYS_LIBS)'])
                              tss2lib=tss2-esys],
                             [:])
-          if test "$tss2lib" = "xxNOTIMPLEMENTEDYETxx"; then
+          if test "$tss2lib" = ""; then
               AC_CHECK_LIB([tss], [TSS_Create], [tss2inc=tss2
                                                  tss2lib=tss],
                            AC_CHECK_LIB([ibmtss], [TSS_Create], [tss2inc=ibmtss
index e000ca745bf141533bcd521e7250f76674362ccc..36d36fa874ba791490e4bfbe94ae0fa01a637077 100644 (file)
@@ -510,7 +510,7 @@ int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, g
                                           &vpninfo->tpm2->pub);
        if (r) {
                vpn_progress(vpninfo, PRG_ERR,
-                            _("Failed to import TPM2 private key data: 0x%x\n"),
+                            _("Failed to import TPM2 public key data: 0x%x\n"),
                             r);
                goto err_out;
        }
index 33f360c87e8ef83b889c98ee46ed79ecd0b5d6e8..a007745752ef8c5b5f205c9e114282dac58dbb13 100644 (file)
@@ -2,8 +2,10 @@
  * OpenConnect (SSL + DTLS) VPN client
  *
  * Copyright © 2018 David Woodhouse.
+ * Copyright © 2017-2018 James Bottomley
  *
- * Author: David Woodhouse <dwmw2@infradead.org>
+ * Authors: James Bottomley <James.Bottomley@hansenpartnership.com>
+ *          David Woodhouse <dwmw2@infradead.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
 
 #define TSSINCLUDE(x) < HAVE_TSS2/x >
 #include TSSINCLUDE(tss.h)
+#include TSSINCLUDE(tssresponsecode.h)
+#include TSSINCLUDE(Unmarshal_fp.h)
+#include TSSINCLUDE(RSA_Decrypt_fp.h)
+#include TSSINCLUDE(Sign_fp.h)
+
+#define KEY_AUTH_FAILED                0x9a2
+#define PARENT_AUTH_FAILED     0x98e
 
 struct oc_tpm2_ctx {
        TPM2B_PUBLIC pub;
        TPM2B_PRIVATE priv;
-       TPM2B_DIGEST userauth;
-       TPM2B_DIGEST ownerauth;
+       char *parent_pass, *key_pass;
        unsigned int need_userauth:1;
-       unsigned int need_ownerauth:1;
+       unsigned int parent;
 };
 
+static void free_pass(char **p)
+{
+       if (!*p)
+               return;
+
+       memset(*p, 0x5a, strlen(*p));
+       free(*p);
+}
+
+static void tpm2_error(TPM_RC rc, const char *reason)
+{
+       const char *msg, *submsg, *num;
+
+       fprintf(stderr, "%s failed with %d\n", reason, rc);
+       TSS_ResponseCode_toString(&msg, &submsg, &num, rc);
+       fprintf(stderr, "%s%s%s\n", msg, submsg, num);
+}
+
+static TPM_RC tpm2_readpublic(TSS_CONTEXT *tssContext, TPM_HANDLE handle,
+                             TPMT_PUBLIC *pub)
+{
+       ReadPublic_In rin;
+       ReadPublic_Out rout;
+       TPM_RC rc;
+
+       rin.objectHandle = handle;
+       rc = TSS_Execute (tssContext,
+                         (RESPONSE_PARAMETERS *)&rout,
+                         (COMMAND_PARAMETERS *)&rin,
+                         NULL,
+                         TPM_CC_ReadPublic,
+                         TPM_RH_NULL, NULL, 0);
+       if (rc) {
+               tpm2_error(rc, "TPM2_ReadPublic");
+               return rc;
+       }
+       if (pub)
+               *pub = rout.outPublic.publicArea;
+
+       return rc;
+}
+
+static TPM_RC tpm2_get_bound_handle(TSS_CONTEXT *tssContext, TPM_HANDLE *handle,
+                                   TPM_HANDLE bind, const char *auth)
+{
+       TPM_RC rc;
+       StartAuthSession_In in;
+       StartAuthSession_Out out;
+       StartAuthSession_Extra extra;
+
+       memset(&in, 0, sizeof(in));
+       memset(&extra, 0 , sizeof(extra));
+       in.bind = bind;
+       extra.bindPassword = auth;
+       in.sessionType = TPM_SE_HMAC;
+       in.authHash = TPM_ALG_SHA256;
+       in.tpmKey = TPM_RH_NULL;
+       in.symmetric.algorithm = TPM_ALG_AES;
+       in.symmetric.keyBits.aes = 128;
+       in.symmetric.mode.aes = TPM_ALG_CFB;
+       rc = TSS_Execute(tssContext,
+                        (RESPONSE_PARAMETERS *)&out,
+                        (COMMAND_PARAMETERS *)&in,
+                        (EXTRA_PARAMETERS *)&extra,
+                        TPM_CC_StartAuthSession,
+                        TPM_RH_NULL, NULL, 0);
+       if (rc) {
+               tpm2_error(rc, "TPM2_StartAuthSession");
+               return rc;
+       }
+
+       *handle = out.sessionHandle;
+
+       return TPM_RC_SUCCESS;
+}
+
+static TPM_RC tpm2_get_session_handle(TSS_CONTEXT *tssContext, TPM_HANDLE *handle,
+                                     TPM_HANDLE salt_key, TPM_SE sessionType)
+{
+       TPM_RC rc;
+       StartAuthSession_In in;
+       StartAuthSession_Out out;
+       StartAuthSession_Extra extra;
+
+       memset(&in, 0, sizeof(in));
+       memset(&extra, 0 , sizeof(extra));
+       in.bind = TPM_RH_NULL;
+       in.sessionType = sessionType;
+       in.authHash = TPM_ALG_SHA256;
+       in.tpmKey = TPM_RH_NULL;
+       in.symmetric.algorithm = TPM_ALG_AES;
+       in.symmetric.keyBits.aes = 128;
+       in.symmetric.mode.aes = TPM_ALG_CFB;
+       if (salt_key) {
+               /* For the TSS to use a key as salt, it must have
+                * access to the public part.  It does this by keeping
+                * key files, but request the public part just to make
+                * sure*/
+               tpm2_readpublic(tssContext, salt_key,  NULL);
+               /* don't care what rout returns, the purpose of the
+                * operation was to get the public key parameters into
+                * the tss so it can construct the salt */
+               in.tpmKey = salt_key;
+       }
+       rc = TSS_Execute(tssContext,
+                        (RESPONSE_PARAMETERS *)&out,
+                        (COMMAND_PARAMETERS *)&in,
+                        (EXTRA_PARAMETERS *)&extra,
+                        TPM_CC_StartAuthSession,
+                        TPM_RH_NULL, NULL, 0);
+       if (rc) {
+               tpm2_error(rc, "TPM2_StartAuthSession");
+               return rc;
+       }
+
+       *handle = out.sessionHandle;
+
+       return TPM_RC_SUCCESS;
+}
+
+static void tpm2_flush_handle(TSS_CONTEXT *tssContext, TPM_HANDLE h)
+{
+       FlushContext_In in;
+
+       if (!h)
+               return;
+
+       in.flushHandle = h;
+       TSS_Execute(tssContext, NULL, 
+                   (COMMAND_PARAMETERS *)&in,
+                   NULL,
+                   TPM_CC_FlushContext,
+                   TPM_RH_NULL, NULL, 0);
+}
+
+static void tpm2_flush_srk(TSS_CONTEXT *tssContext, TPM_HANDLE hSRK)
+{
+       /* only flush if it's a volatile key which we must have created */
+       if ((hSRK & 0xFF000000) == 0x80000000)
+               tpm2_flush_handle(tssContext, hSRK);
+}
+
+
+
+static TPM_RC tpm2_load_srk(TSS_CONTEXT *tssContext, TPM_HANDLE *h,
+                           const char *auth, TPM_HANDLE hierarchy)
+{
+       TPM_RC rc;
+       CreatePrimary_In in;
+       CreatePrimary_Out out;
+       TPM_HANDLE session;
+
+       /* SPS owner */
+       in.primaryHandle = hierarchy;
+       if (auth) {
+               in.inSensitive.sensitive.userAuth.t.size = strlen(auth);
+               memcpy(in.inSensitive.sensitive.userAuth.t.buffer, auth, strlen(auth));
+       } else {
+               in.inSensitive.sensitive.userAuth.t.size = 0;
+       }
+
+       /* no sensitive date for storage keys */
+       in.inSensitive.sensitive.data.t.size = 0;
+       /* no outside info */
+       in.outsideInfo.t.size = 0;
+       /* no PCR state */
+       in.creationPCR.count = 0;
+
+       /* public parameters for an RSA2048 key  */
+       in.inPublic.publicArea.type = TPM_ALG_ECC;
+       in.inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
+       in.inPublic.publicArea.objectAttributes.val =
+               TPMA_OBJECT_NODA |
+               TPMA_OBJECT_SENSITIVEDATAORIGIN |
+               TPMA_OBJECT_USERWITHAUTH |
+               TPMA_OBJECT_DECRYPT |
+               TPMA_OBJECT_RESTRICTED;
+       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.inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
+       in.inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
+       in.inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+
+       in.inPublic.publicArea.unique.ecc.x.t.size = 0;
+       in.inPublic.publicArea.unique.ecc.y.t.size = 0;
+       in.inPublic.publicArea.authPolicy.t.size = 0;
+
+       /* use a bound session here because we have no known key objects
+        * to encrypt a salt to */
+       rc = tpm2_get_bound_handle(tssContext, &session, hierarchy, auth);
+       if (rc)
+               return rc;
+
+       rc = TSS_Execute(tssContext,
+                        (RESPONSE_PARAMETERS *)&out,
+                        (COMMAND_PARAMETERS *)&in,
+                        NULL,
+                        TPM_CC_CreatePrimary,
+                        session, auth, TPMA_SESSION_DECRYPT,
+                        TPM_RH_NULL, NULL, 0);
+
+       if (rc) {
+               tpm2_error(rc, "TSS_CreatePrimary");
+               tpm2_flush_handle(tssContext, session);
+               return rc;
+       }
+
+       *h = out.objectHandle;
+
+       return 0;
+}
+
+
+static TPM_HANDLE tpm2_load_key(struct openconnect_info *vpninfo, TSS_CONTEXT **tsscp)
+{
+       TSS_CONTEXT *tssContext;
+       Load_In in;
+       Load_Out out;
+       TPM_HANDLE key = 0;
+       TPM_RC rc;
+       TPM_HANDLE session;
+       char *pass = vpninfo->tpm2->parent_pass;
+       int need_pw = 0;
+
+       vpninfo->tpm2->parent_pass = NULL;
+
+       rc = TSS_Create(&tssContext);
+       if (rc) {
+               tpm2_error(rc, "TSS_Create");
+               return 0;
+       }
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+
+       if (vpninfo->tpm2->parent >> HR_SHIFT == TPM_HT_PERSISTENT) {
+               if (!pass) {
+                       TPMT_PUBLIC pub;
+                       rc = tpm2_readpublic(tssContext, vpninfo->tpm2->parent, &pub);
+                       if (rc)
+                               goto out;
+
+                       if (!(pub.objectAttributes.val & TPMA_OBJECT_NODA))
+                               need_pw = 1;
+               }
+
+               in.parentHandle = vpninfo->tpm2->parent;
+       } else {
+       reauth_srk:
+               rc = tpm2_load_srk(tssContext, &in.parentHandle, pass, vpninfo->tpm2->parent);
+               if (rc == KEY_AUTH_FAILED) {
+                       free_pass(&pass);
+                       if (!request_passphrase(vpninfo, "openconnect_tpm2_hierarchy", &pass,
+                                               _("Enter TPM2 %s hierarchy password:"), "owner")) {
+                               goto reauth_srk;
+                       }
+               }
+               if (rc)
+                       goto out;
+       }
+       rc = tpm2_get_session_handle(tssContext, &session, in.parentHandle,
+                                    TPM_SE_HMAC);
+       if (rc)
+               goto out_flush_srk;
+
+       memcpy(&in.inPublic, &vpninfo->tpm2->pub, sizeof(in.inPublic));
+       memcpy(&in.inPrivate, &vpninfo->tpm2->priv, sizeof(in.inPrivate));
+       if (need_pw && !pass) {
+       reauth_parent:
+               if (request_passphrase(vpninfo, "openconnect_tpm2_parent", &pass,
+                                      _("Enter TPM2 parent key password:"))) {
+                       tpm2_flush_handle(tssContext, session);
+                       goto out_flush_srk;
+               }
+       }
+       rc = TSS_Execute(tssContext,
+                        (RESPONSE_PARAMETERS *)&out,
+                        (COMMAND_PARAMETERS *)&in,
+                        NULL,
+                        TPM_CC_Load,
+                        session, pass, 0,
+                        TPM_RH_NULL, NULL, 0);
+       if (rc == PARENT_AUTH_FAILED) {
+               free_pass(&pass);
+               goto reauth_parent;
+       }
+       if (rc) {
+               tpm2_error(rc, "TPM2_Load");
+               tpm2_flush_handle(tssContext, session);
+       }
+       else
+               key = out.objectHandle;
+
+ out_flush_srk:
+       tpm2_flush_srk(tssContext, in.parentHandle);
+ out:
+       vpninfo->tpm2->parent_pass = pass;
+       if (!key)
+               TSS_Delete(tssContext);
+       else
+               *tsscp = tssContext;
+       return key;
+}
+
+static void tpm2_unload_key(TSS_CONTEXT *tssContext, TPM_HANDLE key)
+{
+       tpm2_flush_handle(tssContext, key);
+
+       TSS_Delete(tssContext);
+}
+
+#define PKCS1_PAD_OVERHEAD 11
+
 int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
                          void *_vpninfo, unsigned int flags,
                          const gnutls_datum_t *data, gnutls_datum_t *sig)
 {
-       return GNUTLS_E_PK_SIGN_FAILED;
+       struct openconnect_info *vpninfo = _vpninfo;
+       TSS_CONTEXT *tssContext = NULL;
+       RSA_Decrypt_In in;
+       RSA_Decrypt_Out out;
+       int ret = GNUTLS_E_PK_SIGN_FAILED;
+       TPM_HANDLE authHandle;
+       TPM_RC rc;
+       char *pass = vpninfo->tpm2->key_pass;
+
+       vpninfo->tpm2->key_pass = NULL;
+
+       memset(&in, 0, sizeof(in));
+
+       in.cipherText.t.size = vpninfo->tpm2->pub.publicArea.unique.rsa.t.size;
+
+       if (data->size + PKCS1_PAD_OVERHEAD > in.cipherText.t.size) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("TPM2 digest too large: %d > %d\n"),
+                            data->size, in.cipherText.t.size - PKCS1_PAD_OVERHEAD);
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       /* PKCS#1 padding */
+       in.cipherText.t.buffer[0] = 0;
+       in.cipherText.t.buffer[1] = 1;
+       memset(in.cipherText.t.buffer + 2, 0xff, in.cipherText.t.size - data->size - 3);
+       in.cipherText.t.buffer[in.cipherText.t.size - data->size - 1] = 0;
+       memcpy(in.cipherText.t.buffer + in.cipherText.t.size - data->size, data->data, data->size);
+
+       in.inScheme.scheme = TPM_ALG_NULL;
+       in.keyHandle = tpm2_load_key(vpninfo, &tssContext);
+       in.label.t.size = 0;
+       if (!in.keyHandle)
+               return GNUTLS_E_PK_SIGN_FAILED;
+
+       rc = tpm2_get_session_handle(tssContext, &authHandle, 0, TPM_SE_HMAC);
+       if (rc)
+               goto out;
+
+ reauth:
+       rc = TSS_Execute(tssContext,
+                        (RESPONSE_PARAMETERS *)&out,
+                        (COMMAND_PARAMETERS *)&in,
+                        NULL,
+                        TPM_CC_RSA_Decrypt,
+                        authHandle, pass, 0,
+                        TPM_RH_NULL, NULL, 0);
+       if (rc == KEY_AUTH_FAILED) {
+               free_pass(&pass);
+               if (!request_passphrase(vpninfo, "openconnect_tpm2_key",
+                                       &pass, _("Enter TPM2 key password:")))
+                       goto reauth;
+       }
+       if (rc) {
+               tpm2_error(rc, "TPM2_RSA_Decrypt");
+               /* failure means auth handle is not flushed */
+               tpm2_flush_handle(tssContext, authHandle);
+               goto out;
+       }
+
+       vpninfo->tpm2->key_pass = pass;
+
+       sig->data = malloc(out.message.t.size);
+       if (!sig->data)
+               goto out;
+
+       sig->size = out.message.t.size;
+       memcpy(sig->data, out.message.t.buffer, out.message.t.size);
+       ret = 0;
+ out:
+       tpm2_unload_key(tssContext, in.keyHandle);
+
+       return ret;
 }
 
 int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
                         void *_vpninfo, unsigned int flags,
                         const gnutls_datum_t *data, gnutls_datum_t *sig)
 {
-       return GNUTLS_E_PK_SIGN_FAILED;
+       struct openconnect_info *vpninfo = _vpninfo;
+       TSS_CONTEXT *tssContext = NULL;
+       Sign_In in;
+       Sign_Out out;
+       int ret = GNUTLS_E_PK_SIGN_FAILED;
+       TPM_HANDLE authHandle;
+       TPM_RC rc;
+       char *pass = vpninfo->tpm2->key_pass;
+       gnutls_datum_t sig_r, sig_s;
+
+       vpninfo->tpm2->key_pass = NULL;
+
+       vpn_progress(vpninfo, PRG_DEBUG,
+                    _("TPM2 EC sign function called for %d bytes.\n"),
+                    data->size);
+
+       memset(&in, 0, sizeof(in));
+
+       switch (algo) {
+       case GNUTLS_SIGN_ECDSA_SHA1:   in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA1;   break;
+       case GNUTLS_SIGN_ECDSA_SHA256: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA256; break;
+       case GNUTLS_SIGN_ECDSA_SHA384: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA384; break;
+#ifdef TPM_ALG_SHA512
+       case GNUTLS_SIGN_ECDSA_SHA512: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA512; break;
+#endif
+       default:
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Unknown TPM2 EC digest size %d\n"),
+                            data->size);
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       in.inScheme.scheme = TPM_ALG_ECDSA;
+       in.digest.t.size = data->size;
+       memcpy(in.digest.t.buffer, data->data, data->size);
+       in.validation.tag = TPM_ST_HASHCHECK;
+       in.validation.hierarchy = TPM_RH_NULL;
+       in.validation.digest.t.size = 0;
+
+       in.keyHandle = tpm2_load_key(vpninfo, &tssContext);
+       if (!in.keyHandle)
+               return GNUTLS_E_PK_SIGN_FAILED;
+
+       rc = tpm2_get_session_handle(tssContext, &authHandle, 0, TPM_SE_HMAC);
+       if (rc)
+               goto out;
+
+ reauth:
+       rc = TSS_Execute(tssContext,
+                        (RESPONSE_PARAMETERS *)&out,
+                        (COMMAND_PARAMETERS *)&in,
+                        NULL,
+                        TPM_CC_Sign,
+                        authHandle, pass, 0,
+                        TPM_RH_NULL, NULL, 0);
+       if (rc == KEY_AUTH_FAILED) {
+               free_pass(&pass);
+               if (!request_passphrase(vpninfo, "openconnect_tpm2_key",
+                                       &pass, _("Enter TPM2 key password:")))
+                       goto reauth;
+       }
+       if (rc) {
+               tpm2_error(rc, "TPM2_Sign");
+               tpm2_flush_handle(tssContext, authHandle);
+               goto out;
+       }
+
+       vpninfo->tpm2->key_pass = pass;
+       sig_r.data = out.signature.signature.ecdsa.signatureR.t.buffer;
+       sig_r.size = out.signature.signature.ecdsa.signatureR.t.size;
+       sig_s.data = out.signature.signature.ecdsa.signatureS.t.buffer;
+       sig_s.size = out.signature.signature.ecdsa.signatureS.t.size;
+
+       ret = gnutls_encode_rs_value(sig, &sig_r, &sig_s);
+ out:
+       tpm2_unload_key(tssContext, in.keyHandle);
+
+
+       return ret;
 }
 
 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)
 {
-       vpn_progress(vpninfo, PRG_ERR,
-                    _("TPM2 support via IBM TSS not yet implemented\n"));
+       TPM_RC rc;
+       BYTE *der;
+       INT32 dersize;
+
+       if (parent >> HR_SHIFT != TPM_HT_PERSISTENT &&
+           parent != TPM_RH_OWNER && parent != TPM_RH_NULL &&
+           parent != TPM_RH_ENDORSEMENT && parent != TPM_RH_PLATFORM) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Invalid TPM2 parent handle 0x%08x\n"), parent);
+               return -EINVAL;
+       }
 
+       vpninfo->tpm2 = calloc(1, sizeof(*vpninfo->tpm2));
+       if (!vpninfo->tpm2)
+               return -ENOMEM;
+
+       vpninfo->tpm2->parent = parent;
+       vpninfo->tpm2->need_userauth = !emptyauth;
+
+       der = privdata->data;
+       dersize = privdata->size;
+       rc = TPM2B_PRIVATE_Unmarshal(&vpninfo->tpm2->priv, &der, &dersize);
+       if (rc) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to import TPM2 private key data: 0x%x\n"),
+                            rc);
+               goto err_out;
+       }
+
+       der = pubdata->data;
+       dersize = pubdata->size;
+       rc = TPM2B_PUBLIC_Unmarshal(&vpninfo->tpm2->pub, &der, &dersize, FALSE);
+       if (rc) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("Failed to import TPM2 public key data: 0x%x\n"),
+                            rc);
+               goto err_out;
+       }
+
+       switch(vpninfo->tpm2->pub.publicArea.type) {
+       case TPM_ALG_RSA: return GNUTLS_PK_RSA;
+       case TPM_ALG_ECC: return GNUTLS_PK_ECDSA;
+       }
+
+       vpn_progress(vpninfo, PRG_ERR,
+                    _("Unsupported TPM2 key type %d\n"),
+                    vpninfo->tpm2->pub.publicArea.type);
+;
+ err_out:
+       release_tpm2_ctx(vpninfo);
        return -EINVAL;
 }
 
 
 void release_tpm2_ctx(struct openconnect_info *vpninfo)
 {
-       if (vpninfo->tpm2)
+       if (vpninfo->tpm2) {
+               free_pass(&vpninfo->tpm2->parent_pass);
+               free_pass(&vpninfo->tpm2->key_pass);
                free(vpninfo->tpm2);
-       vpninfo->tpm2 = NULL;
+               vpninfo->tpm2 = NULL;
+       }
 }
index 7200a92af74d4620dab4c0d2064237ea96b1320d..64e0b87a1a17ce1d159a8369b1608edb9388f7c9 100644 (file)
@@ -32,7 +32,7 @@ And <em>optionally</em> also:
   <li><b><tt><a href="https://github.com/OpenSC/libp11/wiki">libp11</a></tt></b> <i>(also needed for PKCS#11 support if using OpenSSL)</i></li>
   <li><b><tt><a href="http://code.google.com/p/libproxy/">libproxy</a></tt></b></li>
   <li><b><tt><a href="http://trousers.sourceforge.net/">trousers</a></tt></b> <i>(for TPMv1 support if using GnuTLS)</i></li>
-  <li><b><tt><a href="https://github.com/tpm2-software/tpm2-tss">tss2-esys</a></tt></b> and <b><tt><a href="https://www.gnu.org/software/libtasn1/">libtasn1</a></tt></b> <i>(for TPMv2 support if using GnuTLS)</i></li>
+  <li><b><tt><a href="https://www.gnu.org/software/libtasn1/">libtasn1</a></tt></b> and <em>either</em> <b><tt><a href="https://github.com/tpm2-software/tpm2-tss">tss2-esys</a></tt></b> or <b><tt><a href="http://sourceforge.net/projects/ibmtpm20tss/">IBM's TPM 2.0 TSS</a></tt></b>. <i>(for TPMv2 support if using GnuTLS)</i></li>
   <li><b><tt><a href="http://stoken.sourceforge.net/">libstoken</a></tt></b> <i>(for SecurID software token support)</i></li>
   <li><b><tt><a href="http://www.nongnu.org/oath-toolkit/">libpskc</a></tt></b> <i>(for RFC6030 PSKC file storage of HOTP/TOTP keys)</i></li>
   <li><b><tt><a href="https://pcsclite.alioth.debian.org/pcsclite.html">libpcsclite</a></tt></b> <i>(for Yubikey hardware HOTP/HOTP support)</i></li>
index df17c8bcdce9315e6bc9edd61fa23ecd0caa9fc5..d04295d081ac492da3d417a9f9a701ba74b32e1c 100644 (file)
@@ -47,7 +47,7 @@ The <a href="https://github.com/tpm2-software/tpm2-tss-engine">tpm2-tss-engine</
 
 Both of these OpenSSL engines can be used by OpenConnect if they are installed.</p>
 
-<p>The GnuTLS build of OpenConnect supports the former variant, when built with the <tt>libtasn1</tt> and <tt>tss2-esys</tt> libraries.</p>
+<p>The GnuTLS build of OpenConnect supports the former variant, when built with <tt>libtasn1</tt> and either <tt>tss2-esys</tt> or IBM TSS 2.0 libraries.</p>
 
 <INCLUDE file="inc/footer.tmpl" />
 </PAGE>