]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Support TPM2 auth
authorDavid Woodhouse <dwmw2@infradead.org>
Wed, 3 Oct 2018 22:40:00 +0000 (23:40 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Mon, 8 Oct 2018 19:18:20 +0000 (20:18 +0100)
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
gnutls_tpm2_esys.c

index 815cc8ea5680bba3e98fb628ab3ea7f89bbf2a8c..c68baa280a4426a8221b61b83f3a175dcc7515c5 100644 (file)
 #include <tss2/tss2_esys.h>
 
 struct oc_tpm2_ctx {
-       TPM2B_DIGEST userauth;
        TPM2B_PUBLIC pub;
        TPM2B_PRIVATE priv;
+       TPM2B_DIGEST userauth;
        TPM2B_DIGEST ownerauth;
+       unsigned int need_userauth:1;
+       unsigned int need_ownerauth:1;
 };
 
 static TPM2B_PUBLIC primaryTemplate = {
@@ -111,8 +113,8 @@ static TPML_PCR_SELECTION allCreationPCR = {
  * @retval TSS2_RC_SUCCESS on success
  * @retval TSS2_RCs according to the error
  */
-static TSS2_RC init_tpm2_primary(struct openconnect_info *vpninfo,
-                                ESYS_CONTEXT **ctx, ESYS_TR *primaryHandle)
+static int init_tpm2_primary(struct openconnect_info *vpninfo,
+                            ESYS_CONTEXT **ctx, ESYS_TR *primaryHandle)
 {
        TSS2_RC r;
        *primaryHandle = ESYS_TR_NONE;
@@ -140,7 +142,26 @@ static TSS2_RC init_tpm2_primary(struct openconnect_info *vpninfo,
        }
 
        vpn_progress(vpninfo, PRG_DEBUG, _("Creating primary key under owner.\n"));
+ reauth:
+       if (vpninfo->tpm2->need_ownerauth) {
+               char *pass = NULL;
+               int err = request_passphrase(vpninfo, "openconnect_tpm2_owner",
+                                            &pass, _("Enter TPM2 owner password:"));
+               if (err)
+                       goto error;
+
+               if (strlen(pass) > sizeof(vpninfo->tpm2->ownerauth.buffer) - 1) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("TPM2 owner password too long; truncating\n"));
+                       pass[sizeof(vpninfo->tpm2->ownerauth.buffer) - 1] = 0;
+               }
+               vpninfo->tpm2->ownerauth.size = strlen(pass);
+               strcpy((char *)vpninfo->tpm2->ownerauth.buffer, pass);
+               memset(pass, 0, strlen(pass));
+               free(pass);
 
+               vpninfo->tpm2->need_ownerauth = 0;
+       }
        r = Esys_TR_SetAuth(*ctx, ESYS_TR_RH_OWNER, &vpninfo->tpm2->ownerauth);
        if (r) {
                vpn_progress(vpninfo, PRG_ERR,
@@ -157,8 +178,8 @@ static TSS2_RC init_tpm2_primary(struct openconnect_info *vpninfo,
        if (r == 0x000009a2) {
                vpn_progress(vpninfo, PRG_DEBUG,
                             _("TPM2 Esys_CreatePrimary owner auth failed\n"));
-               /* XXX: Prompt and retry */
-               goto error;
+               vpninfo->tpm2->need_ownerauth = 1;
+               goto reauth;
        } else if (r) {
                vpn_progress(vpninfo, PRG_ERR,
                             _("TPM2 Esys_CreatePrimary failed: 0x%x\n"),
@@ -166,14 +187,14 @@ static TSS2_RC init_tpm2_primary(struct openconnect_info *vpninfo,
                goto error;
        }
 
-       return TSS2_RC_SUCCESS;
+       return 0;
  error:
        if (*primaryHandle != ESYS_TR_NONE)
                Esys_FlushContext(*ctx, *primaryHandle);
        *primaryHandle = ESYS_TR_NONE;
 
        Esys_Finalize(ctx);
-       return r;
+       return -EIO;
 }
 
 /** Initialize the ESYS TPM connection and load the key
@@ -187,15 +208,14 @@ static TSS2_RC init_tpm2_primary(struct openconnect_info *vpninfo,
  * @retval TSS2_RC_SUCCESS on success
  * @retval TSS2_RCs according to the error
  */
-static TSS2_RC init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *keyHandle,
-                            struct openconnect_info *vpninfo)
+static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *keyHandle,
+                        struct openconnect_info *vpninfo)
 {
        TSS2_RC r;
        ESYS_TR primaryHandle = ESYS_TR_NONE;
        *keyHandle = ESYS_TR_NONE;
 
-       r = init_tpm2_primary(vpninfo, ctx, &primaryHandle);
-       if (r)
+       if (init_tpm2_primary(vpninfo, ctx, &primaryHandle))
                goto error;
 
        vpn_progress(vpninfo, PRG_DEBUG, _("Loading TPM2 key blob.\n"));
@@ -220,15 +240,7 @@ static TSS2_RC init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *keyHandle,
        }
        primaryHandle = ESYS_TR_NONE;
 
-       r = Esys_TR_SetAuth(*ctx, *keyHandle, &vpninfo->tpm2->userauth);
-       if (r) {
-               vpn_progress(vpninfo, PRG_ERR,
-                            _("TPM2 Esys_TR_SetAuth failed: 0x%x\n"),
-                            r);
-               goto error;
-       }
-
-       return TSS2_RC_SUCCESS;
+       return 0;
  error:
        if (primaryHandle != ESYS_TR_NONE)
                Esys_FlushContext(*ctx, primaryHandle);
@@ -237,7 +249,46 @@ static TSS2_RC init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *keyHandle,
        *keyHandle = ESYS_TR_NONE;
 
        Esys_Finalize(ctx);
-       return r;
+       return -EIO;
+}
+
+static int auth_tpm2_key(struct openconnect_info *vpninfo, ESYS_CONTEXT *ctx, ESYS_TR key_handle)
+{
+       TSS2_RC r;
+
+       if (vpninfo->tpm2->need_userauth || vpninfo->cert_password) {
+               char *pass = NULL;
+
+               if (vpninfo->cert_password) {
+                       pass = vpninfo->cert_password;
+                       vpninfo->cert_password = NULL;
+               } else {
+                       int err = request_passphrase(vpninfo, "openconnect_tpm2_key",
+                                                    &pass, _("Enter TPM2 key password:"));
+                       if (err)
+                               return err;
+               }
+               if (strlen(pass) > sizeof(vpninfo->tpm2->userauth.buffer) - 1) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("TPM2 key password too long; truncating\n"));
+                       pass[sizeof(vpninfo->tpm2->userauth.buffer) - 1] = 0;
+               }
+               vpninfo->tpm2->userauth.size = strlen(pass);
+               strcpy((char *)vpninfo->tpm2->userauth.buffer, pass);
+               memset(pass, 0, strlen(pass));
+               free(pass);
+
+               vpninfo->tpm2->need_userauth = 0;
+       }
+
+       r = Esys_TR_SetAuth(ctx, key_handle, &vpninfo->tpm2->userauth);
+       if (r) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("TPM2 Esys_TR_SetAuth failed: 0x%x\n"),
+                            r);
+               return -EIO;
+       }
+       return 0;
 }
 
 #define PKCS1_PAD_OVERHEAD 11
