diff options
-rw-r--r-- | src/commonlib/bsd/include/commonlib/bsd/tpm_log_defs.h | 64 | ||||
-rw-r--r-- | util/cbmem/cbmem.c | 241 |
2 files changed, 300 insertions, 5 deletions
diff --git a/src/commonlib/bsd/include/commonlib/bsd/tpm_log_defs.h b/src/commonlib/bsd/include/commonlib/bsd/tpm_log_defs.h index 3a754173e5..041b636574 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/tpm_log_defs.h +++ b/src/commonlib/bsd/include/commonlib/bsd/tpm_log_defs.h @@ -9,6 +9,26 @@ #define TCPA_SPEC_ID_EVENT_SIGNATURE "Spec ID Event00" #define TCG_EFI_SPEC_ID_EVENT_SIGNATURE "Spec ID Event03" +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; + #define TPM2_ALG_ERROR 0x0000 #define TPM2_ALG_HMAC 0x0005 #define TPM2_ALG_NULL 0x0010 @@ -56,6 +76,28 @@ struct spec_id_event_data { uint8_t vendor_info_size; } __packed; +union tpm_hash_digest { + 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]; +}; + +struct tpm_hash_algorithm { + uint16_t hashAlg; + union tpm_hash_digest digest; +} __packed; + +struct tcg_pcr_event2_header { + uint32_t pcr_index; + uint32_t event_type; + uint32_t digest_count; + uint8_t digests[0]; + /* uint32_t event_size; */ + /* uint8_t event[0]; */ +} __packed; + struct tpm_digest_sizes { uint16_t alg_id; uint16_t digest_size; @@ -78,4 +120,26 @@ struct tcg_efi_spec_id_event { /* uint8_t vendor_info[vendor_info_size]; */ } __packed; +static const char *tpm_event_types[] __maybe_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/util/cbmem/cbmem.c b/util/cbmem/cbmem.c index 65c8544656..73c410cbb7 100644 --- a/util/cbmem/cbmem.c +++ b/util/cbmem/cbmem.c @@ -19,6 +19,7 @@ #include <assert.h> #include <regex.h> #include <commonlib/bsd/cbmem_id.h> +#include <commonlib/bsd/tpm_log_defs.h> #include <commonlib/loglevel.h> #include <commonlib/timestamp_serialized.h> #include <commonlib/tpm_log_serialized.h> @@ -841,6 +842,227 @@ static void timestamp_add_now(uint32_t timestamp_id) unmap_memory(×tamp_mapping); } +static bool can_print(const uint8_t *data, size_t len) +{ + unsigned int i; + for (i = 0; i < len; i++) { + if (!isprint(data[i]) && !isspace(data[i])) { + /* If printable prefix is followed by zeroes, this is a valid string */ + for (; i < len; i++) { + if (data[i] != 0) + return false; + } + return true; + } + } + return true; +} + +static void print_hex_string(const uint8_t *hex, size_t len) +{ + unsigned int i; + for (i = 0; i < len; i++) + printf("%02x", hex[i]); +} + +static void print_hex_line(const uint8_t *hex, size_t len) +{ + print_hex_string(hex, len); + printf("\n"); +} + +static void print_event_type(uint32_t event_type) +{ + unsigned int known_event_count = ARRAY_SIZE(tpm_event_types); + if (event_type >= known_event_count) + printf("Unknown (0x%x >= %u)", event_type, known_event_count); + else + printf("%s", tpm_event_types[event_type]); +} + +static void parse_tpm12_log(const struct tcpa_spec_entry *spec_log) +{ + const uint8_t zero_block[sizeof(struct tcpa_spec_entry)] = {0}; + + uintptr_t current; + uint32_t counter = 0; + + printf("TCPA log:\n"); + printf("\tSpecification: %d.%d%d\n", + spec_log->spec_version_major, + spec_log->spec_version_minor, + spec_log->spec_errata); + printf("\tPlatform class: %s\n", + le32toh(spec_log->platform_class) == 0 ? "PC Client" : + le32toh(spec_log->platform_class) == 1 ? "Server" : "Unknown"); + + current = (uintptr_t)&spec_log->vendor_info[spec_log->vendor_info_size]; + while (memcmp((const void *)current, (const void *)zero_block, sizeof(zero_block))) { + uint32_t len; + struct tcpa_log_entry *log_entry = (void *)current; + uint32_t event_type = le32toh(log_entry->event_type); + + printf("TCPA log entry %u:\n", ++counter); + printf("\tPCR: %d\n", le32toh(log_entry->pcr)); + printf("\tEvent type: "); + print_event_type(event_type); + printf("\n"); + printf("\tDigest: "); + print_hex_line(log_entry->digest, SHA1_DIGEST_SIZE); + current += sizeof(struct tcpa_log_entry); + len = le32toh(log_entry->event_data_size); + if (len != 0) { + current += len; + printf("\tEvent data: "); + if (can_print(log_entry->event, len)) + printf("%.*s\n", len, log_entry->event); + else + print_hex_line(log_entry->event, len); + } else { + printf("\tEvent data not provided\n"); + } + } +} + +static uint32_t print_tpm2_digests(struct tcg_pcr_event2_header *log_entry) +{ + unsigned int i; + uintptr_t current = (uintptr_t)log_entry->digests; + + for (i = 0; i < le32toh(log_entry->digest_count); i++) { + struct tpm_hash_algorithm *hash = (struct tpm_hash_algorithm *)current; + switch (le16toh(hash->hashAlg)) { + case TPM2_ALG_SHA1: + printf("\t\t SHA1: "); + print_hex_line(hash->digest.sha1, SHA1_DIGEST_SIZE); + current += sizeof(hash->hashAlg) + SHA1_DIGEST_SIZE; + break; + case TPM2_ALG_SHA256: + printf("\t\t SHA256: "); + print_hex_line(hash->digest.sha256, SHA256_DIGEST_SIZE); + current += sizeof(hash->hashAlg) + SHA256_DIGEST_SIZE; + break; + case TPM2_ALG_SHA384: + printf("\t\t SHA384: "); + print_hex_line(hash->digest.sha384, SHA384_DIGEST_SIZE); + current += sizeof(hash->hashAlg) + SHA384_DIGEST_SIZE; + break; + case TPM2_ALG_SHA512: + printf("\t\t SHA512: "); + print_hex_line(hash->digest.sha512, SHA512_DIGEST_SIZE); + current += sizeof(hash->hashAlg) + SHA512_DIGEST_SIZE; + break; + case TPM2_ALG_SM3_256: + printf("\t\t SM3: "); + print_hex_line(hash->digest.sm3_256, SM3_256_DIGEST_SIZE); + current += sizeof(hash->hashAlg) + SM3_256_DIGEST_SIZE; + break; + default: + die("Unknown hash algorithm\n"); + } + } + + return current - (uintptr_t)&log_entry->digest_count; +} + +static void parse_tpm2_log(const struct tcg_efi_spec_id_event *tpm2_log) +{ + const uint8_t zero_block[12] = {0}; /* Only PCR index, event type and digest count */ + + uintptr_t current; + uint32_t counter = 0; + + printf("TPM2 log:\n"); + printf("\tSpecification: %d.%d%d\n", + tpm2_log->spec_version_major, + tpm2_log->spec_version_minor, + tpm2_log->spec_errata); + printf("\tPlatform class: %s\n", + le32toh(tpm2_log->platform_class) == 0 ? "PC Client" : + le32toh(tpm2_log->platform_class) == 1 ? "Server" : "Unknown"); + + /* Start after the first variable-sized part of the header */ + current = (uintptr_t)&tpm2_log->digest_sizes[le32toh(tpm2_log->num_of_algorithms)]; + /* current is at `uint8_t vendor_info_size` here */ + current += 1 + *(uint8_t *)current; + + while (memcmp((const void *)current, (const void *)zero_block, sizeof(zero_block))) { + uint32_t len; + struct tcg_pcr_event2_header *log_entry = (void *)current; + uint32_t event_type = le32toh(log_entry->event_type); + + printf("TPM2 log entry %u:\n", ++counter); + printf("\tPCR: %d\n", le32toh(log_entry->pcr_index)); + printf("\tEvent type: "); + print_event_type(event_type); + printf("\n"); + + current = (uintptr_t)&log_entry->digest_count; + if (le32toh(log_entry->digest_count) > 0) { + printf("\tDigests:\n"); + current += print_tpm2_digests(log_entry); + } else { + printf("\tNo digests in this log entry\n"); + current += sizeof(log_entry->digest_count); + } + /* Now event size and event are left to be parsed */ + len = le32toh(*(uint32_t *)current); + current += sizeof(uint32_t); + if (len != 0) { + printf("\tEvent data: %.*s\n", len, (const char *)current); + current += len; + } else { + printf("\tEvent data not provided\n"); + } + } +} + +/* Dump the TPM log table in format defined by specifications */ +static void dump_tpm_std_log(uint64_t addr, size_t size) +{ + const void *event_log; + const struct tcpa_spec_entry *tspec_entry; + const struct tcg_efi_spec_id_event *tcg_spec_entry; + struct mapping log_mapping; + + event_log = map_memory(&log_mapping, addr, size); + if (!event_log) + die("Unable to map TPM eventlog\n"); + + tspec_entry = event_log; + if (!strcmp((const char *)tspec_entry->signature, TCPA_SPEC_ID_EVENT_SIGNATURE)) { + if (tspec_entry->spec_version_major == 1 && + tspec_entry->spec_version_minor == 2 && + tspec_entry->spec_errata >= 1 && + le32toh(tspec_entry->entry.event_type) == EV_NO_ACTION) { + parse_tpm12_log(tspec_entry); + } else { + fprintf(stderr, "Unknown TPM1.2 log specification\n"); + } + unmap_memory(&log_mapping); + return; + } + + tcg_spec_entry = event_log; + if (!strcmp((const char *)tcg_spec_entry->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE)) { + if (tcg_spec_entry->spec_version_major == 2 && + tcg_spec_entry->spec_version_minor == 0 && + le32toh(tcg_spec_entry->event_type) == EV_NO_ACTION) { + parse_tpm2_log(tcg_spec_entry); + } else { + fprintf(stderr, "Unknown TPM2 log specification.\n"); + } + unmap_memory(&log_mapping); + return; + } + + fprintf(stderr, "Unknown TPM log specification: %.*s\n", + (int)sizeof(tcg_spec_entry->signature), + (const char *)tcg_spec_entry->signature); + + unmap_memory(&log_mapping); +} + /* dump the TPM CB log table */ static void dump_tpm_cb_log(void) { @@ -872,16 +1094,25 @@ static void dump_tpm_cb_log(void) const struct tpm_cb_log_entry *tce = &tclt_p->entries[i]; printf(" PCR-%u ", tce->pcr); - - for (uint32_t j = 0; j < tce->digest_length; j++) - printf("%02x", tce->digest[j]); - + print_hex_string(tce->digest, tce->digest_length); printf(" %s [%s]\n", tce->digest_type, tce->name); } unmap_memory(&log_mapping); } +static void dump_tpm_log(void) +{ + uint64_t start; + size_t size; + + if (!find_cbmem_entry(CBMEM_ID_TCPA_TCG_LOG, &start, &size) || + !find_cbmem_entry(CBMEM_ID_TPM2_TCG_LOG, &start, &size)) + dump_tpm_std_log(start, size); + else + dump_tpm_cb_log(); +} + struct cbmem_console { u32 size; u32 cursor; @@ -1675,7 +1906,7 @@ int main(int argc, char** argv) dump_timestamps(timestamp_type); if (print_tcpa_log) - dump_tpm_cb_log(); + dump_tpm_log(); unmap_memory(&lbtable_mapping); |