aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sandbox/dts/sandbox.dtsi13
-rw-r--r--arch/sandbox/dts/test.dts13
-rw-r--r--boot/Kconfig32
-rw-r--r--boot/bootm.c74
-rw-r--r--cmd/booti.c1
-rw-r--r--cmd/bootm.c2
-rw-r--r--cmd/bootz.c1
-rw-r--r--configs/sandbox_defconfig1
-rw-r--r--doc/usage/index.rst1
-rw-r--r--doc/usage/measured_boot.rst31
-rw-r--r--drivers/tpm/tpm2_tis_sandbox.c100
-rw-r--r--include/bootm.h11
-rw-r--r--include/efi_tcg2.h44
-rw-r--r--include/image.h1
-rw-r--r--include/test/suites.h1
-rw-r--r--include/tpm-v2.h263
-rw-r--r--lib/Kconfig4
-rw-r--r--lib/efi_loader/Kconfig2
-rw-r--r--lib/efi_loader/efi_tcg2.c1052
-rw-r--r--lib/tpm-v2.c814
-rw-r--r--test/boot/Makefile1
-rw-r--r--test/boot/measurement.c66
-rw-r--r--test/cmd_ut.c4
-rw-r--r--test/py/tests/test_tpm2.py20
24 files changed, 1490 insertions, 1062 deletions
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index ff7e558..241f397 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -4,11 +4,23 @@
* and sandbox64 builds.
*/
+#include <config.h>
#include <dt-bindings/input/input.h>
#define USB_CLASS_HUB 9
/ {
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ event_log: tcg_event_log {
+ no-map;
+ reg = <(CFG_SYS_SDRAM_SIZE - 0x2000) 0x2000>;
+ };
+ };
+
binman {
};
@@ -342,6 +354,7 @@
tpm2 {
compatible = "sandbox,tpm2";
+ memory-region = <&event_log>;
};
triangle {
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 5b54651..2887f6c 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -9,6 +9,7 @@
/dts-v1/;
+#include <config.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/gpio/sandbox-gpio.h>
#include <dt-bindings/input/input.h>
@@ -69,6 +70,17 @@
osd0 = "/osd";
};
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ event_log: tcg_event_log {
+ no-map;
+ reg = <(CFG_SYS_SDRAM_SIZE - 0x2000) 0x2000>;
+ };
+ };
+
binman: binman {
};
@@ -1436,6 +1448,7 @@
tpm2 {
compatible = "sandbox,tpm2";
+ memory-region = <&event_log>;
};
tpm {
diff --git a/boot/Kconfig b/boot/Kconfig
index a01e6cb..fbc49c5 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -685,6 +685,38 @@ config LEGACY_IMAGE_FORMAT
loaded. If a board needs the legacy image format support in this
case, enable it here.
+config MEASURED_BOOT
+ bool "Measure boot images and configuration when booting without EFI"
+ depends on HASH && TPM_V2
+ help
+ This option enables measurement of the boot process when booting
+ without UEFI . Measurement involves creating cryptographic hashes
+ of the binary images that are booting and storing them in the TPM.
+ In addition, a log of these hashes is stored in memory for the OS
+ to verify the booted images and configuration. Enable this if the
+ OS has configured some memory area for the event log and you intend
+ to use some attestation tools on your system.
+
+if MEASURED_BOOT
+ config MEASURE_DEVICETREE
+ bool "Measure the devicetree image"
+ default y if MEASURED_BOOT
+ help
+ On some platforms, the devicetree is not static as it may contain
+ random MAC addresses or other such data that changes each boot.
+ Therefore, it should not be measured into the TPM. In that case,
+ disable the measurement here.
+
+ config MEASURE_IGNORE_LOG
+ bool "Ignore the existing event log"
+ default n
+ help
+ On platforms that use an event log memory region that persists
+ through system resets and are the first stage bootloader, then
+ this option should be enabled to ignore any existing data in the
+ event log memory region.
+endif # MEASURED_BOOT
+
config SUPPORT_RAW_INITRD
bool "Enable raw initrd images"
help
diff --git a/boot/bootm.c b/boot/bootm.c
index 8f96a80..cb61485 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -23,6 +23,7 @@
#include <asm/global_data.h>
#include <asm/io.h>
#include <linux/sizes.h>
+#include <tpm-v2.h>
#if defined(CONFIG_CMD_USB)
#include <usb.h>
#endif
@@ -673,6 +674,75 @@ int bootm_process_cmdline_env(int flags)
return 0;
}
+int bootm_measure(struct bootm_headers *images)
+{
+ int ret = 0;
+
+ /* Skip measurement if EFI is going to do it */
+ if (images->os.os == IH_OS_EFI &&
+ IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL) &&
+ IS_ENABLED(CONFIG_BOOTM_EFI))
+ return ret;
+
+ if (IS_ENABLED(CONFIG_MEASURED_BOOT)) {
+ struct tcg2_event_log elog;
+ struct udevice *dev;
+ void *initrd_buf;
+ void *image_buf;
+ const char *s;
+ u32 rd_len;
+ bool ign;
+
+ elog.log_size = 0;
+ ign = IS_ENABLED(CONFIG_MEASURE_IGNORE_LOG);
+ ret = tcg2_measurement_init(&dev, &elog, ign);
+ if (ret)
+ return ret;
+
+ image_buf = map_sysmem(images->os.image_start,
+ images->os.image_len);
+ ret = tcg2_measure_data(dev, &elog, 8, images->os.image_len,
+ image_buf, EV_COMPACT_HASH,
+ strlen("linux") + 1, (u8 *)"linux");
+ if (ret)
+ goto unmap_image;
+
+ rd_len = images->rd_end - images->rd_start;
+ initrd_buf = map_sysmem(images->rd_start, rd_len);
+ ret = tcg2_measure_data(dev, &elog, 9, rd_len, initrd_buf,
+ EV_COMPACT_HASH, strlen("initrd") + 1,
+ (u8 *)"initrd");
+ if (ret)
+ goto unmap_initrd;
+
+ if (IS_ENABLED(CONFIG_MEASURE_DEVICETREE)) {
+ ret = tcg2_measure_data(dev, &elog, 0, images->ft_len,
+ (u8 *)images->ft_addr,
+ EV_TABLE_OF_DEVICES,
+ strlen("dts") + 1,
+ (u8 *)"dts");
+ if (ret)
+ goto unmap_initrd;
+ }
+
+ s = env_get("bootargs");
+ if (!s)
+ s = "";
+ ret = tcg2_measure_data(dev, &elog, 1, strlen(s) + 1, (u8 *)s,
+ EV_PLATFORM_CONFIG_FLAGS,
+ strlen(s) + 1, (u8 *)s);
+
+unmap_initrd:
+ unmap_sysmem(initrd_buf);
+
+unmap_image:
+ unmap_sysmem(image_buf);
+ tcg2_measurement_term(dev, &elog, ret != 0);
+ }
+
+ return ret;
+}
+
/**
* Execute selected states of the bootm command.
*
@@ -724,6 +794,10 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
if (!ret && (states & BOOTM_STATE_FINDOTHER))
ret = bootm_find_other(cmdtp, flag, argc, argv);
+ if (IS_ENABLED(CONFIG_MEASURED_BOOT) && !ret &&
+ (states & BOOTM_STATE_MEASURE))
+ bootm_measure(images);
+
/* Load the OS */
if (!ret && (states & BOOTM_STATE_LOADOS)) {
iflag = bootm_disable_interrupts();
diff --git a/cmd/booti.c b/cmd/booti.c
index 1d531bd..a6c7db2 100644
--- a/cmd/booti.c
+++ b/cmd/booti.c
@@ -127,6 +127,7 @@ int do_booti(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
BOOTM_STATE_RAMDISK |
#endif
+ BOOTM_STATE_MEASURE |
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
BOOTM_STATE_OS_GO,
&images, 1);
diff --git a/cmd/bootm.c b/cmd/bootm.c
index 3e504cc..6ded091 100644
--- a/cmd/bootm.c
+++ b/cmd/bootm.c
@@ -147,6 +147,8 @@ int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
BOOTM_STATE_OS_GO;
if (IS_ENABLED(CONFIG_SYS_BOOT_RAMDISK_HIGH))
states |= BOOTM_STATE_RAMDISK;
+ if (IS_ENABLED(CONFIG_MEASURED_BOOT))
+ states |= BOOTM_STATE_MEASURE;
if (IS_ENABLED(CONFIG_PPC) || IS_ENABLED(CONFIG_MIPS))
states |= BOOTM_STATE_OS_CMDLINE;
ret = do_bootm_states(cmdtp, flag, argc, argv, states, &images, 1);
diff --git a/cmd/bootz.c b/cmd/bootz.c
index 742889f..dd6fe49 100644
--- a/cmd/bootz.c
+++ b/cmd/bootz.c
@@ -81,6 +81,7 @@ int do_bootz(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
BOOTM_STATE_RAMDISK |
#endif
+ BOOTM_STATE_MEASURE |
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
BOOTM_STATE_OS_GO,
&images, 1);
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index e3a2f9e..c8a4669 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -14,6 +14,7 @@ CONFIG_FIT_RSASSA_PSS=y
CONFIG_FIT_CIPHER=y
CONFIG_FIT_VERBOSE=y
CONFIG_LEGACY_IMAGE_FORMAT=y
+CONFIG_MEASURED_BOOT=y
CONFIG_DISTRO_DEFAULTS=y
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 839589c..d8e23fc 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -14,6 +14,7 @@ Use U-Boot
partitions
cmdline
semihosting
+ measured_boot
Shell commands
--------------
diff --git a/doc/usage/measured_boot.rst b/doc/usage/measured_boot.rst
new file mode 100644
index 0000000..0aad590
--- /dev/null
+++ b/doc/usage/measured_boot.rst
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Measured Boot
+=====================
+
+U-Boot can perform a measured boot, the process of hashing various components
+of the boot process, extending the results in the TPM and logging the
+component's measurement in memory for the operating system to consume.
+
+By default, U-Boot will measure the operating system (linux) image, the
+initrd image, and the "bootargs" environment variable. By enabling
+CONFIG_MEASURE_DEVICETREE, U-Boot will also measure the devicetree image.
+
+The operating system typically would verify that the hashes found in the
+TPM PCRs match the contents of the event log. This can further be checked
+against the hash results of previous boots.
+
+Requirements
+---------------------
+
+* A hardware TPM 2.0 supported by the U-Boot drivers
+* CONFIG_TPM=y
+* CONFIG_MEASURED_BOOT=y
+* Device-tree configuration of the TPM device to specify the memory area
+ for event logging. The TPM device node must either contain a phandle to
+ a reserved memory region or "linux,sml-base" and "linux,sml-size"
+ indicating the address and size of the memory region. An example can be
+ found in arch/sandbox/dts/test.dts
+* The operating system must also be configured to use the memory regions
+ specified in the U-Boot device-tree in order to make use of the event
+ log.
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index e4004cf..d15a28d 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -22,11 +22,6 @@ enum tpm2_hierarchy {
TPM2_HIERARCHY_NB,
};
-/* Subset of supported capabilities */
-enum tpm2_capability {
- TPM_CAP_TPM_PROPERTIES = 0x6,
-};
-
/* Subset of supported properties */
#define TPM2_PROPERTIES_OFFSET 0x0000020E
@@ -38,7 +33,8 @@ enum tpm2_cap_tpm_property {
TPM2_PROPERTY_NB,
};
-#define SANDBOX_TPM_PCR_NB 1
+#define SANDBOX_TPM_PCR_NB TPM2_MAX_PCRS
+#define SANDBOX_TPM_PCR_SELECT_MAX ((SANDBOX_TPM_PCR_NB + 7) / 8)
/*
* Information about our TPM emulation. This is preserved in the sandbox
@@ -433,7 +429,7 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
int i, j;
/* TPM2_GetProperty */
- u32 capability, property, property_count;
+ u32 capability, property, property_count, val;
/* TPM2_PCR_Read/Extend variables */
int pcr_index = 0;
@@ -542,19 +538,32 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
case TPM2_CC_GET_CAPABILITY:
capability = get_unaligned_be32(sent);
sent += sizeof(capability);
- if (capability != TPM_CAP_TPM_PROPERTIES) {
- printf("Sandbox TPM only support TPM_CAPABILITIES\n");
- return TPM2_RC_HANDLE;
- }
-
property = get_unaligned_be32(sent);
sent += sizeof(property);
- property -= TPM2_PROPERTIES_OFFSET;
-
property_count = get_unaligned_be32(sent);
sent += sizeof(property_count);
- if (!property_count ||
- property + property_count > TPM2_PROPERTY_NB) {
+
+ switch (capability) {
+ case TPM2_CAP_PCRS:
+ break;
+ case TPM2_CAP_TPM_PROPERTIES:
+ if (!property_count) {
+ rc = TPM2_RC_HANDLE;
+ return sandbox_tpm2_fill_buf(recv, recv_len,
+ tag, rc);
+ }
+
+ if (property >= TPM2_PROPERTIES_OFFSET &&
+ ((property - TPM2_PROPERTIES_OFFSET) +
+ property_count > TPM2_PROPERTY_NB)) {
+ rc = TPM2_RC_HANDLE;
+ return sandbox_tpm2_fill_buf(recv, recv_len,
+ tag, rc);
+ }
+ break;
+ default:
+ printf("Sandbox TPM2 only supports TPM2_CAP_PCRS or "
+ "TPM2_CAP_TPM_PROPERTIES\n");
rc = TPM2_RC_HANDLE;
return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
}
@@ -578,18 +587,53 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
put_unaligned_be32(capability, recv);
recv += sizeof(capability);
- /* Give the number of properties that follow */
- put_unaligned_be32(property_count, recv);
- recv += sizeof(property_count);
-
- /* Fill with the properties */
- for (i = 0; i < property_count; i++) {
- put_unaligned_be32(TPM2_PROPERTIES_OFFSET + property +
- i, recv);
- recv += sizeof(property);
- put_unaligned_be32(tpm->properties[property + i],
- recv);
- recv += sizeof(property);
+ switch (capability) {
+ case TPM2_CAP_PCRS:
+ /* Give the number of algorithms supported - just SHA256 */
+ put_unaligned_be32(1, recv);
+ recv += sizeof(u32);
+
+ /* Give SHA256 algorithm */
+ put_unaligned_be16(TPM2_ALG_SHA256, recv);
+ recv += sizeof(u16);
+
+ /* Select the PCRs supported */
+ *recv = SANDBOX_TPM_PCR_SELECT_MAX;
+ recv++;
+
+ /* Activate all the PCR bits */
+ for (i = 0; i < SANDBOX_TPM_PCR_SELECT_MAX; ++i) {
+ *recv = 0xff;
+ recv++;
+ }
+ break;
+ case TPM2_CAP_TPM_PROPERTIES:
+ /* Give the number of properties that follow */
+ put_unaligned_be32(property_count, recv);
+ recv += sizeof(property_count);
+
+ /* Fill with the properties */
+ for (i = 0; i < property_count; i++) {
+ put_unaligned_be32(property + i, recv);
+ recv += sizeof(property);
+ if (property >= TPM2_PROPERTIES_OFFSET) {
+ val = tpm->properties[(property -
+ TPM2_PROPERTIES_OFFSET) + i];
+ } else {
+ switch (property) {
+ case TPM2_PT_PCR_COUNT:
+ val = SANDBOX_TPM_PCR_NB;
+ break;
+ default:
+ val = 0xffffffff;
+ break;
+ }
+ }
+
+ put_unaligned_be32(val, recv);
+ recv += sizeof(property);
+ }
+ break;
}
/* Add trailing \0 */
diff --git a/include/bootm.h b/include/bootm.h
index c3c7336..10a1bd6 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -56,6 +56,17 @@ ulong bootm_disable_interrupts(void);
int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
ulong size);
+/*
+ * Measure the boot images. Measurement is the process of hashing some binary
+ * data and storing it into secure memory, i.e. TPM PCRs. In addition, each
+ * measurement is logged into the platform event log such that the operating
+ * system can access it and perform attestation of the boot.
+ *
+ * @images: The structure containing the various images to boot (linux,
+ * initrd, dts, etc.)
+ */
+int bootm_measure(struct bootm_headers *images);
+
int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[], int states, struct bootm_headers *images,
int boot_progress);
diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
index b1c3abd..b21c5cb 100644
--- a/include/efi_tcg2.h
+++ b/include/efi_tcg2.h
@@ -129,50 +129,6 @@ struct efi_tcg2_boot_service_capability {
#define BOOT_SERVICE_CAPABILITY_MIN \
offsetof(struct efi_tcg2_boot_service_capability, number_of_pcr_banks)
-#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03 "Spec ID Event03"
-#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2 2
-#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 0
-#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2 2
-
-/**
- * struct TCG_EfiSpecIdEventAlgorithmSize - hashing algorithm information
- *
- * @algorithm_id: algorithm defined in enum tpm2_algorithms
- * @digest_size: size of the algorithm
- */
-struct tcg_efi_spec_id_event_algorithm_size {
- u16 algorithm_id;
- u16 digest_size;
-} __packed;
-
-/**
- * struct TCG_EfiSpecIDEventStruct - content of the event log header
- *
- * @signature: signature, set to Spec ID Event03
- * @platform_class: class defined in TCG ACPI Specification
- * Client Common Header.
- * @spec_version_minor: minor version
- * @spec_version_major: major version
- * @spec_version_errata: major version
- * @uintn_size: size of the efi_uintn_t fields used in various
- * data structures used in this specification.
- * 0x01 indicates u32 and 0x02 indicates u64
- * @number_of_algorithms: hashing algorithms used in this event log
- * @digest_sizes: array of number_of_algorithms pairs
- * 1st member defines the algorithm id
- * 2nd member defines the algorithm size
- */
-struct tcg_efi_spec_id_event {
- u8 signature[16];
- u32 platform_class;
- u8 spec_version_minor;
- u8 spec_version_major;
- u8 spec_errata;
- u8 uintn_size;
- u32 number_of_algorithms;
- struct tcg_efi_spec_id_event_algorithm_size digest_sizes[];
-} __packed;
-
/**
* struct tdEFI_TCG2_FINAL_EVENTS_TABLE - log entries after Get Event Log
* @version: version number for this structure
diff --git a/include/image.h b/include/image.h
index 5f85bf8..2e3cf83 100644
--- a/include/image.h
+++ b/include/image.h
@@ -409,6 +409,7 @@ struct bootm_headers {
#define BOOTM_STATE_OS_FAKE_GO 0x00000200 /* 'Almost' run the OS */
#define BOOTM_STATE_OS_GO 0x00000400
#define BOOTM_STATE_PRE_LOAD 0x00000800
+#define BOOTM_STATE_MEASURE 0x00001000
int state;
#if defined(CONFIG_LMB) && !defined(USE_HOSTCC)
diff --git a/include/test/suites.h b/include/test/suites.h
index 51acbe4..ad4fc92 100644
--- a/include/test/suites.h
+++ b/include/test/suites.h
@@ -46,6 +46,7 @@ int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_loadm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
+int do_ut_measurement(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc,
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 2b6980e..33dd103 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -169,7 +169,7 @@ struct tcg_pcr_event {
/**
* Definition of TPMU_HA Union
*/
-union tmpu_ha {
+union tpmu_ha {
u8 sha1[TPM2_SHA1_DIGEST_SIZE];
u8 sha256[TPM2_SHA256_DIGEST_SIZE];
u8 sm3_256[TPM2_SM3_256_DIGEST_SIZE];
@@ -185,7 +185,7 @@ union tmpu_ha {
*/
struct tpmt_ha {
u16 hash_alg;
- union tmpu_ha digest;
+ union tpmu_ha digest;
} __packed;
/**
@@ -217,6 +217,50 @@ struct tcg_pcr_event2 {
} __packed;
/**
+ * struct TCG_EfiSpecIdEventAlgorithmSize - hashing algorithm information
+ *
+ * @algorithm_id: algorithm defined in enum tpm2_algorithms
+ * @digest_size: size of the algorithm
+ */
+struct tcg_efi_spec_id_event_algorithm_size {
+ u16 algorithm_id;
+ u16 digest_size;
+} __packed;
+
+#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03 "Spec ID Event03"
+#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2 2
+#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 0
+#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2 2
+
+/**
+ * struct TCG_EfiSpecIDEventStruct - content of the event log header
+ *
+ * @signature: signature, set to Spec ID Event03
+ * @platform_class: class defined in TCG ACPI Specification
+ * Client Common Header.
+ * @spec_version_minor: minor version
+ * @spec_version_major: major version
+ * @spec_version_errata: major version
+ * @uintn_size: size of the efi_uintn_t fields used in various
+ * data structures used in this specification.
+ * 0x01 indicates u32 and 0x02 indicates u64
+ * @number_of_algorithms: hashing algorithms used in this event log
+ * @digest_sizes: array of number_of_algorithms pairs
+ * 1st member defines the algorithm id
+ * 2nd member defines the algorithm size
+ */
+struct tcg_efi_spec_id_event {
+ u8 signature[16];
+ u32 platform_class;
+ u8 spec_version_minor;
+ u8 spec_version_major;
+ u8 spec_errata;
+ u8 uintn_size;
+ u32 number_of_algorithms;
+ struct tcg_efi_spec_id_event_algorithm_size digest_sizes[];
+} __packed;
+
+/**
* TPM2 Structure Tags for command/response buffers.
*
* @TPM2_ST_NO_SESSIONS: the command does not need an authentication.
@@ -342,6 +386,26 @@ enum tpm2_algorithms {
TPM2_ALG_SM3_256 = 0x12,
};
+extern const enum tpm2_algorithms tpm2_supported_algorithms[4];
+
+static inline u16 tpm2_algorithm_to_len(enum tpm2_algorithms a)
+{
+ switch (a) {
+ case TPM2_ALG_SHA1:
+ return TPM2_SHA1_DIGEST_SIZE;
+ case TPM2_ALG_SHA256:
+ return TPM2_SHA256_DIGEST_SIZE;
+ case TPM2_ALG_SHA384:
+ return TPM2_SHA384_DIGEST_SIZE;
+ case TPM2_ALG_SHA512:
+ return TPM2_SHA512_DIGEST_SIZE;
+ default:
+ return 0;
+ }
+}
+
+#define tpm2_algorithm_to_mask(a) (1 << (a))
+
/* NV index attributes */
enum tpm_index_attrs {
TPMA_NV_PPWRITE = 1UL << 0,
@@ -422,6 +486,188 @@ enum {
};
/**
+ * struct tcg2_event_log - Container for managing the platform event log
+ *
+ * @log: Address of the log
+ * @log_position: Current entry position
+ * @log_size: Log space available
+ * @found: Boolean indicating if an existing log was discovered
+ */
+struct tcg2_event_log {
+ u8 *log;
+ u32 log_position;
+ u32 log_size;
+ bool found;
+};
+
+/**
+ * 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
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length,
+ struct tpml_digest_values *digest_list);
+
+/**
+ * Get the event size of the specified digests
+ *
+ * @digest_list List of digests for the event
+ *
+ * Return: Size in bytes of the event
+ */
+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
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+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
+ */
+void tcg2_log_append(u32 pcr_index, u32 event_type,
+ struct tpml_digest_values *digest_list, u32 size,
+ const u8 *event, u8 *log);
+
+/**
+ * Extend the PCR with specified digests
+ *
+ * @dev TPM device
+ * @pcr_index Index of the PCR
+ * @digest_list List of digests to extend
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
+ struct tpml_digest_values *digest_list);
+
+/**
+ * Read the PCR into a list of digests
+ *
+ * @dev TPM device
+ * @pcr_index Index of the PCR
+ * @digest_list List of digests to extend
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_pcr_read(struct udevice *dev, u32 pcr_index,
+ struct tpml_digest_values *digest_list);
+
+/**
+ * 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
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog,
+ u32 pcr_index, u32 size, const u8 *data, u32 event_type,
+ u32 event_size, const u8 *event);
+
+#define tcg2_measure_event(dev, elog, pcr_index, event_type, size, event) \
+ tcg2_measure_data(dev, elog, pcr_index, 0, NULL, event_type, size, \
+ event)
+
+/**
+ * Prepare the event log buffer. This function tries to discover an existing
+ * event log in memory from a previous bootloader stage. If such a log exists
+ * 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
+ * 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
+ * existing platform log in memory
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
+ bool ignore_existing_log);
+
+/**
+ * Begin measurements.
+ *
+ * @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
+ * existing platform log in memory
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog,
+ bool ignore_existing_log);
+
+/**
+ * Stop measurements and record separator events.
+ *
+ * @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);
+
+/**
+ * Get the platform event log address and size.
+ *
+ * @dev TPM device
+ * @addr Address of the log
+ * @size Size of the log
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size);
+
+/**
+ * Get the first TPM2 device found.
+ *
+ * @dev TPM device
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tcg2_platform_get_tpm2(struct udevice **dev);
+
+/**
+ * Platform-specific function for handling TPM startup errors
+ *
+ * @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
@@ -541,6 +787,19 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
void *buf, size_t prop_count);
/**
+ * tpm2_get_pcr_info() - get the supported, active PCRs and number of banks
+ *
+ * @dev: TPM device
+ * @supported_pcr: bitmask with the algorithms supported
+ * @active_pcr: bitmask with the active algorithms
+ * @pcr_banks: number of PCR banks
+ *
+ * @return 0 on success, code of operation or negative errno on failure
+ */
+int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
+ u32 *pcr_banks);
+
+/**
* Issue a TPM2_DictionaryAttackLockReset command.
*
* @dev TPM device
diff --git a/lib/Kconfig b/lib/Kconfig
index f6ca559..1964951 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -431,6 +431,10 @@ config TPM
bool "Trusted Platform Module (TPM) Support"
depends on DM
imply DM_RNG
+ select SHA1
+ select SHA256
+ select SHA384
+ select SHA512
help
This enables support for TPMs which can be used to provide security
features for your board. The TPM can be connected via LPC or I2C
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index d20aaab..4ccd26f 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -379,8 +379,6 @@ config EFI_TCG2_PROTOCOL
bool "EFI_TCG2_PROTOCOL support"
default y
depends on TPM_V2
- # Sandbox TPM currently fails on GetCapabilities needed for TCG2
- depends on !SANDBOX
select SHA1
select SHA256
select SHA384
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index 626df12..2eaa12b 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -66,35 +66,6 @@ static bool tcg2_efi_app_invoked;
static const efi_guid_t efi_guid_tcg2_protocol = EFI_TCG2_PROTOCOL_GUID;
static const efi_guid_t efi_guid_final_events = EFI_TCG2_FINAL_EVENTS_TABLE_GUID;
-struct digest_info {
- u16 hash_alg;
- u32 hash_mask;
- u16 hash_len;
-};
-
-static const struct digest_info hash_algo_list[] = {
- {
- TPM2_ALG_SHA1,
- EFI_TCG2_BOOT_HASH_ALG_SHA1,
- TPM2_SHA1_DIGEST_SIZE,
- },
- {
- TPM2_ALG_SHA256,
- EFI_TCG2_BOOT_HASH_ALG_SHA256,
- TPM2_SHA256_DIGEST_SIZE,
- },
- {
- TPM2_ALG_SHA384,
- EFI_TCG2_BOOT_HASH_ALG_SHA384,
- TPM2_SHA384_DIGEST_SIZE,
- },
- {
- TPM2_ALG_SHA512,
- EFI_TCG2_BOOT_HASH_ALG_SHA512,
- TPM2_SHA512_DIGEST_SIZE,
- },
-};
-
struct variable_info {
const u16 *name;
bool accept_empty;
@@ -113,46 +84,6 @@ static struct variable_info secure_variables[] = {
{u"AuditMode", false, 1},
};
-#define MAX_HASH_COUNT ARRAY_SIZE(hash_algo_list)
-
-/**
- * alg_to_mask - Get a TCG hash mask for algorithms
- *
- * @hash_alg: TCG defined algorithm
- *
- * @Return: TCG hashing algorithm bitmaps, 0 if the algorithm is not supported
- */
-static u32 alg_to_mask(u16 hash_alg)
-{
- size_t i;
-
- for (i = 0; i < MAX_HASH_COUNT; i++) {
- if (hash_algo_list[i].hash_alg == hash_alg)
- return hash_algo_list[i].hash_mask;
- }
-
- return 0;
-}
-
-/**
- * alg_to_len - Get a TCG hash len for algorithms
- *
- * @hash_alg: TCG defined algorithm
- *
- * @Return: len of chosen algorithm, 0 if the algorithm is not supported
- */
-static u16 alg_to_len(u16 hash_alg)
-{
- size_t i;
-
- for (i = 0; i < MAX_HASH_COUNT; i++) {
- if (hash_algo_list[i].hash_alg == hash_alg)
- return hash_algo_list[i].hash_len;
- }
-
- return 0;
-}
-
static bool is_tcg2_protocol_installed(void)
{
struct efi_handler *handler;
@@ -162,145 +93,6 @@ static bool is_tcg2_protocol_installed(void)
return ret == EFI_SUCCESS;
}
-static u32 tcg_event_final_size(struct tpml_digest_values *digest_list)
-{
- u32 len;
- size_t i;
-
- len = offsetof(struct tcg_pcr_event2, digests);
- len += offsetof(struct tpml_digest_values, digests);
- for (i = 0; i < digest_list->count; i++) {
- u16 hash_alg = digest_list->digests[i].hash_alg;
-
- len += offsetof(struct tpmt_ha, digest);
- len += alg_to_len(hash_alg);
- }
- len += sizeof(u32); /* tcg_pcr_event2 event_size*/
-
- return len;
-}
-
-/* tcg2_pcr_extend - Extend 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_extend(struct udevice *dev, u32 pcr_index,
- struct tpml_digest_values *digest_list)
-{
- u32 rc;
- size_t i;
-
- for (i = 0; i < digest_list->count; i++) {
- u32 alg = digest_list->digests[i].hash_alg;
-
- rc = tpm2_pcr_extend(dev, pcr_index, alg,
- (u8 *)&digest_list->digests[i].digest,
- alg_to_len(alg));
- if (rc) {
- EFI_PRINT("Failed to extend PCR\n");
- return EFI_DEVICE_ERROR;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/* tcg2_pcr_read - Read PCRs for a TPM2 device for a given tpml_digest_values
- *
- * @dev: device
- * @pcr_index: PCR index
- * @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;
-}
-
-/* put_event - Append an agile event to an eventlog
- *
- * @pcr_index: PCR index
- * @event_type: type of event added
- * @digest_list: list of digest algorithms to add
- * @size: size of event
- * @event: event to add
- * @log: log buffer to append the event
- *
- */
-static void put_event(u32 pcr_index, u32 event_type,
- struct tpml_digest_values *digest_list, u32 size,
- u8 event[], void *log)
-{
- size_t pos;
- size_t i;
- u32 event_size;
-
- /*
- * size refers to the length of event[] only, we need to check against
- * the final tcg_pcr_event2 size
- */
- event_size = size + tcg_event_final_size(digest_list);
-
- put_unaligned_le32(pcr_index, log);
- pos = offsetof(struct tcg_pcr_event2, event_type);
- put_unaligned_le32(event_type, (void *)((uintptr_t)log + pos));
- pos = offsetof(struct tcg_pcr_event2, digests); /* count */
- put_unaligned_le32(digest_list->count, (void *)((uintptr_t)log + pos));
-
- pos += offsetof(struct tpml_digest_values, digests);
- 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;
-
- put_unaligned_le16(hash_alg, (void *)((uintptr_t)log + pos));
- pos += offsetof(struct tpmt_ha, digest);
- memcpy((void *)((uintptr_t)log + pos), digest, alg_to_len(hash_alg));
- pos += alg_to_len(hash_alg);
- }
-
- put_unaligned_le32(size, (void *)((uintptr_t)log + pos));
- pos += sizeof(u32); /* tcg_pcr_event2 event_size*/
- memcpy((void *)((uintptr_t)log + pos), event, size);
- pos += size;
-
- /*
- * make sure the calculated buffer is what we checked against
- * This check should never fail. It checks the code above is
- * calculating the right length for the event we are adding
- */
- if (pos != event_size)
- log_err("Appending to the EventLog failed\n");
-}
-
/* tcg2_agile_log_append - Append an agile event to an eventlog
*
* @pcr_index: PCR index
@@ -317,7 +109,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type,
u32 size, u8 event[])
{
void *log = (void *)((uintptr_t)event_log.buffer + event_log.pos);
- u32 event_size = size + tcg_event_final_size(digest_list);
+ u32 event_size = size + tcg2_event_get_size(digest_list);
struct efi_tcg2_final_events_table *final_event;
efi_status_t ret = EFI_SUCCESS;
@@ -328,7 +120,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type,
event_log.truncated = true;
return EFI_VOLUME_FULL;
}
- put_event(pcr_index, event_type, digest_list, size, event, log);
+ tcg2_log_append(pcr_index, event_type, digest_list, size, event, log);
event_log.pos += event_size;
event_log.last_event_size = event_size;
}
@@ -341,7 +133,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type,
return EFI_VOLUME_FULL;
log = (void *)((uintptr_t)event_log.final_buffer + event_log.final_pos);
- put_event(pcr_index, event_type, digest_list, size, event, log);
+ tcg2_log_append(pcr_index, event_type, digest_list, size, event, log);
final_event = event_log.final_buffer;
final_event->number_of_events++;
@@ -351,66 +143,6 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type,
}
/**
- * platform_get_tpm_device() - retrieve TPM device
- *
- * This function retrieves the udevice implementing a TPM
- *
- * This function may be overridden if special initialization is needed.
- *
- * @dev: udevice
- * Return: status code
- */
-__weak efi_status_t platform_get_tpm2_device(struct udevice **dev)
-{
- for_each_tpm_device(*dev) {
- /* Only support TPMv2 devices */
- if (tpm_get_version(*dev) == TPM_V2)
- return EFI_SUCCESS;
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- * platform_get_eventlog() - retrieve the eventlog address and size
- *
- * This function retrieves the eventlog address and size if the underlying
- * firmware has done some measurements and passed them.
- *
- * This function may be overridden based on platform specific method of
- * passing the eventlog address and size.
- *
- * @dev: udevice
- * @addr: eventlog address
- * @sz: eventlog size
- * Return: status code
- */
-__weak efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr,
- u32 *sz)
-{
- const u64 *basep;
- const u32 *sizep;
-
- basep = dev_read_prop(dev, "tpm_event_log_addr", NULL);
- if (!basep)
- return EFI_NOT_FOUND;
-
- *addr = be64_to_cpup((__force __be64 *)basep);
-
- sizep = dev_read_prop(dev, "tpm_event_log_size", NULL);
- if (!sizep)
- return EFI_NOT_FOUND;
-
- *sz = be32_to_cpup((__force __be32 *)sizep);
- if (*sz == 0) {
- log_debug("event log empty\n");
- return EFI_NOT_FOUND;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
* tpm2_get_max_command_size() - get the supported max command size
*
* @dev: TPM device
@@ -486,238 +218,6 @@ static int tpm2_get_manufacturer_id(struct udevice *dev, u32 *manufacturer_id)
}
/**
- * tpm2_get_num_pcr() - get the number of PCRs
- *
- * @dev: TPM device
- * @manufacturer_id: output buffer for the number
- *
- * Return: 0 on success, -1 on error
- */
-static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
-{
- u8 response[TPM2_RESPONSE_BUFFER_SIZE];
- u32 ret;
-
- memset(response, 0, sizeof(response));
- ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES,
- TPM2_PT_PCR_COUNT, response, 1);
- if (ret)
- return -1;
-
- *num_pcr = get_unaligned_be32(response + properties_offset);
- if (*num_pcr > TPM2_MAX_PCRS)
- return -1;
-
- return 0;
-}
-
-/**
- * is_active_pcr() - Check if a supported algorithm is active
- *
- * @dev: TPM device
- * @selection: struct of PCR information
- *
- * Return: true if PCR is active
- */
-static bool is_active_pcr(struct tpms_pcr_selection *selection)
-{
- int i;
- /*
- * check the pcr_select. If at least one of the PCRs supports the
- * algorithm add it on the active ones
- */
- for (i = 0; i < selection->size_of_select; i++) {
- if (selection->pcr_select[i])
- return true;
- }
-
- return false;
-}
-
-/**
- * tpm2_get_pcr_info() - get the supported, active PCRs and number of banks
- *
- * @dev: TPM device
- * @supported_pcr: bitmask with the algorithms supported
- * @active_pcr: bitmask with the active algorithms
- * @pcr_banks: number of PCR banks
- *
- * Return: 0 on success, -1 on error
- */
-static int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr,
- u32 *active_pcr, u32 *pcr_banks)
-{
- u8 response[TPM2_RESPONSE_BUFFER_SIZE];
- struct tpml_pcr_selection pcrs;
- u32 ret, num_pcr;
- size_t i;
- int tpm_ret;
-
- *supported_pcr = 0;
- *active_pcr = 0;
- *pcr_banks = 0;
- memset(response, 0, sizeof(response));
- ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
- if (ret)
- goto out;
-
- pcrs.count = get_unaligned_be32(response);
- /*
- * We only support 5 algorithms for now so check against that
- * instead of TPM2_NUM_PCR_BANKS
- */
- if (pcrs.count > MAX_HASH_COUNT || pcrs.count < 1)
- goto out;
-
- tpm_ret = tpm2_get_num_pcr(dev, &num_pcr);
- if (tpm_ret)
- goto out;
-
- for (i = 0; i < pcrs.count; i++) {
- /*
- * Definition of TPMS_PCR_SELECTION Structure
- * hash: u16
- * size_of_select: u8
- * pcr_select: u8 array
- *
- * The offsets depend on the number of the device PCRs
- * so we have to calculate them based on that
- */
- u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
- i * offsetof(struct tpms_pcr_selection, pcr_select) +
- i * ((num_pcr + 7) / 8);
- u32 size_select_offset =
- hash_offset + offsetof(struct tpms_pcr_selection,
- size_of_select);
- u32 pcr_select_offset =
- hash_offset + offsetof(struct tpms_pcr_selection,
- pcr_select);
-
- pcrs.selection[i].hash =
- get_unaligned_be16(response + hash_offset);
- pcrs.selection[i].size_of_select =
- __get_unaligned_be(response + size_select_offset);
- if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX)
- goto out;
- /* copy the array of pcr_select */
- memcpy(pcrs.selection[i].pcr_select, response + pcr_select_offset,
- pcrs.selection[i].size_of_select);
- }
-
- for (i = 0; i < pcrs.count; i++) {
- u32 hash_mask = alg_to_mask(pcrs.selection[i].hash);
-
- if (hash_mask) {
- *supported_pcr |= hash_mask;
- if (is_active_pcr(&pcrs.selection[i]))
- *active_pcr |= hash_mask;
- } else {
- EFI_PRINT("Unknown algorithm %x\n", pcrs.selection[i].hash);
- }
- }
-
- *pcr_banks = pcrs.count;
-
- return 0;
-out:
- return -1;
-}
-
-/**
- * __get_active_pcr_banks() - returns the currently active PCR banks
- *
- * @active_pcr_banks: pointer for receiving the bitmap of currently
- * active PCR banks
- *
- * Return: status code
- */
-static efi_status_t __get_active_pcr_banks(u32 *active_pcr_banks)
-{
- struct udevice *dev;
- u32 active = 0, supported = 0, pcr_banks = 0;
- efi_status_t ret;
- int err;
-
- ret = platform_get_tpm2_device(&dev);
- if (ret != EFI_SUCCESS)
- goto out;
-
- err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks);
- if (err) {
- ret = EFI_DEVICE_ERROR;
- goto out;
- }
-
- *active_pcr_banks = active;
-
-out:
- return ret;
-}
-
-/* tcg2_create_digest - create a list of digests of the supported PCR banks
- * for a given memory range
- *
- * @input: input memory
- * @length: length of buffer to calculate the digest
- * @digest_list: list of digests to fill in
- *
- * Return: status code
- */
-static efi_status_t tcg2_create_digest(const u8 *input, u32 length,
- struct tpml_digest_values *digest_list)
-{
- sha1_context ctx;
- sha256_context ctx_256;
- sha512_context ctx_512;
- u8 final[TPM2_SHA512_DIGEST_SIZE];
- efi_status_t ret;
- u32 active;
- size_t i;
-
- ret = __get_active_pcr_banks(&active);
- if (ret != EFI_SUCCESS)
- return ret;
-
- digest_list->count = 0;
- for (i = 0; i < MAX_HASH_COUNT; i++) {
- u16 hash_alg = hash_algo_list[i].hash_alg;
-
- if (!(active & alg_to_mask(hash_alg)))
- continue;
- switch (hash_alg) {
- case TPM2_ALG_SHA1:
- sha1_starts(&ctx);
- sha1_update(&ctx, input, length);
- sha1_finish(&ctx, final);
- break;
- case TPM2_ALG_SHA256:
- sha256_starts(&ctx_256);
- sha256_update(&ctx_256, input, length);
- sha256_finish(&ctx_256, final);
- break;
- case TPM2_ALG_SHA384:
- sha384_starts(&ctx_512);
- sha384_update(&ctx_512, input, length);
- sha384_finish(&ctx_512, final);
- break;
- case TPM2_ALG_SHA512:
- sha512_starts(&ctx_512);
- sha512_update(&ctx_512, input, length);
- sha512_finish(&ctx_512, final);
- break;
- default:
- continue;
- }
- digest_list->digests[digest_list->count].hash_alg = hash_alg;
- memcpy(&digest_list->digests[digest_list->count].digest, final,
- (u32)alg_to_len(hash_alg));
- digest_list->count++;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
* efi_tcg2_get_capability() - protocol capability information and state information
*
* @this: TCG2 protocol instance
@@ -758,7 +258,7 @@ efi_tcg2_get_capability(struct efi_tcg2_protocol *this,
capability->protocol_version.major = 1;
capability->protocol_version.minor = 1;
- efi_ret = platform_get_tpm2_device(&dev);
+ efi_ret = tcg2_platform_get_tpm2(&dev);
if (efi_ret != EFI_SUCCESS) {
capability->supported_event_logs = 0;
capability->hash_algorithm_bitmap = 0;
@@ -854,7 +354,7 @@ efi_tcg2_get_eventlog(struct efi_tcg2_protocol *this,
goto out;
}
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS) {
event_log_location = NULL;
event_log_last_entry = NULL;
@@ -889,6 +389,7 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size,
struct efi_image_regions *regs = NULL;
void *new_efi = NULL;
u8 hash[TPM2_SHA512_DIGEST_SIZE];
+ struct udevice *dev;
efi_status_t ret;
u32 active;
int i;
@@ -904,16 +405,20 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size,
goto out;
}
- ret = __get_active_pcr_banks(&active);
+ ret = tcg2_platform_get_tpm2(&dev);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ ret = tcg2_get_active_pcr_banks(dev, &active);
if (ret != EFI_SUCCESS) {
goto out;
}
digest_list->count = 0;
- for (i = 0; i < MAX_HASH_COUNT; i++) {
- u16 hash_alg = hash_algo_list[i].hash_alg;
+ for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); i++) {
+ u16 hash_alg = tpm2_supported_algorithms[i];
- if (!(active & alg_to_mask(hash_alg)))
+ if (!(active & tpm2_algorithm_to_mask(hash_alg)))
continue;
switch (hash_alg) {
case TPM2_ALG_SHA1:
@@ -933,7 +438,7 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size,
}
digest_list->digests[digest_list->count].hash_alg = hash_alg;
memcpy(&digest_list->digests[digest_list->count].digest, hash,
- (u32)alg_to_len(hash_alg));
+ (u32)tpm2_algorithm_to_len(hash_alg));
digest_list->count++;
}
@@ -973,7 +478,7 @@ efi_status_t tcg2_measure_pe_image(void *efi, u64 efi_size,
if (!is_tcg2_protocol_installed())
return EFI_SUCCESS;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
return EFI_SECURITY_VIOLATION;
@@ -1082,7 +587,7 @@ efi_tcg2_hash_log_extend_event(struct efi_tcg2_protocol *this, u64 flags,
goto out;
}
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
goto out;
@@ -1117,7 +622,7 @@ efi_tcg2_hash_log_extend_event(struct efi_tcg2_protocol *this, u64 flags,
ret = tcg2_hash_pe_image((void *)(uintptr_t)data_to_hash,
data_to_hash_len, &digest_list);
} else {
- ret = tcg2_create_digest((u8 *)(uintptr_t)data_to_hash,
+ ret = tcg2_create_digest(dev, (u8 *)(uintptr_t)data_to_hash,
data_to_hash_len, &digest_list);
}
@@ -1180,7 +685,7 @@ efi_tcg2_submit_command(struct efi_tcg2_protocol *this,
goto out;
}
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
goto out;
@@ -1209,6 +714,7 @@ static efi_status_t EFIAPI
efi_tcg2_get_active_pcr_banks(struct efi_tcg2_protocol *this,
u32 *active_pcr_banks)
{
+ struct udevice *dev;
efi_status_t ret;
EFI_ENTRY("%p, %p", this, active_pcr_banks);
@@ -1217,8 +723,11 @@ efi_tcg2_get_active_pcr_banks(struct efi_tcg2_protocol *this,
ret = EFI_INVALID_PARAMETER;
goto out;
}
+ ret = tcg2_platform_get_tpm2(&dev);
+ if (ret != EFI_SUCCESS)
+ goto out;
- ret = __get_active_pcr_banks(active_pcr_banks);
+ ret = tcg2_get_active_pcr_banks(dev, active_pcr_banks);
out:
return EFI_EXIT(ret);
@@ -1270,397 +779,6 @@ static const struct efi_tcg2_protocol efi_tcg2_protocol = {
};
/**
- * parse_event_log_header() - Parse and verify the event log header fields
- *
- * @buffer: Pointer to the start of the eventlog
- * @size: Size of the eventlog
- * @pos: Return offset of the next event in buffer right
- * after the event header i.e specID
- *
- * Return: status code
- */
-static efi_status_t parse_event_log_header(void *buffer, u32 size, u32 *pos)
-{
- struct tcg_pcr_event *event_header = (struct tcg_pcr_event *)buffer;
- int i = 0;
-
- if (size < sizeof(*event_header))
- return EFI_COMPROMISED_DATA;
-
- if (get_unaligned_le32(&event_header->pcr_index) != 0 ||
- get_unaligned_le32(&event_header->event_type) != EV_NO_ACTION)
- return EFI_COMPROMISED_DATA;
-
- for (i = 0; i < sizeof(event_header->digest); i++) {
- if (event_header->digest[i])
- return EFI_COMPROMISED_DATA;
- }
-
- *pos += sizeof(*event_header);
-
- return EFI_SUCCESS;
-}
-
-/**
- * parse_specid_event() - Parse and verify the specID Event in the eventlog
- *
- * @dev: udevice
- * @buffer: Pointer to the start of the eventlog
- * @log_size: Size of the eventlog
- * @pos: [in] Offset of specID event in the eventlog buffer
- * [out] Return offset of the next event in the buffer
- * after the specID
- * @digest_list: list of digests in the event
- *
- * Return: status code
- * @pos Offset in the eventlog where the specID event ends
- * @digest_list: list of digests in the event
- */
-static efi_status_t parse_specid_event(struct udevice *dev, void *buffer,
- u32 log_size, u32 *pos,
- struct tpml_digest_values *digest_list)
-{
- struct tcg_efi_spec_id_event *spec_event;
- struct tcg_pcr_event *event_header = (struct tcg_pcr_event *)buffer;
- size_t spec_event_size;
- u32 active = 0, supported = 0, pcr_count = 0, alg_count = 0;
- u32 spec_active = 0;
- u16 hash_alg;
- u8 vendor_sz;
- int err, i;
-
- if (*pos >= log_size || (*pos + sizeof(*spec_event)) > log_size)
- return EFI_COMPROMISED_DATA;
-
- /* Check specID event data */
- spec_event = (struct tcg_efi_spec_id_event *)((uintptr_t)buffer + *pos);
- /* Check for signature */
- if (memcmp(spec_event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03,
- sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03))) {
- log_err("specID Event: Signature mismatch\n");
- return EFI_COMPROMISED_DATA;
- }
-
- if (spec_event->spec_version_minor !=
- TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 ||
- spec_event->spec_version_major !=
- TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2)
- return EFI_COMPROMISED_DATA;
-
- if (spec_event->number_of_algorithms > MAX_HASH_COUNT ||
- spec_event->number_of_algorithms < 1) {
- log_err("specID Event: Number of algorithms incorrect\n");
- return EFI_COMPROMISED_DATA;
- }
-
- alg_count = spec_event->number_of_algorithms;
-
- err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_count);
- if (err)
- return EFI_DEVICE_ERROR;
-
- digest_list->count = 0;
- /*
- * We have to take care that the sequence of algorithms that we record
- * in digest_list matches the sequence in eventlog.
- */
- for (i = 0; i < alg_count; i++) {
- hash_alg =
- get_unaligned_le16(&spec_event->digest_sizes[i].algorithm_id);
-
- if (!(supported & alg_to_mask(hash_alg))) {
- log_err("specID Event: Unsupported algorithm\n");
- return EFI_COMPROMISED_DATA;
- }
- digest_list->digests[digest_list->count++].hash_alg = hash_alg;
-
- spec_active |= alg_to_mask(hash_alg);
- }
-
- /*
- * TCG specification expects the event log to have hashes for all
- * active PCR's
- */
- if (spec_active != active) {
- /*
- * Previous stage bootloader should know all the active PCR's
- * and use them in the Eventlog.
- */
- log_err("specID Event: All active hash alg not present\n");
- return EFI_COMPROMISED_DATA;
- }
-
- /*
- * the size of the spec event and placement of vendor_info_size
- * depends on supported algoriths
- */
- spec_event_size =
- offsetof(struct tcg_efi_spec_id_event, digest_sizes) +
- alg_count * sizeof(spec_event->digest_sizes[0]);
-
- if (*pos + spec_event_size >= log_size)
- return EFI_COMPROMISED_DATA;
-
- vendor_sz = *(uint8_t *)((uintptr_t)buffer + *pos + spec_event_size);
-
- spec_event_size += sizeof(vendor_sz) + vendor_sz;
- *pos += spec_event_size;
-
- if (get_unaligned_le32(&event_header->event_size) != spec_event_size) {
- log_err("specID event: header event size mismatch\n");
- /* Right way to handle this can be to call SetActive PCR's */
- return EFI_COMPROMISED_DATA;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- * tcg2_parse_event() - Parse the event in the eventlog
- *
- * @dev: udevice
- * @buffer: Pointer to the start of the eventlog
- * @log_size: Size of the eventlog
- * @offset: [in] Offset of the event in the eventlog buffer
- * [out] Return offset of the next event in the buffer
- * @digest_list: list of digests in the event
- * @pcr Index of the PCR in the event
- *
- * Return: status code
- */
-static efi_status_t tcg2_parse_event(struct udevice *dev, void *buffer,
- u32 log_size, u32 *offset,
- struct tpml_digest_values *digest_list,
- u32 *pcr)
-{
- struct tcg_pcr_event2 *event = NULL;
- u32 count, size, event_size;
- size_t pos;
-
- event_size = tcg_event_final_size(digest_list);
- if (*offset >= log_size || *offset + event_size > log_size) {
- log_err("Event exceeds log size\n");
- return EFI_COMPROMISED_DATA;
- }
-
- event = (struct tcg_pcr_event2 *)((uintptr_t)buffer + *offset);
- *pcr = get_unaligned_le32(&event->pcr_index);
-
- /* get the count */
- count = get_unaligned_le32(&event->digests.count);
- if (count != digest_list->count)
- return EFI_COMPROMISED_DATA;
-
- pos = offsetof(struct tcg_pcr_event2, digests);
- pos += offsetof(struct tpml_digest_values, digests);
-
- for (int i = 0; i < digest_list->count; i++) {
- u16 alg;
- u16 hash_alg = digest_list->digests[i].hash_alg;
- u8 *digest = (u8 *)&digest_list->digests[i].digest;
-
- alg = get_unaligned_le16((void *)((uintptr_t)event + pos));
-
- if (alg != hash_alg)
- return EFI_COMPROMISED_DATA;
-
- pos += offsetof(struct tpmt_ha, digest);
- memcpy(digest, (void *)((uintptr_t)event + pos), alg_to_len(hash_alg));
- pos += alg_to_len(hash_alg);
- }
-
- size = get_unaligned_le32((void *)((uintptr_t)event + pos));
- event_size += size;
- pos += sizeof(u32); /* tcg_pcr_event2 event_size*/
- pos += size;
-
- /* make sure the calculated buffer is what we checked against */
- if (pos != event_size)
- return EFI_COMPROMISED_DATA;
-
- if (pos > log_size)
- return EFI_COMPROMISED_DATA;
-
- *offset += pos;
-
- return EFI_SUCCESS;
-}
-
-/**
- * tcg2_get_fw_eventlog() - Get the eventlog address and size
- *
- * If the previous firmware has passed some eventlog, this function get it's
- * location and check for it's validity.
- *
- * @dev: udevice
- * @log_buffer: eventlog address
- * @log_sz: eventlog size
- *
- * Return: status code
- */
-static efi_status_t tcg2_get_fw_eventlog(struct udevice *dev, void *log_buffer,
- size_t *log_sz)
-{
- struct tpml_digest_values digest_list;
- void *buffer;
- efi_status_t ret;
- u32 pcr, pos;
- u64 base;
- u32 sz;
- bool extend_pcr = false;
- int i;
-
- ret = platform_get_eventlog(dev, &base, &sz);
- if (ret != EFI_SUCCESS)
- return ret;
-
- if (sz > TPM2_EVENT_LOG_SIZE)
- return EFI_VOLUME_FULL;
-
- buffer = (void *)(uintptr_t)base;
- pos = 0;
- /* Parse the eventlog to check for its validity */
- ret = parse_event_log_header(buffer, sz, &pos);
- if (ret)
- return ret;
-
- ret = parse_specid_event(dev, buffer, sz, &pos, &digest_list);
- if (ret) {
- log_err("Error parsing SPEC ID Event\n");
- return ret;
- }
-
- ret = tcg2_pcr_read(dev, 0, &digest_list);
- if (ret) {
- log_err("Error reading PCR 0\n");
- return ret;
- }
-
- /*
- * 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 hash_buf[TPM2_SHA512_DIGEST_SIZE] = { 0 };
- u16 hash_alg = digest_list.digests[i].hash_alg;
-
- if (!memcmp((u8 *)&digest_list.digests[i].digest, hash_buf,
- alg_to_len(hash_alg)))
- extend_pcr = true;
- }
-
- while (pos < sz) {
- ret = tcg2_parse_event(dev, buffer, sz, &pos, &digest_list,
- &pcr);
- if (ret) {
- log_err("Error parsing event\n");
- return ret;
- }
- if (extend_pcr) {
- ret = tcg2_pcr_extend(dev, pcr, &digest_list);
- if (ret != EFI_SUCCESS) {
- log_err("Error in extending PCR\n");
- return ret;
- }
-
- /* 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(log_buffer, buffer, sz);
- *log_sz = sz;
-
- return ret;
-}
-
-/**
- * create_specid_event() - Create the first event in the eventlog
- *
- * @dev: tpm device
- * @event_header: Pointer to the final event header
- * @event_size: final spec event size
- *
- * Return: status code
- */
-static efi_status_t create_specid_event(struct udevice *dev, void *buffer,
- size_t *event_size)
-{
- struct tcg_efi_spec_id_event *spec_event;
- size_t spec_event_size;
- efi_status_t ret = EFI_DEVICE_ERROR;
- u32 active = 0, supported = 0, pcr_count = 0, alg_count = 0;
- int err;
- size_t i;
-
- /*
- * Create Spec event. This needs to be the first event in the log
- * according to the TCG EFI protocol spec
- */
-
- /* Setup specID event data */
- spec_event = (struct tcg_efi_spec_id_event *)buffer;
- memcpy(spec_event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03,
- sizeof(spec_event->signature));
- put_unaligned_le32(0, &spec_event->platform_class); /* type client */
- spec_event->spec_version_minor =
- TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2;
- spec_event->spec_version_major =
- TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2;
- spec_event->spec_errata =
- TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2;
- spec_event->uintn_size = sizeof(efi_uintn_t) / sizeof(u32);
-
- err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_count);
-
- if (err)
- goto out;
-
- for (i = 0; i < pcr_count; i++) {
- u16 hash_alg = hash_algo_list[i].hash_alg;
- u16 hash_len = hash_algo_list[i].hash_len;
-
- if (active & alg_to_mask(hash_alg)) {
- put_unaligned_le16(hash_alg,
- &spec_event->digest_sizes[alg_count].algorithm_id);
- put_unaligned_le16(hash_len,
- &spec_event->digest_sizes[alg_count].digest_size);
- alg_count++;
- }
- }
-
- spec_event->number_of_algorithms = alg_count;
- if (spec_event->number_of_algorithms > MAX_HASH_COUNT ||
- spec_event->number_of_algorithms < 1)
- goto out;
-
- /*
- * the size of the spec event and placement of vendor_info_size
- * depends on supported algoriths
- */
- spec_event_size =
- offsetof(struct tcg_efi_spec_id_event, digest_sizes) +
- spec_event->number_of_algorithms * sizeof(spec_event->digest_sizes[0]);
- /* no vendor info for us */
- memset(buffer + spec_event_size, 0, 1);
- /* add a byte for vendor_info_size in the spec event */
- spec_event_size += 1;
- *event_size = spec_event_size;
-
- return EFI_SUCCESS;
-
-out:
- return ret;
-}
-
-/**
* tcg2_uninit - remove the final event table and free efi memory on failures
*/
void tcg2_uninit(void)
@@ -1721,7 +839,7 @@ out:
}
/**
- * tcg2_measure_event() - common function to add event log and extend PCR
+ * measure_event() - common function to add event log and extend PCR
*
* @dev: TPM device
* @pcr_index: PCR index
@@ -1731,14 +849,13 @@ out:
*
* Return: status code
*/
-static efi_status_t
-tcg2_measure_event(struct udevice *dev, u32 pcr_index, u32 event_type,
- u32 size, u8 event[])
+static efi_status_t measure_event(struct udevice *dev, u32 pcr_index,
+ u32 event_type, u32 size, u8 event[])
{
struct tpml_digest_values digest_list;
efi_status_t ret;
- ret = tcg2_create_digest(event, size, &digest_list);
+ ret = tcg2_create_digest(dev, event, size, &digest_list);
if (ret != EFI_SUCCESS)
goto out;
@@ -1765,9 +882,8 @@ static efi_status_t efi_append_scrtm_version(struct udevice *dev)
{
efi_status_t ret;
- ret = tcg2_measure_event(dev, 0, EV_S_CRTM_VERSION,
- strlen(version_string) + 1,
- (u8 *)version_string);
+ ret = measure_event(dev, 0, EV_S_CRTM_VERSION,
+ strlen(version_string) + 1, (u8 *)version_string);
return ret;
}
@@ -1783,12 +899,11 @@ static efi_status_t efi_init_event_log(void)
* vendor_info_size is currently set to 0, we need to change the length
* and allocate the flexible array member if this changes
*/
- struct tcg_pcr_event *event_header = NULL;
+ struct tcg2_event_log elog;
struct udevice *dev;
- size_t spec_event_size;
efi_status_t ret;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
return ret;
@@ -1807,7 +922,6 @@ static efi_status_t efi_init_event_log(void)
* The log header is defined to be in SHA1 event log entry format.
* Setup event header
*/
- event_header = (struct tcg_pcr_event *)event_log.buffer;
event_log.pos = 0;
event_log.last_event_size = 0;
event_log.get_event_called = false;
@@ -1818,34 +932,20 @@ static efi_status_t efi_init_event_log(void)
* Check if earlier firmware have passed any eventlog. Different
* platforms can use different ways to do so.
*/
- ret = tcg2_get_fw_eventlog(dev, event_log.buffer, &event_log.pos);
+ elog.log = event_log.buffer;
+ elog.log_size = TPM2_EVENT_LOG_SIZE;
+ ret = tcg2_log_prepare_buffer(dev, &elog, false);
+ if (ret != EFI_SUCCESS)
+ goto free_pool;
+
+ event_log.pos = elog.log_position;
+
/*
- * If earlier firmware hasn't passed any eventlog, go ahead and
- * create the eventlog header.
+ * Add SCRTM version to the log if previous firmmware
+ * doesn't pass an eventlog.
*/
- if (ret == EFI_NOT_FOUND) {
- put_unaligned_le32(0, &event_header->pcr_index);
- put_unaligned_le32(EV_NO_ACTION, &event_header->event_type);
- memset(&event_header->digest, 0, sizeof(event_header->digest));
- ret = create_specid_event(dev,
- (void *)((uintptr_t)event_log.buffer +
- sizeof(*event_header)),
- &spec_event_size);
- if (ret != EFI_SUCCESS)
- goto free_pool;
- put_unaligned_le32(spec_event_size, &event_header->event_size);
- event_log.pos = spec_event_size + sizeof(*event_header);
- event_log.last_event_size = event_log.pos;
-
- /*
- * Add SCRTM version to the log if previous firmmware
- * doesn't pass an eventlog.
- */
+ if (!elog.found)
ret = efi_append_scrtm_version(dev);
- }
-
- if (ret != EFI_SUCCESS)
- goto free_pool;
ret = create_final_event();
if (ret != EFI_SUCCESS)
@@ -1898,8 +998,8 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,
memcpy((u16 *)event->unicode_name + event->unicode_name_length,
data, data_size);
}
- ret = tcg2_measure_event(dev, pcr_index, event_type, event_size,
- (u8 *)event);
+ ret = measure_event(dev, pcr_index, event_type, event_size,
+ (u8 *)event);
free(event);
return ret;
}
@@ -2010,8 +1110,8 @@ tcg2_measure_smbios(struct udevice *dev,
smbios_prepare_measurement(entry, smbios_copy);
- ret = tcg2_measure_event(dev, 1, EV_EFI_HANDOFF_TABLES2, event_size,
- (u8 *)event);
+ ret = measure_event(dev, 1, EV_EFI_HANDOFF_TABLES2, event_size,
+ (u8 *)event);
if (ret != EFI_SUCCESS)
goto out;
@@ -2162,7 +1262,7 @@ tcg2_measure_gpt_data(struct udevice *dev,
gpt_e = (gpt_entry *)((u8 *)gpt_e + gpt_h->sizeof_partition_entry);
}
- ret = tcg2_measure_event(dev, 5, EV_EFI_GPT_EVENT, event_size, (u8 *)event);
+ ret = measure_event(dev, 5, EV_EFI_GPT_EVENT, event_size, (u8 *)event);
out2:
free(gpt_h);
@@ -2216,7 +1316,7 @@ efi_status_t efi_tcg2_measure_dtb(void *dtb)
if (!is_tcg2_protocol_installed())
return EFI_SUCCESS;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
return EFI_SECURITY_VIOLATION;
@@ -2241,7 +1341,7 @@ efi_status_t efi_tcg2_measure_dtb(void *dtb)
sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_mem_rsvmap(dtb), rsvmap_size);
sha256_finish(&hash_ctx, blob->data + blob->blob_description_size);
- ret = tcg2_measure_event(dev, 0, EV_POST_CODE, event_size, (u8 *)blob);
+ ret = measure_event(dev, 0, EV_POST_CODE, event_size, (u8 *)blob);
free(blob);
return ret;
@@ -2266,7 +1366,7 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *ha
if (tcg2_efi_app_invoked)
return EFI_SUCCESS;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
return EFI_SECURITY_VIOLATION;
@@ -2274,9 +1374,9 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *ha
if (ret != EFI_SUCCESS)
goto out;
- ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,
- strlen(EFI_CALLING_EFI_APPLICATION),
- (u8 *)EFI_CALLING_EFI_APPLICATION);
+ ret = measure_event(dev, 4, EV_EFI_ACTION,
+ strlen(EFI_CALLING_EFI_APPLICATION),
+ (u8 *)EFI_CALLING_EFI_APPLICATION);
if (ret != EFI_SUCCESS)
goto out;
@@ -2292,8 +1392,8 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *ha
goto out;
for (pcr_index = 0; pcr_index <= 7; pcr_index++) {
- ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,
- sizeof(event), (u8 *)&event);
+ ret = measure_event(dev, pcr_index, EV_SEPARATOR,
+ sizeof(event), (u8 *)&event);
if (ret != EFI_SUCCESS)
goto out;
}
@@ -2316,13 +1416,13 @@ efi_status_t efi_tcg2_measure_efi_app_exit(void)
if (!is_tcg2_protocol_installed())
return EFI_SUCCESS;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
return ret;
- ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,
- strlen(EFI_RETURNING_FROM_EFI_APPLICATION),
- (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);
+ ret = measure_event(dev, 4, EV_EFI_ACTION,
+ strlen(EFI_RETURNING_FROM_EFI_APPLICATION),
+ (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);
return ret;
}
@@ -2347,19 +1447,19 @@ efi_tcg2_notify_exit_boot_services(struct efi_event *event, void *context)
goto out;
}
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
goto out;
- ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION,
- strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION),
- (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION);
+ ret = measure_event(dev, 5, EV_EFI_ACTION,
+ strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION),
+ (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION);
if (ret != EFI_SUCCESS)
goto out;
- ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION,
- strlen(EFI_EXIT_BOOT_SERVICES_SUCCEEDED),
- (u8 *)EFI_EXIT_BOOT_SERVICES_SUCCEEDED);
+ ret = measure_event(dev, 5, EV_EFI_ACTION,
+ strlen(EFI_EXIT_BOOT_SERVICES_SUCCEEDED),
+ (u8 *)EFI_EXIT_BOOT_SERVICES_SUCCEEDED);
out:
EFI_EXIT(ret);
@@ -2379,19 +1479,19 @@ efi_status_t efi_tcg2_notify_exit_boot_services_failed(void)
if (!is_tcg2_protocol_installed())
return EFI_SUCCESS;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
goto out;
- ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION,
- strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION),
- (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION);
+ ret = measure_event(dev, 5, EV_EFI_ACTION,
+ strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION),
+ (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION);
if (ret != EFI_SUCCESS)
goto out;
- ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION,
- strlen(EFI_EXIT_BOOT_SERVICES_FAILED),
- (u8 *)EFI_EXIT_BOOT_SERVICES_FAILED);
+ ret = measure_event(dev, 5, EV_EFI_ACTION,
+ strlen(EFI_EXIT_BOOT_SERVICES_FAILED),
+ (u8 *)EFI_EXIT_BOOT_SERVICES_FAILED);
out:
return ret;
@@ -2461,7 +1561,7 @@ efi_status_t efi_tcg2_do_initial_measurement(void)
if (!is_tcg2_protocol_installed())
return EFI_SUCCESS;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS)
return EFI_SECURITY_VIOLATION;
@@ -2487,7 +1587,7 @@ efi_status_t efi_tcg2_register(void)
struct efi_event *event;
u32 err;
- ret = platform_get_tpm2_device(&dev);
+ ret = tcg2_platform_get_tpm2(&dev);
if (ret != EFI_SUCCESS) {
log_warning("Missing TPMv2 device for EFI_TCG_PROTOCOL\n");
return EFI_SUCCESS;
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 9ab5b46..bd0fb07 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -1,16 +1,705 @@
// SPDX-License-Identifier: GPL-2.0+
/*
+ * Copyright (c) 2023 Linaro Limited
* Copyright (c) 2018 Bootlin
* Author: Miquel Raynal <miquel.raynal@bootlin.com>
*/
#include <common.h>
#include <dm.h>
+#include <dm/of_access.h>
+#include <tpm_api.h>
#include <tpm-common.h>
#include <tpm-v2.h>
+#include <u-boot/sha1.h>
+#include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
+#include <version_string.h>
+#include <asm/io.h>
#include <linux/bitops.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
+#include <linux/unaligned/le_byteshift.h>
+
#include "tpm-utils.h"
+const enum tpm2_algorithms tpm2_supported_algorithms[4] = {
+ TPM2_ALG_SHA1,
+ TPM2_ALG_SHA256,
+ TPM2_ALG_SHA384,
+ TPM2_ALG_SHA512,
+};
+
+int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks)
+{
+ u32 supported = 0;
+ u32 pcr_banks = 0;
+ u32 active = 0;
+ int rc;
+
+ rc = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks);
+ if (rc)
+ return rc;
+
+ *active_pcr_banks = active;
+
+ return 0;
+}
+
+u32 tcg2_event_get_size(struct tpml_digest_values *digest_list)
+{
+ u32 len;
+ size_t i;
+
+ len = offsetof(struct tcg_pcr_event2, digests);
+ len += offsetof(struct tpml_digest_values, digests);
+ for (i = 0; i < digest_list->count; ++i) {
+ u16 l = tpm2_algorithm_to_len(digest_list->digests[i].hash_alg);
+
+ if (!l)
+ continue;
+
+ len += l + offsetof(struct tpmt_ha, digest);
+ }
+ len += sizeof(u32);
+
+ return len;
+}
+
+int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length,
+ struct tpml_digest_values *digest_list)
+{
+ u8 final[sizeof(union tpmu_ha)];
+ sha256_context ctx_256;
+ sha512_context ctx_512;
+ sha1_context ctx;
+ u32 active;
+ size_t i;
+ u32 len;
+ int rc;
+
+ rc = tcg2_get_active_pcr_banks(dev, &active);
+ if (rc)
+ return rc;
+
+ digest_list->count = 0;
+ for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) {
+ u32 mask =
+ tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]);
+
+ if (!(active & mask))
+ continue;
+
+ switch (tpm2_supported_algorithms[i]) {
+ case TPM2_ALG_SHA1:
+ sha1_starts(&ctx);
+ sha1_update(&ctx, input, length);
+ sha1_finish(&ctx, final);
+ len = TPM2_SHA1_DIGEST_SIZE;
+ break;
+ case TPM2_ALG_SHA256:
+ sha256_starts(&ctx_256);
+ sha256_update(&ctx_256, input, length);
+ sha256_finish(&ctx_256, final);
+ len = TPM2_SHA256_DIGEST_SIZE;
+ break;
+ case TPM2_ALG_SHA384:
+ sha384_starts(&ctx_512);
+ sha384_update(&ctx_512, input, length);
+ sha384_finish(&ctx_512, final);
+ len = TPM2_SHA384_DIGEST_SIZE;
+ break;
+ case TPM2_ALG_SHA512:
+ sha512_starts(&ctx_512);
+ sha512_update(&ctx_512, input, length);
+ sha512_finish(&ctx_512, final);
+ len = TPM2_SHA512_DIGEST_SIZE;
+ break;
+ default:
+ printf("%s: unsupported algorithm %x\n", __func__,
+ tpm2_supported_algorithms[i]);
+ continue;
+ }
+
+ digest_list->digests[digest_list->count].hash_alg =
+ tpm2_supported_algorithms[i];
+ memcpy(&digest_list->digests[digest_list->count].digest, final,
+ len);
+ digest_list->count++;
+ }
+
+ return 0;
+}
+
+void tcg2_log_append(u32 pcr_index, u32 event_type,
+ struct tpml_digest_values *digest_list, u32 size,
+ const u8 *event, u8 *log)
+{
+ size_t len;
+ size_t pos;
+ u32 i;
+
+ pos = offsetof(struct tcg_pcr_event2, pcr_index);
+ put_unaligned_le32(pcr_index, log);
+ pos = offsetof(struct tcg_pcr_event2, event_type);
+ put_unaligned_le32(event_type, log + pos);
+ pos = offsetof(struct tcg_pcr_event2, digests) +
+ offsetof(struct tpml_digest_values, count);
+ put_unaligned_le32(digest_list->count, log + pos);
+
+ pos = offsetof(struct tcg_pcr_event2, digests) +
+ offsetof(struct tpml_digest_values, digests);
+ for (i = 0; i < digest_list->count; ++i) {
+ u16 hash_alg = digest_list->digests[i].hash_alg;
+
+ len = tpm2_algorithm_to_len(hash_alg);
+ if (!len)
+ continue;
+
+ pos += offsetof(struct tpmt_ha, hash_alg);
+ put_unaligned_le16(hash_alg, log + pos);
+ pos += offsetof(struct tpmt_ha, digest);
+ memcpy(log + pos, (u8 *)&digest_list->digests[i].digest, len);
+ pos += len;
+ }
+
+ put_unaligned_le32(size, log + pos);
+ pos += sizeof(u32);
+ memcpy(log + pos, event, size);
+}
+
+static int tcg2_log_append_check(struct tcg2_event_log *elog, u32 pcr_index,
+ u32 event_type,
+ struct tpml_digest_values *digest_list,
+ u32 size, const u8 *event)
+{
+ u32 event_size;
+ u8 *log;
+
+ event_size = size + tcg2_event_get_size(digest_list);
+ if (elog->log_position + event_size > elog->log_size) {
+ printf("%s: log too large: %u + %u > %u\n", __func__,
+ elog->log_position, event_size, elog->log_size);
+ return -ENOBUFS;
+ }
+
+ log = elog->log + elog->log_position;
+ elog->log_position += event_size;
+
+ tcg2_log_append(pcr_index, event_type, digest_list, size, event, log);
+
+ return 0;
+}
+
+static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog)
+{
+ struct tcg_efi_spec_id_event *ev;
+ struct tcg_pcr_event *log;
+ u32 event_size;
+ u32 count = 0;
+ u32 log_size;
+ u32 active;
+ u32 mask;
+ size_t i;
+ u16 len;
+ int rc;
+
+ rc = tcg2_get_active_pcr_banks(dev, &active);
+ if (rc)
+ return rc;
+
+ event_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes);
+ for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) {
+ mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]);
+
+ if (!(active & mask))
+ continue;
+
+ switch (tpm2_supported_algorithms[i]) {
+ case TPM2_ALG_SHA1:
+ case TPM2_ALG_SHA256:
+ case TPM2_ALG_SHA384:
+ case TPM2_ALG_SHA512:
+ count++;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ event_size += 1 +
+ (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count);
+ log_size = offsetof(struct tcg_pcr_event, event) + event_size;
+
+ if (log_size > elog->log_size) {
+ printf("%s: log too large: %u > %u\n", __func__, log_size,
+ elog->log_size);
+ return -ENOBUFS;
+ }
+
+ log = (struct tcg_pcr_event *)elog->log;
+ put_unaligned_le32(0, &log->pcr_index);
+ put_unaligned_le32(EV_NO_ACTION, &log->event_type);
+ memset(&log->digest, 0, sizeof(log->digest));
+ put_unaligned_le32(event_size, &log->event_size);
+
+ ev = (struct tcg_efi_spec_id_event *)log->event;
+ strlcpy((char *)ev->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03,
+ sizeof(ev->signature));
+ put_unaligned_le32(0, &ev->platform_class);
+ ev->spec_version_minor = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2;
+ ev->spec_version_major = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2;
+ ev->spec_errata = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2;
+ ev->uintn_size = sizeof(size_t) / sizeof(u32);
+ put_unaligned_le32(count, &ev->number_of_algorithms);
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) {
+ mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]);
+
+ if (!(active & mask))
+ continue;
+
+ len = tpm2_algorithm_to_len(tpm2_supported_algorithms[i]);
+ if (!len)
+ continue;
+
+ put_unaligned_le16(tpm2_supported_algorithms[i],
+ &ev->digest_sizes[count].algorithm_id);
+ put_unaligned_le16(len, &ev->digest_sizes[count].digest_size);
+ count++;
+ }
+
+ *((u8 *)ev + (event_size - 1)) = 0;
+ elog->log_position = log_size;
+
+ return 0;
+}
+
+static int tcg2_replay_eventlog(struct tcg2_event_log *elog,
+ struct udevice *dev,
+ struct tpml_digest_values *digest_list,
+ u32 log_position)
+{
+ const u32 offset = offsetof(struct tcg_pcr_event2, digests) +
+ offsetof(struct tpml_digest_values, digests);
+ u32 event_size;
+ u32 count;
+ u16 algo;
+ u32 pcr;
+ u32 pos;
+ u16 len;
+ u8 *log;
+ int rc;
+ u32 i;
+
+ while (log_position + offset < elog->log_size) {
+ log = elog->log + log_position;
+
+ pos = offsetof(struct tcg_pcr_event2, pcr_index);
+ pcr = get_unaligned_le32(log + pos);
+ pos = offsetof(struct tcg_pcr_event2, event_type);
+ if (!get_unaligned_le32(log + pos))
+ return 0;
+
+ pos = offsetof(struct tcg_pcr_event2, digests) +
+ offsetof(struct tpml_digest_values, count);
+ count = get_unaligned_le32(log + pos);
+ if (count > ARRAY_SIZE(tpm2_supported_algorithms) ||
+ (digest_list->count && digest_list->count != count))
+ return 0;
+
+ pos = offsetof(struct tcg_pcr_event2, digests) +
+ offsetof(struct tpml_digest_values, digests);
+ for (i = 0; i < count; ++i) {
+ pos += offsetof(struct tpmt_ha, hash_alg);
+ if (log_position + pos + sizeof(u16) >= elog->log_size)
+ return 0;
+
+ algo = get_unaligned_le16(log + pos);
+ pos += offsetof(struct tpmt_ha, digest);
+ switch (algo) {
+ case TPM2_ALG_SHA1:
+ case TPM2_ALG_SHA256:
+ case TPM2_ALG_SHA384:
+ case TPM2_ALG_SHA512:
+ len = tpm2_algorithm_to_len(algo);
+ break;
+ default:
+ return 0;
+ }
+
+ if (digest_list->count) {
+ if (algo != digest_list->digests[i].hash_alg ||
+ log_position + pos + len >= elog->log_size)
+ return 0;
+
+ memcpy(digest_list->digests[i].digest.sha512,
+ log + pos, len);
+ }
+
+ pos += len;
+ }
+
+ if (log_position + pos + sizeof(u32) >= elog->log_size)
+ return 0;
+
+ event_size = get_unaligned_le32(log + pos);
+ pos += event_size + sizeof(u32);
+ if (log_position + pos > elog->log_size)
+ return 0;
+
+ if (digest_list->count) {
+ rc = tcg2_pcr_extend(dev, pcr, digest_list);
+ if (rc)
+ return rc;
+ }
+
+ log_position += pos;
+ }
+
+ elog->log_position = log_position;
+ elog->found = true;
+ return 0;
+}
+
+static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
+{
+ struct tpml_digest_values digest_list;
+ struct tcg_efi_spec_id_event *event;
+ struct tcg_pcr_event *log;
+ u32 log_active;
+ u32 calc_size;
+ u32 active;
+ u32 count;
+ u32 evsz;
+ u32 mask;
+ u16 algo;
+ u16 len;
+ int rc;
+ u32 i;
+ u16 j;
+
+ if (elog->log_size <= offsetof(struct tcg_pcr_event, event))
+ return 0;
+
+ log = (struct tcg_pcr_event *)elog->log;
+ if (get_unaligned_le32(&log->pcr_index) != 0 ||
+ get_unaligned_le32(&log->event_type) != EV_NO_ACTION)
+ return 0;
+
+ for (i = 0; i < sizeof(log->digest); i++) {
+ if (log->digest[i])
+ return 0;
+ }
+
+ evsz = get_unaligned_le32(&log->event_size);
+ if (evsz < offsetof(struct tcg_efi_spec_id_event, digest_sizes) ||
+ evsz + offsetof(struct tcg_pcr_event, event) > elog->log_size)
+ return 0;
+
+ event = (struct tcg_efi_spec_id_event *)log->event;
+ if (memcmp(event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03,
+ sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03)))
+ return 0;
+
+ if (event->spec_version_minor != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 ||
+ event->spec_version_major != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2)
+ return 0;
+
+ count = get_unaligned_le32(&event->number_of_algorithms);
+ if (count > ARRAY_SIZE(tpm2_supported_algorithms))
+ return 0;
+
+ calc_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes) +
+ (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count) +
+ 1;
+ if (evsz != calc_size)
+ return 0;
+
+ rc = tcg2_get_active_pcr_banks(dev, &active);
+ if (rc)
+ return rc;
+
+ digest_list.count = 0;
+ log_active = 0;
+
+ for (i = 0; i < count; ++i) {
+ algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id);
+ mask = tpm2_algorithm_to_mask(algo);
+
+ if (!(active & mask))
+ return 0;
+
+ switch (algo) {
+ case TPM2_ALG_SHA1:
+ case TPM2_ALG_SHA256:
+ case TPM2_ALG_SHA384:
+ case TPM2_ALG_SHA512:
+ len = get_unaligned_le16(&event->digest_sizes[i].digest_size);
+ if (tpm2_algorithm_to_len(algo) != len)
+ return 0;
+ digest_list.digests[digest_list.count++].hash_alg = algo;
+ break;
+ default:
+ return 0;
+ }
+
+ log_active |= mask;
+ }
+
+ /* Ensure the previous firmware extended all the PCRs. */
+ if (log_active != active)
+ return 0;
+
+ /* Read PCR0 to check if previous firmware extended the PCRs or not. */
+ rc = tcg2_pcr_read(dev, 0, &digest_list);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < digest_list.count; ++i) {
+ len = tpm2_algorithm_to_len(digest_list.digests[i].hash_alg);
+ for (j = 0; j < len; ++j) {
+ if (digest_list.digests[i].digest.sha512[j])
+ break;
+ }
+
+ /* PCR is non-zero; it has been extended, so skip extending. */
+ if (j != len) {
+ digest_list.count = 0;
+ break;
+ }
+ }
+
+ return tcg2_replay_eventlog(elog, dev, &digest_list,
+ offsetof(struct tcg_pcr_event, event) +
+ evsz);
+}
+
+int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
+ struct tpml_digest_values *digest_list)
+{
+ u32 rc;
+ u32 i;
+
+ for (i = 0; i < digest_list->count; i++) {
+ u32 alg = digest_list->digests[i].hash_alg;
+
+ rc = tpm2_pcr_extend(dev, pcr_index, alg,
+ (u8 *)&digest_list->digests[i].digest,
+ tpm2_algorithm_to_len(alg));
+ if (rc) {
+ printf("%s: error pcr:%u alg:%08x\n", __func__,
+ pcr_index, alg);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+int tcg2_pcr_read(struct udevice *dev, u32 pcr_index,
+ struct tpml_digest_values *digest_list)
+{
+ struct tpm_chip_priv *priv;
+ u32 rc;
+ u32 i;
+
+ priv = dev_get_uclass_priv(dev);
+ if (!priv)
+ return -ENODEV;
+
+ for (i = 0; i < digest_list->count; i++) {
+ u32 alg = digest_list->digests[i].hash_alg;
+ u8 *digest = (u8 *)&digest_list->digests[i].digest;
+
+ rc = tpm2_pcr_read(dev, pcr_index, priv->pcr_select_min, alg,
+ digest, tpm2_algorithm_to_len(alg), NULL);
+ if (rc) {
+ printf("%s: error pcr:%u alg:%08x\n", __func__,
+ pcr_index, alg);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog,
+ u32 pcr_index, u32 size, const u8 *data, u32 event_type,
+ u32 event_size, const u8 *event)
+{
+ struct tpml_digest_values digest_list;
+ int rc;
+
+ if (data)
+ rc = tcg2_create_digest(dev, data, size, &digest_list);
+ else
+ rc = tcg2_create_digest(dev, event, event_size, &digest_list);
+ if (rc)
+ return rc;
+
+ rc = tcg2_pcr_extend(dev, pcr_index, &digest_list);
+ if (rc)
+ return rc;
+
+ return tcg2_log_append_check(elog, pcr_index, event_type, &digest_list,
+ event_size, event);
+}
+
+int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
+ bool ignore_existing_log)
+{
+ struct tcg2_event_log log;
+ int rc;
+
+ elog->log_position = 0;
+ elog->found = false;
+
+ rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size);
+ if (!rc) {
+ log.log_position = 0;
+ log.found = false;
+
+ if (!ignore_existing_log) {
+ rc = tcg2_log_parse(dev, &log);
+ if (rc)
+ return rc;
+ }
+
+ if (elog->log_size) {
+ if (log.found) {
+ if (elog->log_size < log.log_position)
+ return -ENOSPC;
+
+ /*
+ * Copy the discovered log into the user buffer
+ * if there's enough space.
+ */
+ memcpy(elog->log, log.log, log.log_position);
+ }
+
+ unmap_physmem(log.log, MAP_NOCACHE);
+ } else {
+ elog->log = log.log;
+ elog->log_size = log.log_size;
+ }
+
+ elog->log_position = log.log_position;
+ elog->found = log.found;
+ }
+
+ /*
+ * Initialize the log buffer if no log was discovered and the buffer is
+ * valid. User's can pass in their own buffer as a fallback if no
+ * memory region is found.
+ */
+ if (!elog->found && elog->log_size)
+ rc = tcg2_log_init(dev, elog);
+
+ return rc;
+}
+
+int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog,
+ bool ignore_existing_log)
+{
+ int rc;
+
+ rc = tcg2_platform_get_tpm2(dev);
+ if (rc)
+ return rc;
+
+ rc = tpm_auto_start(*dev);
+ if (rc)
+ return rc;
+
+ rc = tcg2_log_prepare_buffer(*dev, elog, ignore_existing_log);
+ if (rc) {
+ tcg2_measurement_term(*dev, elog, true);
+ return rc;
+ }
+
+ rc = tcg2_measure_event(*dev, elog, 0, EV_S_CRTM_VERSION,
+ strlen(version_string) + 1,
+ (u8 *)version_string);
+ if (rc) {
+ tcg2_measurement_term(*dev, elog, true);
+ return rc;
+ }
+
+ return 0;
+}
+
+void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog,
+ bool error)
+{
+ u32 event = error ? 0x1 : 0xffffffff;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ tcg2_measure_event(dev, elog, i, EV_SEPARATOR, sizeof(event),
+ (const u8 *)&event);
+
+ if (elog->log)
+ unmap_physmem(elog->log, MAP_NOCACHE);
+}
+
+__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
+{
+ const __be32 *addr_prop;
+ const __be32 *size_prop;
+ int asize;
+ int ssize;
+
+ *addr = NULL;
+ *size = 0;
+
+ addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize);
+ if (!addr_prop)
+ addr_prop = dev_read_prop(dev, "linux,sml-base", &asize);
+
+ size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize);
+ if (!size_prop)
+ size_prop = dev_read_prop(dev, "linux,sml-size", &ssize);
+
+ if (addr_prop && size_prop) {
+ u64 a = of_read_number(addr_prop, asize / sizeof(__be32));
+ u64 s = of_read_number(size_prop, ssize / sizeof(__be32));
+
+ *addr = map_physmem(a, s, MAP_NOCACHE);
+ *size = (u32)s;
+ } else {
+ struct ofnode_phandle_args args;
+ phys_addr_t a;
+ fdt_size_t s;
+
+ if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0,
+ 0, &args))
+ return -ENODEV;
+
+ a = ofnode_get_addr_size(args.node, "reg", &s);
+ if (a == FDT_ADDR_T_NONE)
+ return -ENOMEM;
+
+ *addr = map_physmem(a, s, MAP_NOCACHE);
+ *size = (u32)s;
+ }
+
+ return 0;
+}
+
+__weak int tcg2_platform_get_tpm2(struct udevice **dev)
+{
+ for_each_tpm_device(*dev) {
+ if (tpm_get_version(*dev) == TPM_V2)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+__weak void tcg2_platform_startup_error(struct udevice *dev, int rc) {}
+
u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
{
const u8 command_v2[12] = {
@@ -359,6 +1048,131 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
return 0;
}
+static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
+{
+ u8 response[(sizeof(struct tpms_capability_data) -
+ offsetof(struct tpms_capability_data, data))];
+ u32 properties_offset =
+ offsetof(struct tpml_tagged_tpm_property, tpm_property) +
+ offsetof(struct tpms_tagged_property, value);
+ u32 ret;
+
+ memset(response, 0, sizeof(response));
+ ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES,
+ TPM2_PT_PCR_COUNT, response, 1);
+ if (ret)
+ return ret;
+
+ *num_pcr = get_unaligned_be32(response + properties_offset);
+ if (*num_pcr > TPM2_MAX_PCRS) {
+ printf("%s: too many pcrs: %u\n", __func__, *num_pcr);
+ return -E2BIG;
+ }
+
+ return 0;
+}
+
+static bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection)
+{
+ int i;
+
+ /*
+ * check the pcr_select. If at least one of the PCRs supports the
+ * algorithm add it on the active ones
+ */
+ for (i = 0; i < selection->size_of_select; i++) {
+ if (selection->pcr_select[i])
+ return true;
+ }
+
+ return false;
+}
+
+int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
+ u32 *pcr_banks)
+{
+ u8 response[(sizeof(struct tpms_capability_data) -
+ offsetof(struct tpms_capability_data, data))];
+ struct tpml_pcr_selection pcrs;
+ u32 num_pcr;
+ size_t i;
+ u32 ret;
+
+ *supported_pcr = 0;
+ *active_pcr = 0;
+ *pcr_banks = 0;
+ memset(response, 0, sizeof(response));
+ ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
+ if (ret)
+ return ret;
+
+ pcrs.count = get_unaligned_be32(response);
+ /*
+ * We only support 5 algorithms for now so check against that
+ * instead of TPM2_NUM_PCR_BANKS
+ */
+ if (pcrs.count > ARRAY_SIZE(tpm2_supported_algorithms) ||
+ pcrs.count < 1) {
+ printf("%s: too many pcrs: %u\n", __func__, pcrs.count);
+ return -EMSGSIZE;
+ }
+
+ ret = tpm2_get_num_pcr(dev, &num_pcr);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < pcrs.count; i++) {
+ /*
+ * Definition of TPMS_PCR_SELECTION Structure
+ * hash: u16
+ * size_of_select: u8
+ * pcr_select: u8 array
+ *
+ * The offsets depend on the number of the device PCRs
+ * so we have to calculate them based on that
+ */
+ u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
+ i * offsetof(struct tpms_pcr_selection, pcr_select) +
+ i * ((num_pcr + 7) / 8);
+ u32 size_select_offset =
+ hash_offset + offsetof(struct tpms_pcr_selection,
+ size_of_select);
+ u32 pcr_select_offset =
+ hash_offset + offsetof(struct tpms_pcr_selection,
+ pcr_select);
+
+ pcrs.selection[i].hash =
+ get_unaligned_be16(response + hash_offset);
+ pcrs.selection[i].size_of_select =
+ __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);
+ return -ENOBUFS;
+ }
+ /* copy the array of pcr_select */
+ memcpy(pcrs.selection[i].pcr_select, response + pcr_select_offset,
+ pcrs.selection[i].size_of_select);
+ }
+
+ for (i = 0; i < pcrs.count; i++) {
+ u32 hash_mask = tpm2_algorithm_to_mask(pcrs.selection[i].hash);
+
+ if (hash_mask) {
+ *supported_pcr |= hash_mask;
+ if (tpm2_is_active_pcr(&pcrs.selection[i]))
+ *active_pcr |= hash_mask;
+ } else {
+ printf("%s: unknown algorithm %x\n", __func__,
+ pcrs.selection[i].hash);
+ }
+ }
+
+ *pcr_banks = pcrs.count;
+
+ return 0;
+}
+
u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
{
u8 command_v2[COMMAND_BUFFER_SIZE] = {
diff --git a/test/boot/Makefile b/test/boot/Makefile
index 5294758..068522c 100644
--- a/test/boot/Makefile
+++ b/test/boot/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o
obj-$(CONFIG_FIT) += image.o
+obj-$(CONFIG_MEASURED_BOOT) += measurement.o
obj-$(CONFIG_EXPO) += expo.o
obj-$(CONFIG_CEDIT) += cedit.o
diff --git a/test/boot/measurement.c b/test/boot/measurement.c
new file mode 100644
index 0000000..9db2ed3
--- /dev/null
+++ b/test/boot/measurement.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for measured boot functions
+ *
+ * Copyright 2023 IBM Corp.
+ * Written by Eddie James <eajames@linux.ibm.com>
+ */
+
+#include <common.h>
+#include <bootm.h>
+#include <malloc.h>
+#include <test/suites.h>
+#include <test/test.h>
+#include <test/ut.h>
+#include <asm/io.h>
+
+#define MEASUREMENT_TEST(_name, _flags) \
+ UNIT_TEST(_name, _flags, measurement_test)
+
+static int measure(struct unit_test_state *uts)
+{
+ struct bootm_headers images;
+ const size_t size = 1024;
+ u8 *kernel;
+ u8 *initrd;
+ size_t i;
+
+ kernel = malloc(size);
+ initrd = malloc(size);
+
+ images.os.image_start = map_to_sysmem(kernel);
+ images.os.image_len = size;
+
+ images.rd_start = map_to_sysmem(initrd);
+ images.rd_end = images.rd_start + size;
+
+ images.ft_addr = malloc(size);
+ images.ft_len = size;
+
+ env_set("bootargs", "measurement testing");
+
+ for (i = 0; i < size; ++i) {
+ kernel[i] = 0xf0 | (i & 0xf);
+ initrd[i] = (i & 0xf0) | 0xf;
+ images.ft_addr[i] = i & 0xff;
+ }
+
+ ut_assertok(bootm_measure(&images));
+
+ free(images.ft_addr);
+ free(initrd);
+ free(kernel);
+
+ return 0;
+}
+MEASUREMENT_TEST(measure, 0);
+
+int do_ut_measurement(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct unit_test *tests = UNIT_TEST_SUITE_START(measurement_test);
+ const int n_ents = UNIT_TEST_SUITE_COUNT(measurement_test);
+
+ return cmd_ut_category("measurement", "measurement_test_", tests,
+ n_ents, argc, argv);
+}
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index 0343d47..2d5b80f 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -103,6 +103,10 @@ static struct cmd_tbl cmd_ut_sub[] = {
#if CONFIG_IS_ENABLED(UT_UNICODE) && !defined(API_BUILD)
U_BOOT_CMD_MKENT(unicode, CONFIG_SYS_MAXARGS, 1, do_ut_unicode, "", ""),
#endif
+#ifdef CONFIG_MEASURED_BOOT
+ U_BOOT_CMD_MKENT(measurement, CONFIG_SYS_MAXARGS, 1, do_ut_measurement,
+ "", ""),
+#endif
#ifdef CONFIG_SANDBOX
U_BOOT_CMD_MKENT(compression, CONFIG_SYS_MAXARGS, 1, do_ut_compression,
"", ""),
diff --git a/test/py/tests/test_tpm2.py b/test/py/tests/test_tpm2.py
index c2579fa..1d654cd 100644
--- a/test/py/tests/test_tpm2.py
+++ b/test/py/tests/test_tpm2.py
@@ -61,7 +61,7 @@ def test_tpm2_init(u_boot_console):
skip_test = u_boot_console.config.env.get('env__tpm_device_test_skip', False)
if skip_test:
pytest.skip('skip TPM device test')
- u_boot_console.run_command('tpm2 init')
+ u_boot_console.run_command('tpm2 autostart')
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
@@ -100,7 +100,7 @@ def test_tpm2_sandbox_self_test_full(u_boot_console):
"""
if is_sandbox(u_boot_console):
u_boot_console.restart_uboot()
- u_boot_console.run_command('tpm2 init')
+ u_boot_console.run_command('tpm2 autostart')
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
@@ -239,7 +239,7 @@ def test_tpm2_dam_parameters(u_boot_console):
def test_tpm2_pcr_read(u_boot_console):
"""Execute a TPM2_PCR_Read command.
- Perform a PCR read of the 0th PCR. Must be zero.
+ Perform a PCR read of the 10th PCR. Must be zero.
"""
if is_sandbox(u_boot_console):
tpm2_sandbox_init(u_boot_console)
@@ -247,7 +247,7 @@ def test_tpm2_pcr_read(u_boot_console):
force_init(u_boot_console)
ram = u_boot_utils.find_ram_base(u_boot_console)
- read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % ram)
+ read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % ram)
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
@@ -257,7 +257,7 @@ def test_tpm2_pcr_read(u_boot_console):
updates = int(re.findall(r'\d+', str)[0])
# Check the output value
- assert 'PCR #0 content' in read_pcr
+ assert 'PCR #10 content' in read_pcr
assert '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' in read_pcr
@pytest.mark.buildconfigspec('cmd_tpm_v2')
@@ -275,19 +275,19 @@ def test_tpm2_pcr_extend(u_boot_console):
force_init(u_boot_console)
ram = u_boot_utils.find_ram_base(u_boot_console)
- read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % (ram + 0x20))
+ read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % (ram + 0x20))
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
str = re.findall(r'\d+ known updates', read_pcr)[0]
updates = int(re.findall(r'\d+', str)[0])
- u_boot_console.run_command('tpm2 pcr_extend 0 0x%x' % ram)
+ u_boot_console.run_command('tpm2 pcr_extend 10 0x%x' % ram)
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
# Read the value back into a different place so we can still use 'ram' as
# our zero bytes
- read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % (ram + 0x20))
+ read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % (ram + 0x20))
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
assert 'f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b' in read_pcr
@@ -297,11 +297,11 @@ def test_tpm2_pcr_extend(u_boot_console):
new_updates = int(re.findall(r'\d+', str)[0])
assert (updates + 1) == new_updates
- u_boot_console.run_command('tpm2 pcr_extend 0 0x%x' % ram)
+ u_boot_console.run_command('tpm2 pcr_extend 10 0x%x' % ram)
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
- read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % (ram + 0x20))
+ read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % (ram + 0x20))
output = u_boot_console.run_command('echo $?')
assert output.endswith('0')
assert '7a 05 01 f5 95 7b df 9c b3 a8 ff 49 66 f0 22 65' in read_pcr