grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] TPM2 PCR Capping
@ 2025-07-08  8:31 Gary Lin via Grub-devel
  2025-07-08  8:31 ` [PATCH 1/7] tss2: Add TPM2_PCR_Event command Gary Lin via Grub-devel
                   ` (6 more replies)
  0 siblings, 7 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

For users who require a sealed key to be unsealable only once per boot
process, a straightforward technique involves "capping" the key by
extending the associated PCRs. This patch set introduces PCR capping
support for the TPM2 key protector, allowing users to select specific
PCRs to extend immediately after the key is unsealed.

Gary Lin (7):
  tss2: Add TPM2_PCR_Event command
  tss2: Introduce grub_tcg2_cap_pcr()
  tss2: Implement grub_tcg2_cap_pcr() for EFI
  tss2: Implement grub_tcg2_cap_pcr() for ieee1275
  tss2: Implement grub_tcg2_cap_pcr() for EMU
  tpm2_key_protector: Support PCR capping
  tests/tpm2_key_protector_test: Add a test for PCR Capping

 docs/grub.texi                                | 20 +++++-
 grub-core/commands/ieee1275/ibmvtpm.c         | 52 +--------------
 .../commands/tpm2_key_protector/module.c      | 56 +++++++++++++++-
 grub-core/lib/efi/tcg2.c                      | 41 ++++++++++++
 grub-core/lib/ieee1275/tcg2.c                 | 66 +++++++++++++++++++
 grub-core/lib/tss2/tcg2.h                     |  5 ++
 grub-core/lib/tss2/tcg2_emu.c                 | 19 ++++++
 grub-core/lib/tss2/tpm2_cmd.c                 | 51 ++++++++++++++
 grub-core/lib/tss2/tpm2_cmd.h                 |  7 ++
 grub-core/lib/tss2/tss2_mu.c                  | 18 +++++
 grub-core/lib/tss2/tss2_mu.h                  |  4 ++
 grub-core/lib/tss2/tss2_structs.h             |  7 ++
 grub-core/lib/tss2/tss2_types.h               |  1 +
 grub-core/normal/main.c                       |  2 +-
 include/grub/ieee1275/tpm.h                   |  5 ++
 tests/tpm2_key_protector_test.in              | 65 ++++++++++++++++++
 16 files changed, 365 insertions(+), 54 deletions(-)

-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 1/7] tss2: Add TPM2_PCR_Event command
  2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
@ 2025-07-08  8:31 ` Gary Lin via Grub-devel
  2025-07-10 14:54   ` Sudhakar Kuppusamy
  2025-07-08  8:31 ` [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr() Gary Lin via Grub-devel
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

The TPM2_PCR_Event command is introduced to tss2 to allow the user to
extend a specific PCR. The related data structure and unmarshal function
are also introduced.

However, simply invoking TPM2_PCR_Event does not automatically record
the event into the TPM event log. The TPM event log is primarily
maintained by the system firmware (e.g., BIOS/UEFI). Therefore, for most
standard use cases, the recommended method for extending PCRs and
ensuring proper event logging is to utilize the system firmware
functions.

There are specific scenarios where direct use of TPM2_PCR_Event becomes
necessary. For instance, in environments lacking system firmware support
for PCR extension, such as the grub-emu, TPM2_PCR_Event serves as the
only available method to extend PCRs.

Signed-off-by: Gary Lin <glin@suse.com>
---
 grub-core/lib/tss2/tpm2_cmd.c     | 51 +++++++++++++++++++++++++++++++
 grub-core/lib/tss2/tpm2_cmd.h     |  7 +++++
 grub-core/lib/tss2/tss2_mu.c      | 18 +++++++++++
 grub-core/lib/tss2/tss2_mu.h      |  4 +++
 grub-core/lib/tss2/tss2_structs.h |  7 +++++
 grub-core/lib/tss2/tss2_types.h   |  1 +
 6 files changed, 88 insertions(+)

diff --git a/grub-core/lib/tss2/tpm2_cmd.c b/grub-core/lib/tss2/tpm2_cmd.c
index 6d25db1ab..37ca78aee 100644
--- a/grub-core/lib/tss2/tpm2_cmd.c
+++ b/grub-core/lib/tss2/tpm2_cmd.c
@@ -575,6 +575,57 @@ grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
   return TPM_RC_SUCCESS;
 }
 
+extern TPM_RC_t
+grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
+		     const TPMS_AUTH_COMMAND_t *authCommand,
+		     const TPM2B_EVENT_t *eventData,
+		     TPML_DIGEST_VALUES_t *digests,
+		     TPMS_AUTH_RESPONSE_t *authResponse)
+{
+  TPM_RC_t rc;
+  struct grub_tpm2_buffer in;
+  struct grub_tpm2_buffer out;
+  TPML_DIGEST_VALUES_t digestsTmp;
+  TPMS_AUTH_RESPONSE_t authResponseTmp;
+  TPM_RC_t responseCode;
+  grub_uint32_t parameterSize;
+
+  if (eventData == NULL)
+    return TPM_RC_VALUE;
+  if (authCommand == NULL)
+    return TPM_RC_VALUE;
+
+  if (digests == NULL)
+    digests = &digestsTmp;
+  if (authResponse == NULL)
+    authResponse = &authResponseTmp;
+
+  /* Marshal */
+  grub_tpm2_buffer_init (&in);
+  grub_tpm2_buffer_pack_u32 (&in, pcrHandle);
+  grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+  grub_Tss2_MU_TPM2B_Marshal (&in, eventData->size, eventData->buffer);
+  if (in.error != 0)
+    return TPM_RC_FAILURE;
+
+  /* Submit */
+  grub_tpm2_buffer_init (&out);
+  rc = tpm2_submit_command (TPM_ST_SESSIONS, TPM_CC_PCR_Event, &responseCode, &in, &out);
+  if (rc != TPM_RC_SUCCESS)
+    return rc;
+  if (responseCode != TPM_RC_SUCCESS)
+    return responseCode;
+
+  /* Unmarshal */
+  grub_tpm2_buffer_unpack_u32 (&out, &parameterSize);
+  grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (&out, digests);
+  grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+  if (out.error != 0)
+    return TPM_RC_FAILURE;
+
+  return TPM_RC_SUCCESS;
+}
+
 TPM_RC_t
 grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
 		    const TPML_PCR_SELECTION_t *pcrSelectionIn,
diff --git a/grub-core/lib/tss2/tpm2_cmd.h b/grub-core/lib/tss2/tpm2_cmd.h
index 90b42efec..d7ad962ab 100644
--- a/grub-core/lib/tss2/tpm2_cmd.h
+++ b/grub-core/lib/tss2/tpm2_cmd.h
@@ -89,6 +89,13 @@ grub_tpm2_unseal (const TPMI_DH_OBJECT_t item_handle,
 extern TPM_RC_t
 grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle);
 
+extern TPM_RC_t
+grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
+		     const TPMS_AUTH_COMMAND_t *authCommand,
+		     const TPM2B_EVENT_t *eventData,
+		     TPML_DIGEST_VALUES_t *digests,
+		     TPMS_AUTH_RESPONSE_t *authResponse);
+
 extern TPM_RC_t
 grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
 		    const TPML_PCR_SELECTION_t *pcrSelectionIn,
diff --git a/grub-core/lib/tss2/tss2_mu.c b/grub-core/lib/tss2/tss2_mu.c
index 816e5b37f..675a0009a 100644
--- a/grub-core/lib/tss2/tss2_mu.c
+++ b/grub-core/lib/tss2/tss2_mu.c
@@ -1118,6 +1118,24 @@ grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
     grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &digest->digests[i]);
 }
 
+void
+grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
+					  TPML_DIGEST_VALUES_t *digests)
+{
+  grub_uint32_t i;
+
+  grub_tpm2_buffer_unpack_u32 (buffer, &digests->count);
+
+  if (digests->count > TPM_NUM_PCR_BANKS)
+    {
+      buffer->error = 1;
+      return;
+    }
+
+  for (i = 0; i < digests->count; i++)
+    grub_Tss2_MU_TPMT_HA_Unmarshal (buffer, &digests->digests[i]);
+}
+
 void
 grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
                                            TPMS_SIGNATURE_RSA_t *rsa)
diff --git a/grub-core/lib/tss2/tss2_mu.h b/grub-core/lib/tss2/tss2_mu.h
index 6440de57c..76eebc994 100644
--- a/grub-core/lib/tss2/tss2_mu.h
+++ b/grub-core/lib/tss2/tss2_mu.h
@@ -380,6 +380,10 @@ extern void
 grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
 				    TPML_DIGEST_t *digest);
 
+extern void
+grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
+					  TPML_DIGEST_VALUES_t *digests);
+
 extern void
 grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
                                            TPMS_SIGNATURE_RSA_t *p);
diff --git a/grub-core/lib/tss2/tss2_structs.h b/grub-core/lib/tss2/tss2_structs.h
index 2eefba87c..0ac09f50f 100644
--- a/grub-core/lib/tss2/tss2_structs.h
+++ b/grub-core/lib/tss2/tss2_structs.h
@@ -144,6 +144,13 @@ typedef struct TPML_DIGEST TPML_DIGEST_t;
 /* TPM2B_NONCE Type */
 typedef TPM2B_DIGEST_t TPM2B_NONCE_t;
 
+/* TPM2B_EVENT Structure */
+struct TPM2B_EVENT {
+    grub_uint16_t size;
+    grub_uint8_t buffer[1024];
+};
+typedef struct TPM2B_EVENT TPM2B_EVENT_t;
+
 /* TPMA_SESSION Structure */
 struct TPMA_SESSION
 {
diff --git a/grub-core/lib/tss2/tss2_types.h b/grub-core/lib/tss2/tss2_types.h
index bddde7191..52d304b90 100644
--- a/grub-core/lib/tss2/tss2_types.h
+++ b/grub-core/lib/tss2/tss2_types.h
@@ -343,6 +343,7 @@ typedef grub_uint32_t TPM_CC_t;
 #define TPM_CC_NV_Write         ((TPM_CC_t) 0x00000137)
 #define TPM_CC_NV_UndefineSpace ((TPM_CC_t) 0x00000122)
 #define TPM_CC_GetCapability    ((TPM_CC_t) 0x0000017a)
+#define TPM_CC_PCR_Event        ((TPM_CC_t) 0x0000013c)
 #define TPM_CC_PCR_Read         ((TPM_CC_t) 0x0000017e)
 #define TPM_CC_Load             ((TPM_CC_t) 0x00000157)
 #define TPM_CC_LoadExternal     ((TPM_CC_t) 0x00000167)
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr()
  2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
  2025-07-08  8:31 ` [PATCH 1/7] tss2: Add TPM2_PCR_Event command Gary Lin via Grub-devel
@ 2025-07-08  8:31 ` Gary Lin via Grub-devel
  2025-07-08 16:05   ` Stefan Berger
  2025-07-10 15:09   ` Sudhakar Kuppusamy
  2025-07-08  8:31 ` [PATCH 3/7] tss2: Implement grub_tcg2_cap_pcr() for EFI Gary Lin via Grub-devel
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

This commit introduces the definition of grub_tcg2_cap_pcr(), a new
function designed to enhance the security of sealed keys. Its primary
purpose is to "cap" a specific PCR by extending it with a SEPARATOR
event. This action cryptographically alters the PCR value, making it
impossible to unseal any key that was previously sealed to the original
PCR state. Consequently, the sealed key remains protected against
unauthorized unsealing attempts until the associated PCRs are reset to
their initial configuration, typically occurring during a subsequent
system boot.

Signed-off-by: Gary Lin <glin@suse.com>
---
 grub-core/lib/tss2/tcg2.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/grub-core/lib/tss2/tcg2.h b/grub-core/lib/tss2/tcg2.h
index 3d26373dd..c7e80d355 100644
--- a/grub-core/lib/tss2/tcg2.h
+++ b/grub-core/lib/tss2/tcg2.h
@@ -23,6 +23,8 @@
 #include <grub/err.h>
 #include <grub/types.h>
 
+#define EV_SEPARATOR 0x04
+
 extern grub_err_t
 grub_tcg2_get_max_output_size (grub_size_t *size);
 
@@ -32,4 +34,7 @@ grub_tcg2_submit_command (grub_size_t input_size,
 			  grub_size_t output_size,
 			  grub_uint8_t *output);
 
