[PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR

niek.nooijens at omron.com niek.nooijens at omron.com
Thu Mar 7 06:59:31 CET 2024


Hi Illias

I updated all the comments.
I did note that the format in tpm-v2.h of the function description wasn't up to standard even for code I didn't create, so I fixed that as well.
It's also pushed to my github:https://github.com/nieknooijens/u-boot/tree/tpm_policy_patch

Here's the update:

=======================START PATCH=========================
From c0e213d45925da819d7ce41e02072ea740e44014 Mon Sep 17 00:00:00 2001
From: Niek Nooijens <niek.nooijens at omron.com>
Date: Tue, 20 Feb 2024 13:42:57 +0900
Subject: [PATCH] [TPM] implement commands to lock NV-indexes behind a PCR
 policy

Added commands are:
- start auth session
- flush context
- policyPCR
- getPolicyDigest

Signed-off-by: Niek Nooijens <niek.nooijens at omron.com>
---
 cmd/tpm-v2.c         | 247 +++++++++++++++++++++++++-
 include/tpm-common.h |   2 +
 include/tpm-v2.h     | 375 +++++++++++++++++++++++----------------
 lib/tpm-v2.c         | 413 ++++++++++++++++++++++++++++++++++---------
 lib/tpm_api.c        |   4 +-
 5 files changed, 806 insertions(+), 235 deletions(-)

diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
index 7e479b9dfe..5ba82602c2 100644
--- a/cmd/tpm-v2.c
+++ b/cmd/tpm-v2.c
@@ -136,15 +136,12 @@ static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,

      if (argc != 3)
            return CMD_RET_USAGE;
-
      ret = get_tpm(&dev);
      if (ret)
            return ret;
-
      priv = dev_get_uclass_priv(dev);
      if (!priv)
            return -EINVAL;
-
      index = simple_strtoul(argv[1], NULL, 0);
      if (index >= priv->pcr_count)
            return -EINVAL;
@@ -356,6 +353,207 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
                                          key, key_sz));
 }

+static int do_tpm_nv_define(struct cmd_tbl *cmdtp, int flag,
+                 int argc, char *const argv[])
+{
+     struct udevice *dev;
+     struct tpm_chip_priv *priv;
+     u32 nv_addr, nv_size, rc;
+     void *policy_addr = NULL;
+     size_t policy_size = 0;
+     int ret;
+
+     u32 nv_attributes = TPMA_NV_PLATFORMCREATE | TPMA_NV_OWNERWRITE |\
+                 TPMA_NV_OWNERREAD | TPMA_NV_PPWRITE | TPMA_NV_PPREAD;
+
+     if (argc < 3 && argc > 7)
+           return CMD_RET_USAGE;
+
+     ret = get_tpm(&dev);
+     if (ret)
+           return ret;
+
+     priv = dev_get_uclass_priv(dev);
+     if (!priv)
+           return -EINVAL;
+
+     nv_addr = simple_strtoul(argv[1], NULL, 0);
+     nv_size = simple_strtoul(argv[2], NULL, 0);
+     if (argc > 3)
+           nv_attributes = simple_strtoul(argv[3], NULL, 0);
+     if (argc > 4) {
+           policy_addr = map_sysmem(simple_strtoul(argv[4], NULL, 0), 0);
+           //POLICYREAD and POLICYWRITE are obligated when providing policy, so just force it
+           nv_attributes |= (TPMA_NV_POLICYREAD | TPMA_NV_POLICYWRITE);
+           if (argc < 5)
+                 return CMD_RET_USAGE;
+           policy_size = simple_strtoul(argv[5], NULL, 0);
+     }
+
+     rc = tpm2_nv_define_space(dev, nv_addr, nv_size, nv_attributes, policy_addr, policy_size);
+     if (rc)
+           printf("ERROR: nv_define #%u returns: 0x%x\n", nv_addr, rc);
+
+     unmap_sysmem(policy_addr);
+
+     return report_return_code(rc);
+}
+
+static int do_tpm_nv_undefine(struct cmd_tbl *cmdtp, int flag,
+                       int argc, char *const argv[])
+{
+     struct udevice *dev;
+     u32 nv_addr, ret, rc;
+
+     ret = get_tpm(&dev);
+     if (ret)
+           return ret;
+     if (argc != 2)
+           return CMD_RET_USAGE;
+
+     nv_addr = simple_strtoul(argv[1], NULL, 0);
+     rc = tpm2_nv_undefine_space(dev, nv_addr);
+
+     return report_return_code(rc);
+}
+
+static int do_tpm_nv_read_value(struct cmd_tbl *cmdtp, int flag,
+                       int argc, char *const argv[])
+{
+     struct udevice *dev;
+     u32 nv_addr, nv_size, rc;
+     void *session_addr = NULL;
+     int ret;
+     void *out_data;
+
+     ret = get_tpm(&dev);
+     if (ret)
+           return ret;
+     if (argc < 4)
+           return CMD_RET_USAGE;
+
+     nv_addr = simple_strtoul(argv[1], NULL, 0);
+     nv_size = simple_strtoul(argv[2], NULL, 0);
+     out_data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
+     if (argc == 5)
+           session_addr = map_sysmem(simple_strtoul(argv[4], NULL, 0), 0);
+     //if session handle is NULL, Password authorization is used
+     rc = tpm2_nv_read_value(dev, nv_addr, out_data, nv_size, session_addr);
+
+     if (rc)
+           printf("ERROR: nv_read #%u returns: #%u\n", nv_addr, rc);
+
+     unmap_sysmem(out_data);
+     return report_return_code(rc);
+}
+
+static int do_tpm_nv_write_value(struct cmd_tbl *cmdtp, int flag,
+                       int argc, char *const argv[])
+{
+     struct udevice *dev;
+     u32 nv_addr, nv_size, rc;
+     void *session_addr = NULL, *data_to_write = NULL;
+     int ret;
+
+     ret = get_tpm(&dev);
+     if (ret)
+           return ret;
+     if (argc < 4)
+           return CMD_RET_USAGE;
+
+     nv_addr = simple_strtoul(argv[1], NULL, 0); //tpm_addr
+     nv_size = simple_strtoul(argv[2], NULL, 0); //size
+     data_to_write = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
+
+     if (argc == 5)
+           session_addr = map_sysmem(simple_strtoul(argv[4], NULL, 0), 0);
+
+     rc = tpm2_nv_write_value(dev, nv_addr, data_to_write, nv_size, session_addr);
+     if (rc)
+           printf("ERROR: nv_write #%u returns: #%u\n", nv_addr, rc);
+
+     unmap_sysmem(session_addr);
+     unmap_sysmem(data_to_write);
+     return report_return_code(rc);
+}
+
+static int do_start_auth_session(struct cmd_tbl *cmdtp, int flag,
+int argc, char *const argv[])
+{
+     struct udevice *dev;
+     u32 rc;
+     u8 session_type = TPM_SE_POLICY;
+     int ret;
+     void *data_to_write;
+
+     ret = get_tpm(&dev);
+     if (argc < 2)
+           return CMD_RET_USAGE;
+
+     data_to_write = map_sysmem(simple_strtoul(argv[1], NULL, 0), 0);
+     if (argc > 2)
+           session_type = simple_strtoul(argv[2], NULL, 0);
+
+     rc = tpm2_start_auth_session(dev, data_to_write, session_type);
+     if (rc)
+           printf("ERROR: start_auth_session returns: #%u\n", rc);
+
+     unmap_sysmem(data_to_write);
+     return report_return_code(rc);
+}
+
+static int do_flush_context(struct cmd_tbl *cmdtp, int flag,
+                       int argc, char *const argv[])
+{
+     struct udevice *dev;
+     u32 rc;
+     int ret;
+     void *data_to_read;
+
+     ret = get_tpm(&dev);
+
+     if (argc < 2)
+           return CMD_RET_USAGE;
+
+     data_to_read = map_sysmem(simple_strtoul(argv[1], NULL, 0), 0);
+     u32 session_handle = *((u32 *)data_to_read);
+
+     rc = tpm2_flush_context(dev, session_handle);
+
+     if (rc)
+           printf("ERROR: flush_context returns: #%u\n", rc);
+
+     unmap_sysmem(data_to_read);
+     return report_return_code(rc);
+}
+
+static int do_policy_pcr(struct cmd_tbl *cmdtp, int flag,
+                 int argc, char *const argv[])
+{
+     struct udevice *dev;
+     u32 rc, pcr, session_handle;
+     int ret;
+     void *data_to_read, *out_digest;
+
+     ret = get_tpm(&dev);
+
+     if (argc != 4)
+           return CMD_RET_USAGE;
+
+     data_to_read = map_sysmem(simple_strtoul(argv[1], NULL, 0), 0);
+     session_handle = *((u32 *)data_to_read);
+     pcr = simple_strtoul(argv[2], NULL, 0);
+     out_digest = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
+     rc = tpm2_set_policy_pcr(dev, session_handle, pcr, out_digest);
+
+     if (rc)
+           printf("ERROR: policy_pcr returns: #%u\n", rc);
+
+     unmap_sysmem(data_to_read);
+     unmap_sysmem(out_digest);
+     return report_return_code(rc);
+}
+
 static struct cmd_tbl tpm2_commands[] = {
      U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
      U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
@@ -375,6 +573,13 @@ static struct cmd_tbl tpm2_commands[] = {
                   do_tpm_pcr_setauthpolicy, "", ""),
      U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
                   do_tpm_pcr_setauthvalue, "", ""),
+     U_BOOT_CMD_MKENT(nv_define, 0, 1, do_tpm_nv_define, "", ""),
+     U_BOOT_CMD_MKENT(nv_undefine, 0, 1, do_tpm_nv_undefine, "", ""),
+     U_BOOT_CMD_MKENT(nv_read, 0, 1, do_tpm_nv_read_value, "", ""),
+     U_BOOT_CMD_MKENT(nv_write, 0, 1, do_tpm_nv_write_value, "", ""),
+     U_BOOT_CMD_MKENT(start_auth_session, 0, 1, do_start_auth_session, "", ""),
+     U_BOOT_CMD_MKENT(flush_context, 0, 1, do_flush_context, "", ""),
+     U_BOOT_CMD_MKENT(policy_pcr, 0, 1, do_policy_pcr, "", ""),
 };

 struct cmd_tbl *get_tpm2_commands(unsigned int *size)
@@ -453,4 +658,40 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "    <pcr>: index of the PCR\n"
 "    <key>: secret to protect the access of PCR #<pcr>\n"
 "    <password>: optional password of the PLATFORM hierarchy\n"
+"\n"
+"nv_define <tpm_addr> <size> [<attributes> <policy_digest_addr> <policy_size>]\n"
+"    Define new nv index in the TPM at <tpm_addr> with size <size>\n"
+"    <tpm_addr>: the internal address used within the TPM for the NV-index\n"
+"    <attributes>: is described in tpm-v2.h enum tpm_index_attrs. Note; Always use TPMA_NV_PLATFORMCREATE!\n"
+"                  will default to: TPMA_NV_PLATFORMCREATE|TPMA_NV_OWNERWRITE|TPMA_NV_OWNERREAD|TPMA_NV_PPWRITE|TPMA_NV_PPREAD\n"
+"    <policy_digest_addr>: address to a policy digest. (e.g. a PCR value)\n"
+"    <policy_size>: size of the digest in bytes\n"
+"nv_undefine <tpm_addr>\n"
+"    delete nv index\n"
+"nv_read <tpm_addr> <size> <data_addr> [<session_handle_addr>]\n"
+"    Read data stored in TPM nv_memory at <tpm_addr> with size <size>\n"
+"    <tpm_addr>: the internal address used within the TPM for the NV-index\n"
+"    <size>: datasize in bytes\n"
+"    <data_addr>: memory address where to store the data read from the TPM\n"
+"    <session_handle_addr>: addr where the session handle is stored\n"
+"nv_write <tpm_addr> <size> <data_addr> [<session_handle_addr>]\n"
+"    Write data to the TPM's nv_memory at <tpm_addr> with size <size>\n"
+"    <tpm_addr>: the internal address used within the TPM for the NV-index\n"
+"    <size>: datasize in bytes\n"
+"    <data_addr>: memory address of the data to be written to the TPM's NV-index\n"
+"    <session_handle_addr>: addr where the session handle is stored\n"
+"start_auth_session <session_handle_addr> [<session_type>]\n"
+"    Start an authorization session and store it's handle at <session_handle_addr>\n"
+"     <session_handle_addr>: addr where to store the handle data (4 bytes)\n"
+"     <session_type>: type of session: 0x00 for HMAC, 0x01 for policy, 0x03 for trial\n"
+"                    will default to 0x01 (TPM_SE_POLICY) if not provided\n"
+"                    to create a policy, use TPM_SE_TRIAL (0x03), to authenticate TPM_SE_POLICY (0x01)\n"
+"flush_context <session_handle_addr>\n"
+"    flush/terminate a session which's handle is stored at <session_handle_addr>\n"
+"     <session_handle_addr>: addr where the session handle is stored\n"
+"policy_pcr <session_handle_addr> <pcr> <digest_addr>\n"
+"    create a policy to authorize using a PCR\n"
+"    <session_handle_addr>: addr where the session handle is stored\n"
+"    <pcr>: index of the PCR\n"
+"    <digest_addr>: addr where to store the policy digest (for nv_define/nv_read/write)\n"
 );
