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 <[email protected]>
> ---
> 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