+extern grub_err_t
+grub_tcg2_cap_pcr (grub_uint8_t pcr);
+
 #endif /* ! GRUB_TPM2_TCG2_HEADER */
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 3/7] tss2: Implement grub_tcg2_cap_pcr() for EFI
  2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
  2025-07-08  8:31 ` [PATCH 1/7] tss2: Add TPM2_PCR_Event command Gary Lin via Grub-devel
  2025-07-08  8:31 ` [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr() Gary Lin via Grub-devel
@ 2025-07-08  8:31 ` Gary Lin via Grub-devel
  2025-07-08 16:27   ` Stefan Berger
  2025-07-08  8:31 ` [PATCH 4/7] tss2: Implement grub_tcg2_cap_pcr() for ieee1275 Gary Lin via Grub-devel
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

This commit implements grub_tcg2_cap_pcr() for EFI by using the UEFI
TCG2 protocol, HashLogExtendEvent, to extend the specified PCR with a
SEPARATOR event and ensure the event will be recorded properly in the
TPM event log.

Signed-off-by: Gary Lin <glin@suse.com>
---
 grub-core/lib/efi/tcg2.c | 41 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/grub-core/lib/efi/tcg2.c b/grub-core/lib/efi/tcg2.c
index 841bf50bb..81f5dea24 100644
--- a/grub-core/lib/efi/tcg2.c
+++ b/grub-core/lib/efi/tcg2.c
@@ -22,6 +22,7 @@
 #include <grub/efi/tpm.h>
 #include <grub/mm.h>
 
+#include <tss2_types.h>
 #include <tcg2.h>
 
 static grub_err_t
@@ -141,3 +142,43 @@ grub_tcg2_submit_command (grub_size_t input_size,
 
   return GRUB_ERR_NONE;
 }
+
+grub_err_t
+grub_tcg2_cap_pcr (grub_uint8_t pcr)
+{
+  grub_err_t err;
+  grub_efi_status_t status;
+  grub_efi_tpm2_protocol_t *protocol;
+  EFI_TCG2_EVENT *event;
+  grub_uint8_t separator[4] = {0};
+
+  if (pcr >= TPM_MAX_PCRS)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  err = tcg2_get_protocol (&protocol);
+  if (err != GRUB_ERR_NONE)
+    return err;
+
+  event = grub_zalloc (sizeof (EFI_TCG2_EVENT) + sizeof (separator));
+  if (!event)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+		       N_("cannot allocate TPM event buffer"));
+
+  event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
+  event->Header.HeaderVersion = 1;
+  event->Header.PCRIndex = pcr;
+  event->Header.EventType = EV_SEPARATOR;
+  event->Size = sizeof (*event) - sizeof (event->Event) + sizeof (separator);
+  grub_memcpy (event->Event, separator, sizeof (separator));
+
+
+  status = protocol->hash_log_extend_event (protocol, 0,
+					    (grub_addr_t) separator,
+					    sizeof (separator), event);
+  grub_free (event);
+
+  if (status != GRUB_EFI_SUCCESS)
+    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
+
+  return GRUB_ERR_NONE;
+}
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 4/7] tss2: Implement grub_tcg2_cap_pcr() for ieee1275
  2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
                   ` (2 preceding siblings ...)
  2025-07-08  8:31 ` [PATCH 3/7] tss2: Implement grub_tcg2_cap_pcr() for EFI Gary Lin via Grub-devel
@ 2025-07-08  8:31 ` Gary Lin via Grub-devel
  2025-07-08 15:52   ` Stefan Berger
  2025-07-08  8:31 ` [PATCH 5/7] tss2: Implement grub_tcg2_cap_pcr() for EMU Gary Lin via Grub-devel
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

This commit implements grub_tcg2_cap_pcr() for ieee1275 with the
firmware function, 2hash-ext-log, to extend the target PCR with a
SEPARATOR event and record the event into the TPM event log.

To avoid duplicate code, ibmvtpm_2hash_ext_log() is moved to tcg2.c
and exported as a global function.

Signed-off-by: Gary Lin <glin@suse.com>
---
 grub-core/commands/ieee1275/ibmvtpm.c | 52 ++-------------------
 grub-core/lib/ieee1275/tcg2.c         | 66 +++++++++++++++++++++++++++
 include/grub/ieee1275/tpm.h           |  5 ++
 3 files changed, 74 insertions(+), 49 deletions(-)

diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
index 4958b04a9..d0ddc06b0 100644
--- a/grub-core/commands/ieee1275/ibmvtpm.c
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
@@ -27,52 +27,6 @@
 #include <grub/mm.h>
 #include <grub/misc.h>
 
-static int
-ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
-		       grub_uint32_t eventtype,
-		       const char *description,
-		       grub_size_t description_size,
-		       void *buf, grub_size_t size)
-{
-  struct tpm_2hash_ext_log
-  {
-    struct grub_ieee1275_common_hdr common;
-    grub_ieee1275_cell_t method;
-    grub_ieee1275_cell_t ihandle;
-    grub_ieee1275_cell_t size;
-    grub_ieee1275_cell_t buf;
-    grub_ieee1275_cell_t description_size;
-    grub_ieee1275_cell_t description;
-    grub_ieee1275_cell_t eventtype;
-    grub_ieee1275_cell_t pcrindex;
-    grub_ieee1275_cell_t catch_result;
-    grub_ieee1275_cell_t rc;
-  };
-  struct tpm_2hash_ext_log args;
-
-  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
-  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
-  args.ihandle = grub_ieee1275_tpm_ihandle;
-  args.pcrindex = pcrindex;
-  args.eventtype = eventtype;
-  args.description = (grub_ieee1275_cell_t) description;
-  args.description_size = description_size;
-  args.buf = (grub_ieee1275_cell_t) buf;
-  args.size = (grub_ieee1275_cell_t) size;
-
-  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
-    return -1;
-
-  /*
-   * catch_result is set if firmware does not support 2hash-ext-log
-   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
-   */
-  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
-    return -1;
-
-  return 0;
-}
-
 static grub_err_t
 tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
 		const char *description)
@@ -80,9 +34,9 @@ tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
   static int error_displayed = 0;
   int rc;
 
-  rc = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
-			      description, grub_strlen(description) + 1,
-			      buf, size);
+  rc = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_IPL,
+					    description, grub_strlen(description) + 1,
+					    buf, size);
   if (rc && !error_displayed)
     {
       error_displayed++;
diff --git a/grub-core/lib/ieee1275/tcg2.c b/grub-core/lib/ieee1275/tcg2.c
index 40161c2f9..945a3469b 100644
--- a/grub-core/lib/ieee1275/tcg2.c
+++ b/grub-core/lib/ieee1275/tcg2.c
@@ -56,6 +56,52 @@ grub_ieee1275_tpm_init (void)
   return GRUB_ERR_NONE;
 }
 
+int
+grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
+				     grub_uint32_t eventtype,
+				     const char *description,
+				     grub_size_t description_size,
+				     void *buf, grub_size_t size)
+{
+  struct tpm_2hash_ext_log
+  {
+    struct grub_ieee1275_common_hdr common;
+    grub_ieee1275_cell_t method;
+    grub_ieee1275_cell_t ihandle;
+    grub_ieee1275_cell_t size;
+    grub_ieee1275_cell_t buf;
+    grub_ieee1275_cell_t description_size;
+    grub_ieee1275_cell_t description;
+    grub_ieee1275_cell_t eventtype;
+    grub_ieee1275_cell_t pcrindex;
+    grub_ieee1275_cell_t catch_result;
+    grub_ieee1275_cell_t rc;
+  };
+  struct tpm_2hash_ext_log args;
+
+  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
+  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
+  args.ihandle = grub_ieee1275_tpm_ihandle;
+  args.pcrindex = pcrindex;
+  args.eventtype = eventtype;
+  args.description = (grub_ieee1275_cell_t) description;
+  args.description_size = description_size;
+  args.buf = (grub_ieee1275_cell_t) buf;
+  args.size = (grub_ieee1275_cell_t) size;
+
+  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+    return -1;
+
+  /*
+   * catch_result is set if firmware does not support 2hash-ext-log
+   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
+   */
+  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
+    return -1;
+
+  return 0;
+}
+
 grub_err_t
 grub_tcg2_get_max_output_size (grub_size_t *size)
 {
@@ -155,3 +201,23 @@ grub_tcg2_submit_command (grub_size_t input_size,
 
   return GRUB_ERR_NONE;
 }
+
+grub_err_t
+grub_tcg2_cap_pcr (grub_uint8_t pcr)
+{
+  grub_uint8_t separator[4] = {0};
+  static int error_displayed = 0;
+  int rc;
+
+  rc = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_SEPARATOR,
+					    separator, sizeof(separator),
+					    separator, sizeof(separator));
+  if (rc && !error_displayed)
+    {
+      error_displayed++;
+      return grub_error (GRUB_ERR_BAD_DEVICE,
+			 "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
+    }
+
+  return GRUB_ERR_NONE;
+}
diff --git a/include/grub/ieee1275/tpm.h b/include/grub/ieee1275/tpm.h
index fe5cb4713..01065071b 100644
--- a/include/grub/ieee1275/tpm.h
+++ b/include/grub/ieee1275/tpm.h
@@ -27,4 +27,9 @@ extern grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle;
 
 extern grub_err_t grub_ieee1275_tpm_init (void);
 
+extern int grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
+						grub_uint32_t eventtype,
+						const char *description,
+						grub_size_t description_size,
+						void *buf, grub_size_t size);
 #endif
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 5/7] tss2: Implement grub_tcg2_cap_pcr() for EMU
  2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
                   ` (3 preceding siblings ...)
  2025-07-08  8:31 ` [PATCH 4/7] tss2: Implement grub_tcg2_cap_pcr() for ieee1275 Gary Lin via Grub-devel
@ 2025-07-08  8:31 ` Gary Lin via Grub-devel
  2025-07-08 16:19   ` Stefan Berger
  2025-07-08  8:31 ` [PATCH 6/7] tpm2_key_protector: Support PCR capping Gary Lin via Grub-devel
  2025-07-08  8:31 ` [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping Gary Lin via Grub-devel
  6 siblings, 1 reply; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

Since there is no system fimware for grub-emu, the TPM2_PCR_Event
command becomes the only choice to implement grub_tcg2_cap_pcr().

Signed-off-by: Gary Lin <glin@suse.com>
---
 grub-core/lib/tss2/tcg2_emu.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/grub-core/lib/tss2/tcg2_emu.c b/grub-core/lib/tss2/tcg2_emu.c
index cab930d2b..f461515de 100644
--- a/grub-core/lib/tss2/tcg2_emu.c
+++ b/grub-core/lib/tss2/tcg2_emu.c
@@ -22,6 +22,7 @@
 
 #include <tss2_buffer.h>
 #include <tss2_structs.h>
+#include <tpm2_cmd.h>
 #include <tcg2.h>
 
 grub_err_t
@@ -47,3 +48,21 @@ grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
 
   return GRUB_ERR_NONE;
 }
+
+grub_err_t
+grub_tcg2_cap_pcr (grub_uint8_t pcr)
+{
+  TPMS_AUTH_COMMAND_t authCmd = {0};
+  TPM2B_EVENT_t data = {0};
+  TPM_RC_t rc;
+
+  /* A SEPARATOR event is an event with 4 0-bytes. */
+  data.size = 4;
+  authCmd.sessionHandle = TPM_RS_PW;
+
+  rc = grub_tpm2_pcr_event (pcr, &authCmd, &data, NULL, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
+
+  return GRUB_ERR_NONE;
+}
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 6/7] tpm2_key_protector: Support PCR capping
  2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
                   ` (4 preceding siblings ...)
  2025-07-08  8:31 ` [PATCH 5/7] tss2: Implement grub_tcg2_cap_pcr() for EMU Gary Lin via Grub-devel
@ 2025-07-08  8:31 ` Gary Lin via Grub-devel
  2025-07-08 17:00   ` Stefan Berger
  2025-07-10 15:24   ` Sudhakar Kuppusamy
  2025-07-08  8:31 ` [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping Gary Lin via Grub-devel
  6 siblings, 2 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

To prevent a sealed key from being unsealed again, a common and
straightforward method is to "cap" the key by extending the associated
PCRs. When the PCRs associated with the sealed key are extended, TPM will
be unable to unseal the key, as the PCR values required for unsealing no
longer match, effectively rendering the key unusable until the next
system boot or a state where the PCRs are reset to their expected values.

To cap a specific set of PCRs, simply append the argument '-c pcr_list'
to the tpm2_key_protector command. Upon successfully unsealing the key,
the TPM2 key protector will then invoke tpm2_protector_cap_pcrs(). This
function extends the selected PCRs with a SEPARATOR event, effectively
"capping" them. Consequently, the associated key cannot be unsealed in
any subsequent attempts until these PCRs are reset to their original,
pre-capped state, typically occurring upon the next system boot.

Signed-off-by: Gary Lin <glin@suse.com>
---
 docs/grub.texi                                | 20 ++++++-
 .../commands/tpm2_key_protector/module.c      | 56 ++++++++++++++++++-
 grub-core/normal/main.c                       |  2 +-
 3 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 34b3484dc..bd35e9d46 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -8084,7 +8084,7 @@ either @var{expression1} or @var{expression2} is true
 @node tpm2_key_protector_init
 @subsection tpm2_key_protector_init
 
-@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
+@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [@option{--cap-pcrs} | @option{-c} pcrlist] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
 Initialize the TPM2 key protector to unseal the key for the @command{cryptomount}
 (@pxref{cryptomount}) command. There are two supported modes,
 SRK(@kbd{srk}) and NV index(@kbd{nv}), to be specified by the option
@@ -8099,6 +8099,24 @@ bank that the key is sealed with. The PCR list is a comma-separated list, e.g.,
 bank is chosen by selecting a hash algorithm. The current supported PCR banks
 are SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
 
+The @option{-c} option is introduced to enable the "capping" of a specified list of
+PCRs. This feature addresses scenarios where a user wants to ensure a sealed key
+cannot be unsealed again after its initial use. When the @option{-c} option is
+employed, and the key is successfully unsealed, the TPM2 key protector automatically
+extends the selected PCRs with a SEPARATOR event. This action cryptographically
+alters the PCR values, thereby preventing the associated key from being unsealed in
+any subsequent attempts until those specific PCRs are reset to their original state,
+which typically occurs during a system reboot. In general, it is sufficient to
+extend one associated PCR to cap the key.
+
+It's noteworthy that a key sealed against PCR 8 naturally incorporates a "capping"
+behavior, even without explicitly using a @option{-c} option. This is because GRUB
+measures all commands into PCR 8, including those from configuration files. As a
+result, the value of PCR 8 changes with virtually every command execution during
+the boot process. Consequently, a key sealed against PCR 8 can only be unsealed
+once in a given boot session, as any subsequent GRUB command will alter PCR 8,
+invalidating the unsealing policy and effectively "capping" the key.
+
 Some options are only available for the specific mode. The SRK-specific
 options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
 other hand, the NV index-specific option is @option{-n}.
diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
index b84c2234f..1226b65e0 100644
--- a/grub-core/commands/tpm2_key_protector/module.c
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -28,6 +28,7 @@
 #include <tss2_buffer.h>
 #include <tss2_types.h>
 #include <tss2_mu.h>
+#include <tcg2.h>
 
 #include "tpm2_args.h"
 #include "tpm2.h"
@@ -47,6 +48,7 @@ typedef enum tpm2_protector_options
   OPTION_MODE,
   OPTION_PCRS,
   OPTION_BANK,
+  OPTION_CAPPCRS,
   OPTION_TPM2KEY,
   OPTION_KEYFILE,
   OPTION_SRK,
@@ -61,6 +63,8 @@ typedef struct tpm2_protector_context
   grub_uint8_t pcr_count;
   grub_srk_type_t srk_type;
   TPM_ALG_ID_t bank;
+  grub_uint8_t cap_pcrs[TPM_MAX_PCRS];
+  grub_uint8_t cap_pcr_count;
   const char *tpm2key;
   const char *keyfile;
   TPM_HANDLE_t srk;
@@ -100,6 +104,16 @@ static const struct grub_arg_option tpm2_protector_init_cmd_options[] =
 	N_("Bank of PCRs used to authorize key release: "
 	   "SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"),
     },
+    {
+      .longarg  = "cap-pcrs",
+      .shortarg = 'c',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+	N_("Comma-separated list of PCRs to be capped after key release "
+	   "e.g., '7,11'."),
+    },
     /* SRK-mode options */
     {
       .longarg  = "tpm2key",
@@ -1212,19 +1226,45 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
   return err;
 }
 
