diff mbox series

[v4,5/7] trusted keys: Add session encryption protection to the seal/unseal path

Message ID 1540193921.3202.13.camel@HansenPartnership.com (mailing list archive)
State New, archived
Headers show
Series add integrity and security to TPM2 transactions | expand

Commit Message

James Bottomley Oct. 22, 2018, 7:38 a.m. UTC
If some entity is snooping the TPM bus, the can see the data going in
to be sealed and the data coming out as it is unsealed.  Add parameter
and response encryption to these cases to ensure that no secrets are
leaked even if the bus is snooped.

As part of doing this conversion it was discovered that policy
sessions can't work with HMAC protected authority because of missing
pieces (the tpm Nonce).  I've added code to work the same way as
before, which will result in potential authority exposure (while still
adding security for the command and the returned blob), and a fixme to
redo the API to get rid of this security hole.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
 drivers/char/tpm/tpm2-cmd.c | 155 ++++++++++++++++++++++++++++----------------
 1 file changed, 98 insertions(+), 57 deletions(-)

Comments

Jarkko Sakkinen Oct. 24, 2018, 12:03 a.m. UTC | #1
The tag in the short description does not look at all. Should be either
"tpm:" or "keys, trusted:".

On Mon, 22 Oct 2018, James Bottomley wrote:
> If some entity is snooping the TPM bus, the can see the data going in
> to be sealed and the data coming out as it is unsealed.  Add parameter
> and response encryption to these cases to ensure that no secrets are
> leaked even if the bus is snooped.
>
> As part of doing this conversion it was discovered that policy
> sessions can't work with HMAC protected authority because of missing
> pieces (the tpm Nonce).  I've added code to work the same way as
> before, which will result in potential authority exposure (while still
> adding security for the command and the returned blob), and a fixme to
> redo the API to get rid of this security hole.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
> drivers/char/tpm/tpm2-cmd.c | 155 ++++++++++++++++++++++++++++----------------
> 1 file changed, 98 insertions(+), 57 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> index 22f1c7bee173..a8655cd535d1 100644
> --- a/drivers/char/tpm/tpm2-cmd.c
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -425,7 +425,9 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> {
> 	unsigned int blob_len;
> 	struct tpm_buf buf;
> +	struct tpm_buf t2b;
> 	u32 hash;
> +	struct tpm2_auth *auth;
> 	int i;
> 	int rc;
>
> @@ -439,45 +441,56 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> 	if (i == ARRAY_SIZE(tpm2_hash_map))
> 		return -EINVAL;
>
> -	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
> +	rc = tpm2_start_auth_session(chip, &auth);
> 	if (rc)
> 		return rc;
>
> -	tpm_buf_append_u32(&buf, options->keyhandle);
> -	tpm2_buf_append_auth(&buf, TPM2_RS_PW,
> -			     NULL /* nonce */, 0,
> -			     0 /* session_attributes */,
> -			     options->keyauth /* hmac */,
> -			     TPM_DIGEST_SIZE);
> +	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
> +	if (rc) {
> +		tpm2_end_auth_session(auth);
> +		return rc;
> +	}
> +
> +	rc = tpm_buf_init_2b(&t2b);
> +	if (rc) {
> +		tpm_buf_destroy(&buf);
> +		tpm2_end_auth_session(auth);
> +		return rc;
> +	}
>
> +	tpm_buf_append_name(&buf, auth, options->keyhandle, NULL);
> +	tpm_buf_append_hmac_session(&buf, auth, TPM2_SA_DECRYPT,
> +				    options->keyauth, TPM_DIGEST_SIZE);
> 	/* sensitive */
> -	tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len + 1);
> +	tpm_buf_append_u16(&t2b, TPM_DIGEST_SIZE);
> +	tpm_buf_append(&t2b, options->blobauth, TPM_DIGEST_SIZE);
> +	tpm_buf_append_u16(&t2b, payload->key_len + 1);
> +	tpm_buf_append(&t2b, payload->key, payload->key_len);
> +	tpm_buf_append_u8(&t2b, payload->migratable);
>
> -	tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
> -	tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
> -	tpm_buf_append_u16(&buf, payload->key_len + 1);
> -	tpm_buf_append(&buf, payload->key, payload->key_len);
> -	tpm_buf_append_u8(&buf, payload->migratable);
> +	tpm_buf_append_2b(&buf, &t2b);
>
> 	/* public */
> -	tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
> -	tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
> -	tpm_buf_append_u16(&buf, hash);
> +	tpm_buf_append_u16(&t2b, TPM2_ALG_KEYEDHASH);
> +	tpm_buf_append_u16(&t2b, hash);
>
> 	/* policy */
> 	if (options->policydigest_len) {
> -		tpm_buf_append_u32(&buf, 0);
> -		tpm_buf_append_u16(&buf, options->policydigest_len);
> -		tpm_buf_append(&buf, options->policydigest,
> +		tpm_buf_append_u32(&t2b, 0);
> +		tpm_buf_append_u16(&t2b, options->policydigest_len);
> +		tpm_buf_append(&t2b, options->policydigest,
> 			       options->policydigest_len);
> 	} else {
> -		tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
> -		tpm_buf_append_u16(&buf, 0);
> +		tpm_buf_append_u32(&t2b, TPM2_OA_USER_WITH_AUTH);
> +		tpm_buf_append_u16(&t2b, 0);
> 	}
>
> 	/* public parameters */
> -	tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
> -	tpm_buf_append_u16(&buf, 0);
> +	tpm_buf_append_u16(&t2b, TPM2_ALG_NULL);
> +	/* unique (zero) */
> +	tpm_buf_append_u16(&t2b, 0);
> +
> +	tpm_buf_append_2b(&buf, &t2b);
>
> 	/* outside info */
> 	tpm_buf_append_u16(&buf, 0);
> @@ -490,8 +503,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> 		goto out;
> 	}
>
> -	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0,
> -			      "sealing data");
> +	tpm_buf_fill_hmac_session(&buf, auth);
> +
> +	rc = tpm_transmit_cmd(chip, &chip->kernel_space, buf.data,
> +			      PAGE_SIZE, 4, 0, "sealing data");
> +	rc = tpm_buf_check_hmac_response(&buf, auth, rc);
> 	if (rc)
> 		goto out;
>
> @@ -509,6 +525,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> 	payload->blob_len = blob_len;
>
> out:
> +	tpm_buf_destroy(&t2b);
> 	tpm_buf_destroy(&buf);
>
> 	if (rc > 0) {
> @@ -528,7 +545,6 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
>  * @payload: the key data in clear and encrypted form
>  * @options: authentication values and other options
>  * @blob_handle: returned blob handle
> - * @flags: tpm transmit flags
>  *
>  * Return: 0 on success.
>  *        -E2BIG on wrong payload size.
> @@ -538,9 +554,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> static int tpm2_load_cmd(struct tpm_chip *chip,
> 			 struct trusted_key_payload *payload,
> 			 struct trusted_key_options *options,
> -			 u32 *blob_handle, unsigned int flags)
> +			 u32 *blob_handle)
> {
> 	struct tpm_buf buf;
> +	struct tpm2_auth *auth;
> 	unsigned int private_len;
> 	unsigned int public_len;
> 	unsigned int blob_len;
> @@ -555,17 +572,18 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> 	if (blob_len > payload->blob_len)
> 		return -E2BIG;
>
> -	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
> +	rc = tpm2_start_auth_session(chip, &auth);
> 	if (rc)
> 		return rc;
>
> -	tpm_buf_append_u32(&buf, options->keyhandle);
> -	tpm2_buf_append_auth(&buf, TPM2_RS_PW,
> -			     NULL /* nonce */, 0,
> -			     0 /* session_attributes */,
> -			     options->keyauth /* hmac */,
> -			     TPM_DIGEST_SIZE);
> +	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
> +	if (rc) {
> +		tpm2_end_auth_session(auth);
> +		return rc;
> +	}
>
> +	tpm_buf_append_name(&buf, auth, options->keyhandle, NULL);
> +	tpm_buf_append_hmac_session(&buf, auth, 0, options->keyauth, TPM_DIGEST_SIZE);
> 	tpm_buf_append(&buf, payload->blob, blob_len);
>
> 	if (buf.flags & TPM_BUF_OVERFLOW) {
> @@ -573,8 +591,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> 		goto out;
> 	}
>
> -	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags,
> -			      "loading blob");
> +	tpm_buf_fill_hmac_session(&buf, auth);
> +	rc = tpm_transmit_cmd(chip, &chip->kernel_space, buf.data, PAGE_SIZE,
> +			      4, 0, "loading blob");
> +	rc = tpm_buf_check_hmac_response(&buf, auth, rc);
> 	if (!rc)
> 		*blob_handle = be32_to_cpup(
> 			(__be32 *) &buf.data[TPM_HEADER_SIZE]);
> @@ -595,7 +615,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
>  * @payload: the key data in clear and encrypted form
>  * @options: authentication values and other options
>  * @blob_handle: blob handle
> - * @flags: tpm_transmit_cmd flags
>  *
>  * Return: 0 on success
>  *         -EPERM on tpm error status
> @@ -604,28 +623,54 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> static int tpm2_unseal_cmd(struct tpm_chip *chip,
> 			   struct trusted_key_payload *payload,
> 			   struct trusted_key_options *options,
> -			   u32 blob_handle, unsigned int flags)
> +			   u32 blob_handle)
> {
> 	struct tpm_buf buf;
> +	struct tpm2_auth *auth;
> 	u16 data_len;
> 	u8 *data;
> 	int rc;
>
> -	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
> +	rc = tpm2_start_auth_session(chip, &auth);
> 	if (rc)
> 		return rc;
>
> -	tpm_buf_append_u32(&buf, blob_handle);
> -	tpm2_buf_append_auth(&buf,
> -			     options->policyhandle ?
> -			     options->policyhandle : TPM2_RS_PW,
> -			     NULL /* nonce */, 0,
> -			     TPM2_SA_CONTINUE_SESSION,
> -			     options->blobauth /* hmac */,
> -			     TPM_DIGEST_SIZE);
> -
> -	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags,
> -			      "unsealing");
> +	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
> +	if (rc) {
> +		tpm2_end_auth_session(auth);
> +		return rc;
> +	}
> +
> +	tpm_buf_append_name(&buf, auth, blob_handle, NULL);
> +
> +	if (!options->policyhandle) {
> +		tpm_buf_append_hmac_session(&buf, auth, TPM2_SA_ENCRYPT,
> +					    options->blobauth, TPM_DIGEST_SIZE);
> +	} else {
> +		/*
> +		 * FIXME: the policy can't be used for HMAC protection
> +		 * of the authorization because it must be generated
> +		 * with the initial nonces which isn't passed in, so
> +		 * append a second encryption session to at least HMAC
> +		 * protect the command and encrypt the sealed blob on
> +		 * return so the only thing the attacker can get is
> +		 * the password.
> +		 *
> +		 * We also consume the policy session otherwise it
> +		 * would be absorbed into the kernel space.
> +		 */
> +		tpm2_buf_append_auth(&buf, options->policyhandle,
> +				     NULL /* nonce */, 0, 0,
> +				     options->blobauth /* hmac */,
> +				     TPM_DIGEST_SIZE);
> +		tpm_buf_append_hmac_session(&buf, auth, TPM2_SA_ENCRYPT,
> +					    NULL, 0);
> +	}
> +
> +	tpm_buf_fill_hmac_session(&buf, auth);
> +	rc = tpm_transmit_cmd(chip, &chip->kernel_space, buf.data, PAGE_SIZE,
> +			      6, 0, "unsealing");
> +	rc = tpm_buf_check_hmac_response(&buf, auth, rc);
> 	if (rc > 0)
> 		rc = -EPERM;
>
> @@ -669,17 +714,13 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
> 	u32 blob_handle;
> 	int rc;
>
> -	mutex_lock(&chip->tpm_mutex);
> -	rc = tpm2_load_cmd(chip, payload, options, &blob_handle,
> -			   TPM_TRANSMIT_UNLOCKED);
> +	rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
> 	if (rc)
> 		goto out;
>
> -	rc = tpm2_unseal_cmd(chip, payload, options, blob_handle,
> -			     TPM_TRANSMIT_UNLOCKED);
> -	tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED);
> +	rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
> +	tpm2_flush_context_cmd(chip, blob_handle, 0);
> out:
> -	mutex_unlock(&chip->tpm_mutex);
> 	return rc;
> }
>
> -- 
> 2.16.4
>
>

