diff mbox series

[U-Boot,18/18] tpm: add PCR authentication commands support

Message ID 20180308154021.25255-19-miquel.raynal@bootlin.com
State Changes Requested
Delegated to: Simon Glass
Headers show
Series Introduce SPI TPM v2.0 support | expand

Commit Message

Miquel Raynal March 8, 2018, 3:40 p.m. UTC
Add support for the TPM2_PCR_SetAuthPolicy and
TPM2_PCR_SetAuthValue commands.

Change the command file and the help accordingly.

Note: These commands could not be tested because the TPMs available
do not support them, however they could be useful for someone else.
The user is warned by the command help.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 cmd/tpm.c     |  49 +++++++++++++++++++++++++++
 include/tpm.h |  29 ++++++++++++++++
 lib/tpm.c     | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 184 insertions(+)
diff mbox series

Patch

diff --git a/cmd/tpm.c b/cmd/tpm.c
index 3c486c313b..c97babea84 100644
--- a/cmd/tpm.c
+++ b/cmd/tpm.c
@@ -349,6 +349,43 @@  static int do_tpm_pcr_event(cmd_tbl_t *cmdtp, int flag,
 	return report_return_code(rc);
 }
 
+static int do_tpm_pcr_setauthpolicy(cmd_tbl_t *cmdtp, int flag,
+				    int argc, char * const argv[])
+{
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	char *key = argv[2];
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+
+	if (strlen(key) != TPM2_DIGEST_LENGTH)
+		return -EINVAL;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_pcr_setauthpolicy(pw, pw_sz, index,
+							 key));
+}
+
+static int do_tpm_pcr_setauthvalue(cmd_tbl_t *cmdtp, int flag,
+				   int argc, char * const argv[])
+{
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	char *key = argv[2];
+	const ssize_t key_sz = strlen(key);
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+
+	if (strlen(key) != TPM2_DIGEST_LENGTH)
+		return -EINVAL;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_pcr_setauthvalue(pw, pw_sz, index,
+							key, key_sz));
+}
+
 static int do_tpm_pcr_extend(cmd_tbl_t *cmdtp, int flag,
 			     int argc, char * const argv[])
 {
@@ -1003,6 +1040,10 @@  static cmd_tbl_t tpm_commands[] = {
 			 do_tpm_nv_write_value, "", ""),
 	U_BOOT_CMD_MKENT(pcr_event, 0, 1,
 			 do_tpm_pcr_event, "", ""),
+	U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1,
+			 do_tpm_pcr_setauthpolicy, "", ""),
+	U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
+			 do_tpm_pcr_setauthvalue, "", ""),
 	U_BOOT_CMD_MKENT(pcr_extend, 0, 1,
 			 do_tpm_pcr_extend, "", ""),
 	U_BOOT_CMD_MKENT(pcr_read, 0, 1,
@@ -1150,6 +1191,14 @@  U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
 "    - Read <count> bytes of the public endorsement key to memory\n"
 "      address <addr>\n"
 "Integrity Collection and Reporting Commands:\n"
+"  pcr_setauthpolicy <index> <key> <pw>\n"
+"    - Change the <key> to access <index> PCR. <pw> is for the platform\n"
+"      hierarchy and may be empty.\n"
+"      /!\\WARNING: untested function, use at your own risks !\n"
+"  pcr_setauthvalue <index> <key> <pw>\n"
+"    - Change the <key> to access <index> PCR. <pw> is for the platform\n"
+"      hierarchy and may be empty.\n"
+"      /!\\WARNING: untested function, use at your own risks !\n"
 "  pcr_event <index> <digest_in> <digest_out>\n"
 "    - Add a new measurement to a PCR.  Update PCR <index> with\n"
 "      <digest_in>. It must be a 20 byte digest for TPMv1 or a SHA256\n"
diff --git a/include/tpm.h b/include/tpm.h
index cc63f06634..93ec521e74 100644
--- a/include/tpm.h
+++ b/include/tpm.h
@@ -61,11 +61,13 @@  enum tpm2_command_codes {
 	TPM2_CC_CLEAR		= 0x0126,
 	TPM2_CC_CLEARCONTROL	= 0x0127,
 	TPM2_CC_HIERCHANGEAUTH	= 0x0129,
+	TPM2_CC_PCR_SETAUTHPOL	= 0x012C,
 	TPM2_CC_DAM_RESET	= 0x0139,
 	TPM2_CC_DAM_PARAMETERS	= 0x013A,
 	TPM2_CC_GET_CAPABILITY	= 0x017A,
 	TPM2_CC_PCR_READ	= 0x017E,
 	TPM2_CC_PCR_EXTEND	= 0x0182,
+	TPM2_CC_PCR_SETAUTHVAL	= 0x0183,
 };
 
 enum tpm2_return_codes {
@@ -559,6 +561,33 @@  uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length);
  */
 int tpm_pcr_event(u32 index, const void *in_digest, void *out_digest);
 
+/**
+ * Issue a TPM_PCR_SetAuthPolicy command.
+ *
+ * @param pw		Platform password
+ * @param pw_sz		Length of the password
+ * @param index		Index of the PCR
+ * @param digest	New key to access the PCR
+ *
+ * @return return code of the operation
+ */
+int tpm2_pcr_setauthpolicy(const char *pw, const ssize_t pw_sz, u32 index,
+			   const char *key);
+
+/**
+ * Issue a TPM_PCR_SetAuthValue command.
+ *
+ * @param pw		Platform password
+ * @param pw_sz		Length of the password
+ * @param index		Index of the PCR
+ * @param digest	New key to access the PCR
+ * @param key_sz	Length of the new key
+ *
+ * @return return code of the operation
+ */
+int tpm2_pcr_setauthvalue(const char *pw, const ssize_t pw_sz, u32 index,
+			  const char *key, const ssize_t key_sz);
+
 /**
  * Issue a TPM_PCR_Extend command.
  *
diff --git a/lib/tpm.c b/lib/tpm.c
index f09b9ce9eb..542449a4ea 100644
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -527,6 +527,112 @@  int tpm_pcr_event(u32 index, const void *in_digest, void *out_digest)
 	return 0;
 }
 
+int tpm2_pcr_setauthpolicy(const char *pw, const ssize_t pw_sz, u32 index,
+			   const char *key)
+{
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		STRINGIFY16(TPM2_ST_SESSIONS),	/* TAG */
+		STRINGIFY32(35 + pw_sz + TPM2_DIGEST_LENGTH), /* Command size */
+		STRINGIFY32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
+
+		/* HANDLE */
+		STRINGIFY32(TPM2_RH_PLATFORM),	/* TPM resource handle */
+
+		/* AUTH_SESSION */
+		STRINGIFY32(9 + pw_sz),		/* Authorization size */
+		STRINGIFY32(TPM2_RS_PW),	/* session handle */
+		STRINGIFY16(0),			/* Size of <nonce> */
+						/* <nonce> (if any) */
+		0,				/* Attributes: Cont/Excl/Rst */
+		STRINGIFY16(pw_sz)		/* Size of <hmac/password> */
+		/* STRING(pw)			   <hmac/password> (if any) */
+
+		/* TPM2B_AUTH (TPM2B_DIGEST) */
+		/* STRINGIFY16(TPM2_DIGEST_LENGTH) Digest size length */
+		/* STRING(key)			   Digest buffer (PCR key) */
+
+		/* TPMI_ALG_HASH */
+		/* STRINGIFY16(TPM2_ALG_SHA256)	   Algorithm of the hash */
+
+		/* TPMI_DH_PCR */
+		/* STRINGIFY32(index),		   PCR Index */
+	};
+	unsigned int offset = 27;
+	int ret;
+
+	if (!is_tpmv2)
+		return TPM_LIB_ERROR;
+
+	/*
+	 * Fill the command structure starting from the first buffer:
+	 *     - the password (if any)
+	 *     - the PCR key length
+	 *     - the PCR key
+	 *     - the hash algorithm
+	 *     - the PCR index
+	 */
+	ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
+			       offset, pw, pw_sz,
+			       offset + pw_sz, TPM2_DIGEST_LENGTH,
+			       offset + pw_sz + 2, key, TPM2_DIGEST_LENGTH,
+			       offset + pw_sz + 2 + TPM2_DIGEST_LENGTH,
+			       TPM2_ALG_SHA256,
+			       offset + pw_sz + 4 + TPM2_DIGEST_LENGTH, index);
+	offset += pw_sz + 2 + TPM2_DIGEST_LENGTH + 2 + 4;
+	if (ret)
+		return TPM_LIB_ERROR;
+
+	return tpm_sendrecv_command(command_v2, NULL, NULL);
+}
+
+int tpm2_pcr_setauthvalue(const char *pw, const ssize_t pw_sz, u32 index,
+			  const char *key, const ssize_t key_sz)
+{
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		STRINGIFY16(TPM2_ST_SESSIONS),	/* TAG */
+		STRINGIFY32(33 + pw_sz + TPM2_DIGEST_LENGTH), /* Command size */
+		STRINGIFY32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
+
+		/* HANDLE */
+		STRINGIFY32(index),		/* Handle (PCR Index) */
+
+		/* AUTH_SESSION */
+		STRINGIFY32(9 + pw_sz),		/* Authorization size */
+		STRINGIFY32(TPM2_RS_PW),	/* session handle */
+		STRINGIFY16(0),			/* Size of <nonce> */
+						/* <nonce> (if any) */
+		0,				/* Attributes: Cont/Excl/Rst */
+		STRINGIFY16(pw_sz),		/* Size of <hmac/password> */
+		/* STRING(pw)			   <hmac/password> (if any) */
+
+		/* TPM2B_DIGEST */
+		/* STRINGIFY16(key_sz)		   Key length */
+		/* STRING(key)			   Key */
+	};
+	unsigned int offset = 27;
+	int ret;
+
+	if (!is_tpmv2)
+		return TPM_LIB_ERROR;
+
+	/*
+	 * Fill the command structure starting from the first buffer:
+	 *     - the password (if any)
+	 *     - the number of digests, 1 in our case
+	 *     - the algorithm, sha256 in our case
+	 *     - the digest (64 bytes)
+	 */
+	ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
+			       offset, pw, pw_sz,
+			       offset + pw_sz, key_sz,
+			       offset + pw_sz + 2, key, key_sz);
+	offset += pw_sz + 2 + key_sz;
+	if (ret)
+		return TPM_LIB_ERROR;
+
+	return tpm_sendrecv_command(command_v2, NULL, NULL);
+}
+
 int tpm2_pcr_extend(u32 index, const uint8_t *digest)
 {
 	u8 command_v2[COMMAND_BUFFER_SIZE] = {