+static grub_err_t
+tpm2_protector_cap_pcrs (const tpm2_protector_context_t *ctx)
+{
+  grub_uint8_t i;
+  grub_err_t err;
+
+  for (i = 0; i < ctx->cap_pcr_count; i++)
+    {
+	err = grub_tcg2_cap_pcr (ctx->cap_pcrs[i]);
+	if (err != GRUB_ERR_NONE)
+	  return err;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
 static grub_err_t
 tpm2_protector_recover (const tpm2_protector_context_t *ctx,
 			grub_uint8_t **key, grub_size_t *key_size)
 {
+  grub_err_t err;
+
   switch (ctx->mode)
     {
     case TPM2_PROTECTOR_MODE_SRK:
-      return tpm2_protector_srk_recover (ctx, key, key_size);
+      err = tpm2_protector_srk_recover (ctx, key, key_size);
+      break;
     case TPM2_PROTECTOR_MODE_NV:
-      return tpm2_protector_nv_recover (ctx, key, key_size);
+      err = tpm2_protector_nv_recover (ctx, key, key_size);
+      break;
     default:
-      return GRUB_ERR_BAD_ARGUMENT;
+      err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown Mode"));
     }
+
+  /* Cap the selected PCRs when the key is unsealed successfully */
+  if (ctx->cap_pcr_count > 0 && err == GRUB_ERR_NONE)
+    err = tpm2_protector_cap_pcrs (ctx);
+
+  return err;
 }
 
 static grub_err_t
@@ -1364,6 +1404,15 @@ tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
 	return err;
     }
 
+  if (state[OPTION_CAPPCRS].set)  /* cap-pcrs */
+    {
+      err = grub_tpm2_protector_parse_pcrs (state[OPTION_CAPPCRS].arg,
+					    tpm2_protector_ctx.cap_pcrs,
+					    &tpm2_protector_ctx.cap_pcr_count);
+      if (err != GRUB_ERR_NONE)
+	return err;
+    }
+
   if (state[OPTION_TPM2KEY].set)  /* tpm2key */
     {
       err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
@@ -1465,6 +1514,7 @@ GRUB_MOD_INIT (tpm2_key_protector)
 			  N_("[-m mode] "
 			     "[-p pcr_list] "
 			     "[-b pcr_bank] "
+			     "[-c pcr_list] "
 			     "[-T tpm2_key_file_path] "
 			     "[-k sealed_key_file_path] "
 			     "[-s srk_handle] "
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index 96abfda2f..f823851c4 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -512,7 +512,7 @@ static const char *features[] = {
   "feature_default_font_path", "feature_all_video_module",
   "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
   "feature_nativedisk_cmd", "feature_timeout_style",
-  "feature_search_cryptodisk_only"
+  "feature_search_cryptodisk_only", "feature_tpm2_cap_pcrs"
 };
 
 GRUB_MOD_INIT(normal)
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping
  2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
                   ` (5 preceding siblings ...)
  2025-07-08  8:31 ` [PATCH 6/7] tpm2_key_protector: Support PCR capping Gary Lin via Grub-devel
@ 2025-07-08  8:31 ` Gary Lin via Grub-devel
  2025-07-09 12:31   ` Stefan Berger
  2025-07-10 15:26   ` Sudhakar Kuppusamy
  6 siblings, 2 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-08  8:31 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger

A test is introduced to cap PCR 1 and track the PCR 1 value before and
after key unsealing.

Signed-off-by: Gary Lin <glin@suse.com>
---
 tests/tpm2_key_protector_test.in | 65 ++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/tests/tpm2_key_protector_test.in b/tests/tpm2_key_protector_test.in
index 1d80d5d26..5dd86d6ee 100644
--- a/tests/tpm2_key_protector_test.in
+++ b/tests/tpm2_key_protector_test.in
@@ -304,6 +304,58 @@ EOF
     fi
 }
 
+tpm2_seal_unseal_cap() {
+    pcr_bank="sha256"
+
+    original_pcr1="$(tpm2_pcrread ${pcr_bank}:1) | tail -1 | cut -d' ' -f7"
+
+    grub_cfg=${tpm2testdir}/testcase.cfg
+
+    # Seal the password with grub-protect
+    grub-protect \
+	--tpm2-device="${tpm2dev}" \
+	--action=add \
+	--protector=tpm2 \
+	--tpm2key \
+	--tpm2-bank="${pcr_bank}" \
+	--tpm2-pcrs=0,1 \
+	--tpm2-keyfile="${lukskeyfile}" \
+	--tpm2-outfile="${sealedkey}" || ret=$?
+    if [ "${ret}" -ne 0 ]; then
+	echo "Failed to seal the secret key: ${ret}" >&2
+	return 99
+    fi
+
+    # Write the TPM unsealing script and cap PCR 1
+    cat > "${grub_cfg}" <<EOF
+loopback luks (host)${luksfile}
+tpm2_key_protector_init -T (host)${sealedkey} -c 1
+if cryptomount -a --protector tpm2; then
+    cat (crypto0)+1
+fi
+EOF
+
+    # Test TPM unsealing with the same PCR
+    ${grubshell} --timeout=${timeout} --emu-opts="-t ${tpm2dev}" < "${grub_cfg}" > "${testoutput}" || ret=$?
+
+    if [ "${ret}" -eq 0 ]; then
+	if ! grep -q "^${vtext}$" "${testoutput}"; then
+	    echo "error: test not verified [`cat ${testoutput}`]" >&2
+	    return 1
+	fi
+    else
+	echo "grub-emu exited with error: ${ret}" >&2
+	return 99
+    fi
+
+    capped_pcr1="$(tpm2_pcrread ${pcr_bank}:1) | tail -1 | cut -d' ' -f7"
+
+    if [ "${original_pcr1}" = "${capped_pcr1}" ]; then
+	echo "error: PCR 1 not capped" >&2
+	return 1
+    fi
+}
+
 # Testcases for SRK mode
 declare -a srktests=()
 srktests+=("default transient no_fallback_srk sha256")
@@ -357,4 +409,17 @@ for i in "${!nvtests[@]}"; do
     fi
 done
 
+# Testcase for PCR Capping
+tpm2_seal_unseal_cap || ret=$?
+if [ "${ret}" -eq 0 ]; then
+    echo "TPM2 [PCR Capping]: PASS"
+elif [ "${ret}" -eq 1 ]; then
+    echo "TPM2 [PCR Capping]: FAIL"
+    ret=0
+    exit_status=1
+else
+    echo "Unexpected failure [PCR Capping]" >&2
+    exit ${ret}
+fi
+
 exit ${exit_status}
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 4/7] tss2: Implement grub_tcg2_cap_pcr() for ieee1275
  2025-07-08  8:31 ` [PATCH 4/7] tss2: Implement grub_tcg2_cap_pcr() for ieee1275 Gary Lin via Grub-devel
@ 2025-07-08 15:52   ` Stefan Berger
  2025-07-09  2:08     ` Gary Lin via Grub-devel
  0 siblings, 1 reply; 23+ messages in thread
From: Stefan Berger @ 2025-07-08 15:52 UTC (permalink / raw)
  To: Gary Lin, The development of GNU GRUB; +Cc: Daniel Kiper, mchang, patrick.colp



On 7/8/25 4:31 AM, Gary Lin wrote:
> This commit implements grub_tcg2_cap_pcr() for ieee1275 with the
> firmware function, 2hash-ext-log, to extend the target PCR with a
> SEPARATOR event and record the event into the TPM event log.
> 
> To avoid duplicate code, ibmvtpm_2hash_ext_log() is moved to tcg2.c
> and exported as a global function.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>   grub-core/commands/ieee1275/ibmvtpm.c | 52 ++-------------------
>   grub-core/lib/ieee1275/tcg2.c         | 66 +++++++++++++++++++++++++++
>   include/grub/ieee1275/tpm.h           |  5 ++
>   3 files changed, 74 insertions(+), 49 deletions(-)
> 
> diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
> index 4958b04a9..d0ddc06b0 100644
> --- a/grub-core/commands/ieee1275/ibmvtpm.c
> +++ b/grub-core/commands/ieee1275/ibmvtpm.c
> @@ -27,52 +27,6 @@
>   #include <grub/mm.h>
>   #include <grub/misc.h>
>   
> -static int
> -ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
> -		       grub_uint32_t eventtype,
> -		       const char *description,
> -		       grub_size_t description_size,
> -		       void *buf, grub_size_t size)
> -{
> -  struct tpm_2hash_ext_log
> -  {
> -    struct grub_ieee1275_common_hdr common;
> -    grub_ieee1275_cell_t method;
> -    grub_ieee1275_cell_t ihandle;
> -    grub_ieee1275_cell_t size;
> -    grub_ieee1275_cell_t buf;
> -    grub_ieee1275_cell_t description_size;
> -    grub_ieee1275_cell_t description;
> -    grub_ieee1275_cell_t eventtype;
> -    grub_ieee1275_cell_t pcrindex;
> -    grub_ieee1275_cell_t catch_result;
> -    grub_ieee1275_cell_t rc;
> -  };
> -  struct tpm_2hash_ext_log args;
> -
> -  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
> -  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
> -  args.ihandle = grub_ieee1275_tpm_ihandle;
> -  args.pcrindex = pcrindex;
> -  args.eventtype = eventtype;
> -  args.description = (grub_ieee1275_cell_t) description;
> -  args.description_size = description_size;
> -  args.buf = (grub_ieee1275_cell_t) buf;
> -  args.size = (grub_ieee1275_cell_t) size;
> -
> -  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
> -    return -1;
> -
> -  /*
> -   * catch_result is set if firmware does not support 2hash-ext-log
> -   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
> -   */
> -  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
> -    return -1;
> -
> -  return 0;
> -}
> -
>   static grub_err_t
>   tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
>   		const char *description)
> @@ -80,9 +34,9 @@ tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
>     static int error_displayed = 0;
>     int rc;
>   
> -  rc = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
> -			      description, grub_strlen(description) + 1,
> -			      buf, size);
> +  rc = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_IPL,
> +					    description, grub_strlen(description) + 1,
> +					    buf, size);
>     if (rc && !error_displayed)
>       {
>         error_displayed++;
> diff --git a/grub-core/lib/ieee1275/tcg2.c b/grub-core/lib/ieee1275/tcg2.c
> index 40161c2f9..945a3469b 100644
> --- a/grub-core/lib/ieee1275/tcg2.c
> +++ b/grub-core/lib/ieee1275/tcg2.c
> @@ -56,6 +56,52 @@ grub_ieee1275_tpm_init (void)
>     return GRUB_ERR_NONE;
>   }
>   
> +int
> +grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
> +				     grub_uint32_t eventtype,
> +				     const char *description,
> +				     grub_size_t description_size,
> +				     void *buf, grub_size_t size)
> +{
> +  struct tpm_2hash_ext_log
> +  {
> +    struct grub_ieee1275_common_hdr common;
> +    grub_ieee1275_cell_t method;
> +    grub_ieee1275_cell_t ihandle;
> +    grub_ieee1275_cell_t size;
> +    grub_ieee1275_cell_t buf;
> +    grub_ieee1275_cell_t description_size;
> +    grub_ieee1275_cell_t description;
> +    grub_ieee1275_cell_t eventtype;
> +    grub_ieee1275_cell_t pcrindex;
> +    grub_ieee1275_cell_t catch_result;
> +    grub_ieee1275_cell_t rc;
> +  };
> +  struct tpm_2hash_ext_log args;
> +
> +  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
> +  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
> +  args.ihandle = grub_ieee1275_tpm_ihandle;
> +  args.pcrindex = pcrindex;
> +  args.eventtype = eventtype;
> +  args.description = (grub_ieee1275_cell_t) description;
> +  args.description_size = description_size;
> +  args.buf = (grub_ieee1275_cell_t) buf;
> +  args.size = (grub_ieee1275_cell_t) size;
> +
> +  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
> +    return -1;
> +
> +  /*
> +   * catch_result is set if firmware does not support 2hash-ext-log
> +   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
> +   */
> +  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
> +    return -1;

Now there are two callers of this function that each would create an 
error hinting at the firmware being too old if the firmware call fails. 
It's probably worth putting the grub_error call into this function here 
to avoid replication.

The rest looks good.

> +
> +  return 0;
> +}
> +
>   grub_err_t
>   grub_tcg2_get_max_output_size (grub_size_t *size)
>   {
> @@ -155,3 +201,23 @@ grub_tcg2_submit_command (grub_size_t input_size,
>   
>     return GRUB_ERR_NONE;
>   }
> +
> +grub_err_t
> +grub_tcg2_cap_pcr (grub_uint8_t pcr)
> +{
> +  grub_uint8_t separator[4] = {0};
> +  static int error_displayed = 0;
> +  int rc;
> +
> +  rc = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_SEPARATOR,
> +					    separator, sizeof(separator),
> +					    separator, sizeof(separator));
> +  if (rc && !error_displayed)
> +    {
> +      error_displayed++;
> +      return grub_error (GRUB_ERR_BAD_DEVICE,
> +			 "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> diff --git a/include/grub/ieee1275/tpm.h b/include/grub/ieee1275/tpm.h
> index fe5cb4713..01065071b 100644
> --- a/include/grub/ieee1275/tpm.h
> +++ b/include/grub/ieee1275/tpm.h
> @@ -27,4 +27,9 @@ extern grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle;
>   
>   extern grub_err_t grub_ieee1275_tpm_init (void);
>   
> +extern int grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
> +						grub_uint32_t eventtype,
> +						const char *description,
> +						grub_size_t description_size,
> +						void *buf, grub_size_t size);
>   #endif


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr()
  2025-07-08  8:31 ` [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr() Gary Lin via Grub-devel
@ 2025-07-08 16:05   ` Stefan Berger
  2025-07-10 15:09   ` Sudhakar Kuppusamy
  1 sibling, 0 replies; 23+ messages in thread
From: Stefan Berger @ 2025-07-08 16:05 UTC (permalink / raw)
  To: Gary Lin, The development of GNU GRUB; +Cc: Daniel Kiper, mchang, patrick.colp



On 7/8/25 4:31 AM, Gary Lin wrote:
> This commit introduces the definition of grub_tcg2_cap_pcr(), a new
> function designed to enhance the security of sealed keys. Its primary
> purpose is to "cap" a specific PCR by extending it with a SEPARATOR
> event. This action cryptographically alters the PCR value, making it
> impossible to unseal any key that was previously sealed to the original
> PCR state. Consequently, the sealed key remains protected against
> unauthorized unsealing attempts until the associated PCRs are reset to
> their initial configuration, typically occurring during a subsequent
> system boot.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>   grub-core/lib/tss2/tcg2.h | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/grub-core/lib/tss2/tcg2.h b/grub-core/lib/tss2/tcg2.h
> index 3d26373dd..c7e80d355 100644
> --- a/grub-core/lib/tss2/tcg2.h
> +++ b/grub-core/lib/tss2/tcg2.h
> @@ -23,6 +23,8 @@
>   #include <grub/err.h>
>   #include <grub/types.h>
>   
> +#define EV_SEPARATOR 0x04
> +
>   extern grub_err_t
>   grub_tcg2_get_max_output_size (grub_size_t *size);
>   
> @@ -32,4 +34,7 @@ grub_tcg2_submit_command (grub_size_t input_size,
>   			  grub_size_t output_size,
>   			  grub_uint8_t *output);
>   
> +extern grub_err_t
> +grub_tcg2_cap_pcr (grub_uint8_t pcr);
> +
>   #endif /* ! GRUB_TPM2_TCG2_HEADER */

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 5/7] tss2: Implement grub_tcg2_cap_pcr() for EMU
  2025-07-08  8:31 ` [PATCH 5/7] tss2: Implement grub_tcg2_cap_pcr() for EMU Gary Lin via Grub-devel
@ 2025-07-08 16:19   ` Stefan Berger
  2025-07-09  2:35     ` Gary Lin via Grub-devel
  0 siblings, 1 reply; 23+ messages in thread
From: Stefan Berger @ 2025-07-08 16:19 UTC (permalink / raw)
  To: Gary Lin, The development of GNU GRUB; +Cc: Daniel Kiper, mchang, patrick.colp



On 7/8/25 4:31 AM, Gary Lin wrote:
> Since there is no system fimware for grub-emu, the TPM2_PCR_Event

s/fimware/firmware

> command becomes the only choice to implement grub_tcg2_cap_pcr().
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>   grub-core/lib/tss2/tcg2_emu.c | 19 +++++++++++++++++++
>   1 file changed, 19 insertions(+)
> 
> diff --git a/grub-core/lib/tss2/tcg2_emu.c b/grub-core/lib/tss2/tcg2_emu.c
> index cab930d2b..f461515de 100644
> --- a/grub-core/lib/tss2/tcg2_emu.c
> +++ b/grub-core/lib/tss2/tcg2_emu.c
> @@ -22,6 +22,7 @@
>   
>   #include <tss2_buffer.h>
>   #include <tss2_structs.h>
> +#include <tpm2_cmd.h>
>   #include <tcg2.h>
>   
>   grub_err_t
> @@ -47,3 +48,21 @@ grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
>   
>     return GRUB_ERR_NONE;
>   }
> +
> +grub_err_t
> +grub_tcg2_cap_pcr (grub_uint8_t pcr)
> +{
> +  TPMS_AUTH_COMMAND_t authCmd = {0};

TPMS_AUTH_COMMAND_t authCmd = {
     .sessionHandle = TPM_RS_PW,
};
TPM2B_EVENT_t data = {
     .size = 4,
};


> +  TPM2B_EVENT_t data = {0};
> +  TPM_RC_t rc;
> +
> +  /* A SEPARATOR event is an event with 4 0-bytes. */
> +  data.size = 4;
> +  authCmd.sessionHandle = TPM_RS_PW;
> +
> +  rc = grub_tpm2_pcr_event (pcr, &authCmd, &data, NULL, NULL);
> +  if (rc != TPM_RC_SUCCESS)
> +    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
 > +> +  return GRUB_ERR_NONE;
> +}

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/7] tss2: Implement grub_tcg2_cap_pcr() for EFI
  2025-07-08  8:31 ` [PATCH 3/7] tss2: Implement grub_tcg2_cap_pcr() for EFI Gary Lin via Grub-devel
@ 2025-07-08 16:27   ` Stefan Berger
  2025-07-09  2:04     ` Gary Lin via Grub-devel
  0 siblings, 1 reply; 23+ messages in thread
From: Stefan Berger @ 2025-07-08 16:27 UTC (permalink / raw)
  To: Gary Lin, The development of GNU GRUB; +Cc: Daniel Kiper, mchang, patrick.colp



On 7/8/25 4:31 AM, Gary Lin wrote:
> This commit implements grub_tcg2_cap_pcr() for EFI by using the UEFI
> TCG2 protocol, HashLogExtendEvent, to extend the specified PCR with a
> SEPARATOR event and ensure the event will be recorded properly in the

EV_SEPARATOR ?

> TPM event log.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>   grub-core/lib/efi/tcg2.c | 41 ++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 41 insertions(+)
> 
> diff --git a/grub-core/lib/efi/tcg2.c b/grub-core/lib/efi/tcg2.c
> index 841bf50bb..81f5dea24 100644
> --- a/grub-core/lib/efi/tcg2.c
> +++ b/grub-core/lib/efi/tcg2.c
> @@ -22,6 +22,7 @@
>   #include <grub/efi/tpm.h>
>   #include <grub/mm.h>
>   
> +#include <tss2_types.h>
>   #include <tcg2.h>
>   
>   static grub_err_t
> @@ -141,3 +142,43 @@ grub_tcg2_submit_command (grub_size_t input_size,
>   
>     return GRUB_ERR_NONE;
>   }
> +
> +grub_err_t
> +grub_tcg2_cap_pcr (grub_uint8_t pcr)
> +{
> +  grub_err_t err;
> +  grub_efi_status_t status;
> +  grub_efi_tpm2_protocol_t *protocol;
> +  EFI_TCG2_EVENT *event;
> +  grub_uint8_t separator[4] = {0};
> +
> +  if (pcr >= TPM_MAX_PCRS)
> +    return GRUB_ERR_BAD_ARGUMENT;
> +
> +  err = tcg2_get_protocol (&protocol);
> +  if (err != GRUB_ERR_NONE)
> +    return err;
> +
> +  event = grub_zalloc (sizeof (EFI_TCG2_EVENT) + sizeof (separator));
> +  if (!event)
> +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> +		       N_("cannot allocate TPM event buffer"));
> +
> +  event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
> +  event->Header.HeaderVersion = 1;
> +  event->Header.PCRIndex = pcr;
> +  event->Header.EventType = EV_SEPARATOR;
> +  event->Size = sizeof (*event) - sizeof (event->Event) + sizeof (separator);
> +  grub_memcpy (event->Event, separator, sizeof (separator));
> +
> +

One too many empty lines.

> +  status = protocol->hash_log_extend_event (protocol, 0,
> +					    (grub_addr_t) separator,
> +					    sizeof (separator), event);
> +  grub_free (event);
> +
> +  if (status != GRUB_EFI_SUCCESS)
> +    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
> +
> +  return GRUB_ERR_NONE;
> +}

With nit fixed:

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] tpm2_key_protector: Support PCR capping
  2025-07-08  8:31 ` [PATCH 6/7] tpm2_key_protector: Support PCR capping Gary Lin via Grub-devel