This commit makes me almost demand a preliminary patch set that just
does the groundwork and takes new stuff into useĀ (tpm2b).

BTW, the whole patch set should speak integrity and encryption.
"security" essentially means absolutely nothing.

/Jarkko
diff mbox series

Patch

diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 22f1c7bee173..a8655cd535d1 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -425,7 +425,9 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 {
 	unsigned int blob_len;
 	struct tpm_buf buf;
+	struct tpm_buf t2b;
 	u32 hash;
+	struct tpm2_auth *auth;
 	int i;
 	int rc;
 
@@ -439,45 +441,56 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 	if (i == ARRAY_SIZE(tpm2_hash_map))
 		return -EINVAL;
 
-	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
+	rc = tpm2_start_auth_session(chip, &auth);
 	if (rc)
 		return rc;
 
-	tpm_buf_append_u32(&buf, options->keyhandle);
-	tpm2_buf_append_auth(&buf, TPM2_RS_PW,
-			     NULL /* nonce */, 0,
-			     0 /* session_attributes */,
-			     options->keyauth /* hmac */,
-			     TPM_DIGEST_SIZE);
+	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
+	if (rc) {
+		tpm2_end_auth_session(auth);
+		return rc;
+	}
+
+	rc = tpm_buf_init_2b(&t2b);
+	if (rc) {
+		tpm_buf_destroy(&buf);
+		tpm2_end_auth_session(auth);
+		return rc;
+	}
 
+	tpm_buf_append_name(&buf, auth, options->keyhandle, NULL);
+	tpm_buf_append_hmac_session(&buf, auth, TPM2_SA_DECRYPT,
+				    options->keyauth, TPM_DIGEST_SIZE);
 	/* sensitive */
-	tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len + 1);
+	tpm_buf_append_u16(&t2b, TPM_DIGEST_SIZE);
+	tpm_buf_append(&t2b, options->blobauth, TPM_DIGEST_SIZE);
+	tpm_buf_append_u16(&t2b, payload->key_len + 1);
+	tpm_buf_append(&t2b, payload->key, payload->key_len);
+	tpm_buf_append_u8(&t2b, payload->migratable);
 
