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 |
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
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============================
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 >
Hi Illias sure I pushed it here: https://github.com/nieknooijens/u-boot/tree/tpm_policy_patch Niek
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 > >
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
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=======================
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 --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; }