@@ -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 */
};
@@ -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));
@@ -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)
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(-)