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