diff --git a/include/tpm-common.h b/include/tpm-common.h
index 1ba81386ce..5620454da7 100644
--- a/include/tpm-common.h
+++ b/include/tpm-common.h
@@ -69,6 +69,8 @@ struct tpm_chip_priv {
      uint pcr_count;
      uint pcr_select_min;
      bool plat_hier_disabled;
+     u16 nonce_sz;
+     u8 nonce[32]; //NONCE_TPM_SIZE;
 };

 /**
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 33dd103767..cf75495526 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -301,7 +301,8 @@ enum tpm2_startup_types {
  */
 enum tpm2_handles {
      TPM2_RH_OWNER           = 0x40000001,
-     TPM2_RS_PW        = 0x40000009,
+     TPM2_RH_NULL            = 0x40000007,
+     TPM2_RS_PW              = 0x40000009,
      TPM2_RH_LOCKOUT         = 0x4000000A,
      TPM2_RH_ENDORSEMENT     = 0x4000000B,
      TPM2_RH_PLATFORM  = 0x4000000C,
@@ -325,24 +326,30 @@ enum tpm2_handles {
  * @TPM2_CC_PCR_SETAUTHVAL: TPM2_PCR_SetAuthValue().
  */
 enum tpm2_command_codes {
-     TPM2_CC_STARTUP         = 0x0144,
-     TPM2_CC_SELF_TEST = 0x0143,
-     TPM2_CC_HIER_CONTROL    = 0x0121,
-     TPM2_CC_CLEAR           = 0x0126,
-     TPM2_CC_CLEARCONTROL    = 0x0127,
-     TPM2_CC_HIERCHANGEAUTH  = 0x0129,
-     TPM2_CC_NV_DEFINE_SPACE = 0x012a,
-     TPM2_CC_PCR_SETAUTHPOL  = 0x012C,
-     TPM2_CC_NV_WRITE  = 0x0137,
-     TPM2_CC_NV_WRITELOCK    = 0x0138,
-     TPM2_CC_DAM_RESET = 0x0139,
-     TPM2_CC_DAM_PARAMETERS  = 0x013A,
-     TPM2_CC_NV_READ         = 0x014E,
-     TPM2_CC_GET_CAPABILITY  = 0x017A,
-     TPM2_CC_GET_RANDOM      = 0x017B,
-     TPM2_CC_PCR_READ  = 0x017E,
-     TPM2_CC_PCR_EXTEND      = 0x0182,
-     TPM2_CC_PCR_SETAUTHVAL  = 0x0183,
+     TPM2_CC_STARTUP                     = 0x0144,
+     TPM2_CC_SELF_TEST             = 0x0143,
+     TPM2_CC_HIER_CONTROL          = 0x0121,
+     TPM2_CC_CLEAR                       = 0x0126,
+     TPM2_CC_CLEARCONTROL          = 0x0127,
+     TPM2_CC_HIERCHANGEAUTH        = 0x0129,
+     TPM2_CC_NV_DEFINE_SPACE       = 0x012a,
+     TPM2_CC_NV_UNDEFINE_SPACE     = 0x0122,
+     TPM2_CC_PCR_SETAUTHPOL        = 0x012C,
+     TPM2_CC_CREATE_PRIMARY        = 0x0131,
+     TPM2_CC_NV_WRITE              = 0x0137,
+     TPM2_CC_NV_WRITELOCK          = 0x0138,
+     TPM2_CC_DAM_RESET             = 0x0139,
+     TPM2_CC_DAM_PARAMETERS        = 0x013A,
+     TPM2_CC_NV_READ                     = 0x014E,
+     TPM2_CC_FLUSH_CONTEXT         = 0x0165,
+     TPM2_CC_START_AUTH_SESSION    = 0x0176,
+     TPM2_CC_GET_CAPABILITY        = 0x017A,
+     TPM2_CC_GET_RANDOM                  = 0x017B,
+     TPM2_CC_PCR_READ              = 0x017E,
+     TPM2_CC_POLICY_PCR                  = 0x017F,
+     TPM2_CC_PCR_EXTEND                  = 0x0182,
+     TPM2_CC_PCR_SETAUTHVAL        = 0x0183,
+     TPM2_CC_POLICY_GET_DIGEST     = 0x0189,
 };

 /**
@@ -384,6 +391,16 @@ enum tpm2_algorithms {
      TPM2_ALG_SHA512         = 0x0D,
      TPM2_ALG_NULL           = 0x10,
      TPM2_ALG_SM3_256  = 0x12,
+     TPM2_ALG_ECC            = 0x23,
+};
+
+/**
+ * TPM2 session types.
+ */
+enum tpm2_se {
+     TPM_SE_HMAC             = 0x00,
+     TPM_SE_POLICY           = 0x01,
+     TPM_SE_TRIAL            = 0x03,
 };

 extern const enum tpm2_algorithms tpm2_supported_algorithms[4];
@@ -503,10 +520,10 @@ struct tcg2_event_log {
 /**
  * Create a list of digests of the supported PCR banks for a given input data
  *
- * @dev          TPM device
- * @input  Data
- * @length Length of the data to calculate the digest
- * @digest_list  List of digests to fill in
+ * @dev:   TPM device
+ * @input: Data
+ * @length:      Length of the data to calculate the digest
+ * @digest_list: List of digests to fill in
  *
  * Return: zero on success, negative errno otherwise
  */
@@ -516,7 +533,7 @@ int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length,
 /**
  * Get the event size of the specified digests
  *
- * @digest_list  List of digests for the event
+ * @digest_list: List of digests for the event
  *
  * Return: Size in bytes of the event
  */
@@ -525,8 +542,8 @@ u32 tcg2_event_get_size(struct tpml_digest_values *digest_list);
 /**
  * tcg2_get_active_pcr_banks
  *
- * @dev                TPM device
- * @active_pcr_banks   Bitmask of PCR algorithms supported
+ * @dev:         TPM device
+ * @active_pcr_banks:  Bitmask of PCR algorithms supported
  *
  * Return: zero on success, negative errno otherwise
  */
@@ -535,12 +552,12 @@ int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks);
 /**
  * tcg2_log_append - Append an event to an event log
  *
- * @pcr_index    Index of the PCR
- * @event_type   Type of event
- * @digest_list List of digests to add
- * @size   Size of event
- * @event  Event data
- * @log          Log buffer to append the event to
+ * @pcr_index:   Index of the PCR
+ * @event_type:  Type of event
+ * @digest_list: List of digests to add
+ * @size:  Size of event
+ * @event: Event data
+ * @log:         Log buffer to append the event to
  */
 void tcg2_log_append(u32 pcr_index, u32 event_type,
                 struct tpml_digest_values *digest_list, u32 size,
@@ -549,9 +566,9 @@ void tcg2_log_append(u32 pcr_index, u32 event_type,
 /**
  * Extend the PCR with specified digests
  *
- * @dev          TPM device
- * @pcr_index    Index of the PCR
- * @digest_list  List of digests to extend
+ * @dev:   TPM device
+ * @pcr_index:   Index of the PCR
+ * @digest_list: List of digests to extend
  *
  * Return: zero on success, negative errno otherwise
  */
@@ -561,9 +578,9 @@ int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
 /**
  * Read the PCR into a list of digests
  *
- * @dev          TPM device
- * @pcr_index    Index of the PCR
- * @digest_list  List of digests to extend
+ * @dev:   TPM device
+ * @pcr_index:   Index of the PCR
+ * @digest_list: List of digests to extend
  *
  * Return: zero on success, negative errno otherwise
  */
@@ -573,14 +590,14 @@ int tcg2_pcr_read(struct udevice *dev, u32 pcr_index,
 /**
  * Measure data into the TPM PCRs and the platform event log.
  *
- * @dev          TPM device
- * @log          Platform event log
- * @pcr_index    Index of the PCR
- * @size   Size of the data or 0 for event only
- * @data   Pointer to the data or NULL for event only
- * @event_type   Event log type
- * @event_size   Size of the event
- * @event  Pointer to the event
+ * @dev:   TPM device
+ * @log:   Platform event log
+ * @pcr_index:   Index of the PCR
+ * @size:  Size of the data or 0 for event only
+ * @data:  Pointer to the data or NULL for event only
+ * @event_type:  Event log type
+ * @event_size:  Size of the event
+ * @event: Pointer to the event
  *
  * Return: zero on success, negative errno otherwise
  */
@@ -598,13 +615,13 @@ int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog,
  * and the PCRs are not extended, the log is "replayed" to extend the PCRs.
  * If no log is discovered, create the log header.
  *
- * @dev                TPM device
- * @elog         Platform event log. The log pointer and log_size
+ * @dev:         TPM device
+ * @elog:        Platform event log. The log pointer and log_size
  *               members must be initialized to either 0 or to a valid
  *               memory region, in which case any existing log
  *               discovered will be copied to the specified memory
  *               region.
- * @ignore_existing_log      Boolean to indicate whether or not to ignore an
+ * @ignore_existing_log:     Boolean to indicate whether or not to ignore an
  *               existing platform log in memory
  *
  * Return: zero on success, negative errno otherwise
@@ -615,13 +632,13 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
 /**
  * Begin measurements.
  *
- * @dev                TPM device
- * @elog         Platform event log. The log pointer and log_size
+ * @dev:         TPM device
+ * @elog:        Platform event log. The log pointer and log_size
  *               members must be initialized to either 0 or to a valid
  *               memory region, in which case any existing log
  *               discovered will be copied to the specified memory
  *               region.
- * @ignore_existing_log Boolean to indicate whether or not to ignore an
+ * @ignore_existing_log: Boolean to indicate whether or not to ignore an
  *               existing platform log in memory
  *
  * Return: zero on success, negative errno otherwise
@@ -632,9 +649,9 @@ int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog,
 /**
  * Stop measurements and record separator events.
  *
- * @dev          TPM device
- * @elog   Platform event log
- * @error  Boolean to indicate whether an error ocurred or not
+ * @dev:   TPM device
+ * @elog:  Platform event log
+ * @error: Boolean to indicate whether an error ocurred or not
  */
 void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog,
                     bool error);
@@ -642,9 +659,9 @@ void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog,
 /**
  * Get the platform event log address and size.
  *
- * @dev          TPM device
- * @addr   Address of the log
- * @size   Size of the log
+ * @dev:   TPM device
+ * @addr:  Address of the log
+ * @size:  Size of the log
  *
  * Return: zero on success, negative errno otherwise
  */
@@ -653,7 +670,7 @@ int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size);
 /**
  * Get the first TPM2 device found.
  *
- * @dev          TPM device
+ * @dev:   TPM device
  *
  * Return: zero on success, negative errno otherwise
  */
@@ -662,16 +679,16 @@ int tcg2_platform_get_tpm2(struct udevice **dev);
 /**
  * Platform-specific function for handling TPM startup errors
  *
- * @dev          TPM device
- * @rc           The TPM response code
+ * @dev:   TPM device
+ * @rc:          The TPM response code
  */
 void tcg2_platform_startup_error(struct udevice *dev, int rc);

 /**
  * Issue a TPM2_Startup command.
  *
- * @dev          TPM device
- * @mode   TPM startup mode
+ * @dev:   TPM device
+ * @mode:  TPM startup mode
  *
  * Return: code of the operation
  */
@@ -680,8 +697,8 @@ u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode);
 /**
  * Issue a TPM2_SelfTest command.
  *
- * @dev          TPM device
- * @full_test    Asking to perform all tests or only the untested ones
+ * @dev:   TPM device
+ * @full_test:   Asking to perform all tests or only the untested ones
  *
  * Return: code of the operation
  */
@@ -690,41 +707,99 @@ u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test);
 /**
  * Issue a TPM2_Clear command.
  *
- * @dev          TPM device
- * @handle Handle
- * @pw           Password
- * @pw_sz  Length of the password
+ * @dev:   TPM device
+ * @handle:      Handle
+ * @pw:          Password
+ * @pw_sz: Length of the password
  *
  * Return: code of the operation
  */
 u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
             const ssize_t pw_sz);

+/**
+ * Issue a TPM2_StartAuthSession command. (chaining commands together which need authorization)
+ *
+ * @dev:   TPM device
+ * @session_handle:    Pointer to memory where to store the session handle.
+ * @session_type:      tpm2_se value to indicate session type (usually TPM_SE_POLICY)
+ *
+ * Return: code of the operation
+ */
+u32 tpm2_start_auth_session(struct udevice *dev, u32 *session_handle, u8 session_type);
+/**
+ * Issue a TPM2_FlushContext command. (for ending the authorization session)
+ *
+ * @dev:         TPM device
+ * @session_handle:    Authorization session to be terminated.
+ *
+ * Return: code of the operation
+ */
+u32 tpm2_flush_context(struct udevice *dev, u32 session_handle);
+
+/**
+ * Issue a TPM2_PolicyPCR command. (for authenticating using a PCR value)
+ *
+ * @dev:         TPM device
+ * @session_handle:    policy session handle started with start_auth_session.
+ * @index:       Index of the PCR
+ *
+ * @note:        For now only 1 PCR selection is supported,
+ *               since the value of one PCR can be extended with the value of another.
+ *               This achieves the same effect as selecting multiple PCR's
+ * @out_digest:        addr where to write the digest
+ *
+ * Return:       code of the operation
+ */
+u32 tpm2_set_policy_pcr(struct udevice *dev, u32 session_handle, u32 index, void *out_digest);
+
+/**
+ * Issue a TPM2_getPolicyDigest command.
+ *
+ * @dev:         TPM device
+ * @session_handle:    policy session handle started with start_auth_session.
+ * @out_digest:        addr where to write the digest (size is 0x20 for SHA256)
+ * Return:       code of the operation
+ */
+u32 tpm2_get_policy_digest(struct udevice *dev, u32 session_handle, void *out_digest);
+
 /**
  * Issue a TPM_NV_DefineSpace command
  *
  * This allows a space to be defined with given attributes and policy
  *
- * @dev                TPM device
- * @space_index        index of the area
- * @space_size         size of area in bytes
- * @nv_attributes      TPM_NV_ATTRIBUTES of the area
- * @nv_policy          policy to use
- * @nv_policy_size     size of the policy
- * Return: return code of the operation
+ * @dev:         TPM device
+ * @space_index: index of the area
+ * @space_size:        size of area in bytes
+ * @nv_attributes:     TPM_NV_ATTRIBUTES of the area
+ * @session_handle:    handle to a session. can be TPM2_RS_PW
+ * @nv_policy:         policy to use
+ * @nv_policy_size:    size of the policy
+ * Return:       return code of the operation
  */
 u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
                   size_t space_size, u32 nv_attributes,
                   const u8 *nv_policy, size_t nv_policy_size);

+/**
+ * Issue a TPM_NV_UnDefineSpace command
+ *
+ * This allows a space to be removed. Needed because TPM_clear doesn't clear platform entries
+ *
+ * @dev:         TPM device
+ * @space_index: index of the area
+ * Return:       return code of the operation
+ */
+u32 tpm2_nv_undefine_space(struct udevice *dev, u32 space_index);
+
 /**
  * Issue a TPM2_PCR_Extend command.
  *
- * @dev          TPM device
- * @index  Index of the PCR
- * @algorithm    Algorithm used, defined in 'enum tpm2_algorithms'
- * @digest Value representing the event to be recorded
- * @digest_len  len of the hash
+ * @dev:   TPM device
+ * @index: Index of the PCR
+ * @algorithm:   Algorithm used, defined in 'enum tpm2_algorithms'
+ * @digest:      Value representing the event to be recorded
+ * @digest_len:  len of the hash
  *
  * Return: code of the operation
  */
@@ -734,36 +809,38 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
 /**
  * Read data from the secure storage
  *
- * @dev          TPM device
- * @index  Index of data to read
- * @data   Place to put data
- * @count  Number of bytes of data
- * Return: code of the operation
+ * @dev:         TPM device
+ * @index:       Index of data to read
+ * @data:        Place to put data
+ * @count:       Number of bytes of data
+ * @session_handle:    handle of a running authorization session. if NULL->password authorization
+ * Return:       code of the operation
  */
-u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count);
+u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count, u32 *session_handle);

 /**
  * Write data to the secure storage
  *
- * @dev          TPM device
- * @index  Index of data to write
- * @data   Data to write
- * @count  Number of bytes of data
- * Return: code of the operation
+ * @dev:         TPM device
+ * @index:       Index of data to write
+ * @data:        Data to write
+ * @count:       Number of bytes of data
+ * @session_handle:    handle of a running authorization session. if NULL->password authorization
+ * Return:       code of the operation
  */
 u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
-                 u32 count);
+                 u32 count, u32 *session_handle);

 /**
  * Issue a TPM2_PCR_Read command.
  *
- * @dev          TPM device
- * @idx          Index of the PCR
- * @idx_min_sz   Minimum size in bytes of the pcrSelect array
- * @algorithm    Algorithm used, defined in 'enum tpm2_algorithms'
- * @data   Output buffer for contents of the named PCR
- * @digest_len  len of the data
- * @updates      Optional out parameter: number of updates for this PCR
+ * @dev:   TPM device
+ * @idx:   Index of the PCR
+ * @idx_min_sz:  Minimum size in bytes of the pcrSelect array
+ * @algorithm:   Algorithm used, defined in 'enum tpm2_algorithms'
+ * @data:  Output buffer for contents of the named PCR
+ * @digest_len:  len of the data
+ * @updates:     Optional out parameter: number of updates for this PCR
  *
  * Return: code of the operation
  */
@@ -775,13 +852,13 @@ u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
  * Issue a TPM2_GetCapability command.  This implementation is limited
  * to query property index that is 4-byte wide.
  *
- * @dev          TPM device
- * @capability   Partition of capabilities
- * @property     Further definition of capability, limited to be 4 bytes wide
- * @buf          Output buffer for capability information
- * @prop_count   Size of output buffer
+ * @dev:   TPM device
+ * @capability:  Partition of capabilities
+ * @property:    Further definition of capability, limited to be 4 bytes wide
+ * @buf:   Output buffer for capability information
+ * @prop_count:  Size of output buffer
  *
- * Return: code of the operation
+ * Return: code of the operation
  */
 u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
                  void *buf, size_t prop_count);
@@ -802,9 +879,9 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
 /**
  * Issue a TPM2_DictionaryAttackLockReset command.
  *
- * @dev          TPM device
- * @pw           Password
- * @pw_sz  Length of the password
+ * @dev:   TPM device
+ * @pw:          Password
+ * @pw_sz: Length of the password
  *
  * Return: code of the operation
  */
@@ -813,12 +890,12 @@ u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz);
 /**
  * Issue a TPM2_DictionaryAttackParameters command.
  *
- * @dev          TPM device
- * @pw           Password
- * @pw_sz  Length of the password
- * @max_tries    Count of authorizations before lockout
- * @recovery_time Time before decrementation of the failure count
- * @lockout_recovery Time to wait after a lockout
+ * @dev:   TPM device
+ * @pw:          Password
+ * @pw_sz: Length of the password
+ * @max_tries:   Count of authorizations before lockout
+ * @recovery_time: Time before decrementation of the failure count
+ * @lockout_recovery: Time to wait after a lockout
  *
  * Return: code of the operation
  */
@@ -830,12 +907,12 @@ u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
 /**
  * Issue a TPM2_HierarchyChangeAuth command.
  *
- * @dev          TPM device
- * @handle Handle
- * @newpw  New password
- * @newpw_sz     Length of the new password
- * @oldpw  Old password
- * @oldpw_sz     Length of the old password
+ * @dev:   TPM device
+ * @handle:      Handle
+ * @newpw: New password
+ * @newpw_sz:    Length of the new password
+ * @oldpw: Old password
+ * @oldpw_sz:    Length of the old password
  *
  * Return: code of the operation
  */
@@ -846,11 +923,11 @@ int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
 /**
  * Issue a TPM_PCR_SetAuthPolicy command.
  *
- * @dev          TPM device
- * @pw           Platform password
- * @pw_sz  Length of the password
- * @index  Index of the PCR
- * @digest New key to access the PCR
+ * @dev:   TPM device
+ * @pw:          Platform password
+ * @pw_sz: Length of the password
+ * @index: Index of the PCR
+ * @digest:      New key to access the PCR
  *
  * Return: code of the operation
  */
@@ -860,12 +937,12 @@ u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
 /**
  * Issue a TPM_PCR_SetAuthValue command.
  *
- * @dev          TPM device
- * @pw           Platform password
- * @pw_sz  Length of the password
- * @index  Index of the PCR
- * @digest New key to access the PCR
- * @key_sz Length of the new key
+ * @dev:   TPM device
+ * @pw:          Platform password
+ * @pw_sz: Length of the password
+ * @index: Index of the PCR
+ * @digest:      New key to access the PCR
+ * @key_sz:      Length of the new key
  *
  * Return: code of the operation
  */
@@ -876,9 +953,9 @@ u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
 /**
  * Issue a TPM2_GetRandom command.
  *
- * @dev          TPM device
- * @param data         output buffer for the random bytes
- * @param count        size of output buffer
+ * @dev:   TPM device
+ * @data:        output buffer for the random bytes
+ * @count:       size of output buffer
  *
  * Return: return code of the operation
  */
@@ -889,8 +966,8 @@ u32 tpm2_get_random(struct udevice *dev, void *data, u32 count);
  *
  * Once locked the data cannot be written until after a reboot
  *
- * @dev          TPM device
- * @index  Index of data to lock
+ * @dev:   TPM device
+ * @index: Index of data to lock
  * Return: code of the operation
  */
 u32 tpm2_write_lock(struct udevice *dev, u32 index);
@@ -901,7 +978,7 @@ u32 tpm2_write_lock(struct udevice *dev, u32 index);
  * This can be called to close off access to the firmware data in the data,
  * before calling the kernel.
  *
- * @dev          TPM device
+ * @dev:   TPM device
  * Return: code of the operation
  */
 u32 tpm2_disable_platform_hierarchy(struct udevice *dev);
@@ -909,7 +986,7 @@ u32 tpm2_disable_platform_hierarchy(struct udevice *dev);
 /**
  * submit user specified data to the TPM and get response
  *
- * @dev          TPM device
+ * @dev:   TPM device
  * @sendbuf:     Buffer of the data to send
  * @recvbuf:     Buffer to save the response to
  * @recv_size:   Pointer to the size of the response buffer
@@ -930,7 +1007,7 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
  * Return: result of the operation
  */
 u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
-                 u8 *recvbuf, size_t *recv_size);
+                 u8 *recvbuf, size_t *recv_size);

 /**
  * tpm2_enable_nvcommits() - Tell TPM to commit NV data immediately
@@ -941,7 +1018,7 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
  * This vendor command is used to indicate that non-volatile data should be
  * written to its store immediately.
  *
- * @dev          TPM device
+ * @dev:   TPM device
  * @vendor_cmd:  Vendor command number to send
  * @vendor_subcmd: Vendor sub-command number to send
  * Return: result of the operation
@@ -951,16 +1028,16 @@ u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,

 /**
  * tpm2_auto_start() - start up the TPM and perform selftests.
- *                     If a testable function has not been tested and is
- *                     requested the TPM2  will return TPM_RC_NEEDS_TEST.
+ *                           If a testable function has not been tested and is
+ *                           requested the TPM2  will return TPM_RC_NEEDS_TEST.
  *
- * @param dev          TPM device
+ * @dev:   TPM device
  * Return: TPM2_RC_TESTING, if TPM2 self-test is in progress.
- *         TPM2_RC_SUCCESS, if testing of all functions is complete without
- *         functional failures.
- *         TPM2_RC_FAILURE, if any test failed.
- *         TPM2_RC_INITIALIZE, if the TPM has not gone through the Startup
- *         sequence
+ *   TPM2_RC_SUCCESS, if testing of all functions is complete without
+ *   functional failures.
+ *   TPM2_RC_FAILURE, if any test failed.
+ *   TPM2_RC_INITIALIZE, if the TPM has not gone through the Startup
+ *   sequence

  */
 u32 tpm2_auto_start(struct udevice *dev);
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 68eaaa639f..5856b5de03 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -786,19 +786,188 @@ u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
      return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
 }

+u32 tpm2_start_auth_session(struct udevice *dev, u32 *session_handle, u8 session_type)
+{
+     const u16 nonce_size    = TPM2_SHA256_DIGEST_SIZE;
+     const int handles_len = sizeof(u32) * 2;
+     uint offset = TPM2_HDR_LEN + handles_len + sizeof(nonce_size);
+     struct tpm_chip_priv *priv;
+     int ret;
+
+     priv = dev_get_uclass_priv(dev);
+           if (!priv)
+                 return TPM_LIB_ERROR;
+
+     u8 command_v2[COMMAND_BUFFER_SIZE] = {
+                 /* header 10 bytes */
+                 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
+                 tpm_u32(offset + nonce_size + 7),/* Length */
+                 tpm_u32(TPM2_CC_START_AUTH_SESSION),/* Command code */
+
+                 /* handles 8 bytes */
+                 tpm_u32(TPM2_RH_NULL),  /* TPMI_DH_OBJECT+ */
+                 tpm_u32(TPM2_RH_NULL),  /* TPMI_DH_ENTITY+ */
+
+                 /* NONCE 32 bytes -> use pack_byte_string() */
+                 tpm_u16(nonce_size),
+                 /* message 7 bytes -> use pack_byte_string() */
+                 //tpm_u16(0), // salt size
+                 //session_type, // session type
+                 //tpm_u16(TPM2_ALG_NULL), // symmetric key algorythm
+                 //tpm_u16(TPM2_ALG_SHA256), // auth hash
+     };
+
+     u8 Nonce[nonce_size]; //nonce is a random number you use once. (Number ONCE)
+
+     memset(&Nonce, 2, nonce_size); //should use TPM_get_random() to randomize
+
+     ret = pack_byte_string(command_v2, sizeof(command_v2), "swbww",
+                       offset, Nonce, nonce_size,
+                       offset + nonce_size, 0, //salt size
+                       offset + nonce_size + 2, session_type,
+                       offset + nonce_size + 3, TPM2_ALG_NULL,
+                       offset + nonce_size + 5, TPM2_ALG_SHA256);
+
+     if (ret)
+           return TPM_LIB_ERROR;
+
+     size_t response_len = COMMAND_BUFFER_SIZE;
+     u8 response[COMMAND_BUFFER_SIZE];
+     u16 tag;
+     u32 size, code;
+
+     ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
+
+     if (ret)
+           return log_msg_ret("read", ret);
+
+     if (unpack_byte_string(response, response_len, "wdddws",
+                       0, &tag, 2, &size, 6, &code, //header
+                       10, session_handle, //TPMI_SH_AUTH_SESSION
+                       14, &priv->nonce_sz,
+                       16, priv->nonce, TPM2_SHA256_DIGEST_SIZE)) //HACK: we asked for SHA256, so that's what we'll get.
+           return TPM_LIB_ERROR;
+     return ret;
+}
+
+u32 tpm2_flush_context(struct udevice *dev, u32 session_handle)
+{
+     u8 command_v2[COMMAND_BUFFER_SIZE] = {
+                 /* header 10 bytes */
+                 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
+                 tpm_u32(TPM2_HDR_LEN + sizeof(u32)),/* Length */
+                 tpm_u32(TPM2_CC_FLUSH_CONTEXT),/* Command code */
+
+                 /* session handle 4 bytes */
+                 tpm_u32(session_handle),      /* TPMI_DH_CONTEXT+ */
+     };
+     return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+}
+
+u32 tpm2_set_policy_pcr(struct udevice *dev, u32 session_handle, u32 index, void *out_digest)
+{
+     const int offset = TPM2_HDR_LEN + 6;
+     const int message_len = offset + TPM2_SHA256_DIGEST_SIZE + 10;
+     int ret;
+     u8 pcr_sel_bit = BIT(index % 8);
+     struct tpm_chip_priv *priv;
+     struct tpml_digest_values digest_list;
+
+     digest_list.count = 1;
+     digest_list.digests->hash_alg = TPM2_ALG_SHA256;
+     tcg2_pcr_read(dev, index, &digest_list);
+
+     u8 pcr_sha_output[TPM2_SHA256_DIGEST_SIZE];
+     sha256_context ctx_256;
+
+     sha256_starts(&ctx_256);
+     sha256_update(&ctx_256, digest_list.digests[0].digest.sha256, TPM2_SHA256_DIGEST_SIZE);
+     sha256_finish(&ctx_256, pcr_sha_output);
+
+     priv = dev_get_uclass_priv(dev);
+           if (!priv)
+                 return TPM_LIB_ERROR;
+
+     u8 idx_array_sz = max(priv->pcr_select_min, DIV_ROUND_UP(index, 8));
+
+     u8 command_v2[COMMAND_BUFFER_SIZE] = {
+                 /* header 10 bytes */
+                 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG -> TPM2_ST_SESSIONS only for audit or decrypt*/
+                 tpm_u32(message_len),/* Length */
+                 tpm_u32(TPM2_CC_POLICY_PCR),/* Command code */
+                 /* session handle 4 bytes */
+                 tpm_u32(session_handle),      /* TPMI_SH_POLICY */
+                 /* PCR Digest - 32 bytes */
+                 tpm_u16(TPM2_SHA256_DIGEST_SIZE) /*hash size*/
+                 /* digest - 32-bytes */
+                 /* PCR selection */
+                 //tpm_u32(1),                 /* Number of selections */
+                 //tpm_u16(TPM_ALG_SHA256),    /* Algorithm */
+                 //idx_array_sz,               /* Array size for selection */
+                 /* bitmap(idx)                   Selected PCR bitmap */
+     };
+
+     if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "sdwbbw",
+                 offset, pcr_sha_output, TPM2_SHA256_DIGEST_SIZE,
+                 offset + TPM2_SHA256_DIGEST_SIZE, 1, /* Number of selections */
+                 offset + TPM2_SHA256_DIGEST_SIZE + 4, TPM2_ALG_SHA256, /* Algorithm */
+                 offset + TPM2_SHA256_DIGEST_SIZE + 6, idx_array_sz, /* size of select */
+                 offset + TPM2_SHA256_DIGEST_SIZE + 7, pcr_sel_bit,/* Selected PCR bitmap */
+                 offset + TPM2_SHA256_DIGEST_SIZE + 8, 0))  /*padding */
+           return TPM_LIB_ERROR;
+
+     ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+     if (ret)
+           return ret;
+     return tpm2_get_policy_digest(dev, session_handle, out_digest);
+}
+
+u32 tpm2_get_policy_digest(struct udevice *dev, u32 session_handle, void *out_digest)
+{
+     const int message_len = TPM2_HDR_LEN + sizeof(u32);
+
+     u8 command_v2[COMMAND_BUFFER_SIZE] = {
+           /* header 10 bytes */
+           tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG -> SESSIONS only for audit or decrypt */
+           tpm_u32(message_len),/* Length */
+           tpm_u32(TPM2_CC_POLICY_GET_DIGEST),/* Command code */
+           /* session handle 4 bytes */
+           tpm_u32(session_handle),      /* TPMI_SH_POLICY */
+     };
+
+     size_t response_len = COMMAND_BUFFER_SIZE;
+     u8 response[COMMAND_BUFFER_SIZE];
+     int ret;
+     u16 tag;
+     u32 size, code;
+
+     ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
+     if (ret)
+           return log_msg_ret("read", ret);
+
+     if (unpack_byte_string(response, response_len, "wdds",
+                 0, &tag, 2, &size, 6, &code,
+                 12, out_digest, TPM2_SHA256_DIGEST_SIZE)) //digest_size
+           return TPM_LIB_ERROR;
+
+     return ret;
+}
+
 u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
-                  size_t space_size, u32 nv_attributes,
-                  const u8 *nv_policy, size_t nv_policy_size)
+                 size_t space_size, u32 nv_attributes,
+                 const u8 *nv_policy, size_t nv_policy_size)
 {
      /*
       * Calculate the offset of the nv_policy piece by adding each of the
       * chunks below.
       */
      const int platform_len = sizeof(u32);
-     const int session_hdr_len = 13;
+     const int session_hdr_len = 15;
      const int message_len = 14;
-     uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
-           message_len;
+     int ret;
+     uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len + message_len;
+     u8 attrs = 0;
+
      u8 command_v2[COMMAND_BUFFER_SIZE] = {
            /* header 10 bytes */
            tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
@@ -806,43 +975,72 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
            tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */

            /* handles 4 bytes */
-           tpm_u32(TPM2_RH_PLATFORM),    /* Primary platform seed */
+           tpm_u32(TPM2_RH_PLATFORM),    /* platform seed, requires TPMA_NV_PLATFORMCREATE */

-           /* session header 13 bytes */
+
+           /* session header 15 bytes */
+           /*null auth session*/
            tpm_u32(9),             /* Header size */
-           tpm_u32(TPM2_RS_PW),          /* Password authorisation */
+           tpm_u32(TPM2_RS_PW),          /* auth handle if active, otherwise TPM2_RS_PW*/
            tpm_u16(0),             /* nonce_size */
-           0,                      /* session_attrs */
+           attrs,                        /* session_attrs */
+           tpm_u16(0),             /* HMAC size */
+           /*end auth area*/
            tpm_u16(0),             /* auth_size */
-
            /* message 14 bytes + policy */
            tpm_u16(message_len + nv_policy_size),    /* size */
            tpm_u32(space_index),
            tpm_u16(TPM2_ALG_SHA256),
-           tpm_u32(nv_attributes),
+           tpm_u32(nv_attributes | TPMA_NV_PLATFORMCREATE),
            tpm_u16(nv_policy_size),
            /*
             * nv_policy
             * space_size
             */
      };
-     int ret;
-
      /*
       * Fill the command structure starting from the first buffer:
-      *     - the password (if any)
+      *     - the password (if any)
       */
      ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
-                        offset, nv_policy, nv_policy_size,
-                        offset + nv_policy_size, space_size);
+                       offset, nv_policy, nv_policy_size,
+                       offset + nv_policy_size, space_size);
      if (ret)
            return TPM_LIB_ERROR;
+     return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+}
+
+u32 tpm2_nv_undefine_space(struct udevice *dev, u32 space_index)
+{
+     const int platform_len = sizeof(u32);
+     const int session_hdr_len = 13;
+     const int message_len = 4;
+     u8 command_v2[COMMAND_BUFFER_SIZE] = {
+           /* header 10 bytes */
+           tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
+           tpm_u32(TPM2_HDR_LEN + platform_len + session_hdr_len +
+                 message_len),/* Length - header + provision + index + auth area*/
+           tpm_u32(TPM2_CC_NV_UNDEFINE_SPACE),/* Command code */
+
+           /* handles 4 bytes */
+           tpm_u32(TPM2_RH_PLATFORM),    /* Primary platform seed */
+           /* nv_index */
+           tpm_u32(space_index),
+
+           /*null auth session*/
+           tpm_u32(9),             /* Header size */
+           tpm_u32(TPM2_RS_PW),          /* Password authorisation*/
+           tpm_u16(0),             /* nonce_size */
+           0,                      /* session_attrs */
+           tpm_u16(0),             /* HMAC size */
+           /*end auth area*/

+     };
      return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
 }

 u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
-               const u8 *digest, u32 digest_len)
+                 const u8 *digest, u32 digest_len)
 {
      /* Length of the message header, up to start of digest */
      uint offset = 33;
@@ -865,7 +1063,7 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,

            /* hashes */
            tpm_u32(1),             /* Count (number of hashes) */
-           tpm_u16(algorithm),     /* Algorithm of the hash */
+           tpm_u16(algorithm),           /* Algorithm of the hash */
            /* STRING(digest)          Digest */
      };
      int ret;
@@ -874,66 +1072,111 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
            return -EINVAL;
      /*
       * Fill the command structure starting from the first buffer:
-      *     - the digest
+      *     - the digest
       */
      ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
-                        offset, digest, digest_len);
+                       offset, digest, digest_len);
      if (ret)
            return TPM_LIB_ERROR;

      return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
 }

-u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
+u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count, u32 *session_handle)
 {
-     u8 command_v2[COMMAND_BUFFER_SIZE] = {
-           /* header 10 bytes */
-           tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
-           tpm_u32(10 + 8 + 4 + 9 + 4),  /* Length */
-           tpm_u32(TPM2_CC_NV_READ),     /* Command code */
+     static const int handles_len = 8, auth_handle_hdr_len = 10;
+     u32 offset = TPM2_HDR_LEN + handles_len + auth_handle_hdr_len;
+     struct tpm_chip_priv *priv;
+     int ret;
+     u16 tag;
+     u32 size, code;

-           /* handles 8 bytes */
-           tpm_u32(TPM2_RH_PLATFORM),    /* Primary platform seed */
-           tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
+     priv = dev_get_uclass_priv(dev);

-           /* AUTH_SESSION */
-           tpm_u32(9),             /* Authorization size */
-           tpm_u32(TPM2_RS_PW),          /* Session handle */
-           tpm_u16(0),             /* Size of <nonce> */
-                                   /* <nonce> (if any) */
-           0,                      /* Attributes: Cont/Excl/Rst */
-           tpm_u16(0),             /* Size of <hmac/password> */
-                                   /* <hmac/password> (if any) */
+     if (!priv)
+           return TPM_LIB_ERROR;
+
+     u32 nonce_size = priv->nonce_sz;
+     u32 authorization = TPM2_RS_PW;

-           tpm_u16(count),               /* Number of bytes */
-           tpm_u16(0),             /* Offset */
+     priv->nonce[nonce_size - 1]++; //increase nonce.
+     if (session_handle)
+           authorization = *session_handle;
+     else
+           nonce_size = 0; //cannot use nonce when using password authorization
+
+     u8 command_v2[COMMAND_BUFFER_SIZE] = {
+                 /* header 10 bytes */
+                 tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
+                 tpm_u32(offset + nonce_size + 7),   /* Length */
+                 tpm_u32(TPM2_CC_NV_READ),     /* Command code */
+
+                 /* handles 8 bytes */
+                 tpm_u32(index),               /* Primary platform seed */
+                 tpm_u32(index),               /*nv index*/
+
+                 /* AUTH_SESSION */
+                 tpm_u32(9 + nonce_size),      /* Authorization size */
+                 /*auth handle - 9 bytes */
+                 tpm_u32(authorization),
+                 tpm_u16(nonce_size),          /* Size of <nonce> */
+                 /* <nonce> (if any) */
+                 /* Attributes: Cont/Excl/Rst */
+                 /* Size of <hmac/password> */
+                 /* <hmac/password> (if any) */
+                 /* end auth handle */
+                 /* Number of bytes */
+                 /* Offset */
      };
+
      size_t response_len = COMMAND_BUFFER_SIZE;
      u8 response[COMMAND_BUFFER_SIZE];
-     int ret;
-     u16 tag;
-     u32 size, code;
+
+     ret = pack_byte_string(command_v2, sizeof(command_v2), "sbwww",
+                 offset, priv->nonce, nonce_size,
+                 offset + nonce_size, 0,
+                 offset + nonce_size + 1, 0,
+                 offset + nonce_size + 3, count,
+                 offset + nonce_size + 5, 0);
+
+     if (ret)
+           return TPM_LIB_ERROR;

      ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
      if (ret)
            return log_msg_ret("read", ret);
+
      if (unpack_byte_string(response, response_len, "wdds",
-                        0, &tag, 2, &size, 6, &code,
-                        16, data, count))
+                 0, &tag, 2, &size, 6, &code,
+                 16, data, count))
            return TPM_LIB_ERROR;

      return 0;
 }

 u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