@ 2025-07-08 17:00   ` Stefan Berger
  2025-07-10 15:24   ` Sudhakar Kuppusamy
  1 sibling, 0 replies; 23+ messages in thread
From: Stefan Berger @ 2025-07-08 17:00 UTC (permalink / raw)
  To: Gary Lin, The development of GNU GRUB; +Cc: Daniel Kiper, mchang, patrick.colp



On 7/8/25 4:31 AM, Gary Lin wrote:
> To prevent a sealed key from being unsealed again, a common and
> straightforward method is to "cap" the key by extending the associated
> PCRs. When the PCRs associated with the sealed key are extended, TPM will
> be unable to unseal the key, as the PCR values required for unsealing no
> longer match, effectively rendering the key unusable until the next
> system boot or a state where the PCRs are reset to their expected values.
> 
> To cap a specific set of PCRs, simply append the argument '-c pcr_list'
> to the tpm2_key_protector command. Upon successfully unsealing the key,
> the TPM2 key protector will then invoke tpm2_protector_cap_pcrs(). This
> function extends the selected PCRs with a SEPARATOR event, effectively
> "capping" them. Consequently, the associated key cannot be unsealed in
> any subsequent attempts until these PCRs are reset to their original,
> pre-capped state, typically occurring upon the next system boot.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>   docs/grub.texi                                | 20 ++++++-
>   .../commands/tpm2_key_protector/module.c      | 56 ++++++++++++++++++-
>   grub-core/normal/main.c                       |  2 +-
>   3 files changed, 73 insertions(+), 5 deletions(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 34b3484dc..bd35e9d46 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -8084,7 +8084,7 @@ either @var{expression1} or @var{expression2} is true
>   @node tpm2_key_protector_init
>   @subsection tpm2_key_protector_init
>   
> -@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
> +@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [@option{--cap-pcrs} | @option{-c} pcrlist] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
>   Initialize the TPM2 key protector to unseal the key for the @command{cryptomount}
>   (@pxref{cryptomount}) command. There are two supported modes,
>   SRK(@kbd{srk}) and NV index(@kbd{nv}), to be specified by the option
> @@ -8099,6 +8099,24 @@ bank that the key is sealed with. The PCR list is a comma-separated list, e.g.,
>   bank is chosen by selecting a hash algorithm. The current supported PCR banks
>   are SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
>   
> +The @option{-c} option is introduced to enable the "capping" of a specified list of
> +PCRs. This feature addresses scenarios where a user wants to ensure a sealed key
> +cannot be unsealed again after its initial use. When the @option{-c} option is
> +employed, and the key is successfully unsealed, the TPM2 key protector automatically
> +extends the selected PCRs with a SEPARATOR event. This action cryptographically
> +alters the PCR values, thereby preventing the associated key from being unsealed in
> +any subsequent attempts until those specific PCRs are reset to their original state,
> +which typically occurs during a system reboot. In general, it is sufficient to
> +extend one associated PCR to cap the key.
> +
> +It's noteworthy that a key sealed against PCR 8 naturally incorporates a "capping"
> +behavior, even without explicitly using a @option{-c} option. This is because GRUB
> +measures all commands into PCR 8, including those from configuration files. As a
> +result, the value of PCR 8 changes with virtually every command execution during
> +the boot process. Consequently, a key sealed against PCR 8 can only be unsealed
> +once in a given boot session, as any subsequent GRUB command will alter PCR 8,
> +invalidating the unsealing policy and effectively "capping" the key.
> +
>   Some options are only available for the specific mode. The SRK-specific
>   options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
>   other hand, the NV index-specific option is @option{-n}.
> diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
> index b84c2234f..1226b65e0 100644
> --- a/grub-core/commands/tpm2_key_protector/module.c
> +++ b/grub-core/commands/tpm2_key_protector/module.c
> @@ -28,6 +28,7 @@
>   #include <tss2_buffer.h>
>   #include <tss2_types.h>
>   #include <tss2_mu.h>
> +#include <tcg2.h>
>   
>   #include "tpm2_args.h"
>   #include "tpm2.h"
> @@ -47,6 +48,7 @@ typedef enum tpm2_protector_options
>     OPTION_MODE,
>     OPTION_PCRS,
>     OPTION_BANK,
> +  OPTION_CAPPCRS,
>     OPTION_TPM2KEY,
>     OPTION_KEYFILE,
>     OPTION_SRK,
> @@ -61,6 +63,8 @@ typedef struct tpm2_protector_context
>     grub_uint8_t pcr_count;
>     grub_srk_type_t srk_type;
>     TPM_ALG_ID_t bank;
> +  grub_uint8_t cap_pcrs[TPM_MAX_PCRS];
> +  grub_uint8_t cap_pcr_count;
>     const char *tpm2key;
>     const char *keyfile;
>     TPM_HANDLE_t srk;
> @@ -100,6 +104,16 @@ static const struct grub_arg_option tpm2_protector_init_cmd_options[] =
>   	N_("Bank of PCRs used to authorize key release: "
>   	   "SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"),
>       },
> +    {
> +      .longarg  = "cap-pcrs",
> +      .shortarg = 'c',
> +      .flags    = 0,
> +      .arg      = NULL,
> +      .type     = ARG_TYPE_STRING,
> +      .doc      =
> +	N_("Comma-separated list of PCRs to be capped after key release "
> +	   "e.g., '7,11'."),
> +    },
>       /* SRK-mode options */
>       {
>         .longarg  = "tpm2key",
> @@ -1212,19 +1226,45 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
>     return err;
>   }
>   
> +static grub_err_t
> +tpm2_protector_cap_pcrs (const tpm2_protector_context_t *ctx)
> +{
> +  grub_uint8_t i;
> +  grub_err_t err;
> +
> +  for (i = 0; i < ctx->cap_pcr_count; i++)
> +    {
> +	err = grub_tcg2_cap_pcr (ctx->cap_pcrs[i]);
> +	if (err != GRUB_ERR_NONE)
> +	  return err;
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
>   static grub_err_t
>   tpm2_protector_recover (const tpm2_protector_context_t *ctx,
>   			grub_uint8_t **key, grub_size_t *key_size)
>   {
> +  grub_err_t err;
> +
>     switch (ctx->mode)
>       {
>       case TPM2_PROTECTOR_MODE_SRK:
> -      return tpm2_protector_srk_recover (ctx, key, key_size);
> +      err = tpm2_protector_srk_recover (ctx, key, key_size);
> +      break;
>       case TPM2_PROTECTOR_MODE_NV:
> -      return tpm2_protector_nv_recover (ctx, key, key_size);
> +      err = tpm2_protector_nv_recover (ctx, key, key_size);
> +      break;
>       default:
> -      return GRUB_ERR_BAD_ARGUMENT;
> +      err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown Mode"));
>       }
> +
> +  /* Cap the selected PCRs when the key is unsealed successfully */
> +  if (ctx->cap_pcr_count > 0 && err == GRUB_ERR_NONE)
> +    err = tpm2_protector_cap_pcrs (ctx);
> +
> +  return err;
>   }
>   
>   static grub_err_t
> @@ -1364,6 +1404,15 @@ tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
>   	return err;
>       }
>   
> +  if (state[OPTION_CAPPCRS].set)  /* cap-pcrs */
> +    {
> +      err = grub_tpm2_protector_parse_pcrs (state[OPTION_CAPPCRS].arg,
> +					    tpm2_protector_ctx.cap_pcrs,
> +					    &tpm2_protector_ctx.cap_pcr_count);
> +      if (err != GRUB_ERR_NONE)
> +	return err;
> +    }
> +
>     if (state[OPTION_TPM2KEY].set)  /* tpm2key */
>       {
>         err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
> @@ -1465,6 +1514,7 @@ GRUB_MOD_INIT (tpm2_key_protector)
>   			  N_("[-m mode] "
>   			     "[-p pcr_list] "
>   			     "[-b pcr_bank] "
> +			     "[-c pcr_list] "
>   			     "[-T tpm2_key_file_path] "
>   			     "[-k sealed_key_file_path] "
>   			     "[-s srk_handle] "
> diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
> index 96abfda2f..f823851c4 100644
> --- a/grub-core/normal/main.c
> +++ b/grub-core/normal/main.c
> @@ -512,7 +512,7 @@ static const char *features[] = {
>     "feature_default_font_path", "feature_all_video_module",
>     "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
>     "feature_nativedisk_cmd", "feature_timeout_style",
> -  "feature_search_cryptodisk_only"
> +  "feature_search_cryptodisk_only", "feature_tpm2_cap_pcrs"
>   };
>   
>   GRUB_MOD_INIT(normal)


Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/7] tss2: Implement grub_tcg2_cap_pcr() for EFI
  2025-07-08 16:27   ` Stefan Berger
@ 2025-07-09  2:04     ` Gary Lin via Grub-devel
  0 siblings, 0 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-09  2:04 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, mchang,
	patrick.colp

On Tue, Jul 08, 2025 at 12:27:09PM -0400, Stefan Berger wrote:
> 
> 
> On 7/8/25 4:31 AM, Gary Lin wrote:
> > This commit implements grub_tcg2_cap_pcr() for EFI by using the UEFI
> > TCG2 protocol, HashLogExtendEvent, to extend the specified PCR with a
> > SEPARATOR event and ensure the event will be recorded properly in the
> 
> EV_SEPARATOR ?
Hmmm I should use EV_SEPARATOR in the whole patch set. I'll update other
patches to use EV_SEPARATOR.

> 
> > TPM event log.
> > 
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> >   grub-core/lib/efi/tcg2.c | 41 ++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 41 insertions(+)
> > 
> > diff --git a/grub-core/lib/efi/tcg2.c b/grub-core/lib/efi/tcg2.c
> > index 841bf50bb..81f5dea24 100644
> > --- a/grub-core/lib/efi/tcg2.c
> > +++ b/grub-core/lib/efi/tcg2.c
> > @@ -22,6 +22,7 @@
> >   #include <grub/efi/tpm.h>
> >   #include <grub/mm.h>
> > +#include <tss2_types.h>
> >   #include <tcg2.h>
> >   static grub_err_t
> > @@ -141,3 +142,43 @@ grub_tcg2_submit_command (grub_size_t input_size,
> >     return GRUB_ERR_NONE;
> >   }
> > +
> > +grub_err_t
> > +grub_tcg2_cap_pcr (grub_uint8_t pcr)
> > +{
> > +  grub_err_t err;
> > +  grub_efi_status_t status;
> > +  grub_efi_tpm2_protocol_t *protocol;
> > +  EFI_TCG2_EVENT *event;
> > +  grub_uint8_t separator[4] = {0};
> > +
> > +  if (pcr >= TPM_MAX_PCRS)
> > +    return GRUB_ERR_BAD_ARGUMENT;
> > +
> > +  err = tcg2_get_protocol (&protocol);
> > +  if (err != GRUB_ERR_NONE)
> > +    return err;
> > +
> > +  event = grub_zalloc (sizeof (EFI_TCG2_EVENT) + sizeof (separator));
> > +  if (!event)
> > +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> > +		       N_("cannot allocate TPM event buffer"));
> > +
> > +  event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
> > +  event->Header.HeaderVersion = 1;
> > +  event->Header.PCRIndex = pcr;
> > +  event->Header.EventType = EV_SEPARATOR;
> > +  event->Size = sizeof (*event) - sizeof (event->Event) + sizeof (separator);
> > +  grub_memcpy (event->Event, separator, sizeof (separator));
> > +
> > +
> 
> One too many empty lines.
> 
Will fix it in v2.

> > +  status = protocol->hash_log_extend_event (protocol, 0,
> > +					    (grub_addr_t) separator,
> > +					    sizeof (separator), event);
> > +  grub_free (event);
> > +
> > +  if (status != GRUB_EFI_SUCCESS)
> > +    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
> > +
> > +  return GRUB_ERR_NONE;
> > +}
> 
> With nit fixed:
> 
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> 
Thanks!

Gary Lin

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 4/7] tss2: Implement grub_tcg2_cap_pcr() for ieee1275
  2025-07-08 15:52   ` Stefan Berger
@ 2025-07-09  2:08     ` Gary Lin via Grub-devel
  0 siblings, 0 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-09  2:08 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, mchang,
	patrick.colp

