security/tpm/tss/tcg-2.0: Add multi digits support to tlcl_extend()

To support multi digists the tlcl_extend() for TPM2 expects
TPML_DIGEST_VALUE pointer as input argument.

BUG=N/A
TEST=Build binary and verified logging on Facebook FBG-1701

Change-Id: I8d86c41c23e4e93a84e0527d7cddcfd30d5d8394
Signed-off-by: Frans Hendriks <fhendriks@eltan.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/33252
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Lance Zhao <lance.zhao@gmail.com>
diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c
index 4698a4d..4cf3711 100644
--- a/src/security/tpm/tspi/tspi.c
+++ b/src/security/tpm/tspi/tspi.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
  * Copyright 2017 Facebook Inc.
  * Copyright 2018 Siemens AG
+ * Copyright 2019 Eltan B.V.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,6 +21,7 @@
 #include <security/tpm/tspi.h>
 #include <security/tpm/tss.h>
 #include <stdlib.h>
+#include <string.h>
 #if CONFIG(VBOOT)
 #include <vb2_api.h>
 #include <vb2_sha.h>
@@ -209,7 +211,28 @@
 	if (!digest)
 		return TPM_E_IOERROR;
 
+#if CONFIG(TPM2)
+	TPML_DIGEST_VALUES tpml_digests;
+
+	tpml_digests.count = 1;
+	switch (digest_algo) {
+	case VB2_HASH_SHA1:
+		tpml_digests.digests[0].hashAlg = TPM_ALG_SHA1;
+		memcpy(tpml_digests.digests[0].digest.sha1,
+		       digest, sizeof(TPMU_HA));
+		break;
+	case VB2_HASH_SHA256:
+		tpml_digests.digests[0].hashAlg = TPM_ALG_SHA256;
+		memcpy(tpml_digests.digests[0].digest.sha256,
+		       digest, sizeof(TPMU_HA));
+		break;
+	default:
+		return TPM_E_IOERROR;
+	}
+	result = tlcl_extend(pcr, (uint8_t *)&tpml_digests, NULL);
+#else
 	result = tlcl_extend(pcr, digest, NULL);
+#endif
 	if (result != TPM_SUCCESS)
 		return result;
 
diff --git a/src/security/tpm/tss/tcg-2.0/tss.c b/src/security/tpm/tss/tcg-2.0/tss.c
index 16e40fe..fab334f 100644
--- a/src/security/tpm/tss/tcg-2.0/tss.c
+++ b/src/security/tpm/tss/tcg-2.0/tss.c
@@ -127,24 +127,68 @@
 }
 
 /*
- * The caller will provide the digest in a 32 byte buffer, let's consider it a
- * sha256 digest.
+ * The caller will provide the digest in a 32 byte buffer
  */
 uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
 		     uint8_t *out_digest)
 {
 	struct tpm2_pcr_extend_cmd pcr_ext_cmd;
 	struct tpm2_response *response;
+	int i;
+	TPML_DIGEST_VALUES *tpml_digests;
 
 	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));
+	tpml_digests = (TPML_DIGEST_VALUES *)in_digest;
+	pcr_ext_cmd.digests.count = tpml_digests->count;
+
+	for (i = 0; i < tpml_digests->count ; i++) {
+		pcr_ext_cmd.digests.digests[i].hashAlg =
+			tpml_digests->digests[i].hashAlg;
+		switch (tpml_digests->digests[i].hashAlg) {
+		case TPM_ALG_SHA1:
+			memcpy(pcr_ext_cmd.digests.digests[i].digest.sha1,
+			       tpml_digests->digests[i].digest.sha1,
+			       sizeof(TPMU_HA));
+			break;
+		case TPM_ALG_SHA256:
+			memcpy(pcr_ext_cmd.digests.digests[i].digest.sha256,
+			       tpml_digests->digests[i].digest.sha256,
+			       sizeof(TPMU_HA));
+			break;
+		case TPM_ALG_SHA384:
+			memcpy(pcr_ext_cmd.digests.digests[i].digest.sha384,
+			       tpml_digests->digests[i].digest.sha384,
+			       sizeof(TPMU_HA));
+			break;
+		case TPM_ALG_SHA512:
+			memcpy(pcr_ext_cmd.digests.digests[i].digest.sha512,
+			       tpml_digests->digests[i].digest.sha512,
+			       sizeof(TPMU_HA));
+			break;
+		case TPM_ALG_SM3_256:
+			memcpy(pcr_ext_cmd.digests.digests[i].digest.sm3_256,
+			       tpml_digests->digests[i].digest.sm3_256,
+			       sizeof(TPMU_HA));
+			break;
+		}
+	}
 
 	response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
 
