diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 63c175b2165c..c2b73283c46f 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -1365,3 +1365,9 @@ int tpm2_sessions_init(struct tpm_chip *chip)
 
 	return rc;
 }
+
+struct crypto_shash *tpm2_get_policy_hash(struct tpm_chip *chip)
+{
+	return chip->auth->tfm;
+}
+EXPORT_SYMBOL(tpm2_get_policy_hash);
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index 5d1d481a8a19..a6999800055e 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -19,11 +19,12 @@
 
 #define MIN_KEY_SIZE			32
 #define MAX_KEY_SIZE			128
-#define MAX_BLOB_SIZE			512
+#define MAX_BLOB_SIZE			4096
 #define MAX_PCRINFO_SIZE		128
 #define MAX_DIGEST_SIZE			64
 
 #define TPM2_MAX_POLICIES		16
+#define TPM2_MAX_AUTHS			8
 
 struct trusted_key_payload {
 	struct rcu_head rcu;
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 894e51a7fe3a..09f14482675b 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -290,6 +290,8 @@ enum tpm2_command_codes {
 	TPM2_CC_CONTEXT_LOAD	        = 0x0161,
 	TPM2_CC_CONTEXT_SAVE	        = 0x0162,
 	TPM2_CC_FLUSH_CONTEXT	        = 0x0165,
+	TPM2_CC_LOAD_EXTERNAL		= 0x0167,
+	TPM2_CC_POLICY_AUTHORIZE	= 0x016A,
 	TPM2_CC_POLICY_AUTHVALUE	= 0x016B,
 	TPM2_CC_POLICY_COUNTER_TIMER	= 0x016D,
 	TPM2_CC_READ_PUBLIC		= 0x0173,
@@ -299,14 +301,17 @@ enum tpm2_command_codes {
 	TPM2_CC_GET_RANDOM	        = 0x017B,
 	TPM2_CC_PCR_READ	        = 0x017E,
 	TPM2_CC_POLICY_PCR		= 0x017F,
+	TPM2_CC_POLICY_RESTART		= 0x0180,
 	TPM2_CC_PCR_EXTEND	        = 0x0182,
 	TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
 	TPM2_CC_HASH_SEQUENCE_START     = 0x0186,
+	TPM2_CC_POLICY_GET_DIGEST	= 0x0189,
 	TPM2_CC_CREATE_LOADED           = 0x0191,
 	TPM2_CC_LAST		        = 0x0193, /* Spec 1.36 */
 };
 
 enum tpm2_permanent_handles {
+	TPM2_RH_OWNER		= 0x40000001,
 	TPM2_RH_NULL		= 0x40000007,
 	TPM2_RS_PW		= 0x40000009,
 };
@@ -578,6 +583,7 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
 
 int tpm2_start_auth_session(struct tpm_chip *chip);
 int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash);
+struct crypto_shash *tpm2_get_policy_hash(struct tpm_chip *chip);
 void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
 			 u32 handle, u8 *name);
 void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
index c0508cb95923..f9ee57fed8fe 100644
--- a/security/keys/trusted-keys/tpm2-policy.c
+++ b/security/keys/trusted-keys/tpm2-policy.c
@@ -28,13 +28,28 @@ int tpm2_key_code(void *context, size_t hdrlen,
 	u32 code = 0;
 	const u8 *v = value;
 	int i;
+	u8 a = ctx->auth_policies;
 
 	for (i = 0; i < vlen; i++) {
 		code <<= 8;
 		code |= v[i];
 	}
 
-	ctx->policy_code[ctx->policy_count] = code;
+	ctx->policy_code[a][ctx->policy_count[a]] = code;
+
+	return 0;
+}
+
+int tpm2_pol_seq(void *context, size_t hdrlen,
+		 unsigned char tag,
+		 const void *value, size_t vlen)
+{
+	struct tpm2_key_context *ctx = context;
+
+	ctx->auth_policies++;
+
+	if (ctx->auth_policies > TPM2_MAX_AUTHS)
+		return -EINVAL;
 
 	return 0;
 }