-	tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
-	tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
-	tpm_buf_append_u16(&buf, payload->key_len + 1);
-	tpm_buf_append(&buf, payload->key, payload->key_len);
-	tpm_buf_append_u8(&buf, payload->migratable);
+	tpm_buf_append_2b(&buf, &t2b);
 
 	/* public */
-	tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
-	tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
-	tpm_buf_append_u16(&buf, hash);
+	tpm_buf_append_u16(&t2b, TPM2_ALG_KEYEDHASH);
+	tpm_buf_append_u16(&t2b, hash);
 
 	/* policy */
 	if (options->policydigest_len) {
-		tpm_buf_append_u32(&buf, 0);
-		tpm_buf_append_u16(&buf, options->policydigest_len);
-		tpm_buf_append(&buf, options->policydigest,
+		tpm_buf_append_u32(&t2b, 0);
+		tpm_buf_append_u16(&t2b, options->policydigest_len);
+		tpm_buf_append(&t2b, options->policydigest,
 			       options->policydigest_len);
 	} else {
-		tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
-		tpm_buf_append_u16(&buf, 0);
+		tpm_buf_append_u32(&t2b, TPM2_OA_USER_WITH_AUTH);
+		tpm_buf_append_u16(&t2b, 0);
 	}
 
 	/* public parameters */
-	tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
-	tpm_buf_append_u16(&buf, 0);
+	tpm_buf_append_u16(&t2b, TPM2_ALG_NULL);
+	/* unique (zero) */
+	tpm_buf_append_u16(&t2b, 0);
+
+	tpm_buf_append_2b(&buf, &t2b);
 
 	/* outside info */
 	tpm_buf_append_u16(&buf, 0);
@@ -490,8 +503,11 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 		goto out;
 	}
 
