[PATCH 3/3] efi_loader: Extend PCR's for firmware measurements

Ruchika Gupta ruchika.gupta at linaro.org
Thu Nov 18 07:17:51 CET 2021


Firmwares before U-Boot may be capable of doing tpm measurements
and passing them to U-Boot in the form of eventlog. However there
may be scenarios where the firmwares don't have TPM driver and
are not capable of extending the measurements in the PCRs. To
cater to such platforms, read the PCR0 to determine if the
previous firmwares have extended the PCR0. If not, then extend
the PCR's as the eventlog is parsed.

Signed-off-by: Ruchika Gupta <ruchika.gupta at linaro.org>
---
 lib/efi_loader/efi_tcg2.c | 86 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index c97766eae3..cbd0c7d224 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -178,6 +178,43 @@ static efi_status_t tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
 	return EFI_SUCCESS;
 }
 
+/* tcg2_pcr_read - Read PCRs for a TPM2 device for a given tpml_digest_values
+ *
+ * @dev:		device
+ * @digest_list:	list of digest algorithms to extend
+ *
+ * @Return: status code
+ */
+static efi_status_t tcg2_pcr_read(struct udevice *dev, u32 pcr_index,
+				    struct tpml_digest_values *digest_list)
+{
+	struct tpm_chip_priv *priv;
+	unsigned int updates, pcr_select_min;
+	u32 rc;
+	size_t i;
+
+	priv = dev_get_uclass_priv(dev);
+	if (!priv)
+		return EFI_DEVICE_ERROR;
+
+	pcr_select_min = priv->pcr_select_min;
+
+	for (i = 0; i < digest_list->count; i++) {
+		u16 hash_alg = digest_list->digests[i].hash_alg;
+		u8 *digest = (u8 *)&digest_list->digests[i].digest;
+
+		rc = tpm2_pcr_read(dev, pcr_index, pcr_select_min,
+				    hash_alg, digest, alg_to_len(hash_alg),
+				    &updates);
+		if (rc) {
+			EFI_PRINT("Failed to read PCR\n");
+			return EFI_DEVICE_ERROR;
+		}
+	}
+
+	return EFI_SUCCESS;
+}
+
 /* tcg2_agile_log_append - Append an agile event to out eventlog
  *
  * @pcr_index:		PCR index
@@ -1488,10 +1525,12 @@ static efi_status_t efi_init_event_log(struct udevice *dev)
 	struct tcg_pcr_event *event_header = NULL;
 	struct tpml_digest_values digest_list;
 	size_t spec_event_size;
+	bool extend_pcr = false;
 	efi_status_t ret;
 	u32 pcr, pos;
 	u64 base;
 	u32 sz;
+	int i;
 
 	ret = platform_get_tpm2_device(&dev);
 	if (ret != EFI_SUCCESS)
@@ -1541,6 +1580,26 @@ static efi_status_t efi_init_event_log(struct udevice *dev)
 			goto free_pool;
 		}
 
+		ret = tcg2_pcr_read(dev, 0, &digest_list);
+		if (ret) {
+			log_err("Error reading PCR 0\n");
+			goto free_pool;
+		}
+
+		/*
+		 * If PCR0 is 0, previous firmware didn't have the capability
+		 * to extend the PCR. In this scenario, extend the PCR as
+		 * the eventlog is parsed.
+		 */
+		for (i = 0; i < digest_list.count; i++) {
+			u8 buffer[TPM2_DIGEST_LEN] =  { 0 };
+			u16 hash_alg = digest_list.digests[i].hash_alg;
+
+			if (!memcmp((u8 *)&digest_list.digests[i].digest,
+				    buffer, alg_to_len(hash_alg)))
+				extend_pcr = true;
+		}
+
 		while (pos < sz) {
 			ret = tcg2_parse_event(dev, buffer, sz, &pos,
 					       &digest_list, &pcr);
@@ -1548,6 +1607,33 @@ static efi_status_t efi_init_event_log(struct udevice *dev)
 				log_err("Error parsing event\n");
 				goto free_pool;
 			}
+
+			if (pcr != 0) {
+				/*
+				 * Eventlog passed by firmware should extend
+				 * PCR0 only.
+				 */
+				log_err("Invalid PCR\n");
+				goto free_pool;
+			}
+
+			if (extend_pcr) {
+				ret = tcg2_pcr_extend(dev, pcr, &digest_list);
+				if (ret != EFI_SUCCESS) {
+					log_err("Error in extending PCR\n");
+					goto free_pool;
+				}
+
+				/* Clear the digest for next event */
+				for (i = 0; i < digest_list.count; i++) {
+					u16 hash_alg =
+						digest_list.digests[i].hash_alg;
+					u8 *digest =
+					   (u8 *)&digest_list.digests[i].digest;
+
+					memset(digest, 0, alg_to_len(hash_alg));
+				}
+			}
 		}
 
 		memcpy(event_log.buffer, buffer, sz);
-- 
2.25.1



More information about the U-Boot mailing list