On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote: > Signed policy allows key policies to be modified after the TPM key is > created, provided the new policy is signed with a private key whose > public part is encoded into the initial policy. How this works is > described in > > https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html > > Since this means that the key structure now contains public keys and > signatures, the maximum blob size has to be expanded simply to > accommodate a key with several policies. The code assumes (as does > all other signed policy engines) that the first policy is the most > likely one to succeed, so it tries all the available signed policies > in first to last order and loads the key when one of them succeeds. > > This code allows the kernel to process signed policy keys correctly, > it does not allow the kernel to create them. > > Signed-off-by: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx> > --- > drivers/char/tpm/tpm2-sessions.c | 6 + > include/keys/trusted-type.h | 3 +- > include/linux/tpm.h | 6 + > security/keys/trusted-keys/tpm2-policy.c | 473 ++++++++++++++++------ > security/keys/trusted-keys/tpm2-policy.h | 19 +- > security/keys/trusted-keys/tpm2key.asn1 | 12 +- > security/keys/trusted-keys/trusted_tpm2.c | 63 +-- > 7 files changed, 434 insertions(+), 148 deletions(-) > > 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; > +} Please open code. > +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) BR, Jarkko