summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorSergii Dmytruk <sergii.dmytruk@3mdeb.com>2022-10-23 00:55:03 +0300
committerFelix Held <felix-coreboot@felixheld.de>2023-07-04 13:07:13 +0000
commit6da62684dee6b2df49fa1d51e74e14c181c9349e (patch)
tree33a128ed3c2d5b1ec0b99c4da527c401a2fbd023 /util
parent6d169aabbd53aee82d159eb3cb8a952ba0461a53 (diff)
util/cbmem: add parsing of TPM logs per specs
CBMEM can contain log in different forms (at most one is present): - coreboot-specific format (CBMEM_ID_TPM_CB_LOG exported as LB_TAG_TPM_CB_LOG) - TPM1.2 format (CBMEM_ID_TCPA_TCG_LOG) - TPM2 format (CBMEM_ID_TPM2_TCG_LOG) The last two follow specifications by Trusted Computing Group, but until now cbmem couldn't print them. These formats were added not so long ago in: - commit 4191dbf0c9a5 ("security/tpm: add TPM log format as per 1.2 spec") - commit 53db677586e3 ("security/tpm: add TPM log format as per 2.0 spec") These changes make cbmem utility check for existence of TPM1.2/TPM2 logs in CBMEM and add code necessary for parsing and printing of their entries. TEST=`cbmem -L` for CONFIG_TPM1=y case TCPA log: Specification: 1.21 Platform class: PC Client TCPA log entry 1: PCR: 2 Event type: Action Digest: 5622416ea417186aa1ac32b32c527ac09009fb5e Event data: FMAP: FMAP TEST=`cbmem -L` for CONFIG_TPM2=y case TPM2 log: Specification: 2.00 Platform class: PC Client TPM2 log entry 1: PCR: 2 Event type: Action Digests: SHA256: 68d27f08cb261463a6d004524333ac5db1a3c2166721785a6061327b6538657c Event data: FMAP: FMAP Change-Id: Ib76dc7dec56dd1789a219539a1ac05a958f47a5c Ticket: https://ticket.coreboot.org/issues/425 Signed-off-by: Krystian Hebel <krystian.hebel@3mdeb.com> Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com> Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/68749 Reviewed-by: Paul Menzel <paulepanter@mailbox.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'util')
-rw-r--r--util/cbmem/cbmem.c241
1 files changed, 236 insertions, 5 deletions
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(&timestamp_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);