@@ -277,18 +328,26 @@ static int tpm2_rsa_sign_fn(gnutls_privkey_t key, void *_vpninfo,
 
        if (init_tpm2_key(&ectx, &key_handle, vpninfo))
                goto out;
+ reauth:
+       if (auth_tpm2_key(vpninfo, ectx, key_handle))
+               goto out;
 
        r = Esys_RSA_Decrypt(ectx, key_handle,
                             ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                             &digest, &inScheme, &label, &tsig);
+       if (r == 0x9a2) {
+               vpn_progress(vpninfo, PRG_DEBUG,
+                            _("TPM2 Esys_RSA_Decrypt auth failed\n"));
+               vpninfo->tpm2->need_userauth = 1;
+               goto reauth;
+       }
        if (r) {
                vpn_progress(vpninfo, PRG_ERR,
-                            _("TPM2 failed to generate RSA signature: %d\n"),
+                            _("TPM2 failed to generate RSA signature: 0x%x\n"),
                             r);
                goto out;
        }
 
-
        sig->data = malloc(tsig->size);
        if (!sig->data)
                goto out;
@@ -337,7 +396,7 @@ int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, g
                                            &vpninfo->tpm2->priv);
        if (r) {
                vpn_progress(vpninfo, PRG_ERR,
-                            _("Failed to import RPM2 private key data: %d\n"),
+                            _("Failed to import TPM2 private key data: 0x%x\n"),
                             r);
        err_out:
                release_tpm2_ctx(vpninfo);
@@ -348,7 +407,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 RPM2 private key data: %d\n"),
+                            _("Failed to import TPM2 private key data: 0x%x\n"),
                             r);
                goto err_out;
        }