[v3,9/9] security: keys: trusted: add password based authorizations to policy keys
diff mbox series

Message ID 20191218063142.23033-10-James.Bottomley@HansenPartnership.com
State New
Headers show
Series
  • TPM 2.0 trusted keys with attached policy
Related show

Commit Message

James Bottomley Dec. 18, 2019, 6:31 a.m. UTC
TPM 2.0 has a trick where you can turn off the usual HMAC password
session requirement using TPM2_PolicyPassword, so everywhere we see a
TPM2_PolicyAuthValue (which does require HMAC password), we replace
with the TPM2_PolicyPassword command instead.  This allows us to use
passwords with TPM 2.0 trusted keys that also have a policy.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
 include/linux/tpm.h                       |  1 +
 security/keys/trusted-keys/tpm2-policy.c  | 16 ++++++++++++-
 security/keys/trusted-keys/trusted_tpm2.c | 38 ++++++++++++++++++++++++++++---
 3 files changed, 51 insertions(+), 4 deletions(-)

Patch
diff mbox series

diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index e32e9728adce..5026a06977e1 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -233,6 +233,7 @@  enum tpm2_command_codes {
 	TPM2_CC_PCR_EXTEND	        = 0x0182,
 	TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
 	TPM2_CC_HASH_SEQUENCE_START     = 0x0186,
+	TPM2_CC_POLICY_PASSWORD		= 0x018c,
 	TPM2_CC_CREATE_LOADED           = 0x0191,
 	TPM2_CC_LAST		        = 0x0193, /* Spec 1.36 */
 };
diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
index 5698475b30cb..56b99419ce90 100644
--- a/security/keys/trusted-keys/tpm2-policy.c
+++ b/security/keys/trusted-keys/tpm2-policy.c
@@ -193,7 +193,8 @@  int tpm2_generate_policy_digest(struct tpm2_policies *pols,
 			policy = digest;
 			len = *plen;
 		}
-		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);
 
@@ -303,6 +304,16 @@  int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols,
 		u32 cmd = pols->code[i];
 		struct tpm_buf buf;
 
+		if (cmd == TPM2_CC_POLICY_AUTHVALUE)
+			/*
+			 * both PolicyAuthValue and PolicyPassword
+			 * hash to the same thing, but one triggers
+			 * HMAC authentication and the other simple
+			 * authentication.  Since we have no HMAC
+			 * code, we're choosing the simple
+			 */
+			cmd = TPM2_CC_POLICY_PASSWORD;
+
 		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, cmd);
 		if (rc)
 			return rc;
@@ -344,6 +355,9 @@  int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols,
 		}
 		default:
 			failure = "unknown policy";
+			if (pols->len[i])
+				tpm_buf_append(&buf, pols->policies[i],
+					       pols->len[i]);
 			break;
 		}
 		rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 82004273f8d4..085d09c4a4ed 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -53,7 +53,7 @@  static int tpm2_key_encode(struct trusted_key_payload *payload,
 
 	asn1_encode_oid(&work, &work_len, tpm2key_oid,
 			asn1_oid_len(tpm2key_oid));
-	if (options->blobauth[0] == 0) {
+	if (options->blobauth_len == 0) {
 		unsigned char bool[3], *w = bool;
 		int bool_len = sizeof(bool);
 		/* tag 0 is emptyAuth */
@@ -247,6 +247,7 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 	u32 flags;
 	int i;
 	int rc;
+	static const int POLICY_SIZE = 2 * PAGE_SIZE;
 
 	for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
 		if (options->hash == tpm2_hash_map[i].crypto_id) {
@@ -267,7 +268,7 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 		/* 4 array len, 2 hash alg */
 		const int len = 4 + 2 + options->pcrinfo_len;
 
-		pols = kmalloc(sizeof(*pols) + len, GFP_KERNEL);
+		pols = kmalloc(POLICY_SIZE, GFP_KERNEL);
 		if (!pols)
 			return -ENOMEM;
 
@@ -288,6 +289,37 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 		return -EINVAL;
 	}
 
+	/*
+	 * if we already have a policy, we have to add authorization
+	 * to it.  If we don't, we can simply follow the usual
+	 * non-policy route.
+	 */
+	if (options->blobauth_len != 0 && payload->policies) {
+		struct tpm2_policies *pols;
+		static u8 *scratch;
+		int i;
+		bool found = false;
+
+		pols = payload->policies;
+
+		/* make sure it's not already in policy */
+		for (i = 0; i < pols->count; i++) {
+			if (pols->code[i] == TPM2_CC_POLICY_AUTHVALUE) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			i = pols->count++;
+			scratch = pols->policies[i - 1] + pols->len[i - 1];
+			/* the TPM2_PolicyPassword command has no payload */
+			pols->policies[i] = scratch;
+			pols->len[i] = 0;
+			pols->code[i] = TPM2_CC_POLICY_AUTHVALUE;
+		}
+	}
+
 	if (payload->policies) {
 		rc = tpm2_generate_policy_digest(payload->policies,
 						 options->hash,
@@ -526,7 +558,7 @@  static int tpm2_unseal_cmd(struct tpm_chip *chip,
 			     NULL /* nonce */, 0,
 			     TPM2_SA_CONTINUE_SESSION,
 			     options->blobauth /* hmac */,
-			     TPM_DIGEST_SIZE);
+			     options->blobauth_len);
 
 	rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
 	if (payload->policies)