From: Matthew Garrett <matthewg@nvidia.com>
To: mjg59@srcf.ucam.org
Cc: keyrings@vger.kernel.org, James.Bottomley@HansenPartnership.com,
linux-integrity@vger.kernel.org, rafael@kernel.org,
linux-pm@vger.kernel.org, linux-efi@vger.kernel.org,
Matthew Garrett <matthewg@nvidia.com>
Subject: [PATCH 10/17] tpm: Move the bounds-checked response reader to a header
Date: Thu, 8 Oct 2026 06:20:26 -0700 [thread overview]
Message-ID: <20261008132532.1155166-11-matthewg@nvidia.com> (raw)
In-Reply-To: <20261008132532.1155166-1-matthewg@nvidia.com>
"tpm: Add NV define, undefine and write helpers" added some helper code
to reduce duplication in parsing TPM responses. This could be useful
elsewhere, so move it out to a header and add some additional features
that will be used shortly.
Signed-off-by: Matthew Garrett <matthewg@nvidia.com>
---
drivers/char/tpm/tpm2-ak.c | 89 +-----------------------
drivers/char/tpm/tpm2-rsp.h | 132 ++++++++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+), 87 deletions(-)
create mode 100644 drivers/char/tpm/tpm2-rsp.h
diff --git a/drivers/char/tpm/tpm2-ak.c b/drivers/char/tpm/tpm2-ak.c
index ad24d36b1728..18968c8d2b48 100644
--- a/drivers/char/tpm/tpm2-ak.c
+++ b/drivers/char/tpm/tpm2-ak.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/unaligned.h>
#include "tpm.h"
+#include "tpm2-rsp.h"
/*
* Restricted signing key whose private part never leaves the TPM. NO_DA
@@ -36,96 +37,10 @@
static const u8 tpm2_kernel_ak_seed[EC_PT_SZ] =
"Linux kernel attestation key v1";
-/* Bounds-checked reader for TPM response data */
-struct tpm2_rsp {
- const u8 *data;
- u32 len;
- u32 off;
- bool err;
-};
-
-static const u8 *tpm2_rsp_bytes(struct tpm2_rsp *r, u32 count)
-{
- const u8 *p;
-
- if (r->err || r->len - r->off < count) {
- r->err = true;
- return NULL;
- }
-
- p = &r->data[r->off];
- r->off += count;
- return p;
-}
-
-static u16 tpm2_rsp_u16(struct tpm2_rsp *r)
-{
- const u8 *p = tpm2_rsp_bytes(r, sizeof(u16));
-
- return p ? get_unaligned_be16(p) : 0;
-}
-
-static u32 tpm2_rsp_u32(struct tpm2_rsp *r)
-{
- const u8 *p = tpm2_rsp_bytes(r, sizeof(u32));
-
- return p ? get_unaligned_be32(p) : 0;
-}
-
-/* Initialise a reader over the response held in @buf */
-static void tpm2_rsp_init(struct tpm2_rsp *r, struct tpm_buf *buf)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
-
- r->data = buf->data;
- r->len = min_t(u32, be32_to_cpu(head->length), TPM_BUFSIZE);
- r->off = TPM_HEADER_SIZE;
- r->err = r->len < TPM_HEADER_SIZE;
-}
-
-/* Read a TPM2B_ECC_PARAMETER, left-padding it to EC_PT_SZ bytes */
-static void tpm2_rsp_ecc_param(struct tpm2_rsp *r, u8 *out)
-{
- u16 len = tpm2_rsp_u16(r);
- const u8 *p;
-
- if (len > EC_PT_SZ) {
- r->err = true;
- return;
- }
-
- p = tpm2_rsp_bytes(r, len);
- if (!p)
- return;
-
- memset(out, 0, EC_PT_SZ - len);
- memcpy(out + EC_PT_SZ - len, p, len);
-}
-
/* Parse and validate the TPM2B_PUBLIC of the kernel AK */
static int tpm2_parse_kernel_ak_public(struct tpm2_rsp *r, u8 *x, u8 *y)
{
- u16 size = tpm2_rsp_u16(r);
- u32 end = r->off + size;
-
- if (tpm2_rsp_u16(r) != TPM_ALG_ECC ||
- tpm2_rsp_u16(r) != TPM_ALG_SHA256 ||
- tpm2_rsp_u32(r) != TPM2_OA_KERNEL_AK ||
- tpm2_rsp_u16(r) != 0 || /* authPolicy */
- tpm2_rsp_u16(r) != TPM_ALG_NULL || /* symmetric */
- tpm2_rsp_u16(r) != TPM_ALG_ECDSA || /* scheme */
- tpm2_rsp_u16(r) != TPM_ALG_SHA256 || /* scheme hash */
- tpm2_rsp_u16(r) != TPM2_ECC_NIST_P256 ||
- tpm2_rsp_u16(r) != TPM_ALG_NULL) /* kdf */
- return -EINVAL;
-
- tpm2_rsp_ecc_param(r, x);
- tpm2_rsp_ecc_param(r, y);
-
- if (r->err || r->off != end)
- return -EINVAL;
-
- return 0;
+ return tpm2_rsp_ecdsa_public(r, TPM2_OA_KERNEL_AK, x, y);
}
/**
diff --git a/drivers/char/tpm/tpm2-rsp.h b/drivers/char/tpm/tpm2-rsp.h
new file mode 100644
index 000000000000..3ee1f0f2e6ad
--- /dev/null
+++ b/drivers/char/tpm/tpm2-rsp.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Bounds-checked reader for data returned by the TPM. Reading past the
+ * end of the data sets an error flag and returns zeros, so a sequence of
+ * reads can be checked once at the end.
+ */
+#ifndef __TPM2_RSP_H__
+#define __TPM2_RSP_H__
+
+#include <linux/tpm.h>
+#include <linux/unaligned.h>
+
+struct tpm2_rsp {
+ const u8 *data;
+ u32 len;
+ u32 off;
+ bool err;
+};
+
+static inline void tpm2_rsp_init_data(struct tpm2_rsp *r, const u8 *data,
+ u32 len)
+{
+ r->data = data;
+ r->len = len;
+ r->off = 0;
+ r->err = false;
+}
+
+/* Initialise a reader over the parameters of the response held in @buf */
+static inline void tpm2_rsp_init(struct tpm2_rsp *r, struct tpm_buf *buf)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+
+ r->data = buf->data;
+ r->len = min_t(u32, be32_to_cpu(head->length), TPM_BUFSIZE);
+ r->off = TPM_HEADER_SIZE;
+ r->err = r->len < TPM_HEADER_SIZE;
+}
+
+static inline const u8 *tpm2_rsp_bytes(struct tpm2_rsp *r, u32 count)
+{
+ const u8 *p;
+
+ if (r->err || r->len - r->off < count) {
+ r->err = true;
+ return NULL;
+ }
+
+ p = &r->data[r->off];
+ r->off += count;
+ return p;
+}
+
+static inline u8 tpm2_rsp_u8(struct tpm2_rsp *r)
+{
+ const u8 *p = tpm2_rsp_bytes(r, sizeof(u8));
+
+ return p ? *p : 0;
+}
+
+static inline u16 tpm2_rsp_u16(struct tpm2_rsp *r)
+{
+ const u8 *p = tpm2_rsp_bytes(r, sizeof(u16));
+
+ return p ? get_unaligned_be16(p) : 0;
+}
+
+static inline u32 tpm2_rsp_u32(struct tpm2_rsp *r)
+{
+ const u8 *p = tpm2_rsp_bytes(r, sizeof(u32));
+
+ return p ? get_unaligned_be32(p) : 0;
+}
+
+/* Read a TPM2B, returning its contents and setting @len */
+static inline const u8 *tpm2_rsp_tpm2b(struct tpm2_rsp *r, u16 *len)
+{
+ *len = tpm2_rsp_u16(r);
+ return tpm2_rsp_bytes(r, *len);
+}
+
+/* Read a TPM2B_ECC_PARAMETER, left-padding it to EC_PT_SZ bytes */
+static inline void tpm2_rsp_ecc_param(struct tpm2_rsp *r, u8 *out)
+{
+ u16 len = tpm2_rsp_u16(r);
+ const u8 *p;
+
+ if (len > EC_PT_SZ) {
+ r->err = true;
+ return;
+ }
+
+ p = tpm2_rsp_bytes(r, len);
+ if (!p)
+ return;
+
+ memset(out, 0, EC_PT_SZ - len);
+ memcpy(out + EC_PT_SZ - len, p, len);
+}
+
+/*
+ * Parse a TPM2B_PUBLIC for an ECDSA-SHA256 P-256 signing key with no
+ * symmetric algorithm, KDF or policy, checking that it has exactly the
+ * object attributes @attrs, and return its public point.
+ */
+static inline int tpm2_rsp_ecdsa_public(struct tpm2_rsp *r, u32 attrs,
+ u8 *x, u8 *y)
+{
+ u16 size = tpm2_rsp_u16(r);
+ u32 end = r->off + size;
+
+ if (tpm2_rsp_u16(r) != TPM_ALG_ECC ||
+ tpm2_rsp_u16(r) != TPM_ALG_SHA256 ||
+ tpm2_rsp_u32(r) != attrs ||
+ tpm2_rsp_u16(r) != 0 || /* authPolicy */
+ tpm2_rsp_u16(r) != TPM_ALG_NULL || /* symmetric */
+ tpm2_rsp_u16(r) != TPM_ALG_ECDSA || /* scheme */
+ tpm2_rsp_u16(r) != TPM_ALG_SHA256 || /* scheme hash */
+ tpm2_rsp_u16(r) != TPM2_ECC_NIST_P256 ||
+ tpm2_rsp_u16(r) != TPM_ALG_NULL) /* kdf */
+ return -EINVAL;
+
+ tpm2_rsp_ecc_param(r, x);
+ tpm2_rsp_ecc_param(r, y);
+
+ if (r->err || r->off != end)
+ return -EINVAL;
+
+ return 0;
+}
+
+#endif
--
2.43.0
next prev parent reply other threads:[~2026-10-08 13:26 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 13:20 [RFC] Make hibernation work with lockdown Matthew Garrett
2026-10-08 13:20 ` [PATCH 01/17] tpm: Define a kernel-owned TPM NV index that can't be modified by userland Matthew Garrett
2026-10-08 13:41 ` Matthew Garrett
2026-10-08 16:24 ` Jarkko Sakkinen
2026-10-08 16:23 ` Jarkko Sakkinen
2026-10-09 8:33 ` Matthew Garrett
2026-10-08 17:06 ` Ilias Apalodimas
2026-10-08 13:20 ` [PATCH 02/17] efi: Add a mechanism to modify TPM state depending on kernel security features Matthew Garrett
2026-10-08 16:38 ` Jarkko Sakkinen
2026-10-08 13:20 ` [PATCH 03/17] tpm: Allow tpm2_start_auth_session() to start an audit session Matthew Garrett
2026-10-08 13:20 ` [PATCH 04/17] tpm: Log commands executed in " Matthew Garrett
2026-10-08 13:20 ` [PATCH 05/17] tpm: Add a kernel attestation key and signed audit digest retrieval Matthew Garrett
2026-10-08 16:45 ` James Bottomley
2026-10-09 8:29 ` Matthew Garrett
2026-10-08 13:20 ` [PATCH 06/17] tpm: Use TPM2_NV_ReadPublic to read NV index names Matthew Garrett
2026-10-08 13:20 ` [PATCH 07/17] tpm: Add in-kernel support for reading NV indices Matthew Garrett
2026-10-08 13:20 ` [PATCH 08/17] tpm: Add NV define, undefine and write helpers Matthew Garrett
2026-10-08 13:20 ` [PATCH 09/17] tpm: Provision the kernel NV index at registration Matthew Garrett
2026-10-08 13:20 ` Matthew Garrett [this message]
2026-10-08 13:20 ` [PATCH 11/17] tpm: Add kernel signing key creation with audited provenance Matthew Garrett
2026-10-08 17:00 ` James Bottomley
2026-10-09 8:31 ` Matthew Garrett
2026-10-08 13:20 ` [PATCH 12/17] tpm: Add signing with the kernel signing key Matthew Garrett
2026-10-08 13:20 ` [PATCH 13/17] tpm: Add verification of kernel signing key provenance Matthew Garrett
2026-10-08 13:20 ` [PATCH 14/17] PM: hibernate: Add image digest and signature page infrastructure Matthew Garrett
2026-10-08 13:20 ` [PATCH 15/17] PM: hibernate: Sign and verify images with a kernel-generated TPM key Matthew Garrett
2026-10-08 13:20 ` [PATCH 16/17] PM: hibernate: Refuse to verify images with a virtual TPM Matthew Garrett
2026-10-08 13:20 ` [PATCH 17/17] PM: hibernate: Allow hibernation under lockdown with signed images Matthew Garrett
2026-10-08 16:53 ` Jarkko Sakkinen
2026-10-09 8:31 ` Matthew Garrett
2026-10-08 15:56 ` [RFC] Make hibernation work with lockdown Jarkko Sakkinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261008132532.1155166-11-matthewg@nvidia.com \
--to=matthewg@nvidia.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=keyrings@vger.kernel.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=mjg59@srcf.ucam.org \
--cc=rafael@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox