#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 = {
* @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;
}
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,
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"),
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
* @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"));
}
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);
*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
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;
&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);
&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;
}