diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h index ae644de27c5..fa5a266174f 100644 --- a/src/commonlib/include/commonlib/cbmem_id.h +++ b/src/commonlib/include/commonlib/cbmem_id.h @@ -56,6 +56,7 @@ #define CBMEM_ID_STAGEx_RAW 0x57a9e200 #define CBMEM_ID_STORAGE_DATA 0x53746f72 #define CBMEM_ID_TCPA_LOG 0x54435041 +#define CBMEM_ID_TCPA_SPEC_LOG 0x54534C47 #define CBMEM_ID_TCPA_TCG_LOG 0x54445041 #define CBMEM_ID_TIMESTAMP 0x54494d45 #define CBMEM_ID_TPM2_TCG_LOG 0x54504d32 @@ -125,6 +126,7 @@ { CBMEM_ID_SMM_SAVE_SPACE, "SMM BACKUP " }, \ { CBMEM_ID_STORAGE_DATA, "SD/MMC/eMMC" }, \ { CBMEM_ID_TCPA_LOG, "TCPA LOG " }, \ + { CBMEM_ID_TCPA_SPEC_LOG, "TCPASPECLOG" }, \ { CBMEM_ID_TCPA_TCG_LOG, "TCPA TCGLOG" }, \ { CBMEM_ID_TIMESTAMP, "TIME STAMP " }, \ { CBMEM_ID_TPM2_TCG_LOG, "TPM2 TCGLOG" }, \ diff --git a/src/commonlib/include/commonlib/coreboot_tables.h b/src/commonlib/include/commonlib/coreboot_tables.h index be40c3818f1..db48d7dbfe8 100644 --- a/src/commonlib/include/commonlib/coreboot_tables.h +++ b/src/commonlib/include/commonlib/coreboot_tables.h @@ -83,6 +83,7 @@ enum { LB_TAG_SMMSTOREV2 = 0x0039, LB_TAG_TPM_PPI_HANDOFF = 0x003a, LB_TAG_BOARD_CONFIG = 0x0040, + LB_TAG_TCPA_SPEC_LOG = 0x00c7, /* The following options are CMOS-related */ LB_TAG_CMOS_OPTION_TABLE = 0x00c8, LB_TAG_OPTION = 0x00c9, diff --git a/src/commonlib/include/commonlib/tpm_log_serialized.h b/src/commonlib/include/commonlib/tpm_log_serialized.h new file mode 100644 index 00000000000..8175c561b45 --- /dev/null +++ b/src/commonlib/include/commonlib/tpm_log_serialized.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __TPM_LOG_SERIALIZED_H__ +#define __TPM_LOG_SERIALIZED_H__ + +#include +#include + +#define TCPA_SPEC_ID_EVENT_SIGNATURE "Spec ID Event00" + +struct tcpa_log_entry { + uint32_t pcr; + uint32_t event_type; + uint8_t digest[20]; + uint32_t event_data_size; + uint8_t event[0]; +} __packed; + +struct tcpa_spec_entry { + struct tcpa_log_entry entry; + uint8_t signature[16]; + uint32_t platform_class; + uint8_t spec_version_minor; + uint8_t spec_version_major; + uint8_t spec_errata; + uint8_t reserved; + uint8_t vendor_info_size; + uint8_t vendor_info[0]; +} __packed; + +/* Some hardcoded algorithm values. */ +/* Table 7 - TPM_ALG_ID Constants */ +#define TPM2_ALG_ERROR 0x0000 +#define TPM2_ALG_HMAC 0x0005 +#define TPM2_ALG_NULL 0x0010 +#define TPM2_ALG_SHA1 0x0004 +#define TPM2_ALG_SHA256 0x000b +#define TPM2_ALG_SHA384 0x000c +#define TPM2_ALG_SHA512 0x000d +#define TPM2_ALG_SM3_256 0x0012 + +/* Annex A Algorithm Constants */ + +/* Table 205 - Defines for SHA1 Hash Values */ +#define SHA1_DIGEST_SIZE 20 +/* Table 206 - Defines for SHA256 Hash Values */ +#define SHA256_DIGEST_SIZE 32 +/* Table 207 - Defines for SHA384 Hash Values */ +#define SHA384_DIGEST_SIZE 48 +/* Table 208 - Defines for SHA512 Hash Values */ +#define SHA512_DIGEST_SIZE 64 +/* Table 209 - Defines for SM3_256 Hash Values */ +#define SM3_256_DIGEST_SIZE 32 + +#define HASH_COUNT 2 + +/* Table 66 - TPMU_HA Union */ +typedef union { + uint8_t sha1[SHA1_DIGEST_SIZE]; + uint8_t sha256[SHA256_DIGEST_SIZE]; + uint8_t sm3_256[SM3_256_DIGEST_SIZE]; + uint8_t sha384[SHA384_DIGEST_SIZE]; + uint8_t sha512[SHA512_DIGEST_SIZE]; +} tpm_hash_digest; + +typedef struct { + uint16_t hashAlg; + tpm_hash_digest digest; +} tpm_hash_algorithm; + +/* Table 96 -- TPML_DIGEST_VALUES Structure */ +typedef struct { + uint32_t count; + tpm_hash_algorithm digests[HASH_COUNT]; +} tpm_digest_values; + +typedef struct { + uint16_t alg_id; + uint16_t digest_size; +} __packed tpm_digest_sizes; + +typedef struct { + uint32_t pcr_index; + uint32_t event_type; + tpm_digest_values digest; + uint32_t event_size; + uint8_t event[0]; +} __packed tcg_pcr_event2_header; + +typedef struct { + uint32_t pcr_index; + uint32_t event_type; + uint8_t digest[20]; + uint32_t event_size; + uint8_t signature[16]; + uint32_t platform_class; + uint8_t spec_version_minor; + uint8_t spec_version_major; + uint8_t spec_errata; + uint8_t uintn_size; + uint32_t num_of_algorithms; + tpm_digest_sizes digest_sizes[HASH_COUNT]; + uint8_t vendor_info_size; + uint8_t vendor_info[0]; +} __packed tcg_efi_spec_id_event; + +#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE "Spec ID Event03" + +#define EV_PREBOOT_CERT 0x00000000 +#define EV_POST_CODE 0x00000001 +#define EV_UNUSED 0x00000002 +#define EV_NO_ACTION 0x00000003 +#define EV_SEPARATOR 0x00000004 +#define EV_ACTION 0x00000005 +#define EV_EVENT_TAG 0x00000006 +#define EV_S_CRTM_CONTENTS 0x00000007 +#define EV_S_CRTM_VERSION 0x00000008 +#define EV_CPU_MICROCODE 0x00000009 +#define EV_PLATFORM_CONFIG_FLAGS 0x0000000A +#define EV_TABLE_OF_DEVICES 0x0000000B +#define EV_COMPACT_HASH 0x0000000C +#define EV_IPL 0x0000000D +#define EV_IPL_PARTITION_DATA 0x0000000E +#define EV_NONHOST_CODE 0x0000000F +#define EV_NONHOST_CONFIG 0x00000010 +#define EV_NONHOST_INFO 0x00000011 +#define EV_OMIT_BOOT_DEVICE_EVENTS 0x00000012 + +static const char *tpm_event_types[] __unused = { + [EV_PREBOOT_CERT] = "Reserved", + [EV_POST_CODE] = "POST code", + [EV_UNUSED] = "Unused", + [EV_NO_ACTION] = "No action", + [EV_SEPARATOR] = "Separator", + [EV_ACTION] = "Action", + [EV_EVENT_TAG] = "Event tag", + [EV_S_CRTM_CONTENTS] = "S-CRTM contents", + [EV_S_CRTM_VERSION] = "S-CRTM version", + [EV_CPU_MICROCODE] = "CPU microcode", + [EV_PLATFORM_CONFIG_FLAGS] = "Platform configuration flags", + [EV_TABLE_OF_DEVICES] = "Table of devices", + [EV_COMPACT_HASH] = "Compact hash", + [EV_IPL] = "IPL", + [EV_IPL_PARTITION_DATA] = "IPL partition data", + [EV_NONHOST_CODE] = "Non-host code", + [EV_NONHOST_CONFIG] = "Non-host configuration", + [EV_NONHOST_INFO] = "Non-host information", + [EV_OMIT_BOOT_DEVICE_EVENTS] = "Omit boot device events", +}; + +#endif diff --git a/src/lib/coreboot_table.c b/src/lib/coreboot_table.c index 9264efb6d24..070e56cadc4 100644 --- a/src/lib/coreboot_table.c +++ b/src/lib/coreboot_table.c @@ -249,6 +249,7 @@ static void add_cbmem_pointers(struct lb_header *header) {CBMEM_ID_VPD, LB_TAG_VPD}, {CBMEM_ID_WIFI_CALIBRATION, LB_TAG_WIFI_CALIBRATION}, {CBMEM_ID_TCPA_LOG, LB_TAG_TCPA_LOG}, + {CBMEM_ID_TCPA_SPEC_LOG, LB_TAG_TCPA_SPEC_LOG}, {CBMEM_ID_FMAP, LB_TAG_FMAP}, {CBMEM_ID_VBOOT_WORKBUF, LB_TAG_VBOOT_WORKBUF}, }; diff --git a/src/mainboard/raptor-cs/talos-2/Kconfig b/src/mainboard/raptor-cs/talos-2/Kconfig index ce0a812d06a..97cb65c2b4b 100644 --- a/src/mainboard/raptor-cs/talos-2/Kconfig +++ b/src/mainboard/raptor-cs/talos-2/Kconfig @@ -33,6 +33,7 @@ config TALOS_2_INFINEON_TPM_1 bool "I2C TPM1 chip compatible with SLB9635TT" default n select TPM_MEASURED_BOOT # needed for TCPA log + select TPM_MEASURED_BOOT_SPEC_LOG # don't use coreboot's log format config DRIVER_TPM_I2C_BUS hex diff --git a/src/security/tpm/Kconfig b/src/security/tpm/Kconfig index 13bef069858..7397879fd91 100644 --- a/src/security/tpm/Kconfig +++ b/src/security/tpm/Kconfig @@ -106,6 +106,14 @@ config TPM_MEASURED_BOOT help Enables measured boot (experimental) +config TPM_MEASURED_BOOT_SPEC_LOG + bool "Use TCPA log per specification" + default n + depends on TPM_MEASURED_BOOT + help + Enables writing of TPM event log in format defined by TCPA + specification (TPM2). + config TPM_MEASURED_BOOT_INIT_BOOTBLOCK bool depends on TPM_MEASURED_BOOT && !VBOOT diff --git a/src/security/tpm/Makefile.inc b/src/security/tpm/Makefile.inc index c36183dd9bf..3c03ee276a5 100644 --- a/src/security/tpm/Makefile.inc +++ b/src/security/tpm/Makefile.inc @@ -55,10 +55,22 @@ romstage-y += tspi/crtm.c ramstage-y += tspi/crtm.c postcar-y += tspi/crtm.c +ifeq ($(CONFIG_TPM_MEASURED_BOOT_SPEC_LOG),y) + +ramstage-y += tspi/log-tpm.c +romstage-y += tspi/log-tpm.c +verstage-y += tspi/log-tpm.c +postcar-y += tspi/log-tpm.c +bootblock-y += tspi/log-tpm.c + +else + ramstage-y += tspi/log.c romstage-y += tspi/log.c verstage-y += tspi/log.c postcar-y += tspi/log.c bootblock-y += tspi/log.c +endif # CONFIG_TPM_MEASURED_BOOT_SPEC_LOG + endif # CONFIG_TPM_MEASURED_BOOT diff --git a/src/security/tpm/tcpa_spec_log_serialized.h b/src/security/tpm/tcpa_spec_log_serialized.h new file mode 100644 index 00000000000..6e95bdecab9 --- /dev/null +++ b/src/security/tpm/tcpa_spec_log_serialized.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __TCPA_SPEC_LOG_SERIALIZED_H__ +#define __TCPA_SPEC_LOG_SERIALIZED_H__ + +#include +#include + +#define MAX_TCPA_LOG_ENTRIES 50 +#define TCPA_PCR_HASH_NAME 50 +#define TCPA_PCR_HASH_LEN 10 +/* Assumption of 2K TCPA log size reserved for CAR/SRAM */ +#define MAX_PRERAM_TCPA_LOG_ENTRIES 15 + +/* + * TPM2.0 log entries can't be generally represented as C structures due to + * varying number of digests and their sizes. However, it works as long as + * we're only using and supporting SHA1 digests. + */ +#define TCPA_DIGEST_MAX_LENGTH SHA1_DIGEST_SIZE + +/* TCG_PCR_EVENT2 */ +struct tcpa_entry { + uint32_t pcr; + uint32_t event_type; + uint32_t digest_count; + uint16_t digest_type; + uint8_t digest[TCPA_DIGEST_MAX_LENGTH]; + uint32_t name_length; + char name[TCPA_PCR_HASH_NAME]; +} __packed; + +struct tcpa_table { + uint16_t max_entries; + uint16_t num_entries; + tcg_efi_spec_id_event header; /* TCG_PCR_EVENT actually */ + struct tcpa_entry entries[0]; /* Variable number of entries */ +} __packed; + +#endif diff --git a/src/security/tpm/tspi.h b/src/security/tpm/tspi.h index e040d806116..52dcc729074 100644 --- a/src/security/tpm/tspi.h +++ b/src/security/tpm/tspi.h @@ -4,10 +4,15 @@ #define TSPI_H_ #include -#include #include #include +#if CONFIG(TPM_MEASURED_BOOT_SPEC_LOG) +#include "tcpa_spec_log_serialized.h" +#else +#include +#endif + #define TPM_PCR_MAX_LEN 64 #define HASH_DATA_CHUNK_SIZE 1024 diff --git a/src/security/tpm/tspi/crtm.c b/src/security/tpm/tspi/crtm.c index 147fc76bbf7..cfc8229b86a 100644 --- a/src/security/tpm/tspi/crtm.c +++ b/src/security/tpm/tspi/crtm.c @@ -178,8 +178,8 @@ int tspi_measure_cache_to_pcr(void) if (tce) { printk(BIOS_DEBUG, "TPM: Write digest for" " %s into PCR %d\n", - tce->name, tce->pcr); - int result = tlcl_extend(tce->pcr, + tce->name, le32toh(tce->pcr)); + int result = tlcl_extend(le32toh(tce->pcr), tce->digest, NULL); if (result != TPM_SUCCESS) { diff --git a/src/security/tpm/tspi/log-tpm.c b/src/security/tpm/tspi/log-tpm.c new file mode 100644 index 00000000000..d8085247815 --- /dev/null +++ b/src/security/tpm/tspi/log-tpm.c @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Unlike log.c this implements TCPA log according to TPM2 specification + * rather then using coreboot-specific log format. + * + * First entry is in TPM1.2 format and serves as a header, the rest are in + * a newer format which supports SHA256 and multiple hashes, but we always + * store one hash in SHA1 format. + * + * This is defined in "TCG EFI Protocol Specification" and is what skiboot + * uses. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct tcpa_table *tcpa_cbmem_init(void) +{ + static struct tcpa_table *tclt; + if (tclt) + return tclt; + + if (cbmem_possibly_online()) { + tclt = cbmem_find(CBMEM_ID_TCPA_SPEC_LOG); + if (!tclt) { + size_t tcpa_log_len = sizeof(struct tcpa_table) + + MAX_TCPA_LOG_ENTRIES * sizeof(struct tcpa_entry); + tclt = cbmem_add(CBMEM_ID_TCPA_SPEC_LOG, tcpa_log_len); + if (tclt) { + tclt->max_entries = MAX_TCPA_LOG_ENTRIES; + tclt->num_entries = 0; + + tcg_efi_spec_id_event *hdr = &tclt->header; + memset(hdr, 0, sizeof(*hdr)); + hdr->event_type = htole32(EV_NO_ACTION); + hdr->event_size = htole32(37); + memcpy(hdr->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE, + sizeof(hdr->signature)); + hdr->spec_version_minor = 0; + hdr->spec_version_major = 2; + hdr->uintn_size = 0x02; // 64-bit UINT + hdr->num_of_algorithms = 2; + hdr->digest_sizes[0].alg_id = TPM2_ALG_SHA1; + hdr->digest_sizes[0].digest_size = SHA1_DIGEST_SIZE; + hdr->digest_sizes[1].alg_id = TPM2_ALG_SHA256; + hdr->digest_sizes[1].digest_size = SHA256_DIGEST_SIZE; + } + } + } + return tclt; +} + +struct tcpa_table *tcpa_log_init(void) +{ + static struct tcpa_table *tclt; + + /* We are dealing here with pre CBMEM environment. + * If cbmem isn't available use CAR or SRAM */ + if (!cbmem_possibly_online() && + !CONFIG(VBOOT_RETURN_FROM_VERSTAGE)) + return (struct tcpa_table *)_tpm_tcpa_log; + else if (ENV_ROMSTAGE && + !CONFIG(VBOOT_RETURN_FROM_VERSTAGE)) { + tclt = tcpa_cbmem_init(); + if (!tclt) + return (struct tcpa_table *)_tpm_tcpa_log; + } else { + tclt = tcpa_cbmem_init(); + } + + return tclt; +} + +void tcpa_log_dump(void *unused) +{ + int i, j; + struct tcpa_table *tclt; + + tclt = tcpa_log_init(); + if (!tclt) + return; + + printk(BIOS_INFO, "coreboot TCPA measurements:\n\n"); + for (i = 0; i < tclt->num_entries; i++) { + struct tcpa_entry *tce = &tclt->entries[i]; + + printk(BIOS_INFO, " PCR-%u ", le32toh(tce->pcr)); + + for (j = 0; j < SHA1_DIGEST_SIZE; j++) + printk(BIOS_INFO, "%02x", tce->digest[j]); + + printk(BIOS_INFO, " %s [%s]\n", "SHA1", tce->name); + } + printk(BIOS_INFO, "\n"); +} + +void tcpa_log_add_table_entry(const char *name, const uint32_t pcr, + enum vb2_hash_algorithm digest_algo, + const uint8_t *digest, + const size_t digest_len) +{ + struct tcpa_table *tclt = tcpa_log_init(); + if (!tclt) { + printk(BIOS_WARNING, "TCPA: Log non-existent!\n"); + return; + } + + if (digest_algo != VB2_HASH_SHA1) { + printk(BIOS_WARNING, "TCPA: digest is of unsupported type: %s\n", + vb2_get_hash_algorithm_name(digest_algo)); + return; + } + + if (digest_len != SHA1_DIGEST_SIZE) { + printk(BIOS_WARNING, "TCPA: digest is of unsupported length: %d\n", + (int)digest_len); + return; + } + + if (tclt->num_entries >= tclt->max_entries) { + printk(BIOS_WARNING, "TCPA: TCPA log table is full\n"); + return; + } + + if (!name) { + printk(BIOS_WARNING, "TCPA: TCPA entry name not set\n"); + return; + } + + struct tcpa_entry *tce = &tclt->entries[tclt->num_entries++]; + + tce->pcr = htole32(pcr); + tce->event_type = htole32(EV_ACTION); + + tce->digest_count = htole32(1); + tce->digest_type = htole16(TPM2_ALG_SHA1); + memcpy(tce->digest, digest, SHA1_DIGEST_SIZE); + + tce->name_length = htole32(TCPA_PCR_HASH_NAME); + strncpy(tce->name, name, TCPA_PCR_HASH_NAME - 1); +} + +void tcpa_preram_log_clear(void) +{ + printk(BIOS_INFO, "TCPA: Clearing coreboot TCPA log\n"); + struct tcpa_table *tclt = (struct tcpa_table *)_tpm_tcpa_log; + tclt->max_entries = MAX_TCPA_LOG_ENTRIES; + tclt->num_entries = 0; +} + +#if !CONFIG(VBOOT_RETURN_FROM_VERSTAGE) +static void recover_tcpa_log(int is_recovery) +{ + struct tcpa_table *preram_log = (struct tcpa_table *)_tpm_tcpa_log; + struct tcpa_table *ram_log = NULL; + int i; + + if (preram_log->num_entries > MAX_PRERAM_TCPA_LOG_ENTRIES) { + printk(BIOS_WARNING, "TCPA: Pre-RAM TCPA log is too full, possible corruption\n"); + return; + } + + ram_log = tcpa_cbmem_init(); + if (!ram_log) { + printk(BIOS_WARNING, "TCPA: CBMEM not available something went wrong\n"); + return; + } + + for (i = 0; i < preram_log->num_entries; i++) { + struct tcpa_entry *tce = &ram_log->entries[ram_log->num_entries++]; + + tce->pcr = preram_log->entries[i].pcr; + tce->event_type = preram_log->entries[i].event_type; + + tce->digest_count = preram_log->entries[i].digest_count; + tce->digest_type = preram_log->entries[i].digest_type; + memcpy(tce->digest, preram_log->entries[i].digest, SHA1_DIGEST_SIZE); + + tce->name_length = preram_log->entries[i].name_length; + strncpy(tce->name, preram_log->entries[i].name, TCPA_PCR_HASH_NAME - 1); + } +} +ROMSTAGE_CBMEM_INIT_HOOK(recover_tcpa_log); +#endif + +BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, tcpa_log_dump, NULL); diff --git a/src/soc/ibm/power9/chip.c b/src/soc/ibm/power9/chip.c index 9187bdd5446..72e5887db06 100644 --- a/src/soc/ibm/power9/chip.c +++ b/src/soc/ibm/power9/chip.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -498,6 +498,7 @@ static void add_tpm_node(struct device_tree *tree) uint8_t addr = (CONFIG_DRIVER_TPM_I2C_ADDR & 0x7F); struct device_tree_node *tpm; + struct device_tree_node *sb; char path[64]; char compatible[24]; @@ -512,16 +513,22 @@ static void add_tpm_node(struct device_tree *tree) snprintf(compatible, sizeof(compatible), "infineon,%s", tis_name()); dt_add_string_prop(tpm, "compatible", strdup(compatible)); - dt_add_string_prop(tpm, "status", "okay"); dt_add_u32_prop(tpm, "reg", addr); - tcpa_table = cbmem_find(CBMEM_ID_TCPA_LOG); + tcpa_table = cbmem_find(CBMEM_ID_TCPA_SPEC_LOG); if (tcpa_table == NULL) die("TPM events (TCPA) log is missing from CBMEM!"); - dt_add_u64_prop(tpm, "linux,sml-base", (uintptr_t)tcpa_table + sizeof(*tcpa_table)); + dt_add_u64_prop(tpm, "linux,sml-base", (uintptr_t)&tcpa_table->header); dt_add_u32_prop(tpm, "linux,sml-size", + sizeof(tcg_efi_spec_id_event) + tcpa_table->max_entries * sizeof(struct tcpa_entry)); + + /* Not hard-coding into DTS-file in case will need to store key hash here */ + sb = dt_find_node_by_path(tree, "/ibm,secureboot", NULL, NULL, 1); + dt_add_string_prop(sb, "compatible", "ibm,secureboot-v1-softrom"); + dt_add_string_prop(sb, "hash-algo", "sha512"); + dt_add_u32_prop(sb, "trusted-enabled", 1); #endif }