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