Re: [PATCH 2/6] tpm: add policy sessions

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

 



Please rewrite short summray to something understandable. Perhaps
"tpm: authenticated policy sessions for TPM2" would be more to
the point.

On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote:
> TPM security uses hmac sessions to implement data protection and
  TPM2 sessions use HMAC ...

> integrity.  The hash algorithm of these sessions isn't exposed to the
> user (and doesn't depend on the object being authorized) so it is

Either remove the text in parentheses or rewrite it as a separate
sentence if it is relevant.

> currently fixed at a safe sha256.  Policy sessions may also be used
                            SHA-256

> for the same purpose and in addition, they can be used to express a
> rich policy language.  However, the session hash of policy sessions is
> defined to be the same as the name algorithm of the TPM object they're
> operating on, so we must update the session code to allow a variable

No information about the TPM object in question, which means no
rationale to bundle variable digest size to this patch. I know that
null key uses SHA-256 as name algorithm:

	/* name algorithm */
	if (val != TPM_ALG_SHA256)
		return -EINVAL;
	val = tpm_buf_read_u32(buf, &offset_t);

Please state what other TPM object might be in question.

Also, describe your changes in imperative form. This is also stated in
SubmittingPatches.

> hash algorithm instead of the fixed sha256 one.  Note that while this
> affects most of the code, the KDFe algorithm still uses a fixed sha256
> algorithm because it is define to follow the name algorithm of the
> salt encryption key (which is a key we derive from the null seed and
> set its name algorithm to sha256).

Split the long description to two paragraphs: one that describes the
motivation and one that describes the solution.

>
> Signed-off-by: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx>
> ---
>  drivers/char/tpm/tpm2-sessions.c | 307 +++++++++++++++++++------------
>  include/linux/tpm.h              |   6 +
>  2 files changed, 200 insertions(+), 113 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
> index ea8860661876..63c175b2165c 100644
> --- a/drivers/char/tpm/tpm2-sessions.c
> +++ b/drivers/char/tpm/tpm2-sessions.c
> @@ -105,10 +105,10 @@ struct tpm2_auth {
>  	/*
>  	 * the size here is variable and set by the size of our_nonce
>  	 * which must be between 16 and the name hash length. we set
> -	 * the maximum sha256 size for the greatest protection
> +	 * the maximum hash size for the greatest protection
>  	 */
> -	u8 our_nonce[SHA256_DIGEST_SIZE];
> -	u8 tpm_nonce[SHA256_DIGEST_SIZE];
> +	u8 our_nonce[HASH_MAX_DIGESTSIZE];
> +	u8 tpm_nonce[HASH_MAX_DIGESTSIZE];
>  	/*
>  	 * the salt is only used across the session command/response
>  	 * after that it can be used as a scratch area
> @@ -119,17 +119,15 @@ struct tpm2_auth {
>  		u8 scratch[AES_KEY_BYTES + AES_BLOCK_SIZE];
>  	};
>  	/*
> -	 * the session key and passphrase are the same size as the
> -	 * name digest (sha256 again).  The session key is constant
> -	 * for the use of the session and the passphrase can change
> -	 * with every invocation.
> -	 *
> -	 * Note: these fields must be adjacent and in this order
> -	 * because several HMAC/KDF schemes use the combination of the
> -	 * session_key and passphrase.
> +	 * The session_key and passphrase must be next to each other
> +	 * to allow us to hash them as a unit.  With a variable hash,
> +	 * this means that the passphrase must occur exactly one hash
> +	 * size after the session_key, so make session_key house both
> +	 * and passphrase is a pointer into where the passphrase
> +	 * begins in session_key.
>  	 */
> -	u8 session_key[SHA256_DIGEST_SIZE];
> -	u8 passphrase[SHA256_DIGEST_SIZE];
> +	u8 session_key[2*HASH_MAX_DIGESTSIZE];
> +	u8 *passphrase;
>  	int passphrase_len;
>  	struct crypto_aes_ctx aes_ctx;
>  	/* saved session attributes: */
> @@ -142,7 +140,8 @@ struct tpm2_auth {
>  	 * we must compute and remember
>  	 */
>  	u32 name_h[AUTH_MAX_NAMES];
> -	u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
> +	u8 name[AUTH_MAX_NAMES][2 + HASH_MAX_DIGESTSIZE];
> +	struct crypto_shash *tfm;
>  };
>  
>  /*
> @@ -161,34 +160,36 @@ static u8 name_size(const u8 *name)
>  }
>  
>  /*
> - * It turns out the crypto hmac(sha256) is hard for us to consume
> + * It turns out the crypto hmac(shaX) is hard for us to consume
>   * because it assumes a fixed key and the TPM seems to change the key
>   * on every operation, so we weld the hmac init and final functions in
>   * here to give it the same usage characteristics as a regular hash
>   */
> -static void tpm2_hmac_init(struct sha256_state *sctx, u8 *key, u32 key_len)
> +static void tpm2_hmac_init(struct shash_desc *sdesc, u8 *key, u32 key_len)
>  {
> -	u8 pad[SHA256_BLOCK_SIZE];
> +	const int block_size = crypto_shash_blocksize(sdesc->tfm);
> +	u8 pad[SHA512_BLOCK_SIZE];
>  	int i;
>  
> -	sha256_init(sctx);
> -	for (i = 0; i < sizeof(pad); i++) {
> +	crypto_shash_init(sdesc);
> +	for (i = 0; i < block_size; i++) {
>  		if (i < key_len)
>  			pad[i] = key[i];
>  		else
>  			pad[i] = 0;
>  		pad[i] ^= HMAC_IPAD_VALUE;
>  	}
> -	sha256_update(sctx, pad, sizeof(pad));
> +	crypto_shash_update(sdesc, pad, block_size);
>  }
>  
> -static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len,
> +static void tpm2_hmac_final(struct shash_desc *sdesc, u8 *key, u32 key_len,
>  			    u8 *out)
>  {
> -	u8 pad[SHA256_BLOCK_SIZE];
> +	const int block_size = crypto_shash_blocksize(sdesc->tfm);
> +	u8 pad[SHA512_BLOCK_SIZE];
>  	int i;
>  
> -	for (i = 0; i < sizeof(pad); i++) {
> +	for (i = 0; i < block_size; i++) {
>  		if (i < key_len)
>  			pad[i] = key[i];
>  		else
> @@ -197,35 +198,42 @@ static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len,
>  	}
>  
>  	/* collect the final hash;  use out as temporary storage */
> -	sha256_final(sctx, out);
> +	crypto_shash_final(sdesc, out);
>  
> -	sha256_init(sctx);
> -	sha256_update(sctx, pad, sizeof(pad));
> -	sha256_update(sctx, out, SHA256_DIGEST_SIZE);
> -	sha256_final(sctx, out);
> +	crypto_shash_init(sdesc);
> +	crypto_shash_update(sdesc, pad, block_size);
> +	crypto_shash_update(sdesc, out, crypto_shash_digestsize(sdesc->tfm));
> +	crypto_shash_final(sdesc, out);
>  }
>  
>  /*
> - * assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but
> + * assume hash sha256 and nonces u, v of hash digest size but
>   * otherwise standard tpm2_KDFa.  Note output is in bytes not bits.
>   */
>  static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
> -		      u8 *v, u32 bytes, u8 *out)
> +		      u8 *v, u32 bytes, u8 *out, struct shash_desc *sdesc)
>  {
>  	u32 counter = 1;
>  	const __be32 bits = cpu_to_be32(bytes * 8);
> +	const int digest_size = crypto_shash_digestsize(sdesc->tfm);
>  
>  	while (bytes > 0) {
> -		struct sha256_state sctx;
>  		__be32 c = cpu_to_be32(counter);
>  
> -		tpm2_hmac_init(&sctx, key, key_len);
> -		sha256_update(&sctx, (u8 *)&c, sizeof(c));
> -		sha256_update(&sctx, label, strlen(label)+1);
> -		sha256_update(&sctx, u, SHA256_DIGEST_SIZE);
> -		sha256_update(&sctx, v, SHA256_DIGEST_SIZE);
> -		sha256_update(&sctx, (u8 *)&bits, sizeof(bits));
> -		tpm2_hmac_final(&sctx, key, key_len, out);
> +		tpm2_hmac_init(sdesc, key, key_len);
> +		crypto_shash_update(sdesc, (u8 *)&c, sizeof(c));
> +		crypto_shash_update(sdesc, label, strlen(label)+1);
> +		crypto_shash_update(sdesc, u, digest_size);
> +		crypto_shash_update(sdesc, v, digest_size);
> +		crypto_shash_update(sdesc, (u8 *)&bits, sizeof(bits));
> +		if (bytes < digest_size) {
> +			u8 buf[HASH_MAX_DIGESTSIZE];
> +
> +			tpm2_hmac_final(sdesc, key, key_len, buf);
> +			memcpy(out, buf, bytes);
> +		} else {
> +			tpm2_hmac_final(sdesc, key, key_len, out);
> +		}
>  
>  		bytes -= SHA256_DIGEST_SIZE;
>  		counter++;
> @@ -236,9 +244,9 @@ static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
>  /*
>   * Somewhat of a bastardization of the real KDFe.  We're assuming
>   * we're working with known point sizes for the input parameters and
> - * the hash algorithm is fixed at sha256.  Because we know that the
> - * point size is 32 bytes like the hash size, there's no need to loop
> - * in this KDF.
> + * the hash algorithm is fixed at sha256 (name algorithm of the
> + * encrypting key).  Because we know that the point size is 32 bytes
> + * like the hash size, there's no need to loop in this KDF.
>   */
>  static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v,
>  		      u8 *out)
> @@ -370,9 +378,10 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
>  				 u8 attributes, u8 *passphrase,
>  				 int passphrase_len)
>  {
> -	u8 nonce[SHA256_DIGEST_SIZE];
> +	u8 nonce[HASH_MAX_DIGESTSIZE];
>  	u32 len;
>  	struct tpm2_auth *auth = chip->auth;
> +	const int digest_size = crypto_shash_digestsize(auth->tfm);
>  
>  	/*
>  	 * The Architecture Guide requires us to strip trailing zeros
> @@ -384,8 +393,14 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
>  
>  	auth->attrs = attributes;
>  	auth->passphrase_len = passphrase_len;
> -	if (passphrase_len)
> +	if (passphrase_len) {
> +		/*
> +		 * place the passphrase immediately adjacent to
> +		 * the session key
> +		 */
> +		auth->passphrase = auth->session_key + digest_size;
>  		memcpy(auth->passphrase, passphrase, passphrase_len);
> +	}
>  
>  	if (auth->session != tpm_buf_length(buf)) {
>  		/* we're not the first session */
> @@ -396,23 +411,23 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
>  		}
>  
>  		/* add our new session */
> -		len += 9 + 2 * SHA256_DIGEST_SIZE;
> +		len += 9 + 2 * digest_size;
>  		put_unaligned_be32(len, &buf->data[auth->session]);
>  	} else {
> -		tpm_buf_append_u32(buf, 9 + 2 * SHA256_DIGEST_SIZE);
> +		tpm_buf_append_u32(buf, 9 + 2 * digest_size);
>  	}
>  
>  	/* random number for our nonce */
> -	get_random_bytes(nonce, sizeof(nonce));
> -	memcpy(auth->our_nonce, nonce, sizeof(nonce));
> +	get_random_bytes(nonce, digest_size);
> +	memcpy(auth->our_nonce, nonce, digest_size);
>  	tpm_buf_append_u32(buf, auth->handle);
>  	/* our new nonce */
> -	tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
> -	tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
> +	tpm_buf_append_u16(buf, digest_size);
> +	tpm_buf_append(buf, nonce, digest_size);
>  	tpm_buf_append_u8(buf, auth->attrs);
>  	/* and put a placeholder for the hmac */
> -	tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
> -	tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
> +	tpm_buf_append_u16(buf, digest_size);
> +	tpm_buf_append(buf, nonce, digest_size);
>  }
>  EXPORT_SYMBOL(tpm_buf_append_hmac_session);
>  
> @@ -443,8 +458,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
>  	off_t offset_s = TPM_HEADER_SIZE, offset_p;
>  	u8 *hmac = NULL;
>  	u32 attrs;
> -	u8 cphash[SHA256_DIGEST_SIZE];
> -	struct sha256_state sctx;
> +	const int digest_size = crypto_shash_digestsize(auth->tfm);
> +	u8 cphash[HASH_MAX_DIGESTSIZE];
> +	SHASH_DESC_ON_STACK(sdesc, auth->tfm);
> +
> +	sdesc->tfm = auth->tfm;
>  
>  	/* save the command code in BE format */
>  	auth->ordinal = head->ordinal;
> @@ -515,10 +533,10 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
>  		u16 len;
>  
>  		/* need key and IV */
> -		tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
> +		tpm2_KDFa(auth->session_key, digest_size
>  			  + auth->passphrase_len, "CFB", auth->our_nonce,
>  			  auth->tpm_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
> -			  auth->scratch);
> +			  auth->scratch, sdesc);
>  
>  		len = tpm_buf_read_u16(buf, &offset_p);
>  		aes_expandkey(&auth->aes_ctx, auth->scratch, AES_KEY_BYTES);
> @@ -529,9 +547,10 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
>  		offset_p -= 2;
>  	}
>  
> -	sha256_init(&sctx);
> +	crypto_shash_init(sdesc);
>  	/* ordinal is already BE */
> -	sha256_update(&sctx, (u8 *)&head->ordinal, sizeof(head->ordinal));
> +	crypto_shash_update(sdesc, (u8 *)&head->ordinal,
> +			    sizeof(head->ordinal));
>  	/* add the handle names */
>  	for (i = 0; i < handles; i++) {
>  		enum tpm2_mso_type mso = tpm2_handle_mso(auth->name_h[i]);
> @@ -539,27 +558,27 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
>  		if (mso == TPM2_MSO_PERSISTENT ||
>  		    mso == TPM2_MSO_VOLATILE ||
>  		    mso == TPM2_MSO_NVRAM) {
> -			sha256_update(&sctx, auth->name[i],
> -				      name_size(auth->name[i]));
> +			crypto_shash_update(sdesc, auth->name[i],
> +					    name_size(auth->name[i]));
>  		} else {
>  			__be32 h = cpu_to_be32(auth->name_h[i]);
>  
> -			sha256_update(&sctx, (u8 *)&h, 4);
> +			crypto_shash_update(sdesc, (u8 *)&h, 4);
>  		}
>  	}
>  	if (offset_s != tpm_buf_length(buf))
> -		sha256_update(&sctx, &buf->data[offset_s],
> -			      tpm_buf_length(buf) - offset_s);
> -	sha256_final(&sctx, cphash);
> +		crypto_shash_update(sdesc, &buf->data[offset_s],
> +				    tpm_buf_length(buf) - offset_s);
> +	crypto_shash_final(sdesc, cphash);
>  
>  	/* now calculate the hmac */
> -	tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
> +	tpm2_hmac_init(sdesc, auth->session_key, digest_size
>  		       + auth->passphrase_len);
> -	sha256_update(&sctx, cphash, sizeof(cphash));
> -	sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
> -	sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
> -	sha256_update(&sctx, &auth->attrs, 1);
> -	tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
> +	crypto_shash_update(sdesc, cphash, digest_size);
> +	crypto_shash_update(sdesc, auth->our_nonce, digest_size);
> +	crypto_shash_update(sdesc, auth->tpm_nonce, digest_size);
> +	crypto_shash_update(sdesc, &auth->attrs, 1);
> +	tpm2_hmac_final(sdesc, auth->session_key, digest_size
>  			+ auth->passphrase_len, hmac);
>  }
>  EXPORT_SYMBOL(tpm_buf_fill_hmac_session);
> @@ -695,12 +714,15 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
>  	struct tpm_header *head = (struct tpm_header *)buf->data;
>  	struct tpm2_auth *auth = chip->auth;
>  	off_t offset_s, offset_p;
> -	u8 rphash[SHA256_DIGEST_SIZE];
> +	const int digest_size = crypto_shash_digestsize(auth->tfm);
> +	u8 rphash[HASH_MAX_DIGESTSIZE];
>  	u32 attrs;
> -	struct sha256_state sctx;
>  	u16 tag = be16_to_cpu(head->tag);
>  	u32 cc = be32_to_cpu(auth->ordinal);
>  	int parm_len, len, i, handles;
> +	SHASH_DESC_ON_STACK(sdesc, auth->tfm);
> +
> +	sdesc->tfm = auth->tfm;
>  
>  	if (auth->session >= TPM_HEADER_SIZE) {
>  		WARN(1, "tpm session not filled correctly\n");
> @@ -739,7 +761,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
>  	len = tpm_buf_read_u16(buf, &offset_s);
>  	if (offset_s + len > tpm_buf_length(buf))
>  		goto out;
> -	if (len != SHA256_DIGEST_SIZE)
> +	if (len != digest_size)
>  		goto out;
>  	memcpy(auth->tpm_nonce, &buf->data[offset_s], len);
>  	offset_s += len;
> @@ -747,32 +769,32 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
>  	len = tpm_buf_read_u16(buf, &offset_s);
>  	if (offset_s + len != tpm_buf_length(buf))
>  		goto out;
> -	if (len != SHA256_DIGEST_SIZE)
> +	if (len != digest_size)
>  		goto out;
>  	/*
>  	 * offset_s points to the HMAC. now calculate comparison, beginning
>  	 * with rphash
>  	 */
> -	sha256_init(&sctx);
> +	crypto_shash_init(sdesc);
>  	/* yes, I know this is now zero, but it's what the standard says */
> -	sha256_update(&sctx, (u8 *)&head->return_code,
> -		      sizeof(head->return_code));
> +	crypto_shash_update(sdesc, (u8 *)&head->return_code,
> +			    sizeof(head->return_code));
>  	/* ordinal is already BE */
> -	sha256_update(&sctx, (u8 *)&auth->ordinal, sizeof(auth->ordinal));
> -	sha256_update(&sctx, &buf->data[offset_p], parm_len);
> -	sha256_final(&sctx, rphash);
> +	crypto_shash_update(sdesc, (u8 *)&auth->ordinal, sizeof(auth->ordinal));
> +	crypto_shash_update(sdesc, &buf->data[offset_p], parm_len);
> +	crypto_shash_final(sdesc, rphash);
>  
>  	/* now calculate the hmac */
> -	tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
> +	tpm2_hmac_init(sdesc, auth->session_key, digest_size
>  		       + auth->passphrase_len);
> -	sha256_update(&sctx, rphash, sizeof(rphash));
> -	sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
> -	sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
> -	sha256_update(&sctx, &auth->attrs, 1);
> +	crypto_shash_update(sdesc, rphash, digest_size);
> +	crypto_shash_update(sdesc, auth->tpm_nonce, digest_size);
> +	crypto_shash_update(sdesc, auth->our_nonce, digest_size);
> +	crypto_shash_update(sdesc, &auth->attrs, 1);
>  	/* we're done with the rphash, so put our idea of the hmac there */
> -	tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
> +	tpm2_hmac_final(sdesc, auth->session_key, digest_size
>  			+ auth->passphrase_len, rphash);
> -	if (memcmp(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE) == 0) {
> +	if (memcmp(rphash, &buf->data[offset_s], digest_size) == 0) {
>  		rc = 0;
>  	} else {
>  		dev_err(&chip->dev, "TPM: HMAC check failed\n");
> @@ -782,10 +804,10 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
>  	/* now do response decryption */
>  	if (auth->attrs & TPM2_SA_ENCRYPT) {
>  		/* need key and IV */
> -		tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
> +		tpm2_KDFa(auth->session_key, digest_size
>  			  + auth->passphrase_len, "CFB", auth->tpm_nonce,
>  			  auth->our_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
> -			  auth->scratch);
> +			  auth->scratch, sdesc);
>  
>  		len = tpm_buf_read_u16(buf, &offset_p);
>  		aes_expandkey(&auth->aes_ctx, auth->scratch, AES_KEY_BYTES);
> @@ -799,6 +821,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
>  		if (rc)
>  			/* manually close the session if it wasn't consumed */
>  			tpm2_flush_context(chip, auth->handle);
> +		crypto_free_shash(auth->tfm);
>  		memzero_explicit(auth, sizeof(*auth));
>  	} else {
>  		/* reset for next use  */
> @@ -821,8 +844,11 @@ EXPORT_SYMBOL(tpm_buf_check_hmac_response);
>   */
>  void tpm2_end_auth_session(struct tpm_chip *chip)
>  {
> -	tpm2_flush_context(chip, chip->auth->handle);
> -	memzero_explicit(chip->auth, sizeof(*chip->auth));
> +	struct tpm2_auth *auth = chip->auth;
> +
> +	tpm2_flush_context(chip, auth->handle);
> +	crypto_free_shash(auth->tfm);
> +	memzero_explicit(auth, sizeof(*auth));
>  }
>  EXPORT_SYMBOL(tpm2_end_auth_session);
>  
> @@ -833,23 +859,26 @@ static int tpm2_parse_start_auth_session(struct tpm2_auth *auth,
>  	u32 tot_len = be32_to_cpu(head->length);
>  	off_t offset = TPM_HEADER_SIZE;
>  	u32 val;
> +	const int digest_size = crypto_shash_digestsize(auth->tfm);
> +	SHASH_DESC_ON_STACK(sdesc, auth->tfm);
> +
> +	sdesc->tfm = auth->tfm;
>  
>  	/* we're starting after the header so adjust the length */
>  	tot_len -= TPM_HEADER_SIZE;
>  
>  	/* should have handle plus nonce */
> -	if (tot_len != 4 + 2 + sizeof(auth->tpm_nonce))
> +	if (tot_len != 4 + 2 + digest_size)
>  		return -EINVAL;
>  
>  	auth->handle = tpm_buf_read_u32(buf, &offset);
>  	val = tpm_buf_read_u16(buf, &offset);
> -	if (val != sizeof(auth->tpm_nonce))
> +	if (val != digest_size)
>  		return -EINVAL;
> -	memcpy(auth->tpm_nonce, &buf->data[offset], sizeof(auth->tpm_nonce));
> +	memcpy(auth->tpm_nonce, &buf->data[offset], digest_size);
>  	/* now compute the session key from the nonces */
>  	tpm2_KDFa(auth->salt, sizeof(auth->salt), "ATH", auth->tpm_nonce,
> -		  auth->our_nonce, sizeof(auth->session_key),
> -		  auth->session_key);
> +		  auth->our_nonce, digest_size, auth->session_key, sdesc);
>  
>  	return 0;
>  }
> @@ -885,24 +914,23 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
>  	return rc;
>  }
>  
> -/**
> - * tpm2_start_auth_session() - create a HMAC authentication session with the TPM
> - * @chip: the TPM chip structure to create the session with
> - *
> - * This function loads the NULL seed from its saved context and starts
> - * an authentication session on the null seed, fills in the
> - * @chip->auth structure to contain all the session details necessary
> - * for performing the HMAC, encrypt and decrypt operations and
> - * returns.  The NULL seed is flushed before this function returns.
> - *
> - * Return: zero on success or actual error encountered.
> - */
> -int tpm2_start_auth_session(struct tpm_chip *chip)
> +static int __tpm2_start_session(struct tpm_chip *chip, u8 type, u16 hash)
>  {
>  	struct tpm_buf buf;
>  	struct tpm2_auth *auth = chip->auth;
>  	int rc;
>  	u32 null_key;
> +	int tpm_hash = tpm2_crypto_to_alg(hash);
> +	int digest_size;
> +
> +	if (tpm_hash < 0)
> +		return -EINVAL;
> +
> +	auth->tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
> +	if (IS_ERR(auth->tfm))
> +		return PTR_ERR(auth->tfm);
> +
> +	digest_size = crypto_shash_digestsize(auth->tfm);
>  
>  	rc = tpm2_load_null(chip, &null_key);
>  	if (rc)
> @@ -919,14 +947,14 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
>  	/* bind key handle */
>  	tpm_buf_append_u32(&buf, TPM2_RH_NULL);
>  	/* nonce caller */
> -	get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
> -	tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
> -	tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
> +	get_random_bytes(auth->our_nonce, digest_size);
> +	tpm_buf_append_u16(&buf, digest_size);
> +	tpm_buf_append(&buf, auth->our_nonce, digest_size);
>  
>  	/* append encrypted salt and squirrel away unencrypted in auth */
>  	tpm_buf_append_salt(&buf, chip);
>  	/* session type (HMAC, audit or policy) */
> -	tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
> +	tpm_buf_append_u8(&buf, type);
>  
>  	/* symmetric encryption parameters */
>  	/* symmetric algorithm */
> @@ -936,7 +964,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
>  	/* symmetric algorithm mode (must be CFB) */
>  	tpm_buf_append_u16(&buf, TPM_ALG_CFB);
>  	/* hash algorithm for session */
> -	tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
> +	tpm_buf_append_u16(&buf, tpm_hash);
>  
>  	rc = tpm_transmit_cmd(chip, &buf, 0, "start auth session");
>  	tpm2_flush_context(chip, null_key);
> @@ -949,11 +977,64 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
>  	if (rc)
>  		goto out;
>  
> +	return rc;
> +
>   out:
> +	crypto_free_shash(auth->tfm);
> +	auth->tfm = NULL;
> +
>  	return rc;
>  }
> +
> +/**
> + * tpm2_start_auth_session() - create a HMAC authentication session with the TPM
> + * @chip: the TPM chip structure to create the session with
> + *
> + * This function loads the NULL seed from its saved context and starts
> + * an authentication session on the null seed, fills in the
> + * @chip->auth structure to contain all the session details necessary
> + * for performing the HMAC, encrypt and decrypt operations and
> + * returns.  The NULL seed is flushed before this function returns.
> + *
> + * Return: zero on success or actual error encountered.
> + */
> +int tpm2_start_auth_session(struct tpm_chip *chip)
> +{
> +	return __tpm2_start_session(chip, TPM2_SE_HMAC, HASH_ALGO_SHA256);
> +}
>  EXPORT_SYMBOL(tpm2_start_auth_session);
>  
> +/**
> + * tpm2_start_policy_session - create a policy session with the TPM
> + * @chip: the TPM chip structure to create the session with
> + * @handle: the policy session handle
> + * @hash: the crypto subsystem hash algorithm for the policy
> + *
> + * This function loads the NULL seed from its saved context and starts
> + * a policy session on the null seed, fills in the @chip->auth
> + * structure to contain all the session details necessary for
> + * performing the HMAC, encrypt and decrypt operations and returns.
> + * The NULL seed is flushed before this function returns.
> + *
> + * Note the hash algorthim has to match the name algorithm of the TPM
> + * object the policy will be used to authorize.
> + *
> + * Return: zero on success or actual error encountered.
> + */
> +int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash)
> +{
> +	int rc;
> +
> +	rc = __tpm2_start_session(chip, TPM2_SE_POLICY, hash);
> +	if (rc)
> +		return rc;
> +
> +	*handle = chip->auth->handle;
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL(tpm2_start_policy_session);
> +
>  /**
>   * tpm2_parse_create_primary() - parse the data returned from TPM_CC_CREATE_PRIMARY
>   *
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index 07f532456a0c..dc2dd98cf104 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -560,6 +560,7 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
>  #ifdef CONFIG_TCG_TPM2_HMAC
>  
>  int tpm2_start_auth_session(struct tpm_chip *chip);
> +int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle, u8 hash);
>  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,
> @@ -585,6 +586,11 @@ static inline int tpm2_start_auth_session(struct tpm_chip *chip)
>  {
>  	return 0;
>  }
> +static inline int tpm2_start_policy_session(struct tpm_chip *chip, u32 *handle,
> +					    u8 hash)
> +{
> +	return -EINVAL;
> +}
>  static inline void tpm2_end_auth_session(struct tpm_chip *chip)
>  {
>  }


BR, Jarkko





[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