Re: [PATCH 6/8] security: keys: trusted: add PCR policy to TPM2 keys

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 2019-12-07 at 21:12 -0800, James Bottomley wrote:
> This commit adds the ability to specify a PCR lock policy to TPM2
> keys.  There is a complexity in that the creator of the key must chose
> either to use a PCR lock policy or to use authentication.  At the
> current time they can't use both due to a complexity with the way
> authentication works when policy registers are in use.  The way to
> construct a pcrinfo statement for a key is simply to use the
> TPMS_PCR_SELECT structure to specify the PCRs and follow this by a
> hash of all their values in order of ascending PCR number.
> 
> For simplicity, we require the policy name hash and the hash used for
> the PCRs to be the same.  Thus to construct a policy around the value
> of the resettable PCR 16 using the sha1 bank, first reset the pcr to
> zero giving a hash of all zeros as:
> 
> 6768033e216468247bd031a0a2d9876d79818f8f
> 
> Then the TPMS_PCR_SELECT value for PCR 16 is
> 
> 03000001
> 
> So create a new 32 byte key with a policy policy locking the key to
> this value of PCR 16 with a parent key of 81000001 would be:
> 
> keyctl new 32 keyhandle=0x81000001 hash=sha1 pcrinfo=030000016768033e216468247bd031a0a2d9876d79818f8f" @u

OK... but I've love to see a more formal definition of this binary
format, as part of the "standard" we allegedly have for the overall
ASN.1 representation.