@@ -44,9 +59,15 @@ int tpm2_key_policy(void *context, size_t hdrlen,
 		  const void *value, size_t vlen)
 {
 	struct tpm2_key_context *ctx = context;
+	u8 a = ctx->auth_policies;
+	u8 policy_count = ctx->policy_count[a]++;
+
+	if (policy_count >= TPM2_MAX_POLICIES)
+		return -EINVAL;
 
-	ctx->policies[ctx->policy_count] = value;
-	ctx->policy_len[ctx->policy_count++] = vlen;
+	ctx->policies[a][policy_count] = value;
+	ctx->policy_len[a][policy_count] = vlen;
+	ctx->policy_tot_len += vlen;
 
 	return 0;
 }
@@ -56,21 +77,24 @@ int tpm2_key_policy(void *context, size_t hdrlen,
  */
 static int tpm2_validate_policy(struct tpm2_policies *pols)
 {
-	int i;
+	int i, j;
 
-	if (pols->count == 0)
+	if (pols->auths == 0)
 		return 0;
 
-	for (i = 0; i < pols->count; i++) {
-		switch (pols->code[i]) {
-		case TPM2_CC_POLICY_COUNTER_TIMER:
-		case TPM2_CC_POLICY_PCR:
-		case TPM2_CC_POLICY_AUTHVALUE:
-			break;
-		default:
-			pr_info("tpm2 policy 0x%x is unsupported\n",
-				pols->code[i]);
+	for (i = 0; i < pols->auths; i++) {
+		for (j = 0; j < pols->count[i]; j++) {
+			switch (pols->code[i][j]) {
+			case TPM2_CC_POLICY_COUNTER_TIMER:
+			case TPM2_CC_POLICY_PCR:
+			case TPM2_CC_POLICY_AUTHVALUE:
+			case TPM2_CC_POLICY_AUTHORIZE:
+				break;
+			default:
+				pr_info("tpm2 policy 0x%x is unsupported\n",
+					pols->code[i][j]);
 			return -EINVAL;
+			}
 		}
 	}
 
@@ -89,36 +113,35 @@ static int tpm2_validate_policy(struct tpm2_policies *pols)
 int tpm2_key_policy_process(struct tpm2_key_context *ctx,
 			    struct trusted_key_payload *payload)
 {
-	int tot_len = 0;
 	u8 *buf;
-	int i, ret, len = 0;
+	int i, j, ret, len = 0;
 	struct tpm2_policies *pols;
 	u16 name_alg;
 
-	if (ctx->policy_count == 0)
+	if (ctx->policy_tot_len == 0)
 		return 0;
 
-	for (i = 0; i < ctx->policy_count; i++)
-		tot_len += ctx->policy_len[i];
-	tot_len += sizeof(*pols);
-
-	pols = kmalloc(tot_len, GFP_KERNEL);
+	pols = kmalloc(ctx->policy_tot_len + sizeof(*pols), GFP_KERNEL);
 	if (!pols)
 		return -ENOMEM;
 
 	payload->policies = pols;
 	buf = (u8 *)(pols + 1);
 
-	for (i = 0; i < ctx->policy_count; i++) {
-		pols->policies[i] = &buf[len];
-		pols->len[i] = ctx->policy_len[i];
-		pols->code[i] = ctx->policy_code[i];
-		if (pols->len[i])
-			memcpy(pols->policies[i], ctx->policies[i],
-			       ctx->policy_len[i]);
-		len += ctx->policy_len[i];
+	for (i = 0; i < ctx->auth_policies; i++) {
+		for (j = 0; j < ctx->policy_count[i]; j++) {
+			pols->policies[i][j] = &buf[len];
+			pols->len[i][j] = ctx->policy_len[i][j];
+			pols->code[i][j] = ctx->policy_code[i][j];
+			if (pols->len[i][j])
+				memcpy(pols->policies[i][j],
+				       ctx->policies[i][j],
+				       ctx->policy_len[i][j]);
+			len += ctx->policy_len[i][j];
+		}
+		pols->count[i] = ctx->policy_count[i];
 	}
-	pols->count = ctx->policy_count;
+	pols->auths = ctx->auth_policies;
 
 	ret = tpm2_validate_policy(pols);
 	if (ret)
@@ -148,7 +171,7 @@ int tpm2_key_policy_process(struct tpm2_key_context *ctx,
 int tpm2_generate_policy_digest(struct tpm2_policies *pols,
 				u32 hash, u8 *policydigest, u32 *plen)
 {
-	int i;
+	int i, j;
 	struct crypto_shash *tfm;
 	int rc;
 
@@ -174,45 +197,47 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols,
 	/* policy digests always start out all zeros */
 	memset(policydigest, 0, rc);
 
-	for (i = 0; i < pols->count; i++) {
-		u8 *policy = pols->policies[i];
-		int len = pols->len[i];
-		u32 cmd = pols->code[i];
-		u8 digest[MAX_DIGEST_SIZE];
-		u8 code[4];
-		SHASH_DESC_ON_STACK(sdesc, tfm);
+	for (i = 0; i < pols->auths; i++) {
+		for (j = 0; j < pols->count[i]; j++) {
+			u8 *policy = pols->policies[i][j];
+			int len = pols->len[i][j];
+			u32 cmd = pols->code[i][j];
+			u8 digest[MAX_DIGEST_SIZE];
+			u8 code[4];
+			SHASH_DESC_ON_STACK(sdesc, tfm);
 
-		sdesc->tfm = tfm;
-		rc = crypto_shash_init(sdesc);
-		if (rc)
-			goto err;
+			sdesc->tfm = tfm;
+			rc = crypto_shash_init(sdesc);
+			if (rc)
+				goto err;
 
-		/* first hash the previous digest */
-		crypto_shash_update(sdesc, policydigest, *plen);
+			/* first hash the previous digest */
+			crypto_shash_update(sdesc, policydigest, *plen);
 
-		/* then hash the command code */
-		put_unaligned_be32(cmd, code);
-		crypto_shash_update(sdesc, code, 4);
+			/* then hash the command code */
+			put_unaligned_be32(cmd, code);
+			crypto_shash_update(sdesc, code, 4);
 
-		/* commands that need special handling */
-		if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
-			SHASH_DESC_ON_STACK(sdesc1, tfm);
+			/* commands that need special handling */
+			if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
+				SHASH_DESC_ON_STACK(sdesc1, tfm);
 
-			sdesc1->tfm = tfm;
+				sdesc1->tfm = tfm;
 
-			/* counter timer policies are double hashed */
-			crypto_shash_digest(sdesc1, policy, len,
-					    digest);
-			policy = digest;
-			len = *plen;
-		}
+				/* counter timer policies are double hashed */
+				crypto_shash_digest(sdesc1, policy, len,
+						    digest);
+				policy = digest;
+				len = *plen;
+			}
 
-		if (len)
-			crypto_shash_update(sdesc, policy, len);
+			if (len)
+				crypto_shash_update(sdesc, policy, len);
 
-		/* now output the intermediate to the policydigest */
-		crypto_shash_final(sdesc, policydigest);
+			/* now output the intermediate to the policydigest */
+			crypto_shash_final(sdesc, policydigest);
 
+		}
 	}
 	rc = 0;
 
@@ -228,41 +253,45 @@ int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
 	u8 *work = buf + SCRATCH_SIZE;
 	u8 *ptr;
 	u8 *end_work = work + SCRATCH_SIZE;
-	int i, ret;
+	int i, j, ret;
 
 	if (!buf)
 		return -ENOMEM;
 
-	for (i = 0; i < pols->count; i++) {
-		u8 *seq, *tag;
-		u32 cmd = pols->code[i];
+	for (i = 0; i < pols->auths; i++) {
+		for (j = 0; j < pols->count[i]; j++) {
+			u8 *seq, *tag;
+			u32 cmd = pols->code[i][j];
 
-		if (WARN(work - buf + 14 + pols->len[i] > 2 * SCRATCH_SIZE,
-			 "BUG: scratch buffer is too small"))
-			return -EINVAL;
+			if (WARN(work - buf + 14 + pols->len[i][j] >
+				 2 * SCRATCH_SIZE,
+				 "BUG: scratch buffer is too small"))
+				return -EINVAL;
 
-		work = asn1_encode_sequence(work, end_work, NULL, -1);
-		seq = work;
+			work = asn1_encode_sequence(work, end_work, NULL, -1);
+			seq = work;
 
-		work = asn1_encode_tag(work, end_work, 0, NULL, -1);
-		tag = work;
+			work = asn1_encode_tag(work, end_work, 0, NULL, -1);
+			tag = work;
 
-		work = asn1_encode_integer(work, end_work, cmd);
-		asn1_encode_tag(tag, end_work, 0, NULL, work - tag);
+			work = asn1_encode_integer(work, end_work, cmd);
+			asn1_encode_tag(tag, end_work, 0, NULL, work - tag);
 
-		work = asn1_encode_tag(work, end_work, 1, NULL, -1);
-		tag = work;
+			work = asn1_encode_tag(work, end_work, 1, NULL, -1);
+			tag = work;
 
-		work = asn1_encode_octet_string(work, end_work,
-						pols->policies[i],
-						pols->len[i]);
+			work = asn1_encode_octet_string(work, end_work,
+							pols->policies[i][j],
+							pols->len[i][j]);
 
-		asn1_encode_tag(tag, end_work, 1, NULL, work - tag);
+			asn1_encode_tag(tag, end_work, 1, NULL, work - tag);
 
-		seq = asn1_encode_sequence(seq, end_work, NULL, work - seq);
-		if (IS_ERR(seq)) {
-			ret = PTR_ERR(seq);
-			goto err;
+			seq = asn1_encode_sequence(seq, end_work, NULL,
+						   work - seq);
+			if (IS_ERR(seq)) {
+				ret = PTR_ERR(seq);
+				goto err;
+			}
 		}
 	}
 	ptr = asn1_encode_sequence(buf, buf + SCRATCH_SIZE, buf + PAGE_SIZE,
@@ -282,18 +311,131 @@ int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
 	return ret;
 }
 
-int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
+static int tpm2_policy_restart(struct tpm_chip *chip, u32 handle)
 {
-	int i, rc;
-	u32 handle;
-	const char *failure;
+	struct tpm_buf buf;
+	int rc;
 
-	rc = tpm2_start_policy_session(chip, &handle, pols->hash);
+	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_POLICY_RESTART);
+	if (rc)
+		return rc;
+
+	tpm_buf_append_u32(&buf, handle);
+
+	rc = tpm_transmit_cmd(chip, &buf, 0, "restarting policy");
+	tpm_buf_destroy(&buf);
+	if (rc) {
+		pr_notice("TPM policy restart failed, rc=%d\n", rc);
+		return -EPERM;
+	}
+	return 0;
+}
+
+static int tpm2_policy_gettkhash(struct tpm_chip *chip, u8 *pubkey, u8 *nonce,
+				 u8 *signature, int siglen,
+				 u32 handle, u8 **hash, u8 **name,
+				 u8 **ticket)
+{
+	struct tpm_buf buf;
+	int rc;
+	int len;
+	u32 sigkey;
+	off_t offset;
+	SHASH_DESC_ON_STACK(sdesc, tpm2_get_policy_hash(chip));
+
+	sdesc->tfm = tpm2_get_policy_hash(chip);
+
+	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_POLICY_GET_DIGEST);
 	if (rc)
 		return rc;
 
-	for (i = 0; i < pols->count; i++) {
-		u32 cmd = pols->code[i];
+	tpm_buf_append_u32(&buf, handle);
+
+	rc = tpm_transmit_cmd(chip, &buf, 0, "getting policy hash");
+	if (rc)
+		goto out;
+	len = get_unaligned_be16(&buf.data[TPM_HEADER_SIZE]) + 2;
+	rc = -ENOMEM;
+	*hash = kmalloc(len, GFP_KERNEL);
+	if (!*hash)
+		goto out;
+	memcpy(*hash, &buf.data[TPM_HEADER_SIZE], len);
+
+	tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_LOAD_EXTERNAL);
+
+	/* empty sensitive */
+	tpm_buf_append_u16(&buf, 0);
+	/* TPM2B_PUBLIC */
+	len = get_unaligned_be16(pubkey) + 2;
+	tpm_buf_append(&buf, pubkey, len);
+	/* hierarchy (use null because never a password) */
+	tpm_buf_append_u32(&buf, TPM2_RH_OWNER);
+
+	rc = tpm_transmit_cmd(chip, &buf, 4, "loading external key");
+	if (rc)
+		goto out;
+
+	offset = TPM_HEADER_SIZE;
+	sigkey = tpm_buf_read_u32(&buf, &offset);
+	len = get_unaligned_be16(&buf.data[offset]) + 2;
+	*name = kmalloc(len, GFP_KERNEL);
+	if (!*name) {
+		tpm2_flush_context(chip, sigkey);
+		rc = -ENOMEM;
+		goto out;
+	}
+	memcpy(*name, &buf.data[offset], len);
+
+	tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_VERIFY_SIGNATURE);
+	/* handle of public key to verify with */
+	tpm_buf_append_u32(&buf, sigkey);
+	/* digest hash(policy||nonce) */
+	len = get_unaligned_be16(*hash);
+	tpm_buf_append_u16(&buf, len);
+	/* now compute the signed data which is hash(policy||nonce) */
+	crypto_shash_init(sdesc);
+	len = get_unaligned_be16(*hash); /* better be the tfm hash size */
+	crypto_shash_update(sdesc, *hash + 2, len);
+	len = get_unaligned_be16(nonce);
+	crypto_shash_update(sdesc, nonce + 2, len);
+	crypto_shash_final(sdesc, &buf.data[buf.length]);
+	buf.length += len;
+	/* signature */
+	tpm_buf_append(&buf, signature, siglen);
+
+	rc = tpm_transmit_cmd(chip, &buf, 4, "verifying signature");
+	tpm2_flush_context(chip, sigkey);
+	if (rc)
+		goto out;
+
+	len = tpm_buf_length(&buf) - TPM_HEADER_SIZE;
+	*ticket = kmalloc(len, GFP_KERNEL);
+	if (!*ticket) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memcpy(*ticket, &buf.data[TPM_HEADER_SIZE], len);
+
+ out:
+	if (rc) {
+		kfree(*hash);
+		*hash = NULL;
+		kfree(*name);
+		*name = NULL;
+	}
+	tpm_buf_destroy(&buf);
+	return rc;
+}
+
+
+static int tpm2_try_policy(struct tpm_chip *chip, struct tpm2_policies *pols,
+			   u32 handle, int p)
+{
+	int i, rc;
+	const char *failure;
+
+	for (i = 0; i < pols->count[p]; i++) {
+		u32 cmd = pols->code[p][i];
 		struct tpm_buf buf;
 
 		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, cmd);
@@ -311,10 +453,11 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
 			 * policy command
 			 */
 			tpm_buf_append_u16(&buf, pols->hash_size);
-			tpm_buf_append(&buf, pols->policies[i] + pols->len[i] -
+			tpm_buf_append(&buf, pols->policies[p][i]
+				       + pols->len[p][i] -
 				       pols->hash_size, pols->hash_size);
-			tpm_buf_append(&buf, pols->policies[i],
-				       pols->len[i] - pols->hash_size);
+			tpm_buf_append(&buf, pols->policies[p][i],
+				       pols->len[p][i] - pols->hash_size);
 			break;
 
 		case TPM2_CC_POLICY_COUNTER_TIMER: {
@@ -324,26 +467,82 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
 			 * respectively.  The rest is operandB which
 			 * must be zero padded in a hash digest
 			 */
-			u16 opb_len = pols->len[i] - 4;
+			u16 opb_len = pols->len[p][i] - 4;
 
 			if (opb_len > pols->hash_size)
 				return -EINVAL;
 
 			tpm_buf_append_u16(&buf, opb_len);
-			tpm_buf_append(&buf, pols->policies[i], opb_len);
+			tpm_buf_append(&buf, pols->policies[p][i], opb_len);
 
 			/* offset and operand*/
-			tpm_buf_append(&buf, pols->policies[i] + opb_len, 4);
+			tpm_buf_append(&buf, pols->policies[p][i] + opb_len, 4);
 			failure = "Counter Timer";
 
 			break;
 		}
+		case TPM2_CC_POLICY_AUTHORIZE: {
+			u8 *pubkey = pols->policies[p][i];
+			u8 *nonce;
+			u8 *signature;
+			u8 *ticket = NULL;
+			u8 *hash = NULL;
+			u8 *name = NULL;
+			int len, siglen;
+			const int maxlen = pols->len[p][i];
+
+			if (i == 0)
+				/*
+				 * If this is the first policy then skip
+				 * because we should already have executed
+				 * a successful PolicyAuthorize before getting
+				 * here
+				 */
+				continue;
+
+			len = get_unaligned_be16(pubkey);
+			if (len + 2 > maxlen) {
+				failure = "malformed policy";
+				break;
+			}
+			nonce = pubkey + len + 2;
+			len = get_unaligned_be16(nonce);
+			if (len + 2 > maxlen) {
+				failure = "malformed policy";
+				break;
+			}
+			signature = nonce + len + 2;
+			siglen = pubkey + maxlen - signature;
+			failure = "policy authorize";
+			rc = tpm2_policy_gettkhash(chip, pubkey, nonce,
+						   signature, siglen,
+						   handle, &hash,
+						   &name, &ticket);
+			if (rc)
+				break;
+			len = get_unaligned_be16(hash);
+			tpm_buf_append(&buf, hash, len + 2);
+			kfree(hash);
+
+			len = get_unaligned_be16(nonce);
+			tpm_buf_append(&buf, nonce, len + 2);
+
+			len = get_unaligned_be16(name);
+			tpm_buf_append(&buf, name, len + 2);
+			kfree(name);
+
+			len = get_unaligned_be16(ticket + 6) + 8;
+			tpm_buf_append(&buf, ticket, len);
+			kfree(ticket);
+
+			break;
+		}
 
 		default:
 			failure = "unknown policy";
-			if (pols->len[i])
-				tpm_buf_append(&buf, pols->policies[i],
-					       pols->len[i]);
+			if (pols->len[p][i])
+				tpm_buf_append(&buf, pols->policies[p][i],
+					       pols->len[p][i]);
 
 			break;
 		}
@@ -353,14 +552,62 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
 		if (rc) {
 			pr_notice("TPM policy %s failed, rc=%d\n",
 				  failure, rc);
-			tpm2_end_auth_session(chip);
-			return -EPERM;
+			return rc;
 		}
 	}
-
 	return 0;
 }
 
+int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols)
+{
+	int rc;
+	u32 handle;
+
+	if (pols->code[0][0] == TPM2_CC_POLICY_AUTHORIZE &&
+	    pols->auths == 1) {
+		pr_notice("TPM Key requires signed policies but has none\n");
+		return -EINVAL;
+	}
+
+	rc = tpm2_start_policy_session(chip, &handle, pols->hash);
+	if (rc)
+		return rc;
+
+	if (pols->code[0][0] == TPM2_CC_POLICY_AUTHORIZE) {
+		int p;
+
+		for (p = 1; p < pols->auths; p++) {
+			if (p != 1) {
+				/* restart policy if looping */
+				rc = tpm2_policy_restart(chip, handle);
+				if (rc)
+					goto out;
+			}
+
+			rc = tpm2_try_policy(chip, pols, handle, p);
+			if (rc) {
+				pr_notice("TPM signed policy %d failed\n", p);
+			} else {
+				pr_notice("TPM signed policy %d succeeded\n",
+					  p);
+				break;
+			}
+		}
+		if (rc)
+			/* no signed policies succeeded */
+			goto out;
+	}
+
+	rc = tpm2_try_policy(chip, pols, handle, 0);
+ out:
+	if (rc) {
+		rc = -EPERM;
+		tpm2_end_auth_session(chip);
+	}
+
+	return rc;
+}
+
 int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
 {
 	struct tpm2_policies *pols;
@@ -379,22 +626,22 @@ int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
 		if (*p == '\0' || *p == '\n')
 			continue;
 
-		pols->len[i] = strlen(p)/2;
-		if (pols->len[i] > left) {
+		pols->len[0][i] = strlen(p)/2;
+		if (pols->len[0][i] > left) {
 			res = -E2BIG;
 			goto err;
 		}
 
-		res = hex2bin(ptr, p, pols->len[i]);
+		res = hex2bin(ptr, p, pols->len[0][i]);
 		if (res)
 			goto err;
 
 		/* get command code and skip past */
-		pols->code[i] = get_unaligned_be32(ptr);
-		pols->policies[i] = ptr + 4;
-		ptr += pols->len[i];
-		left -= pols->len[i];
-		pols->len[i] -= 4;
+		pols->code[0][i] = get_unaligned_be32(ptr);
+		pols->policies[0][i] = ptr + 4;
+		ptr += pols->len[0][i];
+		left -= pols->len[0][i];
+		pols->len[0][i] -= 4;
 
 		/*
 		 * FIXME: this does leave the code embedded in dead
@@ -404,7 +651,7 @@ int tpm2_parse_policies(struct tpm2_policies **ppols, char *str)
 		i++;
 	}
 
-	pols->count = i;
+	pols->count[0] = i;
 	*ppols = pols;
 
 	return 0;
diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h
index 8ddf235b3fec..da0ab99078b8 100644
--- a/security/keys/trusted-keys/tpm2-policy.h
+++ b/security/keys/trusted-keys/tpm2-policy.h
@@ -6,17 +6,20 @@ struct tpm2_key_context {
 	u32 pub_len;
 	const u8 *priv;
 	u32 priv_len;
-	const u8 *policies[TPM2_MAX_POLICIES];
-	u32 policy_code[TPM2_MAX_POLICIES];
-	u16 policy_len[TPM2_MAX_POLICIES];
-	u8 policy_count;
+	const u8 *policies[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+	u32 policy_code[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+	u16 policy_len[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+	u8 policy_count[TPM2_MAX_AUTHS];
+	u8 auth_policies;
+	int policy_tot_len;
 };
 
 struct tpm2_policies {
-	u32 code[TPM2_MAX_POLICIES];
-	u8 *policies[TPM2_MAX_POLICIES];
-	u16 len[TPM2_MAX_POLICIES];
-	u8 count;
+	u32 code[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+	u8 *policies[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+	u16 len[TPM2_MAX_AUTHS][TPM2_MAX_POLICIES];
+	u8 count[TPM2_MAX_AUTHS];
+	u8 auths;
 	int hash;		/* crypto not TPM hash algorithm */
 	u16 hash_size;
 };
diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/trusted-keys/tpm2key.asn1
index 1684bd8f725e..c5a68b3e354f 100644
--- a/security/keys/trusted-keys/tpm2key.asn1
+++ b/security/keys/trusted-keys/tpm2key.asn1
@@ -5,12 +5,13 @@
 ---       However, the Linux asn.1 parser doesn't understand
 ---       [2] EXPLICIT SEQUENCE OF OPTIONAL
 ---       So there's an extra intermediate TPMPolicySequence
----       definition to work around this
+---       and TPMAuthPolicySequence definitions to work around this
 
 TPMKey ::= SEQUENCE {
 	type		OBJECT IDENTIFIER ({tpm2_key_type}),
 	emptyAuth	[0] EXPLICIT BOOLEAN OPTIONAL,
-	policy		[1] EXPLICIT TPMPolicySequence OPTIONAL,
+	policy		[1] EXPLICIT TPMPolicySequence OPTIONAL ({tpm2_pol_seq}),
+	authPolicy	[3] EXPLICIT TPMAuthPolicySequence OPTIONAL,
 	parent		INTEGER ({tpm2_key_parent}),
 	pubkey		OCTET STRING ({tpm2_key_pub}),
 	privkey		OCTET STRING ({tpm2_key_priv})
@@ -22,3 +23,10 @@ TPMPolicy ::= SEQUENCE {
 	commandCode		[0] EXPLICIT INTEGER ({tpm2_key_code}),
 	commandPolicy		[1] EXPLICIT OCTET STRING ({tpm2_key_policy})
 	}
+
+TPMAuthPolicySequence ::= SEQUENCE OF TPMAuthPolicy ({tpm2_pol_seq})
+
+TPMAuthPolicy ::= SEQUENCE {
+	name		[0] EXPLICIT UTF8String OPTIONAL,
+	policy		[1] EXPLICIT TPMPolicySequence
+	}
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 64c922bbc36c..e2d937e44274 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -98,38 +98,45 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
 			   u8 **buf)
 {
 	int ret;
-	struct tpm2_key_context ctx;
+	struct tpm2_key_context *ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	u8 *blob;
 
-	memset(&ctx, 0, sizeof(ctx));
+	if (!ctx)
+		return -ENOMEM;
 
-	ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob,
+	ret = asn1_ber_decoder(&tpm2key_decoder, ctx, payload->blob,
 			       payload->blob_len);
 	if (ret < 0)
-		return ret;
+		goto out;
 
-	if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE)
-		return -EINVAL;
+	if (ctx->priv_len + ctx->pub_len > MAX_BLOB_SIZE) {
+		ret = -EINVAL;
+		goto out;
+	}
 
-	blob = kmalloc(ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL);
-	if (!blob)
-		return -ENOMEM;
+	blob = kmalloc(ctx->priv_len + ctx->pub_len + 4, GFP_KERNEL);
+	if (!blob) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
-	ret = tpm2_key_policy_process(&ctx, payload);
+	ret = tpm2_key_policy_process(ctx, payload);
 	if (ret) {
 		kfree(blob);
-		return ret;
+		goto out;
 	}
 
 	*buf = blob;
-	options->keyhandle = ctx.parent;
+	options->keyhandle = ctx->parent;
 
-	memcpy(blob, ctx.priv, ctx.priv_len);
-	blob += ctx.priv_len;
+	memcpy(blob, ctx->priv, ctx->priv_len);
+	blob += ctx->priv_len;
 
-	memcpy(blob, ctx.pub, ctx.pub_len);
+	memcpy(blob, ctx->pub, ctx->pub_len);
 
-	return 0;
+ out:
+	kfree(ctx);
+	return ret;
 }
 
 int tpm2_key_parent(void *context, size_t hdrlen,
@@ -264,7 +271,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 		pols = kmalloc(POLICY_SIZE, GFP_KERNEL);
 		if (!pols)
 			return -ENOMEM;
-		pols->count = 0;
+		pols->count[0] = 0;
+		pols->auths = 1;
 		payload->policies = pols;
 		scratch = (u8 *)(pols + 1);
 	}
@@ -275,10 +283,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 		/* 4 array len */
 		const int len = 4 + options->pcrinfo_len;
 
-		i = pols->count++;
-		pols->len[i] = len;
-		pols->policies[i] = scratch;
-		pols->code[i] = TPM2_CC_POLICY_PCR;
+		i = pols->count[0]++;
+		pols->len[0][i] = len;
+		pols->policies[0][i] = scratch;
+		pols->code[0][i] = TPM2_CC_POLICY_PCR;
 
 		/* only a single TPMS_PCR_SELECTION */
 		put_unaligned_be32(1, &scratch[0]);
@@ -300,11 +308,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 		int i;
 
 		pols = payload->policies;
-		i = pols->count++;
+		i = pols->count[0]++;
 
 		/* the TPM2_PolicyPassword command has no payload */
-		pols->len[i] = 0;
-		pols->code[i] = TPM2_CC_POLICY_AUTHVALUE;
+		pols->len[0][i] = 0;
+		pols->code[0][i] = TPM2_CC_POLICY_AUTHVALUE;
 	}
 
 	if (payload->policies) {
@@ -685,6 +693,13 @@ int __weak tpm2_key_code(void *context, size_t hdrlen,
 	return -EINVAL;
 }
 
+int __weak tpm2_pol_seq(void *context, size_t hdrlen,
+			unsigned char tag,
+			const void *value, size_t vlen)
+{
+	return -EINVAL;
+}
+
 int __weak tpm2_key_policy(void *context, size_t hdrlen,
 		  unsigned char tag,
 		  const void *value, size_t vlen)