On Tue, Jul 08, 2025 at 11:52:48AM -0400, Stefan Berger wrote:
> 
> 
> On 7/8/25 4:31 AM, Gary Lin wrote:
> > This commit implements grub_tcg2_cap_pcr() for ieee1275 with the
> > firmware function, 2hash-ext-log, to extend the target PCR with a
> > SEPARATOR event and record the event into the TPM event log.
> > 
> > To avoid duplicate code, ibmvtpm_2hash_ext_log() is moved to tcg2.c
> > and exported as a global function.
> > 
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> >   grub-core/commands/ieee1275/ibmvtpm.c | 52 ++-------------------
> >   grub-core/lib/ieee1275/tcg2.c         | 66 +++++++++++++++++++++++++++
> >   include/grub/ieee1275/tpm.h           |  5 ++
> >   3 files changed, 74 insertions(+), 49 deletions(-)
> > 
> > diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
> > index 4958b04a9..d0ddc06b0 100644
> > --- a/grub-core/commands/ieee1275/ibmvtpm.c
> > +++ b/grub-core/commands/ieee1275/ibmvtpm.c
> > @@ -27,52 +27,6 @@
> >   #include <grub/mm.h>
> >   #include <grub/misc.h>
> > -static int
> > -ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
> > -		       grub_uint32_t eventtype,
> > -		       const char *description,
> > -		       grub_size_t description_size,
> > -		       void *buf, grub_size_t size)
> > -{
> > -  struct tpm_2hash_ext_log
> > -  {
> > -    struct grub_ieee1275_common_hdr common;
> > -    grub_ieee1275_cell_t method;
> > -    grub_ieee1275_cell_t ihandle;
> > -    grub_ieee1275_cell_t size;
> > -    grub_ieee1275_cell_t buf;
> > -    grub_ieee1275_cell_t description_size;
> > -    grub_ieee1275_cell_t description;
> > -    grub_ieee1275_cell_t eventtype;
> > -    grub_ieee1275_cell_t pcrindex;
> > -    grub_ieee1275_cell_t catch_result;
> > -    grub_ieee1275_cell_t rc;
> > -  };
> > -  struct tpm_2hash_ext_log args;
> > -
> > -  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
> > -  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
> > -  args.ihandle = grub_ieee1275_tpm_ihandle;
> > -  args.pcrindex = pcrindex;
> > -  args.eventtype = eventtype;
> > -  args.description = (grub_ieee1275_cell_t) description;
> > -  args.description_size = description_size;
> > -  args.buf = (grub_ieee1275_cell_t) buf;
> > -  args.size = (grub_ieee1275_cell_t) size;
> > -
> > -  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
> > -    return -1;
> > -
> > -  /*
> > -   * catch_result is set if firmware does not support 2hash-ext-log
> > -   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
> > -   */
> > -  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
> > -    return -1;
> > -
> > -  return 0;
> > -}
> > -
> >   static grub_err_t
> >   tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
> >   		const char *description)
> > @@ -80,9 +34,9 @@ tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
> >     static int error_displayed = 0;
> >     int rc;
> > -  rc = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
> > -			      description, grub_strlen(description) + 1,
> > -			      buf, size);
> > +  rc = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_IPL,
> > +					    description, grub_strlen(description) + 1,
> > +					    buf, size);
> >     if (rc && !error_displayed)
> >       {
> >         error_displayed++;
> > diff --git a/grub-core/lib/ieee1275/tcg2.c b/grub-core/lib/ieee1275/tcg2.c
> > index 40161c2f9..945a3469b 100644
> > --- a/grub-core/lib/ieee1275/tcg2.c
> > +++ b/grub-core/lib/ieee1275/tcg2.c
> > @@ -56,6 +56,52 @@ grub_ieee1275_tpm_init (void)
> >     return GRUB_ERR_NONE;
> >   }
> > +int
> > +grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
> > +				     grub_uint32_t eventtype,
> > +				     const char *description,
> > +				     grub_size_t description_size,
> > +				     void *buf, grub_size_t size)
> > +{
> > +  struct tpm_2hash_ext_log
> > +  {
> > +    struct grub_ieee1275_common_hdr common;
> > +    grub_ieee1275_cell_t method;
> > +    grub_ieee1275_cell_t ihandle;
> > +    grub_ieee1275_cell_t size;
> > +    grub_ieee1275_cell_t buf;
> > +    grub_ieee1275_cell_t description_size;
> > +    grub_ieee1275_cell_t description;
> > +    grub_ieee1275_cell_t eventtype;
> > +    grub_ieee1275_cell_t pcrindex;
> > +    grub_ieee1275_cell_t catch_result;
> > +    grub_ieee1275_cell_t rc;
> > +  };
> > +  struct tpm_2hash_ext_log args;
> > +
> > +  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
> > +  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
> > +  args.ihandle = grub_ieee1275_tpm_ihandle;
> > +  args.pcrindex = pcrindex;
> > +  args.eventtype = eventtype;
> > +  args.description = (grub_ieee1275_cell_t) description;
> > +  args.description_size = description_size;
> > +  args.buf = (grub_ieee1275_cell_t) buf;
> > +  args.size = (grub_ieee1275_cell_t) size;
> > +
> > +  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
> > +    return -1;
> > +
> > +  /*
> > +   * catch_result is set if firmware does not support 2hash-ext-log
> > +   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
> > +   */
> > +  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
> > +    return -1;
> 
> Now there are two callers of this function that each would create an error
> hinting at the firmware being too old if the firmware call fails. It's
> probably worth putting the grub_error call into this function here to avoid
> replication.
> 
Ok, I'll update the function to return a proper grub_err.

> The rest looks good.

Thanks!

Gary Lin

> 
> > +
> > +  return 0;
> > +}
> > +
> >   grub_err_t
> >   grub_tcg2_get_max_output_size (grub_size_t *size)
> >   {
> > @@ -155,3 +201,23 @@ grub_tcg2_submit_command (grub_size_t input_size,
> >     return GRUB_ERR_NONE;
> >   }
> > +
> > +grub_err_t
> > +grub_tcg2_cap_pcr (grub_uint8_t pcr)
> > +{
> > +  grub_uint8_t separator[4] = {0};
> > +  static int error_displayed = 0;
> > +  int rc;
> > +
> > +  rc = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_SEPARATOR,
> > +					    separator, sizeof(separator),
> > +					    separator, sizeof(separator));
> > +  if (rc && !error_displayed)
> > +    {
> > +      error_displayed++;
> > +      return grub_error (GRUB_ERR_BAD_DEVICE,
> > +			 "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
> > +    }
> > +
> > +  return GRUB_ERR_NONE;
> > +}
> > diff --git a/include/grub/ieee1275/tpm.h b/include/grub/ieee1275/tpm.h
> > index fe5cb4713..01065071b 100644
> > --- a/include/grub/ieee1275/tpm.h
> > +++ b/include/grub/ieee1275/tpm.h
> > @@ -27,4 +27,9 @@ extern grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle;
> >   extern grub_err_t grub_ieee1275_tpm_init (void);
> > +extern int grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
> > +						grub_uint32_t eventtype,
> > +						const char *description,
> > +						grub_size_t description_size,
> > +						void *buf, grub_size_t size);
> >   #endif
> 

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 5/7] tss2: Implement grub_tcg2_cap_pcr() for EMU
  2025-07-08 16:19   ` Stefan Berger
@ 2025-07-09  2:35     ` Gary Lin via Grub-devel
  0 siblings, 0 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-09  2:35 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, mchang,
	patrick.colp

On Tue, Jul 08, 2025 at 12:19:18PM -0400, Stefan Berger wrote:
> 
> 
> On 7/8/25 4:31 AM, Gary Lin wrote:
> > Since there is no system fimware for grub-emu, the TPM2_PCR_Event
> 
> s/fimware/firmware
Will fix the typo in v2.

> 
> > command becomes the only choice to implement grub_tcg2_cap_pcr().
> > 
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> >   grub-core/lib/tss2/tcg2_emu.c | 19 +++++++++++++++++++
> >   1 file changed, 19 insertions(+)
> > 
> > diff --git a/grub-core/lib/tss2/tcg2_emu.c b/grub-core/lib/tss2/tcg2_emu.c
> > index cab930d2b..f461515de 100644
> > --- a/grub-core/lib/tss2/tcg2_emu.c
> > +++ b/grub-core/lib/tss2/tcg2_emu.c
> > @@ -22,6 +22,7 @@
> >   #include <tss2_buffer.h>
> >   #include <tss2_structs.h>
> > +#include <tpm2_cmd.h>
> >   #include <tcg2.h>
> >   grub_err_t
> > @@ -47,3 +48,21 @@ grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
> >     return GRUB_ERR_NONE;
> >   }
> > +
> > +grub_err_t
> > +grub_tcg2_cap_pcr (grub_uint8_t pcr)
> > +{
> > +  TPMS_AUTH_COMMAND_t authCmd = {0};
> 
> TPMS_AUTH_COMMAND_t authCmd = {
>     .sessionHandle = TPM_RS_PW,
> };
> TPM2B_EVENT_t data = {
>     .size = 4,
> };
> 
Will update the initialization of the variables in v2.

> 
> > +  TPM2B_EVENT_t data = {0};
> > +  TPM_RC_t rc;
> > +
> > +  /* A SEPARATOR event is an event with 4 0-bytes. */
> > +  data.size = 4;
> > +  authCmd.sessionHandle = TPM_RS_PW;
> > +
> > +  rc = grub_tpm2_pcr_event (pcr, &authCmd, &data, NULL, NULL);
> > +  if (rc != TPM_RC_SUCCESS)
> > +    return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
> > +> +  return GRUB_ERR_NONE;
> > +}
> 
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> 
Thanks,

