* [PATCH v2 0/5] Streamline TPM2 HMAC sessions
@ 2025-12-09 10:05 Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 1/5] KEYS: trusted: Remove dead branch from tpm2_unseal_cmd Jarkko Sakkinen
` (5 more replies)
0 siblings, 6 replies; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 10:05 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, Peter Huewe, Jason Gunthorpe, open list
Since we cannot at this point cache names of the keys given limitations
of the ASN.1 file format, I'll start a fresh patch set. Let's fixup what
we can right now.
This patch set addresses two major issues in the feature:
1. Dynamic resolution without gain. All kernel sites have at most single
handle to authorize. Even if this changes some day this is how it is
as of today and we definitely do not want to dictate the future but
instead downscale code to the metrics that we have as of today.
2. Eliminate at least one unnnecessary tpm2_read_public() call.
Jarkko Sakkinen (5):
KEYS: trusted: Remove dead branch from tpm2_unseal_cmd
tpm2-sessions: Define TPM2_NAME_MAX_SIZE
KEYS: trusted: Re-orchestrate tpm2_read_public() calls
tpm2-sessions: Remove AUTH_MAX_NAMES
tpm-buf: Remove tpm_buf_append_handle
drivers/char/tpm/tpm-buf.c | 25 ----
drivers/char/tpm/tpm-sysfs.c | 2 +-
drivers/char/tpm/tpm2-cmd.c | 9 +-
drivers/char/tpm/tpm2-sessions.c | 130 ++++++---------------
include/linux/tpm.h | 49 +++++---
security/keys/trusted-keys/trusted_tpm2.c | 134 +++++++++++++---------
6 files changed, 155 insertions(+), 194 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/5] KEYS: trusted: Remove dead branch from tpm2_unseal_cmd
2025-12-09 10:05 [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
@ 2025-12-09 10:05 ` Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 2/5] tpm2-sessions: Define TPM2_NAME_MAX_SIZE Jarkko Sakkinen
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 10:05 UTC (permalink / raw)
To: linux-integrity
Cc: Jarkko Sakkinen, Peter Huewe, Jason Gunthorpe, James Bottomley,
Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, open list, open list:KEYS-TRUSTED,
open list:SECURITY SUBSYSTEM
TPM2_Unseal requires TPM2_ST_SESSIONS, and tpm2_unseal_cmd() always does
set up either password or HMAC session.
Remove the branch in tpm2_unseal_cmd() conditionally setting
TPM2_ST_NO_SESSIONS. It is faulty but luckily it is never exercised at
run-time, and thus does not cause regressions.
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
security/keys/trusted-keys/trusted_tpm2.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 9074ae1a5896..27424e1a4a63 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -450,9 +450,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 blob_handle)
{
- struct tpm_header *head;
u16 data_len;
- int offset;
u8 *data;
int rc;
@@ -488,14 +486,8 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
tpm_buf_append_u16(buf, options->blobauth_len);
tpm_buf_append(buf, options->blobauth, options->blobauth_len);
- if (tpm2_chip_auth(chip)) {
+ if (tpm2_chip_auth(chip))
tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT, NULL, 0);
- } else {
- offset = buf->handles * 4 + TPM_HEADER_SIZE;
- head = (struct tpm_header *)buf->data;
- if (tpm_buf_length(buf) == offset)
- head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
- }
}
rc = tpm_buf_fill_hmac_session(chip, buf);
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/5] tpm2-sessions: Define TPM2_NAME_MAX_SIZE
2025-12-09 10:05 [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 1/5] KEYS: trusted: Remove dead branch from tpm2_unseal_cmd Jarkko Sakkinen
@ 2025-12-09 10:05 ` Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 3/5] KEYS: trusted: Re-orchestrate tpm2_read_public() calls Jarkko Sakkinen
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 10:05 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, Peter Huewe, Jason Gunthorpe, open list
This is somewhat cosmetic change but it does serve a purpose on tracking
the value set for the maximum length of TPM names, and to clearly states
what components it is composed of. It also anchors the value so that when
buffers are declared for this particular purpose, the same value is used
for the capacity.
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
v2:
- Rename TPM2_NAME_SIZE as TPM2_NULL_NAME_SIZE.
---
drivers/char/tpm/tpm-sysfs.c | 2 +-
drivers/char/tpm/tpm2-sessions.c | 2 +-
include/linux/tpm.h | 37 +++++++++++++++++++++-----------
3 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index f5dcadb1ab3c..0f321c307bc6 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -313,7 +313,7 @@ static ssize_t null_name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tpm_chip *chip = to_tpm_chip(dev);
- int size = TPM2_NAME_SIZE;
+ int size = TPM2_NULL_NAME_SIZE;
bin2hex(buf, chip->null_key_name, size);
size *= 2;
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 79f27a46bd7f..a0c88fb1804c 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -137,7 +137,7 @@ 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][TPM2_MAX_NAME_SIZE];
};
#ifdef CONFIG_TCG_TPM2_HMAC
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 42e2a091f43d..922a43ef23b5 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -28,9 +28,33 @@
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
#define TPM_BUFSIZE 4096
+/*
+ * SHA-512 is, as of today, the largest digest in the TCG algorithm repository.
+ */
#define TPM2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+
+/*
+ * A TPM name digest i.e., TPMT_HA, is a concatenation of TPM_ALG_ID of the
+ * name algorithm and hash of TPMT_PUBLIC.
+ */
+#define TPM2_MAX_NAME_SIZE (TPM2_MAX_DIGEST_SIZE + 2)
+
+/*
+ * The maximum number of PCR banks.
+ */
#define TPM2_MAX_PCR_BANKS 8
+/*
+ * fixed define for the size of a name. This is actually HASHALG size
+ * plus 2, so 32 for SHA256
+ */
+#define TPM2_NULL_NAME_SIZE 34
+
+/*
+ * The maximum size for an object context
+ */
+#define TPM2_MAX_CONTEXT_SIZE 4096
+
struct tpm_chip;
struct trusted_key_payload;
struct trusted_key_options;
@@ -140,17 +164,6 @@ struct tpm_chip_seqops {
/* fixed define for the curve we use which is NIST_P256 */
#define EC_PT_SZ 32
-/*
- * fixed define for the size of a name. This is actually HASHALG size
- * plus 2, so 32 for SHA256
- */
-#define TPM2_NAME_SIZE 34
-
-/*
- * The maximum size for an object context
- */
-#define TPM2_MAX_CONTEXT_SIZE 4096
-
struct tpm_chip {
struct device dev;
struct device devs;
@@ -212,7 +225,7 @@ struct tpm_chip {
/* saved context for NULL seed */
u8 null_key_context[TPM2_MAX_CONTEXT_SIZE];
/* name of NULL seed */
- u8 null_key_name[TPM2_NAME_SIZE];
+ u8 null_key_name[TPM2_NULL_NAME_SIZE];
u8 null_ec_key_x[EC_PT_SZ];
u8 null_ec_key_y[EC_PT_SZ];
struct tpm2_auth *auth;
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 3/5] KEYS: trusted: Re-orchestrate tpm2_read_public() calls
2025-12-09 10:05 [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 1/5] KEYS: trusted: Remove dead branch from tpm2_unseal_cmd Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 2/5] tpm2-sessions: Define TPM2_NAME_MAX_SIZE Jarkko Sakkinen
@ 2025-12-09 10:05 ` Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 4/5] tpm2-sessions: Remove AUTH_MAX_NAMES Jarkko Sakkinen
` (2 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 10:05 UTC (permalink / raw)
To: linux-integrity
Cc: Jarkko Sakkinen, Peter Huewe, Jason Gunthorpe, James Bottomley,
Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, open list, open list:KEYS-TRUSTED,
open list:SECURITY SUBSYSTEM
tpm2_load_cmd() and tpm2_unseal_cmd() use the same parent, and calls to
tpm_buf_append_name() cause the exact same TPM2_ReadPublic command to be
sent to the chip, causing unnecessary traffic.
1. Export tpm2_read_public in order to make it callable from
'trusted_tpm2'.
2. Re-orchestrate tpm2_seal_trusted() and tpm2_unseal_trusted() in order to
halve the name resolutions required:
2a. Move tpm2_read_public() calls into trusted_tpm2.
2b. Pass TPM name to tpm_buf_append_name().
2c. Rework tpm_buf_append_name() to use the pre-resolved name.
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
drivers/char/tpm/tpm2-cmd.c | 3 +-
drivers/char/tpm/tpm2-sessions.c | 95 +++++------------
include/linux/tpm.h | 10 +-
security/keys/trusted-keys/trusted_tpm2.c | 124 ++++++++++++++--------
4 files changed, 118 insertions(+), 114 deletions(-)
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 2682f5ec09cb..5b04e74b6377 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -199,7 +199,8 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (!disable_pcr_integrity) {
- rc = tpm_buf_append_name(chip, buf, pcr_idx, NULL);
+ rc = tpm_buf_append_name(chip, buf, pcr_idx, (u8 *)&pcr_idx,
+ sizeof(u32));
if (rc)
return rc;
tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index a0c88fb1804c..0816a91134fc 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -136,8 +136,8 @@ struct tpm2_auth {
* handle, but they are part of the session by name, which
* we must compute and remember
*/
- u32 name_h[AUTH_MAX_NAMES];
u8 name[AUTH_MAX_NAMES][TPM2_MAX_NAME_SIZE];
+ u16 name_size_tbl[AUTH_MAX_NAMES];
};
#ifdef CONFIG_TCG_TPM2_HMAC
@@ -163,7 +163,17 @@ static int name_size(const u8 *name)
}
}
-static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
+/**
+ * tpm2_read_public: Resolve TPM name for a handle
+ * @chip: TPM chip to use.
+ * @handle: TPM handle.
+ * @name: A buffer for returning the name blob. Must have a
+ * capacity of 'SHA512_DIGET_SIZE + 2' bytes at minimum
+ *
+ * Returns size of TPM handle name of success.
+ * Returns tpm_transmit_cmd error codes when TPM2_ReadPublic fails.
+ */
+int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
{
u32 mso = tpm2_handle_mso(handle);
off_t offset = TPM_HEADER_SIZE;
@@ -212,14 +222,16 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
memcpy(name, &buf->data[offset], rc);
return name_size_alg;
}
+EXPORT_SYMBOL_GPL(tpm2_read_public);
#endif /* CONFIG_TCG_TPM2_HMAC */
/**
- * tpm_buf_append_name() - add a handle area to the buffer
- * @chip: the TPM chip structure
- * @buf: The buffer to be appended
- * @handle: The handle to be appended
- * @name: The name of the handle (may be NULL)
+ * tpm_buf_append_name() - Append a handle and store TPM name
+ * @chip: TPM chip to use.
+ * @buf: TPM buffer containing the TPM command in-transit.
+ * @handle: TPM handle to be appended.
+ * @name: TPM name of the handle
+ * @name_size: Size of the TPM name.
*
* In order to compute session HMACs, we need to know the names of the
* objects pointed to by the handles. For most objects, this is simply
@@ -236,15 +248,14 @@ static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name)
* will be caused by an incorrect programming model and indicated by a
* kernel message.
*
- * Ends the authorization session on failure.
+ * Returns zero on success.
+ * Returns -EIO when the authorization area state is malformed.
*/
int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
- u32 handle, u8 *name)
+ u32 handle, u8 *name, u16 name_size)
{
#ifdef CONFIG_TCG_TPM2_HMAC
- enum tpm2_mso_type mso = tpm2_handle_mso(handle);
struct tpm2_auth *auth;
- u16 name_size_alg;
int slot;
int ret;
#endif
@@ -269,36 +280,15 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
}
tpm_buf_append_u32(buf, handle);
auth->session += 4;
-
- if (mso == TPM2_MSO_PERSISTENT ||
- mso == TPM2_MSO_VOLATILE ||
- mso == TPM2_MSO_NVRAM) {
- if (!name) {
- ret = tpm2_read_public(chip, handle, auth->name[slot]);
- if (ret < 0)
- goto err;
-
- name_size_alg = ret;
- }
- } else {
- if (name) {
- dev_err(&chip->dev, "handle 0x%08x does not use a name\n",
- handle);
- ret = -EIO;
- goto err;
- }
- }
-
- auth->name_h[slot] = handle;
- if (name)
- memcpy(auth->name[slot], name, name_size_alg);
+ memcpy(auth->name[slot], name, name_size);
+ auth->name_size_tbl[slot] = name_size;
#endif
return 0;
#ifdef CONFIG_TCG_TPM2_HMAC
err:
tpm2_end_auth_session(chip);
- return tpm_ret_to_err(ret);
+ return ret;
#endif
}
EXPORT_SYMBOL_GPL(tpm_buf_append_name);
@@ -606,22 +596,8 @@ int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
attrs = chip->cc_attrs_tbl[i];
handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
+ offset_s += handles * sizeof(u32);
- /*
- * just check the names, it's easy to make mistakes. This
- * would happen if someone added a handle via
- * tpm_buf_append_u32() instead of tpm_buf_append_name()
- */
- for (i = 0; i < handles; i++) {
- u32 handle = tpm_buf_read_u32(buf, &offset_s);
-
- if (auth->name_h[i] != handle) {
- dev_err(&chip->dev, "invalid handle 0x%08x\n", handle);
- ret = -EIO;
- goto err;
- }
- }
- /* point offset_s to the start of the sessions */
val = tpm_buf_read_u32(buf, &offset_s);
/* point offset_p to the start of the parameters */
offset_p = offset_s + val;
@@ -682,23 +658,8 @@ int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
/* ordinal is already BE */
sha256_update(&sctx, (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]);
-
- if (mso == TPM2_MSO_PERSISTENT ||
- mso == TPM2_MSO_VOLATILE ||
- mso == TPM2_MSO_NVRAM) {
- ret = name_size(auth->name[i]);
- if (ret < 0)
- goto err;
-
- sha256_update(&sctx, auth->name[i], ret);
- } else {
- __be32 h = cpu_to_be32(auth->name_h[i]);
-
- sha256_update(&sctx, (u8 *)&h, 4);
- }
- }
+ for (i = 0; i < handles; i++)
+ sha256_update(&sctx, auth->name[i], auth->name_size_tbl[i]);
if (offset_s != tpm_buf_length(buf))
sha256_update(&sctx, &buf->data[offset_s],
tpm_buf_length(buf) - offset_s);
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 922a43ef23b5..9f684fc7ae04 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -543,7 +543,7 @@ static inline struct tpm2_auth *tpm2_chip_auth(struct tpm_chip *chip)
}
int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
- u32 handle, u8 *name);
+ u32 handle, u8 *name, u16 name_size);
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
u8 attributes, u8 *passphrase,
int passphraselen);
@@ -557,6 +557,7 @@ int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf);
int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
int rc);
void tpm2_end_auth_session(struct tpm_chip *chip);
+int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name);
#else
#include <linux/unaligned.h>
@@ -580,6 +581,13 @@ static inline int tpm_buf_check_hmac_response(struct tpm_chip *chip,
{
return rc;
}
+
+static inline int tpm2_read_public(struct tpm_chip *chip, u32 handle,
+ void *name)
+{
+ memcpy(name, &handle, sizeof(u32));
+ return sizeof(u32);
+}
#endif /* CONFIG_TCG_TPM2_HMAC */
#endif
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 27424e1a4a63..63539b344ffb 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -203,7 +203,9 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
+ u8 parent_name[TPM2_MAX_NAME_SIZE];
off_t offset = TPM_HEADER_SIZE;
+ u16 parent_name_size;
int blob_len = 0;
int hash;
u32 flags;
@@ -220,6 +222,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (rc)
return rc;
+ rc = tpm2_read_public(chip, options->keyhandle, parent_name);
+ if (rc < 0)
+ goto out_put;
+
+ parent_name_size = rc;
+
rc = tpm2_start_auth_session(chip);
if (rc)
goto out_put;
@@ -234,7 +242,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
- rc = tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
+ rc = tpm_buf_append_name(chip, buf, options->keyhandle, parent_name,
+ parent_name_size);
if (rc)
goto out_put;
@@ -326,48 +335,38 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
}
/**
- * tpm2_load_cmd() - execute a TPM2_Load command
- *
- * @chip: TPM chip to use
- * @payload: the key data in clear and encrypted form
- * @options: authentication values and other options
- * @blob_handle: returned blob handle
+ * tpm2_load_cmd() - Execute TPM2_Load
+ * @chip: TPM chip to use.
+ * @payload: Key data in clear text.
+ * @options: Trusted key options.
+ * @parent_name: A cryptographic name, i.e. a TPMT_HA blob, of the
+ * parent key.
+ * @blob: The decoded payload for the key.
+ * @blob_handle: On success, will contain handle to the loaded keyedhash
+ * blob.
*
- * Return: 0 on success.
- * -E2BIG on wrong payload size.
- * -EPERM on tpm error status.
- * < 0 error from tpm_send.
+ * Return -E2BIG when the blob size is too small for all the data.
+ * Returns tpm_transmit_cmd() error codes when either TPM2_Load fails.
*/
static int tpm2_load_cmd(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options,
+ u8 *parent_name,
+ u16 parent_name_size,
+ const u8 *blob,
u32 *blob_handle)
{
u8 *blob_ref __free(kfree) = NULL;
unsigned int private_len;
unsigned int public_len;
unsigned int blob_len;
- u8 *blob, *pub;
+ const u8 *pub;
int rc;
u32 attrs;
- rc = tpm2_key_decode(payload, options, &blob);
- if (rc) {
- /* old form */
- blob = payload->blob;
- payload->old_format = 1;
- } else {
- /* Bind for cleanup: */
- blob_ref = blob;
- }
-
- /* new format carries keyhandle but old format doesn't */
- if (!options->keyhandle)
- return -EINVAL;
-
/* must be big enough for at least the two be16 size counts */
if (payload->blob_len < 4)
- return -EINVAL;
+ return -E2BIG;
private_len = get_unaligned_be16(blob);
@@ -406,7 +405,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
- rc = tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
+ rc = tpm_buf_append_name(chip, buf, options->keyhandle, parent_name,
+ parent_name_size);
if (rc)
return rc;
@@ -434,20 +434,23 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
}
/**
- * tpm2_unseal_cmd() - execute a TPM2_Unload command
+ * tpm2_unseal_cmd() - Execute TPM2_Unload
*
- * @chip: TPM chip to use
- * @payload: the key data in clear and encrypted form
- * @options: authentication values and other options
- * @blob_handle: blob handle
+ * @chip: TPM chip to use
+ * @payload: Key data in clear text.
+ * @options: Trusted key options.
+ * @parent_name: A cryptographic name, i.e. a TPMT_HA blob, of the
+ * parent key.
+ * @blob_handle: Handle to the loaded keyedhash blob.
*
- * Return: 0 on success
- * -EPERM on tpm error status
- * < 0 error from tpm_send
+ * Return -E2BIG when the blob size is too small for all the data.
+ * Returns tpm_transmit_cmd() error codes when either TPM2_Load fails.
*/
static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options,
+ u8 *parent_name,
+ u16 parent_name_size,
u32 blob_handle)
{
u16 data_len;
@@ -465,7 +468,8 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
tpm_buf_init(buf, TPM_BUFSIZE);
tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
- rc = tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
+ rc = tpm_buf_append_name(chip, buf, options->keyhandle, parent_name,
+ parent_name_size);
if (rc)
return rc;
@@ -526,30 +530,60 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
}
/**
- * tpm2_unseal_trusted() - unseal the payload of a trusted key
+ * tpm2_unseal_trusted() - Unseal a trusted key
+ * @chip: TPM chip to use.
+ * @payload: Key data in clear text.
+ * @options: Trusted key options.
*
- * @chip: TPM chip to use
- * @payload: the key data in clear and encrypted form
- * @options: authentication values and other options
- *
- * Return: Same as with tpm_send.
+ * Return -E2BIG when the blob size is too small for all the data.
+ * Return -EINVAL when parent's key handle has not been set.
+ * Returns tpm_transmit_cmd() error codes when either TPM2_Load or TPM2_Unseal
+ * fails.
*/
int tpm2_unseal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
+ u8 *blob_ref __free(kfree) = NULL;
+ u8 parent_name[TPM2_MAX_NAME_SIZE];
+ u16 parent_name_size;
u32 blob_handle;
+ u8 *blob;
int rc;
+ /*
+ * Try to decode the provided blob as an ASN.1 blob. Assume that the
+ * blob is in the legacy format if decoding does not end successfully.
+ */
+ rc = tpm2_key_decode(payload, options, &blob);
+ if (rc) {
+ blob = payload->blob;
+ payload->old_format = 1;
+ } else {
+ blob_ref = blob;
+ }
+
+ if (!options->keyhandle)
+ return -EINVAL;
+
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
- rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
+ rc = tpm2_read_public(chip, options->keyhandle, parent_name);
+ if (rc < 0)
+ goto out;
+
+ parent_name_size = rc;
+
+ rc = tpm2_load_cmd(chip, payload, options, parent_name,
+ parent_name_size, blob, &blob_handle);
if (rc)
goto out;
- rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
+ rc = tpm2_unseal_cmd(chip, payload, options, parent_name,
+ parent_name_size, blob_handle);
+
tpm2_flush_context(chip, blob_handle);
out:
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 4/5] tpm2-sessions: Remove AUTH_MAX_NAMES
2025-12-09 10:05 [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
` (2 preceding siblings ...)
2025-12-09 10:05 ` [PATCH v2 3/5] KEYS: trusted: Re-orchestrate tpm2_read_public() calls Jarkko Sakkinen
@ 2025-12-09 10:05 ` Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 5/5] tpm-buf: Remove tpm_buf_append_handle Jarkko Sakkinen
2025-12-09 15:42 ` [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
5 siblings, 0 replies; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 10:05 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, Peter Huewe, Jason Gunthorpe, open list
In all of the call sites only one session is ever append. Thus, reduce
AUTH_MAX_NAMES, which leads into removing constant completely.
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
drivers/char/tpm/tpm2-sessions.c | 31 +++++++++++--------------------
1 file changed, 11 insertions(+), 20 deletions(-)
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 0816a91134fc..62a200ae72d7 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -72,9 +72,6 @@
#include <crypto/sha2.h>
#include <crypto/utils.h>
-/* maximum number of names the TPM must remember for authorization */
-#define AUTH_MAX_NAMES 3
-
#define AES_KEY_BYTES AES_KEYSIZE_128
#define AES_KEY_BITS (AES_KEY_BYTES*8)
@@ -136,8 +133,8 @@ struct tpm2_auth {
* handle, but they are part of the session by name, which
* we must compute and remember
*/
- u8 name[AUTH_MAX_NAMES][TPM2_MAX_NAME_SIZE];
- u16 name_size_tbl[AUTH_MAX_NAMES];
+ u8 name[TPM2_MAX_NAME_SIZE];
+ u16 name_size;
};
#ifdef CONFIG_TCG_TPM2_HMAC
@@ -254,11 +251,14 @@ EXPORT_SYMBOL_GPL(tpm2_read_public);
int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
u32 handle, u8 *name, u16 name_size)
{
-#ifdef CONFIG_TCG_TPM2_HMAC
struct tpm2_auth *auth;
- int slot;
int ret;
-#endif
+
+ if (tpm_buf_length(buf) != TPM_HEADER_SIZE) {
+ dev_err(&chip->dev, "too many handles\n");
+ ret = -EIO;
+ goto err;
+ }
if (!tpm2_chip_auth(chip)) {
tpm_buf_append_handle(buf, handle);
@@ -266,12 +266,6 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
}
#ifdef CONFIG_TCG_TPM2_HMAC
- slot = (tpm_buf_length(buf) - TPM_HEADER_SIZE) / 4;
- if (slot >= AUTH_MAX_NAMES) {
- dev_err(&chip->dev, "too many handles\n");
- ret = -EIO;
- goto err;
- }
auth = chip->auth;
if (auth->session != tpm_buf_length(buf)) {
dev_err(&chip->dev, "session state malformed");
@@ -280,16 +274,14 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
}
tpm_buf_append_u32(buf, handle);
auth->session += 4;
- memcpy(auth->name[slot], name, name_size);
- auth->name_size_tbl[slot] = name_size;
+ memcpy(auth->name, name, name_size);
+ auth->name_size = name_size;
#endif
return 0;
-#ifdef CONFIG_TCG_TPM2_HMAC
err:
tpm2_end_auth_session(chip);
return ret;
-#endif
}
EXPORT_SYMBOL_GPL(tpm_buf_append_name);
@@ -658,8 +650,7 @@ int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
/* ordinal is already BE */
sha256_update(&sctx, (u8 *)&head->ordinal, sizeof(head->ordinal));
/* add the handle names */
- for (i = 0; i < handles; i++)
- sha256_update(&sctx, auth->name[i], auth->name_size_tbl[i]);
+ sha256_update(&sctx, auth->name, auth->name_size);
if (offset_s != tpm_buf_length(buf))
sha256_update(&sctx, &buf->data[offset_s],
tpm_buf_length(buf) - offset_s);
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 5/5] tpm-buf: Remove tpm_buf_append_handle
2025-12-09 10:05 [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
` (3 preceding siblings ...)
2025-12-09 10:05 ` [PATCH v2 4/5] tpm2-sessions: Remove AUTH_MAX_NAMES Jarkko Sakkinen
@ 2025-12-09 10:05 ` Jarkko Sakkinen
2025-12-09 15:42 ` [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
5 siblings, 0 replies; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 10:05 UTC (permalink / raw)
To: linux-integrity; +Cc: Jarkko Sakkinen, Peter Huewe, Jason Gunthorpe, open list
Since the number of handles is fixed to a single handle, eliminate all uses
of buf->handles and deduce values during compile-time.
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
v2:
- Streamline the code change and remove dead code.
---
drivers/char/tpm/tpm-buf.c | 25 -------------------------
drivers/char/tpm/tpm2-cmd.c | 6 ++----
drivers/char/tpm/tpm2-sessions.c | 14 ++------------
include/linux/tpm.h | 2 --
4 files changed, 4 insertions(+), 43 deletions(-)
diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
index 73be8a87b472..752c69b8a4f5 100644
--- a/drivers/char/tpm/tpm-buf.c
+++ b/drivers/char/tpm/tpm-buf.c
@@ -40,7 +40,6 @@ static void __tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordi
buf->flags = 0;
buf->length = sizeof(*head);
buf->capacity = buf_size - sizeof(*buf);
- buf->handles = 0;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
@@ -56,7 +55,6 @@ static void __tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
buf->flags = TPM_BUF_TPM2B;
buf->length = 2;
buf->capacity = buf_size - sizeof(*buf);
- buf->handles = 0;
buf->data[0] = 0;
buf->data[1] = 0;
}
@@ -177,29 +175,6 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
}
EXPORT_SYMBOL_GPL(tpm_buf_append_u32);
-/**
- * tpm_buf_append_handle() - Add a handle
- * @buf: &tpm_buf instance
- * @handle: a TPM object handle
- *
- * Add a handle to the buffer, and increase the count tracking the number of
- * handles in the command buffer. Works only for command buffers.
- */
-void tpm_buf_append_handle(struct tpm_buf *buf, u32 handle)
-{
- if (buf->flags & TPM_BUF_INVALID)
- return;
-
- if (buf->flags & TPM_BUF_TPM2B) {
- WARN(1, "tpm-buf: invalid type: TPM2B\n");
- buf->flags |= TPM_BUF_INVALID;
- return;
- }
-
- tpm_buf_append_u32(buf, handle);
- buf->handles++;
-}
-
/**
* tpm_buf_read() - Read from a TPM buffer
* @buf: &tpm_buf instance
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 5b04e74b6377..dbcd46c5e09d 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -205,7 +205,7 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
return rc;
tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
} else {
- tpm_buf_append_handle(buf, pcr_idx);
+ tpm_buf_append_u32(buf, pcr_idx);
tpm_buf_append_auth(chip, buf, NULL, 0);
}
@@ -281,10 +281,8 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
TPM2_SA_CONTINUE_SESSION,
NULL, 0);
} else {
- offset = buf->handles * 4 + TPM_HEADER_SIZE;
head = (struct tpm_header *)buf->data;
- if (tpm_buf_length(buf) == offset)
- head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
+ head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
}
tpm_buf_append_u16(buf, num_bytes);
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 62a200ae72d7..f2b8ca893e15 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -261,7 +261,7 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
}
if (!tpm2_chip_auth(chip)) {
- tpm_buf_append_handle(buf, handle);
+ tpm_buf_append_u32(buf, handle);
return 0;
}
@@ -288,17 +288,7 @@ EXPORT_SYMBOL_GPL(tpm_buf_append_name);
void tpm_buf_append_auth(struct tpm_chip *chip, struct tpm_buf *buf,
u8 *passphrase, int passphrase_len)
{
- /* offset tells us where the sessions area begins */
- int offset = buf->handles * 4 + TPM_HEADER_SIZE;
- u32 len = 9 + passphrase_len;
-
- if (tpm_buf_length(buf) != offset) {
- /* not the first session so update the existing length */
- len += get_unaligned_be32(&buf->data[offset]);
- put_unaligned_be32(len, &buf->data[offset]);
- } else {
- tpm_buf_append_u32(buf, len);
- }
+ tpm_buf_append_u32(buf, 9 + passphrase_len);
/* auth handle */
tpm_buf_append_u32(buf, TPM2_RS_PW);
/* nonce */
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 9f684fc7ae04..e68995df8796 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -395,7 +395,6 @@ enum tpm_buf_flags {
*/
struct tpm_buf {
u8 flags;
- u8 handles;
u16 length;
u16 capacity;
u8 data[];
@@ -441,7 +440,6 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value);
u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset);
u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset);
u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset);
-void tpm_buf_append_handle(struct tpm_buf *buf, u32 handle);
/*
* Check if TPM device is in the firmware upgrade mode.
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 0/5] Streamline TPM2 HMAC sessions
2025-12-09 10:05 [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
` (4 preceding siblings ...)
2025-12-09 10:05 ` [PATCH v2 5/5] tpm-buf: Remove tpm_buf_append_handle Jarkko Sakkinen
@ 2025-12-09 15:42 ` Jarkko Sakkinen
2025-12-09 17:32 ` Jarkko Sakkinen
5 siblings, 1 reply; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 15:42 UTC (permalink / raw)
To: linux-integrity; +Cc: Peter Huewe, Jason Gunthorpe, open list
On Tue, Dec 09, 2025 at 12:05:23PM +0200, Jarkko Sakkinen wrote:
> Since we cannot at this point cache names of the keys given limitations
> of the ASN.1 file format, I'll start a fresh patch set. Let's fixup what
> we can right now.
>
> This patch set addresses two major issues in the feature:
>
> 1. Dynamic resolution without gain. All kernel sites have at most single
> handle to authorize. Even if this changes some day this is how it is
> as of today and we definitely do not want to dictate the future but
> instead downscale code to the metrics that we have as of today.
> 2. Eliminate at least one unnnecessary tpm2_read_public() call.
>
> Jarkko Sakkinen (5):
> KEYS: trusted: Remove dead branch from tpm2_unseal_cmd
> tpm2-sessions: Define TPM2_NAME_MAX_SIZE
> KEYS: trusted: Re-orchestrate tpm2_read_public() calls
> tpm2-sessions: Remove AUTH_MAX_NAMES
> tpm-buf: Remove tpm_buf_append_handle
>
> drivers/char/tpm/tpm-buf.c | 25 ----
> drivers/char/tpm/tpm-sysfs.c | 2 +-
> drivers/char/tpm/tpm2-cmd.c | 9 +-
> drivers/char/tpm/tpm2-sessions.c | 130 ++++++---------------
> include/linux/tpm.h | 49 +++++---
> security/keys/trusted-keys/trusted_tpm2.c | 134 +++++++++++++---------
> 6 files changed, 155 insertions(+), 194 deletions(-)
>
> --
> 2.52.0
>
For hwrng we can e.g., calculate factor by timing tpm2_get_random() with
and without HMAC encryption. Then we can use this as frequency how often
data is pulled.
The other angle to combine this is to maintain largeish FIFO of random
bytes and fill this when it goes below a treshold.
Probably some combination of these will provide answer to performance
and latency problem with hwrng when HMAC encryption is turned on:
1. The first amortizes the overall quota.
2. Second provides constant latency without major spikes.
BR, Jarkko
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 0/5] Streamline TPM2 HMAC sessions
2025-12-09 15:42 ` [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
@ 2025-12-09 17:32 ` Jarkko Sakkinen
2025-12-09 18:27 ` Jarkko Sakkinen
0 siblings, 1 reply; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 17:32 UTC (permalink / raw)
To: linux-integrity; +Cc: Peter Huewe, Jason Gunthorpe, open list
On Tue, Dec 09, 2025 at 05:42:55PM +0200, Jarkko Sakkinen wrote:
> On Tue, Dec 09, 2025 at 12:05:23PM +0200, Jarkko Sakkinen wrote:
> > Since we cannot at this point cache names of the keys given limitations
> > of the ASN.1 file format, I'll start a fresh patch set. Let's fixup what
> > we can right now.
> >
> > This patch set addresses two major issues in the feature:
> >
> > 1. Dynamic resolution without gain. All kernel sites have at most single
> > handle to authorize. Even if this changes some day this is how it is
> > as of today and we definitely do not want to dictate the future but
> > instead downscale code to the metrics that we have as of today.
> > 2. Eliminate at least one unnnecessary tpm2_read_public() call.
> >
> > Jarkko Sakkinen (5):
> > KEYS: trusted: Remove dead branch from tpm2_unseal_cmd
> > tpm2-sessions: Define TPM2_NAME_MAX_SIZE
> > KEYS: trusted: Re-orchestrate tpm2_read_public() calls
> > tpm2-sessions: Remove AUTH_MAX_NAMES
> > tpm-buf: Remove tpm_buf_append_handle
> >
> > drivers/char/tpm/tpm-buf.c | 25 ----
> > drivers/char/tpm/tpm-sysfs.c | 2 +-
> > drivers/char/tpm/tpm2-cmd.c | 9 +-
> > drivers/char/tpm/tpm2-sessions.c | 130 ++++++---------------
> > include/linux/tpm.h | 49 +++++---
> > security/keys/trusted-keys/trusted_tpm2.c | 134 +++++++++++++---------
> > 6 files changed, 155 insertions(+), 194 deletions(-)
> >
> > --
> > 2.52.0
> >
>
> For hwrng we can e.g., calculate factor by timing tpm2_get_random() with
> and without HMAC encryption. Then we can use this as frequency how often
> data is pulled.
>
> The other angle to combine this is to maintain largeish FIFO of random
> bytes and fill this when it goes below a treshold.
>
> Probably some combination of these will provide answer to performance
> and latency problem with hwrng when HMAC encryption is turned on:
>
> 1. The first amortizes the overall quota.
> 2. Second provides constant latency without major spikes.
Another perhaps more unorthodox idea:
1. Calculate factor as said above. Let's call it N.
2. Every Nth step seed a pseudo rng from TPM.
3. On steps not divisible by N, pull from pseud rng.
I'm not a cryptographer but would randomness suffer from this? Then the
seeds that woud come from TPM are HMAC encrypted at least without major
hits on performance.
Just enumerated this. Not sure about this idea yet by any means but I do
like simplicy of it (and that also makes me concerned about missed
details).
BR, Jarkko
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 0/5] Streamline TPM2 HMAC sessions
2025-12-09 17:32 ` Jarkko Sakkinen
@ 2025-12-09 18:27 ` Jarkko Sakkinen
2025-12-10 1:15 ` Jarkko Sakkinen
0 siblings, 1 reply; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-09 18:27 UTC (permalink / raw)
To: linux-integrity; +Cc: Peter Huewe, Jason Gunthorpe, open list
On Tue, Dec 09, 2025 at 07:32:27PM +0200, Jarkko Sakkinen wrote:
> On Tue, Dec 09, 2025 at 05:42:55PM +0200, Jarkko Sakkinen wrote:
> > On Tue, Dec 09, 2025 at 12:05:23PM +0200, Jarkko Sakkinen wrote:
> > > Since we cannot at this point cache names of the keys given limitations
> > > of the ASN.1 file format, I'll start a fresh patch set. Let's fixup what
> > > we can right now.
> > >
> > > This patch set addresses two major issues in the feature:
> > >
> > > 1. Dynamic resolution without gain. All kernel sites have at most single
> > > handle to authorize. Even if this changes some day this is how it is
> > > as of today and we definitely do not want to dictate the future but
> > > instead downscale code to the metrics that we have as of today.
> > > 2. Eliminate at least one unnnecessary tpm2_read_public() call.
> > >
> > > Jarkko Sakkinen (5):
> > > KEYS: trusted: Remove dead branch from tpm2_unseal_cmd
> > > tpm2-sessions: Define TPM2_NAME_MAX_SIZE
> > > KEYS: trusted: Re-orchestrate tpm2_read_public() calls
> > > tpm2-sessions: Remove AUTH_MAX_NAMES
> > > tpm-buf: Remove tpm_buf_append_handle
> > >
> > > drivers/char/tpm/tpm-buf.c | 25 ----
> > > drivers/char/tpm/tpm-sysfs.c | 2 +-
> > > drivers/char/tpm/tpm2-cmd.c | 9 +-
> > > drivers/char/tpm/tpm2-sessions.c | 130 ++++++---------------
> > > include/linux/tpm.h | 49 +++++---
> > > security/keys/trusted-keys/trusted_tpm2.c | 134 +++++++++++++---------
> > > 6 files changed, 155 insertions(+), 194 deletions(-)
> > >
> > > --
> > > 2.52.0
> > >
> >
> > For hwrng we can e.g., calculate factor by timing tpm2_get_random() with
> > and without HMAC encryption. Then we can use this as frequency how often
> > data is pulled.
> >
> > The other angle to combine this is to maintain largeish FIFO of random
> > bytes and fill this when it goes below a treshold.
> >
> > Probably some combination of these will provide answer to performance
> > and latency problem with hwrng when HMAC encryption is turned on:
> >
> > 1. The first amortizes the overall quota.
> > 2. Second provides constant latency without major spikes.
>
> Another perhaps more unorthodox idea:
>
> 1. Calculate factor as said above. Let's call it N.
> 2. Every Nth step seed a pseudo rng from TPM.
> 3. On steps not divisible by N, pull from pseud rng.
>
> I'm not a cryptographer but would randomness suffer from this? Then the
> seeds that woud come from TPM are HMAC encrypted at least without major
> hits on performance.
>
> Just enumerated this. Not sure about this idea yet by any means but I do
> like simplicy of it (and that also makes me concerned about missed
> details).
Third option would be to have simply a kthread with a rate that fills a
pool and hwrng callbacks serves from that pool. If there is no bytes,
there is no bytes (which is fine as far as API is concerned).
This has optimal system latency properties I'd figure.
BR, Jarkko
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 0/5] Streamline TPM2 HMAC sessions
2025-12-09 18:27 ` Jarkko Sakkinen
@ 2025-12-10 1:15 ` Jarkko Sakkinen
0 siblings, 0 replies; 10+ messages in thread
From: Jarkko Sakkinen @ 2025-12-10 1:15 UTC (permalink / raw)
To: linux-integrity
Cc: Peter Huewe, Jason Gunthorpe, open list, Herbert Xu,
David S. Miller
On Tue, Dec 09, 2025 at 08:27:25PM +0200, Jarkko Sakkinen wrote:
> On Tue, Dec 09, 2025 at 07:32:27PM +0200, Jarkko Sakkinen wrote:
> > On Tue, Dec 09, 2025 at 05:42:55PM +0200, Jarkko Sakkinen wrote:
> > > On Tue, Dec 09, 2025 at 12:05:23PM +0200, Jarkko Sakkinen wrote:
> > > > Since we cannot at this point cache names of the keys given limitations
> > > > of the ASN.1 file format, I'll start a fresh patch set. Let's fixup what
> > > > we can right now.
> > > >
> > > > This patch set addresses two major issues in the feature:
> > > >
> > > > 1. Dynamic resolution without gain. All kernel sites have at most single
> > > > handle to authorize. Even if this changes some day this is how it is
> > > > as of today and we definitely do not want to dictate the future but
> > > > instead downscale code to the metrics that we have as of today.
> > > > 2. Eliminate at least one unnnecessary tpm2_read_public() call.
> > > >
> > > > Jarkko Sakkinen (5):
> > > > KEYS: trusted: Remove dead branch from tpm2_unseal_cmd
> > > > tpm2-sessions: Define TPM2_NAME_MAX_SIZE
> > > > KEYS: trusted: Re-orchestrate tpm2_read_public() calls
> > > > tpm2-sessions: Remove AUTH_MAX_NAMES
> > > > tpm-buf: Remove tpm_buf_append_handle
> > > >
> > > > drivers/char/tpm/tpm-buf.c | 25 ----
> > > > drivers/char/tpm/tpm-sysfs.c | 2 +-
> > > > drivers/char/tpm/tpm2-cmd.c | 9 +-
> > > > drivers/char/tpm/tpm2-sessions.c | 130 ++++++---------------
> > > > include/linux/tpm.h | 49 +++++---
> > > > security/keys/trusted-keys/trusted_tpm2.c | 134 +++++++++++++---------
> > > > 6 files changed, 155 insertions(+), 194 deletions(-)
> > > >
> > > > --
> > > > 2.52.0
> > > >
> > >
> > > For hwrng we can e.g., calculate factor by timing tpm2_get_random() with
> > > and without HMAC encryption. Then we can use this as frequency how often
> > > data is pulled.
> > >
> > > The other angle to combine this is to maintain largeish FIFO of random
> > > bytes and fill this when it goes below a treshold.
> > >
> > > Probably some combination of these will provide answer to performance
> > > and latency problem with hwrng when HMAC encryption is turned on:
> > >
> > > 1. The first amortizes the overall quota.
> > > 2. Second provides constant latency without major spikes.
> >
> > Another perhaps more unorthodox idea:
> >
> > 1. Calculate factor as said above. Let's call it N.
> > 2. Every Nth step seed a pseudo rng from TPM.
> > 3. On steps not divisible by N, pull from pseud rng.
> >
> > I'm not a cryptographer but would randomness suffer from this? Then the
> > seeds that woud come from TPM are HMAC encrypted at least without major
> > hits on performance.
> >
> > Just enumerated this. Not sure about this idea yet by any means but I do
> > like simplicy of it (and that also makes me concerned about missed
> > details).
>
> Third option would be to have simply a kthread with a rate that fills a
> pool and hwrng callbacks serves from that pool. If there is no bytes,
> there is no bytes (which is fine as far as API is concerned).
>
> This has optimal system latency properties I'd figure.
OK so the very first thing that should be done with hwrng is this: it
should be opportunistic instead of being committing (to X number of
bytes). Further optimizations should be considered only after changing
this heuristics.
That guarantees that when hwrng's thread queries bytes from TPM driver
it is guaranteed to cause always exactly one TPM2_GetRandom transaction.
How this can be done is to first re-orchestrate tpm_get_random() along
the lines (out of top of my head, did not even compile this):
int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
{
u32 num_bytes = max;
u8 *out_ptr = out;
int retries = 5;
int total = 0;
int rc;
if (!out || !max || max > TPM_MAX_RNG_DATA)
return -EINVAL;
if (!chip)
return -ENODEV;
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
rc = tpm2_start_auth_session(chip);
if (rc)
return rc;
}
do {
if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm2_get_random(chip, out_ptr, num_bytes);
else
rc = tpm1_get_random(chip, out_ptr, num_bytes);
if (rc < 0)
goto err;
out_ptr += rc;
total += rc;
num_bytes -= rc;
} while (retries-- && total < max);
tpm_put_ops(chip);
return total ? total : -EIO;
err:
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_end_auth_session(chip);
tpm_put_ops(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_get_random);
{tpm1,tpm2}_get_random() are changed to do exactly single transaction
and on success they return how many bytes were read.
hwrng code should also use {tpm1,tpm2}_get_random() and use the
requested size as a hint not as something that we commit into.
I think this will benefit kernel even without HMAC encryption because
it objectively makes things a bit more deterministic.
BR, Jarkko
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-12-10 1:15 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-09 10:05 [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 1/5] KEYS: trusted: Remove dead branch from tpm2_unseal_cmd Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 2/5] tpm2-sessions: Define TPM2_NAME_MAX_SIZE Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 3/5] KEYS: trusted: Re-orchestrate tpm2_read_public() calls Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 4/5] tpm2-sessions: Remove AUTH_MAX_NAMES Jarkko Sakkinen
2025-12-09 10:05 ` [PATCH v2 5/5] tpm-buf: Remove tpm_buf_append_handle Jarkko Sakkinen
2025-12-09 15:42 ` [PATCH v2 0/5] Streamline TPM2 HMAC sessions Jarkko Sakkinen
2025-12-09 17:32 ` Jarkko Sakkinen
2025-12-09 18:27 ` Jarkko Sakkinen
2025-12-10 1:15 ` Jarkko Sakkinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).