tpm2_lite: implement TlclExtend

Implement TlclExtend, which sends a TPM2_PCR_Extend command to extend
the indicated PCR.

BUG=b:174807059
BRANCH=none
TEST=After stopped trunksd run "tpmc pcrextend <index> <extend hex>" to
     extend the PCR. Start trunksd and run "trunks_client --read_pcr
     --index=<index>" would see the PCR value changed.

Disallow-Recycled-Builds: test-failures
Signed-off-by: Yi Chou <yich@google.com>
Change-Id: I5b11fcf7de83186a29e1abed43f443ac9ca426fb
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2632019
Reviewed-by: Leo Lai <cylai@google.com>
diff --git a/firmware/include/tpm2_tss_constants.h b/firmware/include/tpm2_tss_constants.h
index 7374735..becd710 100644
--- a/firmware/include/tpm2_tss_constants.h
+++ b/firmware/include/tpm2_tss_constants.h
@@ -34,9 +34,13 @@
 #define TPM2_NV_ReadPublic     ((TPM_CC)0x00000169)
 #define TPM2_GetCapability     ((TPM_CC)0x0000017A)
 #define TPM2_GetRandom         ((TPM_CC)0x0000017B)
+#define TPM2_PCR_Extend        ((TPM_CC)0x00000182)
+
+#define TPM_HT_PCR             0x00
+#define TPM_HT_NV_INDEX        0x01
 
 #define HR_SHIFT               24
-#define TPM_HT_NV_INDEX        0x01
+#define HR_PCR                (TPM_HT_PCR <<  HR_SHIFT)
 #define HR_NV_INDEX           (TPM_HT_NV_INDEX <<  HR_SHIFT)
 #define TPM_RH_OWNER        0x40000001
 #define TPM_RH_PLATFORM     0x4000000C
@@ -110,9 +114,15 @@
 #define TPMI_RH_NV_INDEX_TCG_WG_START	((TPMI_RH_NV_INDEX)0x01C40000)
 #define TPMI_RH_NV_INDEX_RESERVED_START	((TPMI_RH_NV_INDEX)0x01C90000)
 
+#define HASH_COUNT 1 /* Only SHA-256 is supported */
+
+/* Table 206 - Defines for SHA256 Hash Values */
+#define SHA256_DIGEST_SIZE  32
+
 typedef uint8_t TPMI_YES_NO;
 typedef uint32_t TPM_CC;
 typedef uint32_t TPM_HANDLE;
+typedef TPM_HANDLE TPMI_DH_PCR;
 typedef TPM_HANDLE TPMI_RH_NV_INDEX;
 typedef TPM_HANDLE TPMI_RH_ENABLES;
 typedef uint32_t TPM_CAP;
@@ -146,6 +156,20 @@
 } TPML_TAGGED_TPM_PROPERTY;
 
 typedef union {
+	uint8_t sha256[SHA256_DIGEST_SIZE];
+} TPMU_HA;
+
+typedef struct {
+	TPMI_ALG_HASH  hashAlg;
+	TPMU_HA        digest;
+} TPMT_HA;
+
+typedef struct {
+	uint32_t   count;
+	TPMT_HA digests[HASH_COUNT];
+} TPML_DIGEST_VALUES;
+
+typedef union {
 	TPML_TAGGED_TPM_PROPERTY tpm_properties;
 } TPMU_CAPABILITIES;
 
@@ -223,6 +247,11 @@
 	TPM_SU shutdown_type;
 };
 
+struct tpm2_pcr_extend_cmd {
+	TPMI_DH_PCR pcrHandle;
+	TPML_DIGEST_VALUES digests;
+};
+
 /* Common command/response header. */
 struct tpm_header {
 	uint16_t tpm_tag;
diff --git a/firmware/lib/tpm2_lite/marshaling.c b/firmware/lib/tpm2_lite/marshaling.c
index ef3606b..b9857d4 100644
--- a/firmware/lib/tpm2_lite/marshaling.c
+++ b/firmware/lib/tpm2_lite/marshaling.c
@@ -283,7 +283,7 @@
 	}
 
 	memcpy(*buffer, blob, blob_size);
