diff mbox series

implement policy_pcr commands to lock NV-indexes behind a PCR

Message ID OS3P286MB14956B3F726B34ECC742119CF6502@OS3P286MB1495.JPNP286.PROD.OUTLOOK.COM
State New
Delegated to: Ilias Apalodimas
Headers show
Series implement policy_pcr commands to lock NV-indexes behind a PCR | expand

Commit Message

niek.nooijens@omron.com Feb. 20, 2024, 5:59 a.m. UTC
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@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@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(-)

--
2.34.1
==========================END PATCH=======================

Comments

Dan Carpenter Feb. 20, 2024, 5:56 p.m. UTC | #1
I'm kind of new to u-boot and I'm not really able to review this code
as well as I should.

But also I can't apply the patch.  It seems white space damaged?  The
kernel has a good document on how to do this.  I'm pretty sure u-boot
does as well but I'm new.
https://www.kernel.org/doc/Documentation/process/email-clients.rst

Please run your patch through the scripts/checkpatch.pl script.  Stuff
like this triggers a warning:

> +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;


WARNING: suspect code indent for conditional statements (0, 0)
#250: FILE: cmd/tpm-v2.c:437:
+     if (ret)
+           return ret;

WARNING: suspect code indent for conditional statements (0, 0)
#253: FILE: cmd/tpm-v2.c:440:
+     if (argc < 4)
+           return CMD_RET_USAGE;

Also the subject should have a subsystem prefix and the information from
the email should be moved into the commit message.  Currently the commit
message is empty.

> 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,

Changing TPM2_RS_PW is an unrelated whitespace change.  Do that as a
separate patch.  But I don't get it at all because the TPM2_RS_PW enum
has always been indented correctly as far as I can see.  So it's a
puzzle.

I mean there are a lot of TODOs and I understand that you just wanted a
high level review but I kept getting distracted and lost and I couldn't
apply the patch so it was just really hard to figure out what was going
on.  :(

regards,
dan carpenter
niek.nooijens@omron.com Feb. 21, 2024, 12:12 a.m. UTC | #2
Hi dan

This might be because I used the checkpatch.pl script.
Here's one without it.

Niek

=========================START PATCH =======================
From de056f510156a2fa1b4b439e1fa1f44516aa8add Mon Sep 17 00:00:00 2001
From: Niek Nooijens <niek.nooijens@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@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,221 @@ 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 +590,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 +675,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 +786,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 +1090,99 @@ 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 != NULL)
+           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 +1190,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============================
Ilias Apalodimas Feb. 21, 2024, 9:01 a.m. UTC | #3
Hi Niek,

Thanks for the patch. The reason it's hard for us to apply it, is that
this patch seems copy-pasted on an email.

Instead, you should follow the guidelines here [0]. Till you get this
sorted, do you have it on a git branch somewhere, so I can cherry-pick
it and run it through the CI?

[0] https://docs.u-boot.org/en/latest/develop/sending_patches.html

Thanks
/Ilias


On Wed, 21 Feb 2024 at 02:12, niek.nooijens@omron.com
<niek.nooijens@omron.com> wrote:
>
> Hi dan
>
> This might be because I used the checkpatch.pl script.
> Here's one without it.
>
> Niek
>
> =========================START PATCH =======================
> From de056f510156a2fa1b4b439e1fa1f44516aa8add Mon Sep 17 00:00:00 2001
> From: Niek Nooijens <niek.nooijens@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@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,221 @@ 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 +590,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 +675,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 +786,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 +1090,99 @@ 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 != NULL)
> +           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 +1190,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============================
> ________________________________
> 差出人: Dan Carpenter <dan.carpenter@linaro.org>
> 送信日時: 2024年2月21日 02:56
> 宛先: Niek Nooijens / OC-IAB PBD-C DEVEL 1-1 <niek.nooijens@omron.com>
> CC: Ilias Apalodimas <ilias.apalodimas@linaro.org>; u-boot@lists.denx.de <u-boot@lists.denx.de>
> 件名: Re: [PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR
>
> [dan.carpenter@linaro.org からのメールを受け取る頻度は高くありません。これが問題である可能性の理由については、https://aka.ms/LearnAboutSenderIdentification をご覧ください。]
>
> I'm kind of new to u-boot and I'm not really able to review this code
> as well as I should.
>
> But also I can't apply the patch.  It seems white space damaged?  The
> kernel has a good document on how to do this.  I'm pretty sure u-boot
> does as well but I'm new.
> https://jpn01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2FDocumentation%2Fprocess%2Femail-clients.rst&data=05%7C02%7Cniek.nooijens%40omron.com%7Cfff2a571b0f64e4cee7308dc323d3de9%7C0ecff5a94bef4a7b96eca96579b4ac37%7C0%7C0%7C638440485810051997%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=dU5lPn1UMeoLauNg2lVkRsopKimQ5qwJda11ZRm%2FJhQ%3D&reserved=0
>
> Please run your patch through the scripts/checkpatch.pl script.  Stuff
> like this triggers a warning:
>
> > +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;
>
>
> WARNING: suspect code indent for conditional statements (0, 0)
> #250: FILE: cmd/tpm-v2.c:437:
> +     if (ret)
> +           return ret;
>
> WARNING: suspect code indent for conditional statements (0, 0)
> #253: FILE: cmd/tpm-v2.c:440:
> +     if (argc < 4)
> +           return CMD_RET_USAGE;
>
> Also the subject should have a subsystem prefix and the information from
> the email should be moved into the commit message.  Currently the commit
> message is empty.
>
> > 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,
>
> Changing TPM2_RS_PW is an unrelated whitespace change.  Do that as a
> separate patch.  But I don't get it at all because the TPM2_RS_PW enum
> has always been indented correctly as far as I can see.  So it's a
> puzzle.
>
> I mean there are a lot of TODOs and I understand that you just wanted a
> high level review but I kept getting distracted and lost and I couldn't
> apply the patch so it was just really hard to figure out what was going
> on.  :(
>
> regards,
> dan carpenter
>
niek.nooijens@omron.com Feb. 22, 2024, 6:16 a.m. UTC | #4
Hi Illias

sure I pushed it here:
https://github.com/nieknooijens/u-boot/tree/tpm_policy_patch


Niek
Ilias Apalodimas March 5, 2024, 9:11 a.m. UTC | #5
Hi Niek,

Those patches apply cleanly, I do have some comments on the code.

I will try to answer on the public thread here instead of github, but
for the next version try to send it with git send-email. It makes the
whole review/test/apply process  easier for me

Thanks
/Ilias

On Thu, 22 Feb 2024 at 08:16, niek.nooijens@omron.com
<niek.nooijens@omron.com> wrote:
>
> Hi Illias
>
> sure I pushed it here:
> https://github.com/nieknooijens/u-boot/tree/tpm_policy_patch
>
>
> Niek
>
> ________________________________
> 差出人: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> 送信日時: 2024年2月21日 18:01
> 宛先: Niek Nooijens / OC-IAB PBD-C DEVEL 1-1 <niek.nooijens@omron.com>
> CC: Dan Carpenter <dan.carpenter@linaro.org>; u-boot@lists.denx.de <u-boot@lists.denx.de>
> 件名: Re: [PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR
>
> [ilias.apalodimas@linaro.org からのメールを受け取る頻度は高くありません。これが問題である可能性の理由については、https://aka.ms/LearnAboutSenderIdentification をご覧ください。]
>
> Hi Niek,
>
> Thanks for the patch. The reason it's hard for us to apply it, is that
> this patch seems copy-pasted on an email.
>
> Instead, you should follow the guidelines here [0]. Till you get this
> sorted, do you have it on a git branch somewhere, so I can cherry-pick
> it and run it through the CI?
>
> [0] https://jpn01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.u-boot.org%2Fen%2Flatest%2Fdevelop%2Fsending_patches.html&data=05%7C02%7Cniek.nooijens%40omron.com%7Ccecf2d3ccfee492b819a08dc32bbd390%7C0ecff5a94bef4a7b96eca96579b4ac37%7C0%7C0%7C638441029505061036%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=UFTu5wiss76QRjy6rZxMRl43o90j%2BWn0UVrSPGRdaLU%3D&reserved=0
>
> Thanks
> /Ilias
>
>
> On Wed, 21 Feb 2024 at 02:12, niek.nooijens@omron.com
> <niek.nooijens@omron.com> wrote:
> >
> > Hi dan
> >
> > This might be because I used the checkpatch.pl script.
> > Here's one without it.
> >
> > Niek
> >
> > =========================START PATCH =======================
> > From de056f510156a2fa1b4b439e1fa1f44516aa8add Mon Sep 17 00:00:00 2001
> > From: Niek Nooijens <niek.nooijens@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@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,221 @@ 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 +590,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 +675,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 +786,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 +1090,99 @@ 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 != NULL)
> > +           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 +1190,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============================
> > ________________________________
> > 差出人: Dan Carpenter <dan.carpenter@linaro.org>
> > 送信日時: 2024年2月21日 02:56
> > 宛先: Niek Nooijens / OC-IAB PBD-C DEVEL 1-1 <niek.nooijens@omron.com>
> > CC: Ilias Apalodimas <ilias.apalodimas@linaro.org>; u-boot@lists.denx.de <u-boot@lists.denx.de>
> > 件名: Re: [PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR
> >
> > [dan.carpenter@linaro.org からのメールを受け取る頻度は高くありません。これが問題である可能性の理由については、https://aka.ms/LearnAboutSenderIdentification をご覧ください。]
> >
> > I'm kind of new to u-boot and I'm not really able to review this code
> > as well as I should.
> >
> > But also I can't apply the patch.  It seems white space damaged?  The
> > kernel has a good document on how to do this.  I'm pretty sure u-boot
> > does as well but I'm new.
> > https://jpn01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2FDocumentation%2Fprocess%2Femail-clients.rst&data=05%7C02%7Cniek.nooijens%40omron.com%7Ccecf2d3ccfee492b819a08dc32bbd390%7C0ecff5a94bef4a7b96eca96579b4ac37%7C0%7C0%7C638441029505074060%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=AGVulkGYczDB1uPfXOFptjNJgqOkgsOQssE4j6ZGsOk%3D&reserved=0
> >
> > Please run your patch through the scripts/checkpatch.pl script.  Stuff
> > like this triggers a warning:
> >
> > > +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;
> >
> >
> > WARNING: suspect code indent for conditional statements (0, 0)
> > #250: FILE: cmd/tpm-v2.c:437:
> > +     if (ret)
> > +           return ret;
> >
> > WARNING: suspect code indent for conditional statements (0, 0)
> > #253: FILE: cmd/tpm-v2.c:440:
> > +     if (argc < 4)
> > +           return CMD_RET_USAGE;
> >
> > Also the subject should have a subsystem prefix and the information from
> > the email should be moved into the commit message.  Currently the commit
> > message is empty.
> >
> > > 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,
> >
> > Changing TPM2_RS_PW is an unrelated whitespace change.  Do that as a
> > separate patch.  But I don't get it at all because the TPM2_RS_PW enum
> > has always been indented correctly as far as I can see.  So it's a
> > puzzle.
> >
> > I mean there are a lot of TODOs and I understand that you just wanted a
> > high level review but I kept getting distracted and lost and I couldn't
> > apply the patch so it was just really hard to figure out what was going
> > on.  :(
> >
> > regards,
> > dan carpenter
> >
Ilias Apalodimas March 5, 2024, 10:47 a.m. UTC | #6
On Tue, 20 Feb 2024 at 07:59, niek.nooijens@omron.com
<niek.nooijens@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@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@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
niek.nooijens@omron.com March 7, 2024, 5:59 a.m. UTC | #7
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@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@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 March 27, 2024, 2:47 p.m. UTC | #8
Hi Niek,

On Thu, 7 Mar 2024 at 07:59, niek.nooijens@omron.com
<niek.nooijens@omron.com> wrote:
>
> 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

Thanks, I'll have a look within the week. That being said, please try
to read the guidelines and send the patch properly using git-send
email if a new version is required, along with
- the version number in the topic
-  a short description of the changes between revisions

I am receiving enough patches and it's pretty easy for me to lose
track without those

Thanks
/Ilias

>
> Here's the update:
>
> =======================START PATCH=========================
> From c0e213d45925da819d7ce41e02072ea740e44014 Mon Sep 17 00:00:00 2001
> From: Niek Nooijens <niek.nooijens@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@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@linaro.org>
> 送信日時: 2024年3月5日 19:47
> 宛先: Niek Nooijens / OC-IAB PBD-C DEVEL 1-1 <niek.nooijens@omron.com>
> CC: u-boot@lists.denx.de <u-boot@lists.denx.de>
> 件名: Re: [PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR
>
> [ilias.apalodimas@linaro.org からのメールを受け取る頻度は高くありません。これが問題である可能性の理由については、https://aka.ms/LearnAboutSenderIdentification をご覧ください。]
>
> On Tue, 20 Feb 2024 at 07:59, niek.nooijens@omron.com
> <niek.nooijens@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@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@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
diff mbox series

Patch

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;
 }