-	printk(BIOS_INFO, "%s: response is %x\n",
+	/*
+	 * Check if we are invalidating the pcrs, ignore the error if this is
+	 * the case
+	 */
+	if ((tpml_digests->count == 1) &&
+	    (tpml_digests->digests[0].hashAlg == TPM_ALG_ERROR) &&
+	    response && (response->hdr.tpm_code & ~TPM_RC_N_MASK) ==
+	      (TPM_RC_P | TPM_RC_HASH)) {
+		printk(BIOS_SPEW, "%s: TPM_RC_HASH returned this is"
+		       " expected\n", __func__);
+		return TPM_SUCCESS;
+	}
+
+	printk(BIOS_INFO, "%s: response is 0x%x\n",
 	       __func__, response ? response->hdr.tpm_code : -1);
 	if (!response || response->hdr.tpm_code)
 		return TPM_E_IOERROR;
diff --git a/src/security/tpm/tss/tcg-2.0/tss_structures.h b/src/security/tpm/tss/tcg-2.0/tss_structures.h
index 6a017bbb..1530613 100644
--- a/src/security/tpm/tss/tcg-2.0/tss_structures.h
+++ b/src/security/tpm/tss/tcg-2.0/tss_structures.h
@@ -97,6 +97,12 @@
    space is defined by the lower 16 bits. */
 #define TPM_CC_VENDOR_BIT_MASK 0x20000000
 
+/* Table 15 - TPM_RC Constants (Actions) */
+#define RC_FMT1                (TPM_RC)(0x080)
+#define TPM_RC_HASH            (TPM_RC)(RC_FMT1 + 0x003)
+#define TPM_RC_P               (TPM_RC)(0x040)
+#define TPM_RC_N_MASK          (TPM_RC)(0xF00)
+
 /* Startup values. */
 #define TPM_SU_CLEAR 0
 #define TPM_SU_STATE 1
@@ -311,12 +317,13 @@
 	TPM2B b;
 } TPM2B_MAX_NV_BUFFER;
 
-/*
- * This is a union, but as of now we support just one digest - sha256, so
- * there is just one element.
- */
+/* Table 66 - TPMU_HA Union */
 typedef union {
-	uint8_t  sha256[SHA256_DIGEST_SIZE];
+	uint8_t sha1[SHA1_DIGEST_SIZE];
+	uint8_t sha256[SHA256_DIGEST_SIZE];
+	uint8_t sm3_256[SM3_256_DIGEST_SIZE];
+	uint8_t sha384[SHA384_DIGEST_SIZE];
+	uint8_t sha512[SHA512_DIGEST_SIZE];
 } TPMU_HA;
 
 typedef struct {
@@ -324,9 +331,10 @@
 	TPMU_HA        digest;
 } TPMT_HA;
 
+/* Table 96 -- TPML_DIGEST_VALUES Structure <I/O> */
 typedef struct {
 	uint32_t   count;
-	TPMT_HA  digests[1];  /* Limit max number of hashes to 1. */
+	TPMT_HA digests[HASH_COUNT];
 } TPML_DIGEST_VALUES;
 
 struct nv_read_response {