-	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0,
-			      "sealing data");
+	tpm_buf_fill_hmac_session(&buf, auth);
+
+	rc = tpm_transmit_cmd(chip, &chip->kernel_space, buf.data,
+			      PAGE_SIZE, 4, 0, "sealing data");
+	rc = tpm_buf_check_hmac_response(&buf, auth, rc);
 	if (rc)
 		goto out;
 
@@ -509,6 +525,7 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 	payload->blob_len = blob_len;
 
 out:
+	tpm_buf_destroy(&t2b);
 	tpm_buf_destroy(&buf);
 
 	if (rc > 0) {
@@ -528,7 +545,6 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
  * @payload: the key data in clear and encrypted form
  * @options: authentication values and other options
  * @blob_handle: returned blob handle
- * @flags: tpm transmit flags
  *
  * Return: 0 on success.
  *        -E2BIG on wrong payload size.
@@ -538,9 +554,10 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 static int tpm2_load_cmd(struct tpm_chip *chip,
 			 struct trusted_key_payload *payload,
 			 struct trusted_key_options *options,
-			 u32 *blob_handle, unsigned int flags)
+			 u32 *blob_handle)
 {
 	struct tpm_buf buf;
+	struct tpm2_auth *auth;
 	unsigned int private_len;
 	unsigned int public_len;
 	unsigned int blob_len;
@@ -555,17 +572,18 @@  static int tpm2_load_cmd(struct tpm_chip *chip,
 	if (blob_len > payload->blob_len)
 		return -E2BIG;
 
-	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
+	rc = tpm2_start_auth_session(chip, &auth);
 	if (rc)
 		return rc;
 
-	tpm_buf_append_u32(&buf, options->keyhandle);
-	tpm2_buf_append_auth(&buf, TPM2_RS_PW,
-			     NULL /* nonce */, 0,
-			     0 /* session_attributes */,
-			     options->keyauth /* hmac */,
-			     TPM_DIGEST_SIZE);
+	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
+	if (rc) {
+		tpm2_end_auth_session(auth);
+		return rc;
+	}
 
+	tpm_buf_append_name(&buf, auth, options->keyhandle, NULL);
+	tpm_buf_append_hmac_session(&buf, auth, 0, options->keyauth, TPM_DIGEST_SIZE);
 	tpm_buf_append(&buf, payload->blob, blob_len);
 
 	if (buf.flags & TPM_BUF_OVERFLOW) {
@@ -573,8 +591,10 @@  static int tpm2_load_cmd(struct tpm_chip *chip,
 		goto out;
 	}
 
-	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags,
-			      "loading blob");
+	tpm_buf_fill_hmac_session(&buf, auth);
+	rc = tpm_transmit_cmd(chip, &chip->kernel_space, buf.data, PAGE_SIZE,
+			      4, 0, "loading blob");
+	rc = tpm_buf_check_hmac_response(&buf, auth, rc);
 	if (!rc)
 		*blob_handle = be32_to_cpup(
 			(__be32 *) &buf.data[TPM_HEADER_SIZE]);
@@ -595,7 +615,6 @@  static int tpm2_load_cmd(struct tpm_chip *chip,
  * @payload: the key data in clear and encrypted form
  * @options: authentication values and other options
  * @blob_handle: blob handle
- * @flags: tpm_transmit_cmd flags
  *
  * Return: 0 on success
  *         -EPERM on tpm error status
@@ -604,28 +623,54 @@  static int tpm2_load_cmd(struct tpm_chip *chip,
 static int tpm2_unseal_cmd(struct tpm_chip *chip,
 			   struct trusted_key_payload *payload,
 			   struct trusted_key_options *options,
-			   u32 blob_handle, unsigned int flags)
+			   u32 blob_handle)
 {
 	struct tpm_buf buf;
+	struct tpm2_auth *auth;
 	u16 data_len;
 	u8 *data;
 	int rc;
 
-	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
+	rc = tpm2_start_auth_session(chip, &auth);
 	if (rc)
 		return rc;
 
-	tpm_buf_append_u32(&buf, blob_handle);
-	tpm2_buf_append_auth(&buf,
-			     options->policyhandle ?
-			     options->policyhandle : TPM2_RS_PW,
-			     NULL /* nonce */, 0,
-			     TPM2_SA_CONTINUE_SESSION,
-			     options->blobauth /* hmac */,
-			     TPM_DIGEST_SIZE);
-
-	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags,
-			      "unsealing");
+	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
+	if (rc) {
+		tpm2_end_auth_session(auth);
+		return rc;
+	}
+
+	tpm_buf_append_name(&buf, auth, blob_handle, NULL);
+
+	if (!options->policyhandle) {
+		tpm_buf_append_hmac_session(&buf, auth, TPM2_SA_ENCRYPT,
+					    options->blobauth, TPM_DIGEST_SIZE);
+	} else {
+		/*
+		 * FIXME: the policy can't be used for HMAC protection
+		 * of the authorization because it must be generated
+		 * with the initial nonces which isn't passed in, so
+		 * append a second encryption session to at least HMAC
+		 * protect the command and encrypt the sealed blob on
+		 * return so the only thing the attacker can get is
+		 * the password.
+		 *
+		 * We also consume the policy session otherwise it
+		 * would be absorbed into the kernel space.
+		 */
+		tpm2_buf_append_auth(&buf, options->policyhandle,
+				     NULL /* nonce */, 0, 0,
+				     options->blobauth /* hmac */,
+				     TPM_DIGEST_SIZE);
+		tpm_buf_append_hmac_session(&buf, auth, TPM2_SA_ENCRYPT,
+					    NULL, 0);
+	}
+
+	tpm_buf_fill_hmac_session(&buf, auth);
+	rc = tpm_transmit_cmd(chip, &chip->kernel_space, buf.data, PAGE_SIZE,
+			      6, 0, "unsealing");
+	rc = tpm_buf_check_hmac_response(&buf, auth, rc);
 	if (rc > 0)
 		rc = -EPERM;
 
@@ -669,17 +714,13 @@  int tpm2_unseal_trusted(struct tpm_chip *chip,
 	u32 blob_handle;
 	int rc;
 
-	mutex_lock(&chip->tpm_mutex);
-	rc = tpm2_load_cmd(chip, payload, options, &blob_handle,
-			   TPM_TRANSMIT_UNLOCKED);
+	rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
 	if (rc)
 		goto out;
 
-	rc = tpm2_unseal_cmd(chip, payload, options, blob_handle,
-			     TPM_TRANSMIT_UNLOCKED);
-	tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED);
+	rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
+	tpm2_flush_context_cmd(chip, blob_handle, 0);
 out:
-	mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }