[PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR
niek.nooijens at omron.com
niek.nooijens at omron.com
Wed Feb 21 01:12:21 CET 2024
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 at omron.com>
Date: Tue, 20 Feb 2024 13:42:57 +0900
Subject: [PATCH] [TPM] implement commands to lock NV-indexes behind a PCR
policy
Added commands are:
- start auth session
- flush context
- policyPCR
- getPolicyDigest
Signed-off-by: Niek Nooijens <niek.nooijens at omron.com>
---
cmd/tpm-v2.c | 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 at linaro.org>
送信日時: 2024年2月21日 02:56
宛先: Niek Nooijens / OC-IAB PBD-C DEVEL 1-1 <niek.nooijens at omron.com>
CC: Ilias Apalodimas <ilias.apalodimas at linaro.org>; u-boot at lists.denx.de <u-boot at lists.denx.de>
件名: Re: [PATCH] implement policy_pcr commands to lock NV-indexes behind a PCR
[dan.carpenter at 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<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
More information about the U-Boot
mailing list