Linux EFI development
 help / color / mirror / Atom feed
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


  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