> Signed-off-by: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx>
> ---
>  Documentation/security/keys/trusted-encrypted.rst |  25 +-
>  include/keys/trusted-type.h                       |   5 +-
>  include/linux/tpm.h                               |   5 +
>  security/keys/Kconfig                             |   2 +
>  security/keys/trusted-keys/Makefile               |   2 +-
>  security/keys/trusted-keys/tpm2-policy.c          | 344 ++++++++++++++++++++++
>  security/keys/trusted-keys/tpm2-policy.h          |  30 ++
>  security/keys/trusted-keys/tpm2key.asn1           |   4 +-
>  security/keys/trusted-keys/trusted_tpm1.c         |  32 +-
>  security/keys/trusted-keys/trusted_tpm2.c         |  77 ++++-
>  10 files changed, 478 insertions(+), 48 deletions(-)
>  create mode 100644 security/keys/trusted-keys/tpm2-policy.c
>  create mode 100644 security/keys/trusted-keys/tpm2-policy.h
> 
> diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
> index 50ac8bcd6970..1a3ca84ad3cd 100644
> --- a/Documentation/security/keys/trusted-encrypted.rst
> +++ b/Documentation/security/keys/trusted-encrypted.rst
> @@ -60,19 +60,16 @@ Usage::
>                       (40 ascii zeros)
>         blobauth=     ascii hex auth for sealed data default 0x00...
>                       (40 ascii zeros)
> -       pcrinfo=	     ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
> +       pcrinfo=      ascii hex of PCR_INFO or PCR_INFO_LONG (no
> +                     default) on TPM 1.2 and a TPMS_PCR_SELECTION
> +                     coupled with a hash of all the selected PCRs on
> +                     TPM 2.0 using the selected hash.
>         pcrlock=	     pcr number to be extended to "lock" blob
>         migratable=   0|1 indicating permission to reseal to new PCR values,
>                       default 1 (resealing allowed)
>         hash=         hash algorithm name as a string. For TPM 1.x the only
>                       allowed value is sha1. For TPM 2.x the allowed values
>                       are sha1, sha256, sha384, sha512 and sm3-256.
> -       policydigest= digest for the authorization policy. must be calculated
> -                     with the same hash algorithm as specified by the 'hash='
> -                     option.
> -       policyhandle= handle to an authorization policy session that defines the
> -                     same policy and with the same hash algorithm as was used to
> -                     seal the key.
>  
>  "keyctl print" returns an ascii hex copy of the sealed key, which is in standard
>  TPM_STORED_DATA format.  The key length for new keys are always in bytes.
> @@ -151,6 +148,20 @@ Load a trusted key from the saved blob::
>      f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
>      e4a8aea2b607ec96931e6f4d4fe563ba
>  
> +Create a trusted key on TPM 2.0 using an all zero value of PCR16 and
> +using the NV storage root 81000001 as the parent::
> +
> +    $ keyctl add trusted kmk "new 32 keyhandle=0x81000001 hash=sha1 pcrinfo=030000016768033e216468247bd031a0a2d9876d79818f8f" @u
> +
> +Note the TPMS_PCR_SELECT value for PCR 16 is 03000001 because all
> +current TPMs have 24 PCRs, so the initial 03 says there are three
> +following bytes of selection and then because the bytes are big
> +endian, 16 is bit zero of byte 2. the hash is the sha1 sum of all
> +zeros (the value of PCR 16)::
> +
> +    $ dd if=/dev/zero bs=1 count=20 2>/dev/null|sha1sum
> +    6768033e216468247bd031a0a2d9876d79818f8f
> +
>  Reseal a trusted key under new pcr values::
>  
>      $ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
> diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
> index 4728e13aada8..fc9c13802c06 100644
> --- a/include/keys/trusted-type.h
> +++ b/include/keys/trusted-type.h
> @@ -14,9 +14,11 @@
>  #define MIN_KEY_SIZE			32
>  #define MAX_KEY_SIZE			128
>  #define MAX_BLOB_SIZE			512
> -#define MAX_PCRINFO_SIZE		64
> +#define MAX_PCRINFO_SIZE		128
>  #define MAX_DIGEST_SIZE			64
>  
> +#define TPM2_MAX_POLICIES		16
> +
>  struct trusted_key_payload {
>  	struct rcu_head rcu;
>  	unsigned int key_len;
> @@ -25,6 +27,7 @@ struct trusted_key_payload {
>  	unsigned char old_format;
>  	unsigned char key[MAX_KEY_SIZE + 1];
>  	unsigned char blob[MAX_BLOB_SIZE];
> +	struct tpm2_policies *policies;
>  };
>  
>  struct trusted_key_options {
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index cd46ab27baa5..e32e9728adce 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -222,10 +222,14 @@ enum tpm2_command_codes {
>  	TPM2_CC_CONTEXT_LOAD	        = 0x0161,
>  	TPM2_CC_CONTEXT_SAVE	        = 0x0162,
>  	TPM2_CC_FLUSH_CONTEXT	        = 0x0165,
> +	TPM2_CC_POLICY_AUTHVALUE	= 0x016B,
> +	TPM2_CC_POLICY_COUNTER_TIMER	= 0x016D,
> +	TPM2_CC_START_AUTH_SESS		= 0x0176,
>  	TPM2_CC_VERIFY_SIGNATURE        = 0x0177,
>  	TPM2_CC_GET_CAPABILITY	        = 0x017A,
>  	TPM2_CC_GET_RANDOM	        = 0x017B,
>  	TPM2_CC_PCR_READ	        = 0x017E,
> +	TPM2_CC_POLICY_PCR		= 0x017F,
>  	TPM2_CC_PCR_EXTEND	        = 0x0182,
>  	TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
>  	TPM2_CC_HASH_SEQUENCE_START     = 0x0186,
> @@ -234,6 +238,7 @@ enum tpm2_command_codes {
>  };
>  
>  enum tpm2_permanent_handles {
> +	TPM2_RH_NULL		= 0x40000007,
>  	TPM2_RS_PW		= 0x40000009,
>  };
>  
> diff --git a/security/keys/Kconfig b/security/keys/Kconfig
> index dd313438fecf..6c2f2c22b284 100644
> --- a/security/keys/Kconfig
> +++ b/security/keys/Kconfig
> @@ -80,6 +80,8 @@ config TRUSTED_KEYS
>  	select CRYPTO
>  	select CRYPTO_HMAC
>  	select CRYPTO_SHA1
> +	select CRYPTO_SHA256
> +	select CRYPTO_SHA512
>  	select CRYPTO_HASH_INFO
>  	help
>  	  This option provides support for creating, sealing, and unsealing
> diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile
> index e0198641eff2..194febacf362 100644
> --- a/security/keys/trusted-keys/Makefile
> +++ b/security/keys/trusted-keys/Makefile
> @@ -5,4 +5,4 @@
>  
>  obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
>  trusted-y += trusted_tpm1.o
> -trusted-y += trusted_tpm2.o tpm2key.asn1.o
> +trusted-y += trusted_tpm2.o tpm2key.asn1.o tpm2-policy.o
> diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c
> new file mode 100644
> index 000000000000..ae83636ece37
> --- /dev/null
> +++ b/security/keys/trusted-keys/tpm2-policy.c
> @@ -0,0 +1,344 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2019 James.Bottomley@xxxxxxxxxxxxxxxxxxxxx
> + */
> +
> +#include <linux/asn1_encoder.h>
> +#include <linux/err.h>
> +#include <linux/types.h>
> +#include <linux/printk.h>
> +#include <linux/string.h>
> +#include <linux/tpm.h>
> +
> +#include <asm/unaligned.h>
> +
> +#include <crypto/hash.h>
> +
> +#include <keys/trusted-type.h>
> +#include <keys/trusted_tpm.h>
> +
> +#include "tpm2key.asn1.h"
> +#include "tpm2-policy.h"
> +
> +int tpmkey_code(void *context, size_t hdrlen,
> +		unsigned char tag,
> +		const void *value, size_t vlen)
> +{
> +	struct tpm2key_context *ctx = context;
> +	u32 code = 0;
> +	const u8 *v = value;
> +	int i;
> +
> +	for (i = 0; i < vlen; i++) {
> +		code <<= 8;
> +		code |= v[i];
> +	}
> +
> +	ctx->policy_code[ctx->policy_count] = code;
> +
> +	return 0;
> +}
> +
> +int tpmkey_policy(void *context, size_t hdrlen,
> +		  unsigned char tag,
> +		  const void *value, size_t vlen)
> +{
> +	struct tpm2key_context *ctx = context;
> +
> +	ctx->policies[ctx->policy_count] = value;
> +	ctx->policy_len[ctx->policy_count++] = vlen;
> +
> +	return 0;
> +}
> +
> +/* we only support a limited number of policy statement so
> + * make sure we don't have anything we can't support
> + */
> +static int tpm2_validate_policy(struct tpm2_policies *pols)
> +{
> +	int i;
> +
> +	if (pols->count == 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:
> +			printk(KERN_INFO "tpm2 policy 0x%x is unsupported",
> +			       pols->code[i]);
> +			return -EINVAL;
> +		}
> +	}
> +	return 0;
> +}
> +
> +/**
> + * tpmkey_process_policy - collect the policty from the context
> + * @ctx: the context to collect from
> + * @payload: the payload structure to place it in
> + *
> + * THis function sizes the policy statements and allocates space
> + * within the payload to receive them before copying them over.  It
> + * should be used after the ber decoder has completed successfully
> + */
> +int tpmkey_policy_process(struct tpm2key_context *ctx,
> +			  struct trusted_key_payload *payload)
> +{
> +	int tot_len = 0;
> +	u8 *buf;
> +	int i, ret, len = 0;
> +	struct tpm2_policies *pols;
> +
> +	if (ctx->policy_count == 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);
> +	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];
> +	}
> +	pols->count = ctx->policy_count;
> +
> +	ret = tpm2_validate_policy(pols);
> +	if (ret) {
> +		kfree(pols);
> +		payload->policies = NULL;
> +	}
> +
> +	/* capture the hash and size */
> +
> +	/* the hash is the second algorithm */
> +	pols->hash = get_unaligned_be16(&ctx->pub[2]);
> +	/* and the digest appears after the attributes */
> +	pols->hash_size = get_unaligned_be16(&ctx->pub[8]);
> +
> +	return ret;
> +}
> +
> +int tpm2_generate_policy_digest(struct tpm2_policies *pols,
> +				u32 hash, u8 *policydigest, u32 *plen)
> +{
> +	int i;
> +	struct crypto_shash *tfm;
> +	int rc;
> +
> +	if (pols->count == 0)
> +		return 0;
> +
> +	tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
> +	if (IS_ERR(tfm))
> +		return PTR_ERR(tfm);
> +
> +	rc = crypto_shash_digestsize(tfm);
> +	if (WARN(rc > MAX_DIGEST_SIZE,
> +		 "BUG: trusted key code has alg %s with digest too large (%d)",
> +		 hash_algo_name[hash], rc)) {
> +		rc = -EINVAL;
> +		goto err;
> +	}
> +	pols->hash = hash;
> +	pols->hash_size = rc;
> +	*plen = rc;
> +
> +	/* 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);
> +
> +		sdesc->tfm = tfm;
> +		rc = crypto_shash_init(sdesc);
> +		if (rc)
> +			goto err;
> +
> +		/* 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);
> +
> +		/* commands that need special handling */
> +		if (cmd == TPM2_CC_POLICY_COUNTER_TIMER) {
> +			SHASH_DESC_ON_STACK(sdesc1, tfm);
> +
> +			sdesc1->tfm = tfm;
> +
> +			/* counter timer policies are double hashed */
> +			crypto_shash_digest(sdesc1, policy, len,
> +					    digest);
> +			policy = digest;
> +			len = *plen;
> +		}
> +		crypto_shash_update(sdesc, policy, len);
> +		/* now output the intermediate to the policydigest */
> +		crypto_shash_final(sdesc, policydigest);
> +
> +	}
> +	rc = 0;
> +
> + err:
> +	crypto_free_shash(tfm);
> +	return rc;
> +}
> +
> +int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len)
> +{
> +	u8 *buf = kmalloc(2 * PAGE_SIZE, GFP_KERNEL);
> +	u8 *work = buf + PAGE_SIZE, *ptr;
> +	int i;
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < pols->count; i++) {
> +		u8 *seq_len, *tag_len;
> +		u32 cmd = pols->code[i];
> +		int l;
> +
> +		/*
> +		 * cheat a bit here: we know a policy is < 128 bytes,
> +		 * so the sequence and cons tags will only be two
> +		 * bytes long
> +		 */
> +		*work++ = _tag(UNIV, CONS, SEQ);
> +		seq_len = work++;
> +		*work++ = _tagn(CONT, CONS, 0);
> +		tag_len = work++;
> +		asn1_encode_integer(&work, cmd);
> +		*tag_len = work - tag_len - 1;
> +		*work++ = _tagn(CONT, CONS, 1);
> +		tag_len = work++;
> +		asn1_encode_octet_string(&work, pols->policies[i],
> +					 pols->len[i]);
> +		*tag_len = work - tag_len - 1;
> +		l = work - seq_len - 1;
> +		/* our assumption about policy length failed */
> +		if (WARN(l > 127,
> +			 "policy is too long: %d but must be < 128", l)) {
> +			kfree(buf);
> +			return -EINVAL;
> +		}
> +		*seq_len = l;



You're not even using your own sequence encoding here, because it only
works when you know the length in advance. How about setting *seq_len
to 0x80 to start with, for an indeterminate length.

Then in the happy case where it is <128, just go back and fill it in as
you currently do. Otherwise append 0x00 0x00 as the end marker.

None of this has to be DER, does it?

<Insert more whining about PAGE_SIZE assumptions and buffer overflows>

> +	}
> +	ptr = buf;
> +	asn1_encode_sequence(&ptr, buf + PAGE_SIZE, work - buf - PAGE_SIZE);
> +	*data = buf;
> +	*len = ptr - buf;
> +
> +	return 0;
> +}
> +
> +int tpm2_start_policy_session(struct tpm_chip *chip, u16 hash, u32 *handle)
> +{
> +	struct tpm_buf buf;
> +	int rc;
> +	int i;
> +
> +	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
> +	if (rc)
> +		return rc;
> +
> +	/* NULL salt key handle */
> +	tpm_buf_append_u32(&buf, TPM2_RH_NULL);
> +	/* NULL bind key handle */
> +	tpm_buf_append_u32(&buf, TPM2_RH_NULL);
> +	/* empty nonce caller */
> +	tpm_buf_append_u16(&buf, 20);
> +	for (i = 0; i < 20; i++)
> +		tpm_buf_append_u8(&buf, 0);
> +	/* empty auth */
> +	tpm_buf_append_u16(&buf, 0);
> +	/* session type policy */
> +	tpm_buf_append_u8(&buf, 0x01);
> +
> +	/* symmetric encryption parameters */
> +	/* symmetric algorithm  */
> +	tpm_buf_append_u16(&buf, TPM_ALG_NULL);
> +	/* hash algorithm for session */
> +	tpm_buf_append_u16(&buf, hash);
> +
> +	rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
> +	if (rc)
> +		goto out;
> +
> +	*handle = get_unaligned_be32(buf.data + TPM_HEADER_SIZE);
> + out:
> +	tpm_buf_destroy(&buf);
> +
> +	return rc <= 0 ? rc : -EPERM;
> +}
> +
> +int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols,
> +			    u32 *handle)
> +{
> +	int i, rc;
> +	const char *failure;
> +
> +	rc = tpm2_start_policy_session(chip, pols->hash, handle);
> +	if (rc)
> +		return rc;
> +
> +	for (i = 0; i < pols->count; i++) {
> +		u32 cmd = pols->code[i];
> +		struct tpm_buf buf;
> +
> +		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, cmd);
> +		if (rc)
> +			return rc;
> +
> +		tpm_buf_append_u32(&buf, *handle);
> +
> +		switch (cmd) {
> +		case TPM2_CC_POLICY_PCR:
> +			failure = "PCR";
> +			/*
> +			 * for reasons best known to the TCG we have
> +			 * to reverse the two arguments to send to the
> +			 * policy command
> +			 */
> +			tpm_buf_append_u16(&buf, pols->hash_size);
> +			tpm_buf_append(&buf, pols->policies[i] + pols->len[i] -
> +				       pols->hash_size, pols->hash_size);
> +			tpm_buf_append(&buf, pols->policies[i],
> +				       pols->len[i] - pols->hash_size);
> +			break;
> +		default:
> +			failure = "unknown policy";
> +			break;
> +		}
> +		rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
> +		tpm_buf_destroy(&buf);
> +		if (rc) {
> +			printk(KERN_NOTICE "TPM policy %s failed, rc=%d\n",
> +			       failure, rc);
> +			tpm2_flush_context(chip, *handle);
> +			*handle = 0;
> +			return -EPERM;
> +		}
> +	}
> +	return 0;
> +}
> diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h
> new file mode 100644
> index 000000000000..152c948743f3
> --- /dev/null
> +++ b/security/keys/trusted-keys/tpm2-policy.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +struct tpm2key_context {
> +	u32 parent;
> +	const u8 *pub;
> +	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;
> +};
> +
> +struct tpm2_policies {
> +	u32 code[TPM2_MAX_POLICIES];
> +	u8 *policies[TPM2_MAX_POLICIES];
> +	u16 len[TPM2_MAX_POLICIES];
> +	u8 count;
> +	u16 hash;
> +	u16 hash_size;
> +};
> +
> +int tpmkey_policy_process(struct tpm2key_context *ctx,
> +			  struct trusted_key_payload *payload);
> +int tpm2_generate_policy_digest(struct tpm2_policies *pols, u32 hash,
> +				u8 *policydigest, u32 *plen);
> +int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len);
> +int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols,
> +			    u32 *handle);
> diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/trusted-keys/tpm2key.asn1
> index 1851b7c80f08..f930fd812db3 100644
> --- a/security/keys/trusted-keys/tpm2key.asn1
> +++ b/security/keys/trusted-keys/tpm2key.asn1
> @@ -18,6 +18,6 @@ TPMKey ::= SEQUENCE {
>  TPMPolicySequence ::= SEQUENCE OF TPMPolicy
>  
>  TPMPolicy ::= SEQUENCE {
> -	commandCode		[0] EXPLICIT INTEGER,
> -	commandPolicy		[1] EXPLICIT OCTET STRING
> +	commandCode		[0] EXPLICIT INTEGER ({tpmkey_code}),
> +	commandPolicy		[1] EXPLICIT OCTET STRING ({tpmkey_policy})
>  	}
> diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
> index d744a0d1cb89..6290e611b632 100644
> --- a/security/keys/trusted-keys/trusted_tpm1.c
> +++ b/security/keys/trusted-keys/trusted_tpm1.c
> @@ -707,8 +707,6 @@ enum {
>  	Opt_keyhandle, Opt_keyauth, Opt_blobauth,
>  	Opt_pcrinfo, Opt_pcrlock, Opt_migratable,
>  	Opt_hash,
> -	Opt_policydigest,
> -	Opt_policyhandle,
>  };
>  
>  static const match_table_t key_tokens = {
> @@ -722,8 +720,6 @@ static const match_table_t key_tokens = {
>  	{Opt_pcrlock, "pcrlock=%s"},
>  	{Opt_migratable, "migratable=%s"},
>  	{Opt_hash, "hash=%s"},
> -	{Opt_policydigest, "policydigest=%s"},
> -	{Opt_policyhandle, "policyhandle=%s"},
>  	{Opt_err, NULL}
>  };
>  
> @@ -738,7 +734,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
>  	unsigned long handle;
>  	unsigned long lock;
>  	unsigned long token_mask = 0;
> -	unsigned int digest_len;
>  	int i;
>  	int tpm2;
>  
> @@ -801,8 +796,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
>  			opt->pcrlock = lock;
>  			break;
>  		case Opt_hash:
> -			if (test_bit(Opt_policydigest, &token_mask))
> -				return -EINVAL;
>  			for (i = 0; i < HASH_ALGO__LAST; i++) {
>  				if (!strcmp(args[0].from, hash_algo_name[i])) {
>  					opt->hash = i;
> @@ -816,24 +809,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
>  				return -EINVAL;
>  			}
>  			break;
> -		case Opt_policydigest:
> -			digest_len = hash_digest_size[opt->hash];
> -			if (!tpm2 || strlen(args[0].from) != (2 * digest_len))
> -				return -EINVAL;
> -			res = hex2bin(opt->policydigest, args[0].from,
> -				      digest_len);
> -			if (res < 0)
> -				return -EINVAL;
> -			opt->policydigest_len = digest_len;
> -			break;
> -		case Opt_policyhandle:
> -			if (!tpm2)
> -				return -EINVAL;
> -			res = kstrtoul(args[0].from, 16, &handle);
> -			if (res < 0)
> -				return -EINVAL;
> -			opt->policyhandle = handle;
> -			break;
>  		default:
>  			return -EINVAL;
>  		}
> @@ -1045,6 +1020,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
>  	struct trusted_key_payload *p;
>  
>  	p = container_of(rcu, struct trusted_key_payload, rcu);
> +	kzfree(p->policies);
>  	kzfree(p);
>  }
>  
> @@ -1164,7 +1140,11 @@ static long trusted_read(const struct key *key, char __user *buffer,
>   */
>  static void trusted_destroy(struct key *key)
>  {
> -	kzfree(key->payload.data[0]);
> +	struct trusted_key_payload *p;
> +
> +	p = key->payload.data[0];
> +	kzfree(p->policies);
> +	kzfree(p);
>  }
>  
>  struct key_type key_type_trusted = {
> diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> index a34ab6f90f76..6d0d427bc5c5 100644
> --- a/security/keys/trusted-keys/trusted_tpm2.c
> +++ b/security/keys/trusted-keys/trusted_tpm2.c
> @@ -17,6 +17,7 @@
>  #include <asm/unaligned.h>
>  
>  #include "tpm2key.asn1.h"
> +#include "tpm2-policy.h"
>  
>  static struct tpm2_hash tpm2_hash_map[] = {
>  	{HASH_ALGO_SHA1, TPM_ALG_SHA1},
> @@ -55,6 +56,20 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
>  		asn1_encode_boolean(&w, true);
>  		asn1_encode_tag(&work, 0, bool, w - bool);
>  	}
> +	if (payload->policies) {
> +		u8 *encoded_pols;
> +		u32 encoded_pol_len;
> +		int ret;
> +
> +		ret = tpm2_encode_policy(payload->policies, &encoded_pols,
> +					 &encoded_pol_len);
> +
> +		if (!ret) {
> +			asn1_encode_tag(&work, 1, encoded_pols,
> +					encoded_pol_len);
> +			kfree(encoded_pols);
> +		}
> +	}
>  	asn1_encode_integer(&work, options->keyhandle);
>  	asn1_encode_octet_string(&work, pub, pub_len);
>  	asn1_encode_octet_string(&work, priv, priv_len);
> @@ -65,14 +80,6 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
>  	return work1 - payload->blob;
>  }
>  
> -struct tpm2key_context {
> -	u32 parent;
> -	const u8 *pub;
> -	u32 pub_len;
> -	const u8 *priv;
> -	u32 priv_len;
> -};
> -
>  static int tpm2_key_decode(struct trusted_key_payload *payload,
>  			   struct trusted_key_options *options,
>  			   u8 **buf)
> @@ -81,6 +88,8 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
>  	struct tpm2key_context ctx;
>  	u8 *blob;
>  
> +	memset(&ctx, 0, sizeof(ctx));
> +
>  	ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob,
>  			       payload->blob_len);
>  	if (ret < 0)
> @@ -93,6 +102,12 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
>  	if (!blob)
>  		return -ENOMEM;
>  
> +	ret = tpmkey_policy_process(&ctx, payload);
> +	if (ret) {
> +		kfree(blob);
> +		return ret;
> +	}
> +
>  	*buf = blob;
>  	options->keyhandle = ctx.parent;
>  	put_unaligned_be16(ctx.priv_len, blob);
> @@ -224,6 +239,37 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
>  	if (!options->keyhandle)
>  		return -EINVAL;
>  
> +	if (options->pcrinfo_len != 0) {
> +		struct tpm2_policies *pols;
> +		static u8 *scratch;
> +		/* 4 array len, 2 hash alg */
> +		const int len = 4 + 2 + options->pcrinfo_len;
> +
> +		pols = kmalloc(sizeof(*pols) + len, GFP_KERNEL);
> +		if (!pols)
> +			return -ENOMEM;
> +
> +		pols->count = 1;
> +		pols->len[0] = len;
> +		scratch = (u8 *)(pols + 1);
> +		pols->policies[0] = scratch;
> +		pols->code[0] = TPM2_CC_POLICY_PCR;
> +
> +		put_unaligned_be32(1, &scratch[0]);
> +		put_unaligned_be16(hash, &scratch[4]);
> +		memcpy(&scratch[6], options->pcrinfo, options->pcrinfo_len);
> +		payload->policies = pols;
> +	}
> +
> +	if (payload->policies) {
> +		rc = tpm2_generate_policy_digest(payload->policies,
> +						 options->hash,
> +						 options->policydigest,
> +						 &options->policydigest_len);
> +		if (rc)
> +			return rc;
> +	}
> +
>  	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
>  	if (rc)
>  		return rc;
> @@ -421,21 +467,30 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
>  	u16 data_len;
>  	u8 *data;
>  	int rc;
> +	u32 policyhandle = 0;
>  
>  	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
>  	if (rc)
>  		return rc;
>  
> +	if (payload->policies) {
> +		rc = tpm2_get_policy_session(chip, payload->policies,
> +					     &policyhandle);
> +		if (rc)
> +			return rc;
> +	}
> +
>  	tpm_buf_append_u32(&buf, blob_handle);
>  	tpm2_buf_append_auth(&buf,
> -			     options->policyhandle ?
> -			     options->policyhandle : TPM2_RS_PW,
> +			     policyhandle ?
> +			     policyhandle : TPM2_RS_PW,
>  			     NULL /* nonce */, 0,
>  			     TPM2_SA_CONTINUE_SESSION,
>  			     options->blobauth /* hmac */,
> -			     TPM_DIGEST_SIZE);
> +			     policyhandle ? 0 : TPM_DIGEST_SIZE);
>  
>  	rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
> +	tpm2_flush_context(chip, policyhandle);
>  	if (rc > 0)
>  		rc = -EPERM;
>  

Attachment: smime.p7s
Description: S/MIME cryptographic signature


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux