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

niek.nooijens at omron.com niek.nooijens at omron.com
Tue Feb 20 06:59:45 CET 2024


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:

  1.  set the PCR's to some value
  2.  start an auth session
  3.
create a policy_pcr
  4.  get that policy's digest
  5.  use NV_define together with the policy digest.
  6.  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:

  1.
set the PCR's to the correct value
  2.  start an auth session
  3.  create a policy_pcr
  4.  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;
+
+     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
+           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);
+
+     if (policy_addr)
+           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);
+
+     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[]) //TODO: session handle from auth session!
+{
+     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;
 };

 /**
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,
+     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
+ * 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)
+
      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 */
      };
+
      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)
 {
      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;
+
      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=======================


More information about the U-Boot mailing list