-                 u32 count)
+                 u32 count, u32 *session_handle)
 {
+     int ret;
+     u32 authorization = TPM2_RS_PW;
      struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
-     uint offset = 10 + 8 + 4 + 9 + 2;
-     uint len = offset + count + 2;
-     /* Use empty password auth if platform hierarchy is disabled */
-     u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
-           TPM2_RH_PLATFORM;
+
+     if (!priv)
+           return TPM_LIB_ERROR;
+
+     u32 nonce_size = priv->nonce_sz;
+
+     priv->nonce[nonce_size - 1]++;
+
+     if (session_handle)
+           authorization = *session_handle;
+     else
+           nonce_size = 0; //cannot use nonce when using password authorization
+
+     static const int handles_len = 8, auth_handle_hdr_len = 10, nv_info_sz = 7;
+     u32 offset = TPM2_HDR_LEN + handles_len + auth_handle_hdr_len;
+     uint len = offset + nonce_size + count + nv_info_sz;
+
      u8 command_v2[COMMAND_BUFFER_SIZE] = {
            /* header 10 bytes */
            tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
@@ -941,27 +1184,34 @@ u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
            tpm_u32(TPM2_CC_NV_WRITE),    /* Command code */

            /* handles 8 bytes */
-           tpm_u32(auth),                /* Primary platform seed */
-           tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
+           tpm_u32(index),               /* Primary platform seed */
+           tpm_u32(index),               /*nv index*/

            /* AUTH_SESSION */
-           tpm_u32(9),             /* Authorization size */
-           tpm_u32(TPM2_RS_PW),          /* Session handle */
-           tpm_u16(0),             /* Size of <nonce> */
-                                   /* <nonce> (if any) */
-           0,                      /* Attributes: Cont/Excl/Rst */
-           tpm_u16(0),             /* Size of <hmac/password> */
-                                   /* <hmac/password> (if any) */
-
-           tpm_u16(count),
+           tpm_u32(9 + nonce_size),      /* Authorization size */
+           /*auth handle - 9 bytes */
+           tpm_u32(authorization),
+           tpm_u16(nonce_size),          /* Size of <nonce> */
+           /* <nonce> (if any) */
+           /* Attributes: Cont/Excl/Rst */
+           /* Size of <hmac/password> */
+           /* <hmac/password> (if any) */
+           /* end auth handle */
+           /* size of buffer - 2 bytes*/
+           /* data (buffer)*/
+           /* offset -> the octet offset into the NV Area*/
      };
      size_t response_len = COMMAND_BUFFER_SIZE;
      u8 response[COMMAND_BUFFER_SIZE];
-     int ret;

-     ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
-                        offset, data, count,
-                        offset + count, 0);
+     ret = pack_byte_string(command_v2, sizeof(command_v2), "sbwwsw",
+                 offset, priv->nonce, nonce_size,
+                 offset + nonce_size, 0, //attrs
+                 offset + nonce_size + 1, 0, //hmac sz
+                 offset + nonce_size + 3, count,
+                 offset + nonce_size + 5, data, count,
+                 offset + nonce_size + count, 0);
+
      if (ret)
            return TPM_LIB_ERROR;

@@ -972,6 +1222,8 @@ u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
              u16 algorithm, void *data, u32 digest_len,
              unsigned int *updates)
 {
+     int ret;
+
      u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
      u8 command_v2[COMMAND_BUFFER_SIZE] = {
            tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
@@ -982,17 +1234,16 @@ u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
            tpm_u32(1),             /* Number of selections */
            tpm_u16(algorithm),           /* Algorithm of the hash */
            idx_array_sz,                 /* Array size for selection */
-           /* bitmap(idx)                   Selected PCR bitmap */
+           /* Selected PCR bitmap */
      };
      size_t response_len = COMMAND_BUFFER_SIZE;
      u8 response[COMMAND_BUFFER_SIZE];
      unsigned int pcr_sel_idx = idx / 8;
      u8 pcr_sel_bit = BIT(idx % 8);
      unsigned int counter = 0;
-     int ret;

      if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
-                      17 + pcr_sel_idx, pcr_sel_bit))
+                       17 + pcr_sel_idx, pcr_sel_bit))
            return TPM_LIB_ERROR;

      ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
@@ -1003,9 +1254,9 @@ u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
            return TPM_LIB_ERROR;

      if (unpack_byte_string(response, response_len, "ds",
-                        10, &counter,
-                        response_len - digest_len, data,
-                        digest_len))
+                       10, &counter,
+                       response_len - digest_len, data,
+                       digest_len))
            return TPM_LIB_ERROR;

      if (updates)
@@ -1088,7 +1339,7 @@ static bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection)
 }

 int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
-                 u32 *pcr_banks)
+                 u32 *pcr_banks)
 {
      u8 response[(sizeof(struct tpms_capability_data) -
            offsetof(struct tpms_capability_data, data))];
@@ -1111,7 +1362,7 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
       * instead of TPM2_NUM_PCR_BANKS
       */
      if (pcrs.count > ARRAY_SIZE(tpm2_supported_algorithms) ||
-         pcrs.count < 1) {
+           pcrs.count < 1) {
            printf("%s: too many pcrs: %u\n", __func__, pcrs.count);
            return -EMSGSIZE;
      }
@@ -1135,10 +1386,10 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
                  i * ((num_pcr + 7) / 8);
            u32 size_select_offset =
                  hash_offset + offsetof(struct tpms_pcr_selection,
-                                    size_of_select);
+                                   size_of_select);
            u32 pcr_select_offset =
                  hash_offset + offsetof(struct tpms_pcr_selection,
-                                    pcr_select);
+                                   pcr_select);

            pcrs.selection[i].hash =
                  get_unaligned_be16(response + hash_offset);
@@ -1146,12 +1397,12 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
                  __get_unaligned_be(response + size_select_offset);
            if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX) {
                  printf("%s: pcrs selection too large: %u\n", __func__,
-                        pcrs.selection[i].size_of_select);
+                       pcrs.selection[i].size_of_select);
                  return -ENOBUFS;
            }
            /* copy the array of pcr_select */
            memcpy(pcrs.selection[i].pcr_select, response + pcr_select_offset,
-                  pcrs.selection[i].size_of_select);
+                 pcrs.selection[i].size_of_select);
      }

      for (i = 0; i < pcrs.count; i++) {
@@ -1163,7 +1414,7 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
                        *active_pcr |= hash_mask;
            } else {
                  printf("%s: unknown algorithm %x\n", __func__,
-                        pcrs.selection[i].hash);
+                       pcrs.selection[i].hash);
            }
      }

@@ -1196,10 +1447,10 @@ u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)

      /*
       * Fill the command structure starting from the first buffer:
-      *     - the password (if any)
+      *    - the password (if any)
       */
      ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
-                        offset, pw, pw_sz);
+                       offset, pw, pw_sz);
      offset += pw_sz;
      if (ret)
            return TPM_LIB_ERROR;
@@ -1511,7 +1762,7 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
 }

 u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
-                 u8 *recvbuf, size_t *recv_size)
+                 u8 *recvbuf, size_t *recv_size)
 {
      u8 command_v2[COMMAND_BUFFER_SIZE] = {
            /* header 10 bytes */
diff --git a/lib/tpm_api.c b/lib/tpm_api.c
index 39a5121e30..5875e7b085 100644
--- a/lib/tpm_api.c
+++ b/lib/tpm_api.c
@@ -128,7 +128,7 @@ u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
      if (tpm_is_v1(dev))
            return tpm1_nv_read_value(dev, index, data, count);
      else if (tpm_is_v2(dev))
-           return tpm2_nv_read_value(dev, index, data, count);
+           return tpm2_nv_read_value(dev, index, data, count, NULL);
      else
            return -ENOSYS;
 }
@@ -139,7 +139,7 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
      if (tpm_is_v1(dev))
            return tpm1_nv_write_value(dev, index, data, count);
      else if (tpm_is_v2(dev))
-           return tpm2_nv_write_value(dev, index, data, count);
+           return tpm2_nv_write_value(dev, index, data, count, NULL);
      else
            return -ENOSYS;
 }
--
2.34.1
===========================END PATCH=======================
________________________________
差出人: Ilias Apalodimas <ilias.apalodimas at linaro.org>
送信日時: 2024年3月5日 19:47
宛先: Niek Nooijens / OC-IAB PBD-C DEVEL 1-1 <niek.nooijens at omron.com>
CC: u-boot at lists.denx.de <u-boot at lists.denx.de>
件名: Re: [PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR

[ilias.apalodimas at linaro.org からのメールを受け取る頻度は高くありません。これが問題である可能性の理由については、https://aka.ms/LearnAboutSenderIdentification をご覧ください。]

On Tue, 20 Feb 2024 at 07:59, niek.nooijens at omron.com
<niek.nooijens at omron.com> wrote:
>
> Hi there
>
> After the NV-memory read/write code I'm here again for another patch.
> This time I implemented code to allow an NV-index to be locked behind a PCR value.
> This can be used together with the new measured-boot code allowing you to store encryption keys inside the TPM and locking them behind PCR's.
> To do that you:
>
> set the PCR's to some value
> start an auth session
> create a policy_pcr
> get that policy's digest
> use NV_define together with the policy digest.
> use nv_write together with the session handle in which the policy_digest was generated.
>
> After another PCR extend, the NV index will be locked and cannot be read.
> At next boot, when the PCR's are in the correct state again, you can read the NV_index by authenticating with a PCR value.
> To do that you:
>
> set the PCR's to the correct value
> start an auth session
> create a policy_pcr
> nv_read whilst providing the session handle in which the policy was created.
>
>
> It might not be perfect yet, but at least it vastly extends the TPM capabilities of uboot.
> I generated the patch against latest github master.
> Feedback is welcome.
>
> Niek
>
> =================START PATCH========================
> From 8d3ea3130794d9db51d95056eb42044a2c5d9f4f Mon Sep 17 00:00:00 2001
> From: Niek Nooijens <niek.nooijens at omron.com>
> Date: Tue, 20 Feb 2024 13:42:57 +0900
> Subject: [PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR
>  policy
>
> Signed-off-by: Niek Nooijens <niek.nooijens at omron.com>
> ---
>  cmd/tpm-v2.c         | 258 +++++++++++++++++++++++++++++++
>  include/tpm-common.h |   2 +
>  include/tpm-v2.h     | 126 ++++++++++++---
>  lib/tpm-v2.c         | 355 +++++++++++++++++++++++++++++++++++++------
>  lib/tpm_api.c        |   4 +-
>  5 files changed, 669 insertions(+), 76 deletions(-)
>
> diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
> index 7e479b9dfe..6b6f4629ea 100644
> --- a/cmd/tpm-v2.c
> +++ b/cmd/tpm-v2.c
> @@ -356,6 +356,222 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
>  key, key_sz));
>  }
>
> +static int do_tpm_nv_define(struct cmd_tbl *cmdtp, int flag,
> +                     int argc, char *const argv[])
> +{
> +     struct udevice *dev;
> +     struct tpm_chip_priv *priv;
> +     u32 nv_addr, nv_size, rc;
> +     void *policy_addr = NULL;
> +     size_t policy_size = 0;
> +     int ret;
> +
> +     u32 nv_attributes = TPMA_NV_PLATFORMCREATE | TPMA_NV_OWNERWRITE | TPMA_NV_OWNERREAD | TPMA_NV_PPWRITE | TPMA_NV_PPREAD;

You need to break this at 80 chars
u32 nv_attributes = TPMA_NV_PLATFORMCREATE | TPMA_NV_OWNERWRITE | \
                                  ...etc

> +
> +     if (argc < 3 && argc > 7)
> +           return CMD_RET_USAGE;
> +
> +     ret = get_tpm(&dev);
> +     if (ret)
> +           return ret;
> +
> +     priv = dev_get_uclass_priv(dev);
> +     if (!priv)
> +           return -EINVAL;
> +
> +     nv_addr = simple_strtoul(argv[1], NULL, 0);
> +
> +     nv_size = simple_strtoul(argv[2], NULL, 0);
> +
> +     if (argc > 3)
> +           nv_attributes = simple_strtoul(argv[3], NULL, 0);
> +
> +     if (argc > 4) {
> +           policy_addr = map_sysmem(simple_strtoul(argv[4], NULL, 0), 0);
> +           nv_attributes |= (TPMA_NV_POLICYREAD | TPMA_NV_POLICYWRITE); //obligated, might as well force it

I am not sure I understand the comment

> +           if (argc < 5)
> +                 return CMD_RET_USAGE;
> +           policy_size = simple_strtoul(argv[5], NULL, 0);
> +     }
> +
> +     rc = tpm2_nv_define_space(dev, nv_addr, nv_size, nv_attributes, policy_addr, policy_size);
> +

You don't need an empty line here

> +     if (rc)
> +           printf("ERROR: nv_define #%u returns: 0x%x\n", nv_addr, rc);
> +
> +     if (policy_addr)
> +           unmap_sysmem(policy_addr);

Later down the code, you unconditionally call unmap_sysmem even for
NULL.  I don't think we need the check here either

> +
> +     return report_return_code(rc);
> +}
> +
> +static int do_tpm_nv_undefine(struct cmd_tbl *cmdtp, int flag,
> +                       int argc, char *const argv[])
> +{
> +     struct udevice *dev;
> +     u32 nv_addr, ret, rc;
> +
> +     ret = get_tpm(&dev);
> +     if (ret)
> +           return ret;
> +
> +     if (argc != 2)
> +           return CMD_RET_USAGE;
> +
> +     nv_addr = simple_strtoul(argv[1], NULL, 0);
> +     rc = tpm2_nv_undefine_space(dev, nv_addr);
> +
> +     return report_return_code(rc);
> +}
> +
> +static int do_tpm_nv_read_value(struct cmd_tbl *cmdtp, int flag,
> +                       int argc, char *const argv[])
> +{
> +     struct udevice *dev;
> +     u32 nv_addr, nv_size, rc;
> +     void *session_addr = NULL;
> +     int ret;
> +     void *out_data;
> +
> +     ret = get_tpm(&dev);
> +     if (ret)
> +           return ret;
> +
> +     if (argc < 4)
> +           return CMD_RET_USAGE;
> +
> +     nv_addr = simple_strtoul(argv[1], NULL, 0);
> +
> +     nv_size = simple_strtoul(argv[2], NULL, 0);
> +
> +     out_data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
> +

Get rid of the empty lines before if() statements in the entire patch please.

> +     if (argc == 5)
> +           session_addr = map_sysmem(simple_strtoul(argv[4], NULL, 0), 0);
> +
> +     rc = tpm2_nv_read_value(dev, nv_addr, out_data, nv_size, session_addr);

What happens if session_addr is NULL?

> +
> +     if (rc)
> +           printf("ERROR: nv_read #%u returns: #%u\n", nv_addr, rc);
> +
> +     unmap_sysmem(out_data);
> +     return report_return_code(rc);
> +}
> +
> +static int do_tpm_nv_write_value(struct cmd_tbl *cmdtp, int flag,
> +                        int argc, char *const argv[]) //TODO: session handle from auth session!