-	buffer_space -= blob_size;
+	*buffer_space -= blob_size;
 	*buffer = (void *)((uintptr_t)(*buffer) + blob_size);
 }
 
@@ -327,6 +327,7 @@
 #define marshal_TPM_HANDLE(a, b, c) marshal_u32(a, b, c)
 #define marshal_TPM_SU(a, b, c) marshal_u16(a, b, c)
 #define marshal_ALG_ID(a, b, c) marshal_u16(a, b, c)
+#define marshal_TPMI_ALG_HASH(a, b, c) marshal_u16(a, b, c)
 
 /*
  * For TPM2B* structures the size field (16 or 32 bits) goes before the data.
@@ -671,6 +672,48 @@
 	marshal_TPM_SU(buffer, command_body->shutdown_type, buffer_space);
 }
 
+static void marshal_TPMT_HA(void **buffer,
+			    TPMT_HA *data,
+			    int *buffer_space)
+{
+	if (data->hashAlg != TPM_ALG_SHA256)
+	{
+		VB2_DEBUG("Unsupported TPMT_HA hash algorithm: %#x\n",
+			  data->hashAlg);
+		*buffer_space = -1;
+		return;
+	}
+	marshal_TPMI_ALG_HASH(buffer, data->hashAlg, buffer_space);
+	/* We only support SHA256 now. */
+	marshal_blob(buffer, data->digest.sha256,
+		     SHA256_DIGEST_SIZE, buffer_space);
+}
+
+static void marshal_TPML_DIGEST_VALUES(void **buffer,
+				       TPML_DIGEST_VALUES *data,
+				       int *buffer_space)
+{
+	int i;
+
+	marshal_u32(buffer, data->count, buffer_space);
+	for (i = 0; i < data->count; i++)
+		marshal_TPMT_HA(buffer, &data->digests[i], buffer_space);
+}
+
+static void marshal_pcr_extend(void **buffer,
+			       struct tpm2_pcr_extend_cmd *command_body,
+			       int *buffer_space)
+{
+	struct tpm2_session_header session_header;
+
+	tpm_tag = TPM_ST_SESSIONS;
+	marshal_TPM_HANDLE(buffer, command_body->pcrHandle, buffer_space);
+	memset(&session_header, 0, sizeof(session_header));
+	session_header.session_handle = TPM_RS_PW;
+	marshal_session_header(buffer, &session_header, buffer_space);
+	marshal_TPML_DIGEST_VALUES(buffer, &command_body->digests, buffer_space);
+}
+
 int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
 			void *buffer, int buffer_size)
 {
@@ -740,6 +783,10 @@
 		marshal_shutdown(&cmd_body, tpm_command_body, &body_size);
 		break;
 
+	case TPM2_PCR_Extend:
+		marshal_pcr_extend(&cmd_body, tpm_command_body, &body_size);
+		break;
+
 	default:
 		body_size = -1;
 		VB2_DEBUG("Request to marshal unsupported command %#x\n",
@@ -811,6 +858,7 @@
 	case TPM2_Shutdown:
 	case TPM2_NV_DefineSpace:
 	case TPM2_NV_UndefineSpace:
+	case TPM2_PCR_Extend:
 		/* Session data included in response can be safely ignored. */
 		cr_size = 0;
 		break;
diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c
index e4695d1..b91119b 100644
--- a/firmware/lib/tpm2_lite/tlcl.c
+++ b/firmware/lib/tpm2_lite/tlcl.c
@@ -314,8 +314,15 @@
 
 uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
 {
-	VB2_DEBUG("NOT YET IMPLEMENTED\n");
-	return TPM_SUCCESS;
+	struct tpm2_pcr_extend_cmd pcr_ext_cmd;
+
+	pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
+	pcr_ext_cmd.digests.count = 1;
+	pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
+	memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
+	       sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
+
+	return tpm_get_response_code(TPM2_PCR_Extend, &pcr_ext_cmd);
 }