Gary Lin


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping
  2025-07-08  8:31 ` [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping Gary Lin via Grub-devel
@ 2025-07-09 12:31   ` Stefan Berger
  2025-07-10 15:26   ` Sudhakar Kuppusamy
  1 sibling, 0 replies; 23+ messages in thread
From: Stefan Berger @ 2025-07-09 12:31 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp



On 7/8/25 4:31 AM, Gary Lin via Grub-devel wrote:
> A test is introduced to cap PCR 1 and track the PCR 1 value before and
> after key unsealing.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>   tests/tpm2_key_protector_test.in | 65 ++++++++++++++++++++++++++++++++
>   1 file changed, 65 insertions(+)
> 
> diff --git a/tests/tpm2_key_protector_test.in b/tests/tpm2_key_protector_test.in
> index 1d80d5d26..5dd86d6ee 100644
> --- a/tests/tpm2_key_protector_test.in
> +++ b/tests/tpm2_key_protector_test.in
> @@ -304,6 +304,58 @@ EOF
>       fi
>   }
>   
> +tpm2_seal_unseal_cap() {
> +    pcr_bank="sha256"
> +
> +    original_pcr1="$(tpm2_pcrread ${pcr_bank}:1) | tail -1 | cut -d' ' -f7"
> +
> +    grub_cfg=${tpm2testdir}/testcase.cfg
> +
> +    # Seal the password with grub-protect
> +    grub-protect \
> +	--tpm2-device="${tpm2dev}" \
> +	--action=add \
> +	--protector=tpm2 \
> +	--tpm2key \
> +	--tpm2-bank="${pcr_bank}" \
> +	--tpm2-pcrs=0,1 \
> +	--tpm2-keyfile="${lukskeyfile}" \
> +	--tpm2-outfile="${sealedkey}" || ret=$?
> +    if [ "${ret}" -ne 0 ]; then
> +	echo "Failed to seal the secret key: ${ret}" >&2
> +	return 99
> +    fi
> +
> +    # Write the TPM unsealing script and cap PCR 1
> +    cat > "${grub_cfg}" <<EOF
> +loopback luks (host)${luksfile}
> +tpm2_key_protector_init -T (host)${sealedkey} -c 1
> +if cryptomount -a --protector tpm2; then
> +    cat (crypto0)+1
> +fi
> +EOF
> +
> +    # Test TPM unsealing with the same PCR
> +    ${grubshell} --timeout=${timeout} --emu-opts="-t ${tpm2dev}" < "${grub_cfg}" > "${testoutput}" || ret=$?
> +
> +    if [ "${ret}" -eq 0 ]; then
> +	if ! grep -q "^${vtext}$" "${testoutput}"; then
> +	    echo "error: test not verified [`cat ${testoutput}`]" >&2
> +	    return 1
> +	fi
> +    else
> +	echo "grub-emu exited with error: ${ret}" >&2
> +	return 99
> +    fi
> +
> +    capped_pcr1="$(tpm2_pcrread ${pcr_bank}:1) | tail -1 | cut -d' ' -f7"
> +
> +    if [ "${original_pcr1}" = "${capped_pcr1}" ]; then
> +	echo "error: PCR 1 not capped" >&2
> +	return 1
> +    fi
> +}
> +
>   # Testcases for SRK mode
>   declare -a srktests=()
>   srktests+=("default transient no_fallback_srk sha256")
> @@ -357,4 +409,17 @@ for i in "${!nvtests[@]}"; do
>       fi
>   done
>   
> +# Testcase for PCR Capping
> +tpm2_seal_unseal_cap || ret=$?
> +if [ "${ret}" -eq 0 ]; then
> +    echo "TPM2 [PCR Capping]: PASS"
> +elif [ "${ret}" -eq 1 ]; then
> +    echo "TPM2 [PCR Capping]: FAIL"
> +    ret=0
> +    exit_status=1
> +else
> +    echo "Unexpected failure [PCR Capping]" >&2
> +    exit ${ret}
> +fi
> +
>   exit ${exit_status}

Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/7] tss2: Add TPM2_PCR_Event command
  2025-07-08  8:31 ` [PATCH 1/7] tss2: Add TPM2_PCR_Event command Gary Lin via Grub-devel
@ 2025-07-10 14:54   ` Sudhakar Kuppusamy
  2025-07-11  1:59     ` Gary Lin via Grub-devel
  0 siblings, 1 reply; 23+ messages in thread
From: Sudhakar Kuppusamy @ 2025-07-10 14:54 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger



> On 8 Jul 2025, at 2:01 PM, Gary Lin via Grub-devel <grub-devel@gnu.org> wrote:
> 
> The TPM2_PCR_Event command is introduced to tss2 to allow the user to
> extend a specific PCR. The related data structure and unmarshal function
> are also introduced.
> 
> However, simply invoking TPM2_PCR_Event does not automatically record
> the event into the TPM event log. The TPM event log is primarily
> maintained by the system firmware (e.g., BIOS/UEFI). Therefore, for most
> standard use cases, the recommended method for extending PCRs and
> ensuring proper event logging is to utilize the system firmware
> functions.
> 
> There are specific scenarios where direct use of TPM2_PCR_Event becomes
> necessary. For instance, in environments lacking system firmware support
> for PCR extension, such as the grub-emu, TPM2_PCR_Event serves as the
> only available method to extend PCRs.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
> grub-core/lib/tss2/tpm2_cmd.c     | 51 +++++++++++++++++++++++++++++++
> grub-core/lib/tss2/tpm2_cmd.h     |  7 +++++
> grub-core/lib/tss2/tss2_mu.c      | 18 +++++++++++
> grub-core/lib/tss2/tss2_mu.h      |  4 +++
> grub-core/lib/tss2/tss2_structs.h |  7 +++++
> grub-core/lib/tss2/tss2_types.h   |  1 +
> 6 files changed, 88 insertions(+)
> 
> diff --git a/grub-core/lib/tss2/tpm2_cmd.c b/grub-core/lib/tss2/tpm2_cmd.c
> index 6d25db1ab..37ca78aee 100644
> --- a/grub-core/lib/tss2/tpm2_cmd.c
> +++ b/grub-core/lib/tss2/tpm2_cmd.c
> @@ -575,6 +575,57 @@ grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
>   return TPM_RC_SUCCESS;
> }
> 
> +extern TPM_RC_t
Do you think the extern keyword is required for function definition as well?

> +grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
> +		     const TPMS_AUTH_COMMAND_t *authCommand,
> +		     const TPM2B_EVENT_t *eventData,
> +		     TPML_DIGEST_VALUES_t *digests,
> +		     TPMS_AUTH_RESPONSE_t *authResponse)
> +{
> +  TPM_RC_t rc;
> +  struct grub_tpm2_buffer in;
> +  struct grub_tpm2_buffer out;
> +  TPML_DIGEST_VALUES_t digestsTmp;
> +  TPMS_AUTH_RESPONSE_t authResponseTmp;
> +  TPM_RC_t responseCode;
> +  grub_uint32_t parameterSize;
> +
> +  if (eventData == NULL)
> +    return TPM_RC_VALUE;
> +  if (authCommand == NULL)
> +    return TPM_RC_VALUE;
> +
> +  if (digests == NULL)
> +    digests = &digestsTmp;
> +  if (authResponse == NULL)
> +    authResponse = &authResponseTmp;
> +
> +  /* Marshal */
> +  grub_tpm2_buffer_init (&in);
> +  grub_tpm2_buffer_pack_u32 (&in, pcrHandle);
> +  grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
> +  grub_Tss2_MU_TPM2B_Marshal (&in, eventData->size, eventData->buffer);
> +  if (in.error != 0)

It would be better to use true/false for boolean.  

if (in.error == true)

> +    return TPM_RC_FAILURE;
> +
> +  /* Submit */
> +  grub_tpm2_buffer_init (&out);
> +  rc = tpm2_submit_command (TPM_ST_SESSIONS, TPM_CC_PCR_Event, &responseCode, &in, &out);
> +  if (rc != TPM_RC_SUCCESS)
> +    return rc;
> +  if (responseCode != TPM_RC_SUCCESS)
> +    return responseCode;
> +
> +  /* Unmarshal */
> +  grub_tpm2_buffer_unpack_u32 (&out, &parameterSize);
> +  grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (&out, digests);
> +  grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
> +  if (out.error != 0)

It would be better to use true/false for boolean.  

if (out.error == true)

> +    return TPM_RC_FAILURE;
> +
> +  return TPM_RC_SUCCESS;
> +}
> +
> TPM_RC_t
> grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
> 		    const TPML_PCR_SELECTION_t *pcrSelectionIn,
> diff --git a/grub-core/lib/tss2/tpm2_cmd.h b/grub-core/lib/tss2/tpm2_cmd.h
> index 90b42efec..d7ad962ab 100644
> --- a/grub-core/lib/tss2/tpm2_cmd.h
> +++ b/grub-core/lib/tss2/tpm2_cmd.h
> @@ -89,6 +89,13 @@ grub_tpm2_unseal (const TPMI_DH_OBJECT_t item_handle,
> extern TPM_RC_t
> grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle);
> 
> +extern TPM_RC_t
> +grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
> +		     const TPMS_AUTH_COMMAND_t *authCommand,
> +		     const TPM2B_EVENT_t *eventData,
> +		     TPML_DIGEST_VALUES_t *digests,
> +		     TPMS_AUTH_RESPONSE_t *authResponse);
> +
> extern TPM_RC_t
> grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
> 		    const TPML_PCR_SELECTION_t *pcrSelectionIn,
> diff --git a/grub-core/lib/tss2/tss2_mu.c b/grub-core/lib/tss2/tss2_mu.c
> index 816e5b37f..675a0009a 100644
> --- a/grub-core/lib/tss2/tss2_mu.c
> +++ b/grub-core/lib/tss2/tss2_mu.c
> @@ -1118,6 +1118,24 @@ grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
>     grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &digest->digests[i]);
> }
> 
> +void
> +grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
> +					  TPML_DIGEST_VALUES_t *digests)
> +{
> +  grub_uint32_t i;
> +
> +  grub_tpm2_buffer_unpack_u32 (buffer, &digests->count);
> +
> +  if (digests->count > TPM_NUM_PCR_BANKS)
> +    {
> +      buffer->error = 1;

It would be better to use true/false for boolean.
buffer->error = true;

Thanks,
Sudhakar

> +      return;
> +    }
> +
> +  for (i = 0; i < digests->count; i++)
> +    grub_Tss2_MU_TPMT_HA_Unmarshal (buffer, &digests->digests[i]);
> +}
> +
> void
> grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
>                                            TPMS_SIGNATURE_RSA_t *rsa)
> diff --git a/grub-core/lib/tss2/tss2_mu.h b/grub-core/lib/tss2/tss2_mu.h
> index 6440de57c..76eebc994 100644
> --- a/grub-core/lib/tss2/tss2_mu.h
> +++ b/grub-core/lib/tss2/tss2_mu.h
> @@ -380,6 +380,10 @@ extern void
> grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
> 				    TPML_DIGEST_t *digest);
> 
> +extern void
> +grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
> +					  TPML_DIGEST_VALUES_t *digests);
> +
> extern void
> grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
>                                            TPMS_SIGNATURE_RSA_t *p);
> diff --git a/grub-core/lib/tss2/tss2_structs.h b/grub-core/lib/tss2/tss2_structs.h
> index 2eefba87c..0ac09f50f 100644
> --- a/grub-core/lib/tss2/tss2_structs.h
> +++ b/grub-core/lib/tss2/tss2_structs.h
> @@ -144,6 +144,13 @@ typedef struct TPML_DIGEST TPML_DIGEST_t;
> /* TPM2B_NONCE Type */
> typedef TPM2B_DIGEST_t TPM2B_NONCE_t;
> 
> +/* TPM2B_EVENT Structure */
> +struct TPM2B_EVENT {
> +    grub_uint16_t size;
> +    grub_uint8_t buffer[1024];
> +};
> +typedef struct TPM2B_EVENT TPM2B_EVENT_t;
> +
> /* TPMA_SESSION Structure */
> struct TPMA_SESSION
> {
> diff --git a/grub-core/lib/tss2/tss2_types.h b/grub-core/lib/tss2/tss2_types.h
> index bddde7191..52d304b90 100644
> --- a/grub-core/lib/tss2/tss2_types.h
> +++ b/grub-core/lib/tss2/tss2_types.h
> @@ -343,6 +343,7 @@ typedef grub_uint32_t TPM_CC_t;
> #define TPM_CC_NV_Write         ((TPM_CC_t) 0x00000137)
> #define TPM_CC_NV_UndefineSpace ((TPM_CC_t) 0x00000122)
> #define TPM_CC_GetCapability    ((TPM_CC_t) 0x0000017a)
> +#define TPM_CC_PCR_Event        ((TPM_CC_t) 0x0000013c)
> #define TPM_CC_PCR_Read         ((TPM_CC_t) 0x0000017e)
> #define TPM_CC_Load             ((TPM_CC_t) 0x00000157)
> #define TPM_CC_LoadExternal     ((TPM_CC_t) 0x00000167)
> -- 
> 2.43.0
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr()
  2025-07-08  8:31 ` [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr() Gary Lin via Grub-devel
  2025-07-08 16:05   ` Stefan Berger
@ 2025-07-10 15:09   ` Sudhakar Kuppusamy
  2025-07-11  2:20     ` Gary Lin via Grub-devel
  1 sibling, 1 reply; 23+ messages in thread
From: Sudhakar Kuppusamy @ 2025-07-10 15:09 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger



> On 8 Jul 2025, at 2:01 PM, Gary Lin via Grub-devel <grub-devel@gnu.org> wrote:
> 
> This commit introduces the definition of grub_tcg2_cap_pcr(), a new
> function designed to enhance the security of sealed keys. Its primary
> purpose is to "cap" a specific PCR by extending it with a SEPARATOR
> event. This action cryptographically alters the PCR value, making it
> impossible to unseal any key that was previously sealed to the original
> PCR state. Consequently, the sealed key remains protected against
> unauthorized unsealing attempts until the associated PCRs are reset to
> their initial configuration, typically occurring during a subsequent
> system boot.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
> grub-core/lib/tss2/tcg2.h | 5 +++++
> 1 file changed, 5 insertions(+)
> 
> diff --git a/grub-core/lib/tss2/tcg2.h b/grub-core/lib/tss2/tcg2.h
> index 3d26373dd..c7e80d355 100644
> --- a/grub-core/lib/tss2/tcg2.h
> +++ b/grub-core/lib/tss2/tcg2.h
> @@ -23,6 +23,8 @@
> #include <grub/err.h>
> #include <grub/types.h>
> 
> +#define EV_SEPARATOR 0x04
> +
> extern grub_err_t
> grub_tcg2_get_max_output_size (grub_size_t *size);
> 
> @@ -32,4 +34,7 @@ grub_tcg2_submit_command (grub_size_t input_size,
> 			  grub_size_t output_size,
> 			  grub_uint8_t *output);
> 
> +extern grub_err_t
> +grub_tcg2_cap_pcr (grub_uint8_t pcr);
> +

I think this patch should be merged with patch which define this functions.

Thanks,
Sudhakar

> #endif /* ! GRUB_TPM2_TCG2_HEADER */
> -- 
> 2.43.0
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 6/7] tpm2_key_protector: Support PCR capping
  2025-07-08  8:31 ` [PATCH 6/7] tpm2_key_protector: Support PCR capping Gary Lin via Grub-devel
  2025-07-08 17:00   ` Stefan Berger