Please explain that TODO in more detail

> +{
> +     struct udevice *dev;
> +     u32 nv_addr, nv_size, rc;
> +     void *session_addr = NULL;
> +     int ret;
> +
> +     ret = get_tpm(&dev);
> +           if (ret)
> +                 return ret;
> +
> +           if (argc < 4)
> +                 return CMD_RET_USAGE;
> +
> +     nv_addr = simple_strtoul(argv[1], NULL, 0); //tpm_addr
> +
> +     nv_size = simple_strtoul(argv[2], NULL, 0); //size
> +
> +     void *data_to_write = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
> +
> +     if (argc == 5)
> +           session_addr = map_sysmem(simple_strtoul(argv[4], NULL, 0), 0);
> +
> +     rc = tpm2_nv_write_value(dev, nv_addr, data_to_write, nv_size, session_addr);
> +
> +     if (rc)
> +           printf("ERROR: nv_write #%u returns: #%u\n", nv_addr, rc);
> +
> +     unmap_sysmem(session_addr);
> +     unmap_sysmem(data_to_write);
> +     return report_return_code(rc);
> +}
> +
> +static int do_start_auth_session(struct cmd_tbl *cmdtp, int flag,
> +                        int argc, char *const argv[])
> +{
> +     struct udevice *dev;
> +     u32 rc;
> +     u8 session_type = TPM_SE_POLICY;
> +     int ret;
> +
> +     ret = get_tpm(&dev);
> +
> +     if (argc < 2)
> +           return CMD_RET_USAGE;
> +
> +     void *data_to_write = map_sysmem(simple_strtoul(argv[1], NULL, 0), 0);
> +
> +     if (argc > 2)
> +           session_type = simple_strtoul(argv[2], NULL, 0);
> +
> +     rc = tpm2_start_auth_session(dev, data_to_write, session_type);
> +
> +     if (rc)
> +           printf("ERROR: start_auth_session returns: #%u\n", rc);
> +
> +     unmap_sysmem(data_to_write);
> +     return report_return_code(rc);
> +}
> +
> +static int do_flush_context(struct cmd_tbl *cmdtp, int flag,
> +                     int argc, char *const argv[])
> +{
> +     struct udevice *dev;
> +     u32 rc;
> +     int ret;
> +
> +     ret = get_tpm(&dev);
> +
> +     if (argc < 2)
> +           return CMD_RET_USAGE;
> +
> +     void *data_to_read = map_sysmem(simple_strtoul(argv[1], NULL, 0), 0);
> +     u32 session_handle = *((u32 *)data_to_read);
> +
> +     rc = tpm2_flush_context(dev, session_handle);
> +
> +     if (rc)
> +           printf("ERROR: flush_context returns: #%u\n", rc);
> +
> +     unmap_sysmem(data_to_read);
> +     return report_return_code(rc);
> +}
> +
> +static int do_policy_pcr(struct cmd_tbl *cmdtp, int flag,
> +                  int argc, char *const argv[])
> +{
> +     struct udevice *dev;
> +     u32 rc, pcr;
> +     int ret;
> +
> +     ret = get_tpm(&dev);
> +
> +     if (argc != 4)
> +                 return CMD_RET_USAGE;
> +
> +     void *data_to_read = map_sysmem(simple_strtoul(argv[1], NULL, 0), 0);
> +     u32 session_handle = *((u32 *)data_to_read);
> +
> +     pcr = simple_strtoul(argv[2], NULL, 0);
> +
> +     void *out_digest = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
> +
> +     rc = tpm2_set_policy_pcr(dev, session_handle, pcr, out_digest);
> +
> +     if (rc)
> +           printf("ERROR: policy_pcr returns: #%u\n", rc);
> +
> +     unmap_sysmem(data_to_read);
> +     unmap_sysmem(out_digest);
> +     return report_return_code(rc);
> +}
> +
>  static struct cmd_tbl tpm2_commands[] = {
>  U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
>  U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
> @@ -375,6 +591,13 @@ static struct cmd_tbl tpm2_commands[] = {
>   do_tpm_pcr_setauthpolicy, "", ""),
>  U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
>   do_tpm_pcr_setauthvalue, "", ""),
> +     U_BOOT_CMD_MKENT(nv_define, 0, 1, do_tpm_nv_define, "", ""),
> +     U_BOOT_CMD_MKENT(nv_undefine, 0, 1, do_tpm_nv_undefine, "", ""),
> +     U_BOOT_CMD_MKENT(nv_read, 0, 1, do_tpm_nv_read_value, "", ""),
> +     U_BOOT_CMD_MKENT(nv_write, 0, 1, do_tpm_nv_write_value, "", ""),
> +     U_BOOT_CMD_MKENT(start_auth_session, 0, 1, do_start_auth_session, "", ""),
> +     U_BOOT_CMD_MKENT(flush_context, 0, 1, do_flush_context, "", ""),
> +     U_BOOT_CMD_MKENT(policy_pcr, 0, 1, do_policy_pcr, "", ""),
>  };
>
>  struct cmd_tbl *get_tpm2_commands(unsigned int *size)
> @@ -453,4 +676,40 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
>  "    <pcr>: index of the PCR\n"
>  "    <key>: secret to protect the access of PCR #<pcr>\n"
>  "    <password>: optional password of the PLATFORM hierarchy\n"
> +"\n"
> +"nv_define <tpm_addr> <size> [<attributes> <policy_digest_addr> <policy_size>]\n"
> +"    Define new nv index in the TPM at <tpm_addr> with size <size>\n"
> +"    <tpm_addr>: the internal address used within the TPM for the NV-index\n"
> +"    <attributes>: is described in tpm-v2.h enum tpm_index_attrs. Note; Always use TPMA_NV_PLATFORMCREATE!\n"
> +"                  will default to: TPMA_NV_PLATFORMCREATE|TPMA_NV_OWNERWRITE|TPMA_NV_OWNERREAD|TPMA_NV_PPWRITE|TPMA_NV_PPREAD\n"
> +"    <policy_digest_addr>: address to a policy digest. (e.g. a PCR value)\n"
> +"    <policy_size>: size of the digest in bytes\n"
> +"nv_undefine <tpm_addr>\n"
> +"    delete nv index\n"
> +"nv_read <tpm_addr> <size> <data_addr> [<session_handle_addr>]\n"
> +"    Read data stored in TPM nv_memory at <tpm_addr> with size <size>\n"
> +"    <tpm_addr>: the internal address used within the TPM for the NV-index\n"
> +"    <size>: datasize in bytes\n"
> +"    <data_addr>: memory address where to store the data read from the TPM\n"
> +"    <session_handle_addr>: addr where the session handle is stored\n"
> +"nv_write <tpm_addr> <size> <data_addr> [<session_handle_addr>]\n"
> +"    Write data to the TPM's nv_memory at <tpm_addr> with size <size>\n"
> +"    <tpm_addr>: the internal address used within the TPM for the NV-index\n"
> +"    <size>: datasize in bytes\n"
> +"    <data_addr>: memory address of the data to be written to the TPM's NV-index\n"
> +"    <session_handle_addr>: addr where the session handle is stored\n"
> +"start_auth_session <session_handle_addr> [<session_type>]\n"
> +"    Start an authorization session and store it's handle at <session_handle_addr>\n"
> +"     <session_handle_addr>: addr where to store the handle data (4 bytes)\n"
> +"     <session_type>: type of session: 0x00 for HMAC, 0x01 for policy, 0x03 for trial\n"
> +"                    will default to 0x01 (TPM_SE_POLICY) if not provided\n"
> +"                    to create a policy, use TPM_SE_TRIAL (0x03), to authenticate TPM_SE_POLICY (0x01)\n"
> +"flush_context <session_handle_addr>\n"
> +"    flush/terminate a session which's handle is stored at <session_handle_addr>\n"
> +"     <session_handle_addr>: addr where the session handle is stored\n"
> +"policy_pcr <session_handle_addr> <pcr> <digest_addr>\n"
> +"    create a policy to authorize using a PCR\n"
> +"    <session_handle_addr>: addr where the session handle is stored\n"
> +"    <pcr>: index of the PCR\n"
> +"    <digest_addr>: addr where to store the policy digest (for nv_define/nv_read/write)\n"
>  );
> diff --git a/include/tpm-common.h b/include/tpm-common.h
> index 1ba81386ce..5620454da7 100644
> --- a/include/tpm-common.h
> +++ b/include/tpm-common.h
> @@ -69,6 +69,8 @@ struct tpm_chip_priv {
>  uint pcr_count;
>  uint pcr_select_min;
>  bool plat_hier_disabled;
> +     u16 nonce_sz;
> +     u8 nonce[32]; //NONCE_TPM_SIZE;

Add this on a define on the header file and use it, instead of adding a comment


>  };
>
>  /**
> diff --git a/include/tpm-v2.h b/include/tpm-v2.h
> index 33dd103767..5b60883777 100644
> --- a/include/tpm-v2.h
> +++ b/include/tpm-v2.h
> @@ -301,7 +301,8 @@ enum tpm2_startup_types {
>   */
>  enum tpm2_handles {
>  TPM2_RH_OWNER           = 0x40000001,
> -     TPM2_RS_PW        = 0x40000009,
> +     TPM2_RH_NULL            = 0x40000007,
> +     TPM2_RS_PW              = 0x40000009,
>  TPM2_RH_LOCKOUT         = 0x4000000A,
>  TPM2_RH_ENDORSEMENT     = 0x4000000B,
>  TPM2_RH_PLATFORM  = 0x4000000C,
> @@ -325,24 +326,30 @@ enum tpm2_handles {
>   * @TPM2_CC_PCR_SETAUTHVAL: TPM2_PCR_SetAuthValue().
>   */
>  enum tpm2_command_codes {
> -     TPM2_CC_STARTUP         = 0x0144,
> -     TPM2_CC_SELF_TEST = 0x0143,
> -     TPM2_CC_HIER_CONTROL    = 0x0121,
> -     TPM2_CC_CLEAR           = 0x0126,
> -     TPM2_CC_CLEARCONTROL    = 0x0127,
> -     TPM2_CC_HIERCHANGEAUTH  = 0x0129,
> -     TPM2_CC_NV_DEFINE_SPACE = 0x012a,
> -     TPM2_CC_PCR_SETAUTHPOL  = 0x012C,
> -     TPM2_CC_NV_WRITE  = 0x0137,
> -     TPM2_CC_NV_WRITELOCK    = 0x0138,
> -     TPM2_CC_DAM_RESET = 0x0139,
> -     TPM2_CC_DAM_PARAMETERS  = 0x013A,
> -     TPM2_CC_NV_READ         = 0x014E,
> -     TPM2_CC_GET_CAPABILITY  = 0x017A,
> -     TPM2_CC_GET_RANDOM      = 0x017B,
> -     TPM2_CC_PCR_READ  = 0x017E,
> -     TPM2_CC_PCR_EXTEND      = 0x0182,
> -     TPM2_CC_PCR_SETAUTHVAL  = 0x0183,
> +     TPM2_CC_STARTUP                     = 0x0144,
> +     TPM2_CC_SELF_TEST             = 0x0143,
> +     TPM2_CC_HIER_CONTROL          = 0x0121,
> +     TPM2_CC_CLEAR                       = 0x0126,

Some of the values you added include an extra tab, can you indent all
of these properly?

> +     TPM2_CC_CLEARCONTROL          = 0x0127,
> +     TPM2_CC_HIERCHANGEAUTH        = 0x0129,
> +     TPM2_CC_NV_DEFINE_SPACE       = 0x012a,
> +     TPM2_CC_NV_UNDEFINE_SPACE     = 0x0122,
> +     TPM2_CC_PCR_SETAUTHPOL        = 0x012C,
> +     TPM2_CC_CREATE_PRIMARY        = 0x0131,
> +     TPM2_CC_NV_WRITE              = 0x0137,
> +     TPM2_CC_NV_WRITELOCK          = 0x0138,
> +     TPM2_CC_DAM_RESET             = 0x0139,
> +     TPM2_CC_DAM_PARAMETERS        = 0x013A,
> +     TPM2_CC_NV_READ               = 0x014E,
> +     TPM2_CC_FLUSH_CONTEXT         = 0x0165,
> +     TPM2_CC_START_AUTH_SESSION    = 0x0176,
> +     TPM2_CC_GET_CAPABILITY        = 0x017A,
> +     TPM2_CC_GET_RANDOM            = 0x017B,
> +     TPM2_CC_PCR_READ              = 0x017E,
> +     TPM2_CC_POLICY_PCR                  = 0x017F,
> +     TPM2_CC_PCR_EXTEND                  = 0x0182,
> +     TPM2_CC_PCR_SETAUTHVAL        = 0x0183,
> +     TPM2_CC_POLICY_GET_DIGEST     = 0x0189,
>  };
>
>  /**
> @@ -384,6 +391,16 @@ enum tpm2_algorithms {
>  TPM2_ALG_SHA512         = 0x0D,
>  TPM2_ALG_NULL           = 0x10,
>  TPM2_ALG_SM3_256  = 0x12,
> +     TPM2_ALG_ECC            = 0x23,
> +};
> +
> +/**
> + * TPM2 session types.
> + */
> +enum tpm2_se {
> +     TPM_SE_HMAC             = 0x00,
> +     TPM_SE_POLICY           = 0x01,
> +     TPM_SE_TRIAL            = 0x03,
>  };
>
>  extern const enum tpm2_algorithms tpm2_supported_algorithms[4];
> @@ -700,6 +717,51 @@ u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test);
>  u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
>         const ssize_t pw_sz);
>
> +/**
> + * Issue a TPM2_StartAuthSession command. (chaining several commands together that need authorization)
> + *
> + * @dev          TPM device
> + * @session_handle     Pointer to memory where to store the session handle.
> + * @session_type tpm2_se value to indicate session type (usually TPM_SE_POLICY)
> + *
> + * Return: code of the operation
> + */
> +u32 tpm2_start_auth_session(struct udevice *dev, u32 *session_handle, u8 session_type);
> +/**
> + * Issue a TPM2_FlushContext command. (for ending the authorization session)
> + *
> + * @dev          TPM device
> + * @session_handle     Authorization session to be terminated.
> + *
> + * Return: code of the operation
> + */
> +u32 tpm2_flush_context(struct udevice *dev, u32 session_handle);
> +
> +/**
> + * Issue a TPM2_PolicyPCR command. (for authenticating using a PCR value)
> + *
> + * @dev          TPM device
> + * @session_handle     policy session handle started with start_auth_session.
> + * @index  Index of the PCR
> + *
> + * @note   For now only 1 PCR selection is supported,
> + *               since the value of one PCR can be extended with the value of another.
> + *               This achieves the same effect as selecting multiple PCR's
> + * @out_digest   addr where to write the digest

The comments should be like this
@dev: TPM device
@session_handle: ....
etc
Please fix them on all functions

> + * Return: code of the operation
> + */
> +u32 tpm2_set_policy_pcr(struct udevice *dev, u32 session_handle, u32 index, void *out_digest);
> +
> +/**
> + * Issue a TPM2_getPolicyDigest command.
> + *
> + * @dev          TPM device
> + * @session_handle     policy session handle started with start_auth_session.
> + * @out_digest   addr where to write the digest (size is always 0x20 / TPM2_SHA256_DIGEST_SIZE)
> + * Return: code of the operation
> + */
> +u32 tpm2_get_policy_digest(struct udevice *dev, u32 session_handle, void *out_digest);
> +
>  /**
>   * Issue a TPM_NV_DefineSpace command
>   *
> @@ -709,6 +771,7 @@ u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
>   * @space_index        index of the area
>   * @space_size         size of area in bytes
>   * @nv_attributes      TPM_NV_ATTRIBUTES of the area
> + * @session_handle     handle to a session. can be TPM2_RS_PW
>   * @nv_policy          policy to use
>   * @nv_policy_size     size of the policy
>   * Return: return code of the operation
> @@ -717,6 +780,17 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
>   size_t space_size, u32 nv_attributes,
>   const u8 *nv_policy, size_t nv_policy_size);
>
> +/**
> + * Issue a TPM_NV_UnDefineSpace command
> + *
> + * This allows a space to be removed. Needed because TPM_clear doesn't clear platform entries
> + *
> + * @dev                TPM device
> + * @space_index        index of the area
> + * Return: return code of the operation
> + */
> +u32 tpm2_nv_undefine_space(struct udevice *dev, u32 space_index);
> +
>  /**
>   * Issue a TPM2_PCR_Extend command.
>   *
> @@ -734,13 +808,14 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
>  /**
>   * Read data from the secure storage
>   *
> - * @dev          TPM device
> - * @index  Index of data to read
> - * @data   Place to put data
> - * @count  Number of bytes of data
> + * @dev                      TPM device
> + * @index              Index of data to read
> + * @data               Place to put data
> + * @count              Number of bytes of data
> + * @session_handle     handle of a running authorization session. if NULL->password authorization
>   * Return: code of the operation
>   */
> -u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count);
> +u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count, u32 *session_handle);
>
>  /**
>   * Write data to the secure storage
> @@ -749,10 +824,11 @@ u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count);
>   * @index  Index of data to write
>   * @data   Data to write
>   * @count  Number of bytes of data
> + * @session_handle     handle of a running authorization session. if NULL->password authorization
>   * Return: code of the operation
>   */
>  u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
> -                 u32 count);
> +                 u32 count, u32 *session_handle);
>
>  /**
>   * Issue a TPM2_PCR_Read command.
> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
> index 68eaaa639f..3d5e4e8343 100644
> --- a/lib/tpm-v2.c
> +++ b/lib/tpm-v2.c
> @@ -786,19 +787,192 @@ u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
>  return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
>  }
>
> +u32 tpm2_start_auth_session(struct udevice *dev, u32 *session_handle, u8 session_type)
> +{
> +     const u16 nonce_size    = TPM2_SHA256_DIGEST_SIZE;
> +     const int handles_len = sizeof(u32) * 2;
> +     uint offset = TPM2_HDR_LEN + handles_len + 2;
> +     struct tpm_chip_priv *priv;
> +
> +     priv = dev_get_uclass_priv(dev);
> +           if (!priv)
> +                 return TPM_LIB_ERROR;
> +
> +     u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +                 /* header 10 bytes */
> +                 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
> +                 tpm_u32(offset + nonce_size + 7),/* Length */
> +                 tpm_u32(TPM2_CC_START_AUTH_SESSION),/* Command code */
> +
> +                 /* handles 8 bytes */
> +                 tpm_u32(TPM2_RH_NULL),  /* TPMI_DH_OBJECT+ */
> +                 tpm_u32(TPM2_RH_NULL),  /* TPMI_DH_ENTITY+ */
> +
> +                 /* NONCE 32 bytes -> use pack_byte_string() */
> +                 tpm_u16(nonce_size),
> +                 /* message 7 bytes -> use pack_byte_string() */
> +                 //tpm_u16(0), // salt size
> +                 //session_type, // session type
> +                 //tpm_u16(TPM2_ALG_NULL), // symmetric key algorythm
> +                 //tpm_u16(TPM2_ALG_SHA256), // auth hash
> +    };
> +    u8 Nonce[nonce_size]; //nonce is a random number you use once. (Number ONCE)
> +
> +    memset(&Nonce, 2, nonce_size); //should use TPM_get_random() to randomize
> +    int ret;
> +
> +     ret = pack_byte_string(command_v2, sizeof(command_v2), "swbww",
> +                        offset, Nonce, nonce_size,
> +                 offset + nonce_size, 0, //salt size
> +                 offset + nonce_size + 2, session_type,
> +                 offset + nonce_size + 3, TPM2_ALG_NULL,
> +                 offset + nonce_size + 5, TPM2_ALG_SHA256);
> +
> +     if (ret)
> +           return TPM_LIB_ERROR;
> +
> +    size_t response_len = COMMAND_BUFFER_SIZE;
> +    u8 response[COMMAND_BUFFER_SIZE];
> +    u16 tag;
> +    u32 size, code;
> +
> +     ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
> +
> +     if (ret)
> +           return log_msg_ret("read", ret);
> +
> +     if (unpack_byte_string(response, response_len, "wdddws",
> +                        0, &tag, 2, &size, 6, &code, //header
> +                 10, session_handle, //TPMI_SH_AUTH_SESSION
> +                 14, &priv->nonce_sz,
> +                 16, priv->nonce, TPM2_SHA256_DIGEST_SIZE)) //HACK: we asked for a SHA256, so that's what we'll get. if ret == 0 at least
> +           return TPM_LIB_ERROR;
> +
> +     return ret;
> +}
> +
> +u32 tpm2_flush_context(struct udevice *dev, u32 session_handle)
> +{
> +     u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +                 /* header 10 bytes */
> +                 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
> +                 tpm_u32(TPM2_HDR_LEN + sizeof(u32)),/* Length */
> +                 tpm_u32(TPM2_CC_FLUSH_CONTEXT),/* Command code */
> +
> +                 /* session handle 4 bytes */
> +                 tpm_u32(session_handle),      /* TPMI_DH_CONTEXT+ */
> +     };
> +     return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
> +}
> +
> +u32 tpm2_set_policy_pcr(struct udevice *dev, u32 session_handle, u32 index, void *out_digest)
> +{
> +     const int offset = TPM2_HDR_LEN + 6;
> +     const int message_len = offset + TPM2_SHA256_DIGEST_SIZE + 10;
> +
> +     u8 pcr_sel_bit = BIT(index % 8);
> +     struct tpm_chip_priv *priv;
> +     struct tpml_digest_values digest_list;
> +
> +     digest_list.count = 1;
> +     digest_list.digests->hash_alg = TPM2_ALG_SHA256;
> +     tcg2_pcr_read(dev, index, &digest_list);
> +
> +     u8 pcr_sha_output[TPM2_SHA256_DIGEST_SIZE];
> +     sha256_context ctx_256;
> +
> +     sha256_starts(&ctx_256);
> +     sha256_update(&ctx_256, digest_list.digests[0].digest.sha256, TPM2_SHA256_DIGEST_SIZE);
> +     sha256_finish(&ctx_256, pcr_sha_output);
> +
> +     priv = dev_get_uclass_priv(dev);
> +           if (!priv)
> +                 return TPM_LIB_ERROR;
> +
> +     u8 idx_array_sz = max(priv->pcr_select_min, DIV_ROUND_UP(index, 8));
> +
> +     u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +                 /* header 10 bytes */
> +                 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG -> TPM2_ST_SESSIONS only for audit or decrypt*/
> +                 tpm_u32(message_len),/* Length */
> +                 tpm_u32(TPM2_CC_POLICY_PCR),/* Command code */
> +                 /* session handle 4 bytes */
> +                 tpm_u32(session_handle),      /* TPMI_SH_POLICY */
> +                 /* PCR Digest - 32 bytes */
> +                 tpm_u16(TPM2_SHA256_DIGEST_SIZE) /*hash size*/
> +                 /* digest - 32-bytes */
> +                 /* PCR selection */
> +                 //tpm_u32(1),                 /* Number of selections */
> +                 //tpm_u16(TPM_ALG_SHA256),          /* Algorithm of the hash */
> +                 //idx_array_sz,               /* Array size for selection */
> +                 /* bitmap(idx)                   Selected PCR bitmap */
> +     };
> +
> +     if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "sdwbbw",
> +                      offset, pcr_sha_output, TPM2_SHA256_DIGEST_SIZE,
> +                 offset + TPM2_SHA256_DIGEST_SIZE, 1, /* Number of selections */
> +                 offset + TPM2_SHA256_DIGEST_SIZE + 4, TPM2_ALG_SHA256, /* Algorithm of the hash */
> +                 offset + TPM2_SHA256_DIGEST_SIZE + 6, idx_array_sz, /* Array size for selection */
> +                 offset + TPM2_SHA256_DIGEST_SIZE + 7, pcr_sel_bit,/* Selected PCR bitmap */
> +                 offset + TPM2_SHA256_DIGEST_SIZE + 8, 0))  /*padding */
> +           return TPM_LIB_ERROR;
> +
> +     int ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
> +
> +     if (ret)
> +           return ret;
> +
> +     return tpm2_get_policy_digest(dev, session_handle, out_digest);
> +}
> +
> +u32 tpm2_get_policy_digest(struct udevice *dev, u32 session_handle, void *out_digest)
> +{
> +     const int message_len = TPM2_HDR_LEN + sizeof(u32);
> +
> +     u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +                 /* header 10 bytes */
> +                 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG -> only audit or decrypt session uses TPM2_ST_SESSIONS */
> +                 tpm_u32(message_len),/* Length */
> +                 tpm_u32(TPM2_CC_POLICY_GET_DIGEST),/* Command code */
> +                 /* session handle 4 bytes */
> +                 tpm_u32(session_handle),      /* TPMI_SH_POLICY */
> +     };
> +
> +     size_t response_len = COMMAND_BUFFER_SIZE;
> +     u8 response[COMMAND_BUFFER_SIZE];
> +     int ret;
> +     u16 tag;
> +     u32 size, code;
> +
> +     ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
> +     if (ret)
> +           return log_msg_ret("read", ret);
> +
> +     if (unpack_byte_string(response, response_len, "wdds",
> +                        0, &tag, 2, &size, 6, &code,
> +                 12, out_digest, TPM2_SHA256_DIGEST_SIZE)) //digest_size
> +           return TPM_LIB_ERROR;
> +
> +     return ret;
> +}
> +
>  u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
> -                  size_t space_size, u32 nv_attributes,
> -                  const u8 *nv_policy, size_t nv_policy_size)
> +                 size_t space_size, u32 nv_attributes,
> +                 const u8 *nv_policy, size_t nv_policy_size)
>  {
>  /*
>   * Calculate the offset of the nv_policy piece by adding each of the
>   * chunks below.
>   */
>  const int platform_len = sizeof(u32);
> -     const int session_hdr_len = 13;
> +     const int session_hdr_len = 15;
>  const int message_len = 14;
> -     uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
> -           message_len;
> +     uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len + message_len;
> +     u8 attrs = 0;
> +
> +     //if(session_handle != TPM2_RS_PW)
> +           //attrs = 1; //continue_session (bit 1)

Why is this commented out?

> +
>  u8 command_v2[COMMAND_BUFFER_SIZE] = {
>  /* header 10 bytes */
>  tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
> @@ -806,20 +979,24 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
>  tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
>
>  /* handles 4 bytes */
> -           tpm_u32(TPM2_RH_PLATFORM),    /* Primary platform seed */
> +           tpm_u32(TPM2_RH_PLATFORM),    /* Primary platform seed, requires TPMA_NV_PLATFORMCREATE*/
> +
>
> -           /* session header 13 bytes */
> +           /* session header 15 bytes */
> +           /*null auth session*/
>  tpm_u32(9),             /* Header size */
> -           tpm_u32(TPM2_RS_PW),          /* Password authorisation */
> +           tpm_u32(TPM2_RS_PW),/* auth session handle if it's active, otherwise TPM2_RS_PW*/
>  tpm_u16(0),             /* nonce_size */
> -           0,                      /* session_attrs */
> +           attrs,                        /* session_attrs */
> +           tpm_u16(0),             /* HMAC size */
> +           /*end auth area*/
>  tpm_u16(0),             /* auth_size */
>
>  /* message 14 bytes + policy */
>  tpm_u16(message_len + nv_policy_size),    /* size */
>  tpm_u32(space_index),
>  tpm_u16(TPM2_ALG_SHA256),
> -           tpm_u32(nv_attributes),
> +           tpm_u32(nv_attributes | TPMA_NV_PLATFORMCREATE),
>  tpm_u16(nv_policy_size),
>  /*
>   * nv_policy
> @@ -841,6 +1018,35 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
>  return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
>  }
>
> +u32 tpm2_nv_undefine_space(struct udevice *dev, u32 space_index)
> +{
> +     const int platform_len = sizeof(u32);
> +     const int session_hdr_len = 13;
> +     const int message_len = 4;
> +     u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +           /* header 10 bytes */
> +           tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
> +           tpm_u32(TPM2_HDR_LEN + platform_len + session_hdr_len +
> +                       message_len),/* Length - header + provision + index + auth area*/
> +           tpm_u32(TPM2_CC_NV_UNDEFINE_SPACE),/* Command code */
> +
> +           /* handles 4 bytes */
> +           tpm_u32(TPM2_RH_PLATFORM),    /* Primary platform seed */
> +           /* nv_index */
> +           tpm_u32(space_index),
> +
> +           /*null auth session*/
> +           tpm_u32(9),             /* Header size */
> +           tpm_u32(TPM2_RS_PW),          /* Password authorisation*/
> +           tpm_u16(0),             /* nonce_size */
> +           0,                      /* session_attrs */
> +           tpm_u16(0),             /* HMAC size */
> +           /*end auth area*/
> +
> +     };
> +     return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
> +}
> +
>  u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
>      const u8 *digest, u32 digest_len)
>  {
> @@ -884,56 +1091,101 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
>  return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
>  }
>
> -u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
> +u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count, u32 *session_handle)
>  {
> -     u8 command_v2[COMMAND_BUFFER_SIZE] = {
> -           /* header 10 bytes */
> -           tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
> -           tpm_u32(10 + 8 + 4 + 9 + 4),  /* Length */
> -           tpm_u32(TPM2_CC_NV_READ),     /* Command code */
> +     u32 offset = TPM2_HDR_LEN + 8 + 4 + 6;
> +     struct tpm_chip_priv *priv;
>
> -           /* handles 8 bytes */
> -           tpm_u32(TPM2_RH_PLATFORM),    /* Primary platform seed */
> -           tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
> +     priv = dev_get_uclass_priv(dev);
>
> -           /* AUTH_SESSION */
> -           tpm_u32(9),             /* Authorization size */
> -           tpm_u32(TPM2_RS_PW),          /* Session handle */
> -           tpm_u16(0),             /* Size of <nonce> */
> -                                   /* <nonce> (if any) */
> -           0,                      /* Attributes: Cont/Excl/Rst */
> -           tpm_u16(0),             /* Size of <hmac/password> */
> -                                   /* <hmac/password> (if any) */
> +     if (!priv)
> +           return TPM_LIB_ERROR;
> +
> +     u32 nonce_size = priv->nonce_sz;
> +
> +     priv->nonce[nonce_size - 1]++; //increase nonce.
> +
> +     u32 authorization = TPM2_RS_PW;
>
> -           tpm_u16(count),               /* Number of bytes */
> -           tpm_u16(0),             /* Offset */
> +     if (session_handle)
> +           authorization = *session_handle;
> +     else
> +           nonce_size = 0; //cannot use nonce when using password authorization
> +
> +     u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +                 /* header 10 bytes */
> +                 tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
> +                 tpm_u32(offset + nonce_size + 7),   /* Length */
> +                 tpm_u32(TPM2_CC_NV_READ),     /* Command code */
> +
> +                 /* handles 8 bytes */
> +                 tpm_u32(index),   /* Primary platform seed */
> +                 tpm_u32(index),               /*nv index*/
> +
> +                 /* AUTH_SESSION */
> +                 tpm_u32(9 + nonce_size),                  /* Authorization size - 4 bytes*/
> +                 /*auth handle - 9 bytes */
> +                 tpm_u32(authorization),
> +                 tpm_u16(nonce_size),                /* Size of <nonce> */
> +                 /* <nonce> (if any) */
> +                 //0,                    /* Attributes: Cont/Excl/Rst */
> +                 //tpm_u16(0),                 /* Size of <hmac/password> */
> +                 /* <hmac/password> (if any) */
> +                 /*end auth handle */
> +                 //tpm_u16(count),             /* Number of bytes */
> +                 //tpm_u16(0),                 /* Offset */

I am not sure keeping the values commented out helps in readability.
>  };
> +
>  size_t response_len = COMMAND_BUFFER_SIZE;
>  u8 response[COMMAND_BUFFER_SIZE];
>  int ret;
>  u16 tag;
>  u32 size, code;

Those should be defined on top. IIRC we don't allow declarations here.

>
> +     ret = pack_byte_string(command_v2, sizeof(command_v2), "sbwww",
> +                        offset, priv->nonce, nonce_size,
> +                 offset + nonce_size, 0,
> +                 offset + nonce_size + 1, 0,
> +                 offset + nonce_size + 3, count,
> +                 offset + nonce_size + 5, 0);
> +
> +     if (ret)
> +           return TPM_LIB_ERROR;
> +
>  ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
>  if (ret)
>  return log_msg_ret("read", ret);
> +
>  if (unpack_byte_string(response, response_len, "wdds",
> -                        0, &tag, 2, &size, 6, &code,
> -                        16, data, count))
> +                 0, &tag, 2, &size, 6, &code,
> +                 16, data, count))
>  return TPM_LIB_ERROR;
>
>  return 0;
>  }
>
>  u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
> -                 u32 count)
> +                 u32 count, u32 *session_handle)
>  {
>  struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
> -     uint offset = 10 + 8 + 4 + 9 + 2;
> -     uint len = offset + count + 2;
> -     /* Use empty password auth if platform hierarchy is disabled */
> -     u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
> -           TPM2_RH_PLATFORM;
> +
> +     if (!priv)
> +           return TPM_LIB_ERROR;
> +
> +     u32 nonce_size = priv->nonce_sz;
> +
> +     priv->nonce[nonce_size - 1]++;
> +
> +     u32 authorization = TPM2_RS_PW;
> +
> +     if (session_handle)
> +           authorization = *session_handle;
> +     else
> +           nonce_size = 0; //cannot use nonce when using password authorization
> +
> +     uint offset = TPM2_HDR_LEN + 8 + 4 + 6;
> +     uint len = offset + nonce_size + count + 7;

This isn't a problem of your patch directly, but since you are
changing that, can we get rid of the magic values (e.g 8,4, 7 etc) and
either add a comment or a define that explains it?

> +
>  u8 command_v2[COMMAND_BUFFER_SIZE] = {
>  /* header 10 bytes */
>  tpm_u16(TPM2_ST_SESSIONS),    /* TAG */
> @@ -941,27 +1192,35 @@ u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
>  tpm_u32(TPM2_CC_NV_WRITE),    /* Command code */
>
>  /* handles 8 bytes */
> -           tpm_u32(auth),                /* Primary platform seed */
> -           tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
> +           tpm_u32(index),               /* Primary platform seed */
> +           tpm_u32(index),               /*nv index*/
>
>  /* AUTH_SESSION */
> -           tpm_u32(9),             /* Authorization size */
> -           tpm_u32(TPM2_RS_PW),          /* Session handle */
> -           tpm_u16(0),             /* Size of <nonce> */
> +           tpm_u32(9 + nonce_size),                  /* Authorization size - 4 bytes */
> +           /*auth handle - 9 bytes */
> +           tpm_u32(authorization),
> +           tpm_u16(nonce_size),                /* Size of <nonce> */
>  /* <nonce> (if any) */
> -           0,                      /* Attributes: Cont/Excl/Rst */
> -           tpm_u16(0),             /* Size of <hmac/password> */
> +           //0,                    /* Attributes: Cont/Excl/Rst */
> +           //tpm_u16(0),                 /* Size of <hmac/password> */
>  /* <hmac/password> (if any) */
> -
> -           tpm_u16(count),
> +           /*end auth handle */
> +           //tpm_u16(count),/*size of buffer - 2 bytes*/
> +           /*data (buffer)*/
> +           /*offset -> the octet offset into the NV Area*/
>  };
>  size_t response_len = COMMAND_BUFFER_SIZE;
>  u8 response[COMMAND_BUFFER_SIZE];
>  int ret;
>
> -     ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
> -                        offset, data, count,
> -                        offset + count, 0);
> +     ret = pack_byte_string(command_v2, sizeof(command_v2), "sbwwsw",
> +                        offset, priv->nonce, nonce_size,
> +                 offset + nonce_size, 0, //attrs
> +                 offset + nonce_size + 1, 0, //hmac sz
> +                 offset + nonce_size + 3, count,
> +                 offset + nonce_size + 5, data, count,
> +                 offset + nonce_size + count, 0);
> +
>  if (ret)
>  return TPM_LIB_ERROR;
>
> diff --git a/lib/tpm_api.c b/lib/tpm_api.c
> index 39a5121e30..5875e7b085 100644
> --- a/lib/tpm_api.c
> +++ b/lib/tpm_api.c
> @@ -128,7 +128,7 @@ u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
>  if (tpm_is_v1(dev))
>  return tpm1_nv_read_value(dev, index, data, count);
>  else if (tpm_is_v2(dev))
> -           return tpm2_nv_read_value(dev, index, data, count);
> +           return tpm2_nv_read_value(dev, index, data, count, NULL);
>  else
>  return -ENOSYS;
>  }
> @@ -139,7 +139,7 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
>  if (tpm_is_v1(dev))
>  return tpm1_nv_write_value(dev, index, data, count);
>  else if (tpm_is_v2(dev))
> -           return tpm2_nv_write_value(dev, index, data, count);
> +           return tpm2_nv_write_value(dev, index, data, count, NULL);
>  else
>  return -ENOSYS;
>  }
> --
> 2.34.1
> ==========================END PATCH=======================


Thanks
/Ilias


More information about the U-Boot mailing list