@ 2025-07-10 15:24   ` Sudhakar Kuppusamy
  1 sibling, 0 replies; 23+ messages in thread
From: Sudhakar Kuppusamy @ 2025-07-10 15:24 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger


[-- Attachment #1.1: Type: text/plain, Size: 9055 bytes --]



> On 8 Jul 2025, at 2:01 PM, Gary Lin via Grub-devel <grub-devel@gnu.org> wrote:
> 
> To prevent a sealed key from being unsealed again, a common and
> straightforward method is to "cap" the key by extending the associated
> PCRs. When the PCRs associated with the sealed key are extended, TPM will
> be unable to unseal the key, as the PCR values required for unsealing no
> longer match, effectively rendering the key unusable until the next
> system boot or a state where the PCRs are reset to their expected values.
> 
> To cap a specific set of PCRs, simply append the argument '-c pcr_list'
> to the tpm2_key_protector command. Upon successfully unsealing the key,
> the TPM2 key protector will then invoke tpm2_protector_cap_pcrs(). This
> function extends the selected PCRs with a SEPARATOR event, effectively
> "capping" them. Consequently, the associated key cannot be unsealed in
> any subsequent attempts until these PCRs are reset to their original,
> pre-capped state, typically occurring upon the next system boot.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---

Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>


> docs/grub.texi                                | 20 ++++++-
> .../commands/tpm2_key_protector/module.c      | 56 ++++++++++++++++++-
> grub-core/normal/main.c                       |  2 +-
> 3 files changed, 73 insertions(+), 5 deletions(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 34b3484dc..bd35e9d46 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -8084,7 +8084,7 @@ either @var{expression1} or @var{expression2} is true
> @node tpm2_key_protector_init
> @subsection tpm2_key_protector_init
> 
> -@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
> +@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [@option{--cap-pcrs} | @option{-c} pcrlist] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
> Initialize the TPM2 key protector to unseal the key for the @command{cryptomount}
> (@pxref{cryptomount}) command. There are two supported modes,
> SRK(@kbd{srk}) and NV index(@kbd{nv}), to be specified by the option
> @@ -8099,6 +8099,24 @@ bank that the key is sealed with. The PCR list is a comma-separated list, e.g.,
> bank is chosen by selecting a hash algorithm. The current supported PCR banks
> are SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
> 
> +The @option{-c} option is introduced to enable the "capping" of a specified list of
> +PCRs. This feature addresses scenarios where a user wants to ensure a sealed key
> +cannot be unsealed again after its initial use. When the @option{-c} option is
> +employed, and the key is successfully unsealed, the TPM2 key protector automatically
> +extends the selected PCRs with a SEPARATOR event. This action cryptographically
> +alters the PCR values, thereby preventing the associated key from being unsealed in
> +any subsequent attempts until those specific PCRs are reset to their original state,
> +which typically occurs during a system reboot. In general, it is sufficient to
> +extend one associated PCR to cap the key.
> +
> +It's noteworthy that a key sealed against PCR 8 naturally incorporates a "capping"
> +behavior, even without explicitly using a @option{-c} option. This is because GRUB
> +measures all commands into PCR 8, including those from configuration files. As a
> +result, the value of PCR 8 changes with virtually every command execution during
> +the boot process. Consequently, a key sealed against PCR 8 can only be unsealed
> +once in a given boot session, as any subsequent GRUB command will alter PCR 8,
> +invalidating the unsealing policy and effectively "capping" the key.
> +
> Some options are only available for the specific mode. The SRK-specific
> options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
> other hand, the NV index-specific option is @option{-n}.
> diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
> index b84c2234f..1226b65e0 100644
> --- a/grub-core/commands/tpm2_key_protector/module.c
> +++ b/grub-core/commands/tpm2_key_protector/module.c
> @@ -28,6 +28,7 @@
> #include <tss2_buffer.h>
> #include <tss2_types.h>
> #include <tss2_mu.h>
> +#include <tcg2.h>
> 
> #include "tpm2_args.h"
> #include "tpm2.h"
> @@ -47,6 +48,7 @@ typedef enum tpm2_protector_options
>   OPTION_MODE,
>   OPTION_PCRS,
>   OPTION_BANK,
> +  OPTION_CAPPCRS,
>   OPTION_TPM2KEY,
>   OPTION_KEYFILE,
>   OPTION_SRK,
> @@ -61,6 +63,8 @@ typedef struct tpm2_protector_context
>   grub_uint8_t pcr_count;
>   grub_srk_type_t srk_type;
>   TPM_ALG_ID_t bank;
> +  grub_uint8_t cap_pcrs[TPM_MAX_PCRS];
> +  grub_uint8_t cap_pcr_count;
>   const char *tpm2key;
>   const char *keyfile;
>   TPM_HANDLE_t srk;
> @@ -100,6 +104,16 @@ static const struct grub_arg_option tpm2_protector_init_cmd_options[] =
> 	N_("Bank of PCRs used to authorize key release: "
> 	   "SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"),
>     },
> +    {
> +      .longarg  = "cap-pcrs",
> +      .shortarg = 'c',
> +      .flags    = 0,
> +      .arg      = NULL,
> +      .type     = ARG_TYPE_STRING,
> +      .doc      =
> +	N_("Comma-separated list of PCRs to be capped after key release "
> +	   "e.g., '7,11'."),
> +    },
>     /* SRK-mode options */
>     {
>       .longarg  = "tpm2key",
> @@ -1212,19 +1226,45 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
>   return err;
> }
> 
> +static grub_err_t
> +tpm2_protector_cap_pcrs (const tpm2_protector_context_t *ctx)
> +{
> +  grub_uint8_t i;
> +  grub_err_t err;
> +
> +  for (i = 0; i < ctx->cap_pcr_count; i++)
> +    {
> +	err = grub_tcg2_cap_pcr (ctx->cap_pcrs[i]);
> +	if (err != GRUB_ERR_NONE)
> +	  return err;
> +    }
> +
> +  return GRUB_ERR_NONE;
> +}
> +
> static grub_err_t
> tpm2_protector_recover (const tpm2_protector_context_t *ctx,
> 			grub_uint8_t **key, grub_size_t *key_size)
> {
> +  grub_err_t err;
> +
>   switch (ctx->mode)
>     {
>     case TPM2_PROTECTOR_MODE_SRK:
> -      return tpm2_protector_srk_recover (ctx, key, key_size);
> +      err = tpm2_protector_srk_recover (ctx, key, key_size);
> +      break;
>     case TPM2_PROTECTOR_MODE_NV:
> -      return tpm2_protector_nv_recover (ctx, key, key_size);
> +      err = tpm2_protector_nv_recover (ctx, key, key_size);
> +      break;
>     default:
> -      return GRUB_ERR_BAD_ARGUMENT;
> +      err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown Mode"));
>     }
> +
> +  /* Cap the selected PCRs when the key is unsealed successfully */
> +  if (ctx->cap_pcr_count > 0 && err == GRUB_ERR_NONE)
> +    err = tpm2_protector_cap_pcrs (ctx);
> +
> +  return err;
> }
> 
> static grub_err_t
> @@ -1364,6 +1404,15 @@ tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
> 	return err;
>     }
> 
> +  if (state[OPTION_CAPPCRS].set)  /* cap-pcrs */
> +    {
> +      err = grub_tpm2_protector_parse_pcrs (state[OPTION_CAPPCRS].arg,
> +					    tpm2_protector_ctx.cap_pcrs,
> +					    &tpm2_protector_ctx.cap_pcr_count);
> +      if (err != GRUB_ERR_NONE)
> +	return err;
> +    }
> +
>   if (state[OPTION_TPM2KEY].set)  /* tpm2key */
>     {
>       err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
> @@ -1465,6 +1514,7 @@ GRUB_MOD_INIT (tpm2_key_protector)
> 			  N_("[-m mode] "
> 			     "[-p pcr_list] "
> 			     "[-b pcr_bank] "
> +			     "[-c pcr_list] "
> 			     "[-T tpm2_key_file_path] "
> 			     "[-k sealed_key_file_path] "
> 			     "[-s srk_handle] "
> diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
> index 96abfda2f..f823851c4 100644
> --- a/grub-core/normal/main.c
> +++ b/grub-core/normal/main.c
> @@ -512,7 +512,7 @@ static const char *features[] = {
>   "feature_default_font_path", "feature_all_video_module",
>   "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
>   "feature_nativedisk_cmd", "feature_timeout_style",
> -  "feature_search_cryptodisk_only"
> +  "feature_search_cryptodisk_only", "feature_tpm2_cap_pcrs"
> };
> 
> GRUB_MOD_INIT(normal)
> -- 
> 2.43.0
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


[-- Attachment #1.2: Type: text/html, Size: 14142 bytes --]

[-- Attachment #2: Type: text/plain, Size: 141 bytes --]

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping
  2025-07-08  8:31 ` [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping Gary Lin via Grub-devel
  2025-07-09 12:31   ` Stefan Berger
@ 2025-07-10 15:26   ` Sudhakar Kuppusamy
  1 sibling, 0 replies; 23+ messages in thread
From: Sudhakar Kuppusamy @ 2025-07-10 15:26 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Gary Lin, Daniel Kiper, mchang, patrick.colp, Stefan Berger


[-- Attachment #1.1: Type: text/plain, Size: 2955 bytes --]



> On 8 Jul 2025, at 2:01 PM, Gary Lin via Grub-devel <grub-devel@gnu.org> wrote:
> 
> A test is introduced to cap PCR 1 and track the PCR 1 value before and
> after key unsealing.
> 
> Signed-off-by: Gary Lin <glin@suse.com>
> ---

Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>


> tests/tpm2_key_protector_test.in | 65 ++++++++++++++++++++++++++++++++
> 1 file changed, 65 insertions(+)
> 
> diff --git a/tests/tpm2_key_protector_test.in b/tests/tpm2_key_protector_test.in
> index 1d80d5d26..5dd86d6ee 100644
> --- a/tests/tpm2_key_protector_test.in
> +++ b/tests/tpm2_key_protector_test.in
> @@ -304,6 +304,58 @@ EOF
>     fi
> }
> 
> +tpm2_seal_unseal_cap() {
> +    pcr_bank="sha256"
> +
> +    original_pcr1="$(tpm2_pcrread ${pcr_bank}:1) | tail -1 | cut -d' ' -f7"
> +
> +    grub_cfg=${tpm2testdir}/testcase.cfg
> +
> +    # Seal the password with grub-protect
> +    grub-protect \
> +	--tpm2-device="${tpm2dev}" \
> +	--action=add \
> +	--protector=tpm2 \
> +	--tpm2key \
> +	--tpm2-bank="${pcr_bank}" \
> +	--tpm2-pcrs=0,1 \
> +	--tpm2-keyfile="${lukskeyfile}" \
> +	--tpm2-outfile="${sealedkey}" || ret=$?
> +    if [ "${ret}" -ne 0 ]; then
> +	echo "Failed to seal the secret key: ${ret}" >&2
> +	return 99
> +    fi
> +
> +    # Write the TPM unsealing script and cap PCR 1
> +    cat > "${grub_cfg}" <<EOF
> +loopback luks (host)${luksfile}
> +tpm2_key_protector_init -T (host)${sealedkey} -c 1
> +if cryptomount -a --protector tpm2; then
> +    cat (crypto0)+1
> +fi
> +EOF
> +
> +    # Test TPM unsealing with the same PCR
> +    ${grubshell} --timeout=${timeout} --emu-opts="-t ${tpm2dev}" < "${grub_cfg}" > "${testoutput}" || ret=$?
> +
> +    if [ "${ret}" -eq 0 ]; then
> +	if ! grep -q "^${vtext}$" "${testoutput}"; then
> +	    echo "error: test not verified [`cat ${testoutput}`]" >&2
> +	    return 1
> +	fi
> +    else
> +	echo "grub-emu exited with error: ${ret}" >&2
> +	return 99
> +    fi
> +
> +    capped_pcr1="$(tpm2_pcrread ${pcr_bank}:1) | tail -1 | cut -d' ' -f7"
> +
> +    if [ "${original_pcr1}" = "${capped_pcr1}" ]; then
> +	echo "error: PCR 1 not capped" >&2
> +	return 1
> +    fi
> +}
> +
> # Testcases for SRK mode
> declare -a srktests=()
> srktests+=("default transient no_fallback_srk sha256")
> @@ -357,4 +409,17 @@ for i in "${!nvtests[@]}"; do
>     fi
> done
> 
> +# Testcase for PCR Capping
> +tpm2_seal_unseal_cap || ret=$?
> +if [ "${ret}" -eq 0 ]; then
> +    echo "TPM2 [PCR Capping]: PASS"
> +elif [ "${ret}" -eq 1 ]; then
> +    echo "TPM2 [PCR Capping]: FAIL"
> +    ret=0
> +    exit_status=1
> +else
> +    echo "Unexpected failure [PCR Capping]" >&2
> +    exit ${ret}
> +fi
> +
> exit ${exit_status}
> -- 
> 2.43.0
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


[-- Attachment #1.2: Type: text/html, Size: 5316 bytes --]

[-- Attachment #2: Type: text/plain, Size: 141 bytes --]

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/7] tss2: Add TPM2_PCR_Event command
  2025-07-10 14:54   ` Sudhakar Kuppusamy
@ 2025-07-11  1:59     ` Gary Lin via Grub-devel
  0 siblings, 0 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-11  1:59 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, mchang,
	patrick.colp, Stefan Berger

On Thu, Jul 10, 2025 at 08:24:46PM +0530, Sudhakar Kuppusamy wrote:
> 
> 
> > On 8 Jul 2025, at 2:01 PM, Gary Lin via Grub-devel <grub-devel@gnu.org> wrote:
> > 
> > The TPM2_PCR_Event command is introduced to tss2 to allow the user to
> > extend a specific PCR. The related data structure and unmarshal function
> > are also introduced.
> > 
> > However, simply invoking TPM2_PCR_Event does not automatically record
> > the event into the TPM event log. The TPM event log is primarily
> > maintained by the system firmware (e.g., BIOS/UEFI). Therefore, for most
> > standard use cases, the recommended method for extending PCRs and
> > ensuring proper event logging is to utilize the system firmware
> > functions.
> > 
> > There are specific scenarios where direct use of TPM2_PCR_Event becomes
> > necessary. For instance, in environments lacking system firmware support
> > for PCR extension, such as the grub-emu, TPM2_PCR_Event serves as the
> > only available method to extend PCRs.
> > 
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> > grub-core/lib/tss2/tpm2_cmd.c     | 51 +++++++++++++++++++++++++++++++
> > grub-core/lib/tss2/tpm2_cmd.h     |  7 +++++
> > grub-core/lib/tss2/tss2_mu.c      | 18 +++++++++++
> > grub-core/lib/tss2/tss2_mu.h      |  4 +++
> > grub-core/lib/tss2/tss2_structs.h |  7 +++++
> > grub-core/lib/tss2/tss2_types.h   |  1 +
> > 6 files changed, 88 insertions(+)
> > 
> > diff --git a/grub-core/lib/tss2/tpm2_cmd.c b/grub-core/lib/tss2/tpm2_cmd.c
> > index 6d25db1ab..37ca78aee 100644
> > --- a/grub-core/lib/tss2/tpm2_cmd.c
> > +++ b/grub-core/lib/tss2/tpm2_cmd.c
> > @@ -575,6 +575,57 @@ grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
> >   return TPM_RC_SUCCESS;
> > }
> > 
> > +extern TPM_RC_t
> Do you think the extern keyword is required for function definition as well?
> 
Oops, that's a mistake.

> > +grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
> > +		     const TPMS_AUTH_COMMAND_t *authCommand,
> > +		     const TPM2B_EVENT_t *eventData,
> > +		     TPML_DIGEST_VALUES_t *digests,
> > +		     TPMS_AUTH_RESPONSE_t *authResponse)
> > +{
> > +  TPM_RC_t rc;
> > +  struct grub_tpm2_buffer in;
> > +  struct grub_tpm2_buffer out;
> > +  TPML_DIGEST_VALUES_t digestsTmp;
> > +  TPMS_AUTH_RESPONSE_t authResponseTmp;
> > +  TPM_RC_t responseCode;
> > +  grub_uint32_t parameterSize;
> > +
> > +  if (eventData == NULL)
> > +    return TPM_RC_VALUE;
> > +  if (authCommand == NULL)
> > +    return TPM_RC_VALUE;
> > +
> > +  if (digests == NULL)
> > +    digests = &digestsTmp;
> > +  if (authResponse == NULL)
> > +    authResponse = &authResponseTmp;
> > +
> > +  /* Marshal */
> > +  grub_tpm2_buffer_init (&in);
> > +  grub_tpm2_buffer_pack_u32 (&in, pcrHandle);
> > +  grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
> > +  grub_Tss2_MU_TPM2B_Marshal (&in, eventData->size, eventData->buffer);
> > +  if (in.error != 0)
> 
> It would be better to use true/false for boolean.  
> 
> if (in.error == true)
> 
Will fix it in v2.

> > +    return TPM_RC_FAILURE;
> > +
> > +  /* Submit */
> > +  grub_tpm2_buffer_init (&out);
> > +  rc = tpm2_submit_command (TPM_ST_SESSIONS, TPM_CC_PCR_Event, &responseCode, &in, &out);
> > +  if (rc != TPM_RC_SUCCESS)
> > +    return rc;
> > +  if (responseCode != TPM_RC_SUCCESS)
> > +    return responseCode;
> > +
> > +  /* Unmarshal */
> > +  grub_tpm2_buffer_unpack_u32 (&out, &parameterSize);
> > +  grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (&out, digests);
> > +  grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
> > +  if (out.error != 0)
> 
> It would be better to use true/false for boolean.  
> 
> if (out.error == true)
> 
Ditto.

> > +    return TPM_RC_FAILURE;
> > +
> > +  return TPM_RC_SUCCESS;
> > +}
> > +
> > TPM_RC_t
> > grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
> > 		    const TPML_PCR_SELECTION_t *pcrSelectionIn,
> > diff --git a/grub-core/lib/tss2/tpm2_cmd.h b/grub-core/lib/tss2/tpm2_cmd.h
> > index 90b42efec..d7ad962ab 100644
> > --- a/grub-core/lib/tss2/tpm2_cmd.h
> > +++ b/grub-core/lib/tss2/tpm2_cmd.h
> > @@ -89,6 +89,13 @@ grub_tpm2_unseal (const TPMI_DH_OBJECT_t item_handle,
> > extern TPM_RC_t
> > grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle);
> > 
> > +extern TPM_RC_t
> > +grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
> > +		     const TPMS_AUTH_COMMAND_t *authCommand,
> > +		     const TPM2B_EVENT_t *eventData,
> > +		     TPML_DIGEST_VALUES_t *digests,
> > +		     TPMS_AUTH_RESPONSE_t *authResponse);
> > +
> > extern TPM_RC_t
> > grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
> > 		    const TPML_PCR_SELECTION_t *pcrSelectionIn,
> > diff --git a/grub-core/lib/tss2/tss2_mu.c b/grub-core/lib/tss2/tss2_mu.c
> > index 816e5b37f..675a0009a 100644
> > --- a/grub-core/lib/tss2/tss2_mu.c
> > +++ b/grub-core/lib/tss2/tss2_mu.c
> > @@ -1118,6 +1118,24 @@ grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
> >     grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &digest->digests[i]);
> > }
> > 
> > +void
> > +grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
> > +					  TPML_DIGEST_VALUES_t *digests)
> > +{
> > +  grub_uint32_t i;
> > +
> > +  grub_tpm2_buffer_unpack_u32 (buffer, &digests->count);
> > +
> > +  if (digests->count > TPM_NUM_PCR_BANKS)
> > +    {
> > +      buffer->error = 1;
> 
> It would be better to use true/false for boolean.
> buffer->error = true;
> 
Will fix it in v2.

Thanks,

Gary Lin

> Thanks,
> Sudhakar
> 
> > +      return;
> > +    }
> > +
> > +  for (i = 0; i < digests->count; i++)
> > +    grub_Tss2_MU_TPMT_HA_Unmarshal (buffer, &digests->digests[i]);
> > +}
> > +
> > void
> > grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
> >                                            TPMS_SIGNATURE_RSA_t *rsa)
> > diff --git a/grub-core/lib/tss2/tss2_mu.h b/grub-core/lib/tss2/tss2_mu.h
> > index 6440de57c..76eebc994 100644
> > --- a/grub-core/lib/tss2/tss2_mu.h
> > +++ b/grub-core/lib/tss2/tss2_mu.h
> > @@ -380,6 +380,10 @@ extern void
> > grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
> > 				    TPML_DIGEST_t *digest);
> > 
> > +extern void
> > +grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
> > +					  TPML_DIGEST_VALUES_t *digests);
> > +
> > extern void
> > grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
> >                                            TPMS_SIGNATURE_RSA_t *p);
> > diff --git a/grub-core/lib/tss2/tss2_structs.h b/grub-core/lib/tss2/tss2_structs.h
> > index 2eefba87c..0ac09f50f 100644
> > --- a/grub-core/lib/tss2/tss2_structs.h
> > +++ b/grub-core/lib/tss2/tss2_structs.h
> > @@ -144,6 +144,13 @@ typedef struct TPML_DIGEST TPML_DIGEST_t;
> > /* TPM2B_NONCE Type */
> > typedef TPM2B_DIGEST_t TPM2B_NONCE_t;
> > 
> > +/* TPM2B_EVENT Structure */
> > +struct TPM2B_EVENT {
> > +    grub_uint16_t size;
> > +    grub_uint8_t buffer[1024];
> > +};
> > +typedef struct TPM2B_EVENT TPM2B_EVENT_t;
> > +
> > /* TPMA_SESSION Structure */
> > struct TPMA_SESSION
> > {
> > diff --git a/grub-core/lib/tss2/tss2_types.h b/grub-core/lib/tss2/tss2_types.h
> > index bddde7191..52d304b90 100644
> > --- a/grub-core/lib/tss2/tss2_types.h
> > +++ b/grub-core/lib/tss2/tss2_types.h
> > @@ -343,6 +343,7 @@ typedef grub_uint32_t TPM_CC_t;
> > #define TPM_CC_NV_Write         ((TPM_CC_t) 0x00000137)
> > #define TPM_CC_NV_UndefineSpace ((TPM_CC_t) 0x00000122)
> > #define TPM_CC_GetCapability    ((TPM_CC_t) 0x0000017a)
> > +#define TPM_CC_PCR_Event        ((TPM_CC_t) 0x0000013c)
> > #define TPM_CC_PCR_Read         ((TPM_CC_t) 0x0000017e)
> > #define TPM_CC_Load             ((TPM_CC_t) 0x00000157)
> > #define TPM_CC_LoadExternal     ((TPM_CC_t) 0x00000167)
> > -- 
> > 2.43.0
> > 
> > 
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > https://lists.gnu.org/mailman/listinfo/grub-devel
> 

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr()
  2025-07-10 15:09   ` Sudhakar Kuppusamy
@ 2025-07-11  2:20     ` Gary Lin via Grub-devel
  0 siblings, 0 replies; 23+ messages in thread
From: Gary Lin via Grub-devel @ 2025-07-11  2:20 UTC (permalink / raw)
  To: Sudhakar Kuppusamy
  Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, mchang,
	patrick.colp, Stefan Berger

On Thu, Jul 10, 2025 at 08:39:11PM +0530, Sudhakar Kuppusamy wrote:
> 
> 
> > On 8 Jul 2025, at 2:01 PM, Gary Lin via Grub-devel <grub-devel@gnu.org> wrote:
> > 
> > This commit introduces the definition of grub_tcg2_cap_pcr(), a new
> > function designed to enhance the security of sealed keys. Its primary
> > purpose is to "cap" a specific PCR by extending it with a SEPARATOR
> > event. This action cryptographically alters the PCR value, making it
> > impossible to unseal any key that was previously sealed to the original
> > PCR state. Consequently, the sealed key remains protected against
> > unauthorized unsealing attempts until the associated PCRs are reset to
> > their initial configuration, typically occurring during a subsequent
> > system boot.
> > 
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> > grub-core/lib/tss2/tcg2.h | 5 +++++
> > 1 file changed, 5 insertions(+)
> > 
> > diff --git a/grub-core/lib/tss2/tcg2.h b/grub-core/lib/tss2/tcg2.h
> > index 3d26373dd..c7e80d355 100644
> > --- a/grub-core/lib/tss2/tcg2.h
> > +++ b/grub-core/lib/tss2/tcg2.h
> > @@ -23,6 +23,8 @@
> > #include <grub/err.h>
> > #include <grub/types.h>
> > 
> > +#define EV_SEPARATOR 0x04
> > +
> > extern grub_err_t
> > grub_tcg2_get_max_output_size (grub_size_t *size);
> > 
> > @@ -32,4 +34,7 @@ grub_tcg2_submit_command (grub_size_t input_size,
> > 			  grub_size_t output_size,
> > 			  grub_uint8_t *output);
> > 
> > +extern grub_err_t
> > +grub_tcg2_cap_pcr (grub_uint8_t pcr);
> > +
> 
> I think this patch should be merged with patch which define this functions.
> 
It's platform-specific and I prefer separate patches with implementation
details for each platform.

Gary Lin

> Thanks,
> Sudhakar
> 
> > #endif /* ! GRUB_TPM2_TCG2_HEADER */
> > -- 
> > 2.43.0
> > 
> > 
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > https://lists.gnu.org/mailman/listinfo/grub-devel
> 

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2025-07-11  2:21 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-08  8:31 [PATCH 0/7] TPM2 PCR Capping Gary Lin via Grub-devel
2025-07-08  8:31 ` [PATCH 1/7] tss2: Add TPM2_PCR_Event command Gary Lin via Grub-devel
2025-07-10 14:54   ` Sudhakar Kuppusamy
2025-07-11  1:59     ` Gary Lin via Grub-devel
2025-07-08  8:31 ` [PATCH 2/7] tss2: Introduce grub_tcg2_cap_pcr() Gary Lin via Grub-devel
2025-07-08 16:05   ` Stefan Berger
2025-07-10 15:09   ` Sudhakar Kuppusamy
2025-07-11  2:20     ` Gary Lin via Grub-devel
2025-07-08  8:31 ` [PATCH 3/7] tss2: Implement grub_tcg2_cap_pcr() for EFI Gary Lin via Grub-devel
2025-07-08 16:27   ` Stefan Berger
2025-07-09  2:04     ` Gary Lin via Grub-devel
2025-07-08  8:31 ` [PATCH 4/7] tss2: Implement grub_tcg2_cap_pcr() for ieee1275 Gary Lin via Grub-devel
2025-07-08 15:52   ` Stefan Berger
2025-07-09  2:08     ` Gary Lin via Grub-devel
2025-07-08  8:31 ` [PATCH 5/7] tss2: Implement grub_tcg2_cap_pcr() for EMU Gary Lin via Grub-devel
2025-07-08 16:19   ` Stefan Berger
2025-07-09  2:35     ` Gary Lin via Grub-devel
2025-07-08  8:31 ` [PATCH 6/7] tpm2_key_protector: Support PCR capping Gary Lin via Grub-devel
2025-07-08 17:00   ` Stefan Berger
2025-07-10 15:24   ` Sudhakar Kuppusamy
2025-07-08  8:31 ` [PATCH 7/7] tests/tpm2_key_protector_test: Add a test for PCR Capping Gary Lin via Grub-devel
2025-07-09 12:31   ` Stefan Berger
2025-07-10 15:26   ` Sudhakar Kuppusamy

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).