Message ID | 1593676355-2850-1-git-send-email-ivan.hu@canonical.com |
---|---|
State | Superseded |
Headers | show |
Series | tpmevlogdump: add function for dumping tpm event log | expand |
Thanks, just some corrections and style fixups required. Colin On 02/07/2020 08:52, Ivan Hu wrote: > The tpm event log define in "TCG PC Client Specific Platform Firmware Profile > Specification" chapter 9. > https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ > > Signed-off-by: Ivan Hu <ivan.hu@canonical.com> > --- > src/Makefile.am | 1 + > src/lib/include/fwts_tpm.h | 166 +++++++++++++++ > src/tpm/tpmevlogdump/tpmevlogdump.c | 408 ++++++++++++++++++++++++++++++++++++ > 3 files changed, 575 insertions(+) > create mode 100644 src/lib/include/fwts_tpm.h > create mode 100644 src/tpm/tpmevlogdump/tpmevlogdump.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index b0e51dd..19ae7a0 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -183,6 +183,7 @@ fwts_SOURCES = main.c \ > pci/aspm/aspm.c \ > pci/crs/crs.c \ > pci/maxreadreq/maxreadreq.c \ > + tpm/tpmevlogdump/tpmevlogdump.c \ > uefi/csm/csm.c \ > uefi/uefidump/uefidump.c \ > uefi/uefirttime/uefirttime.c \ > diff --git a/src/lib/include/fwts_tpm.h b/src/lib/include/fwts_tpm.h > new file mode 100644 > index 0000000..baeb5cc > --- /dev/null > +++ b/src/lib/include/fwts_tpm.h > @@ -0,0 +1,166 @@ > +/* > + * Copyright (C) 2020 Canonical > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > + > +#ifndef __FWTS_TPM_H__ > +#define __FWTS_TPM_H__ > + > +PRAGMA_PUSH > +PRAGMA_PACK_WARN_OFF > + > +#define FWTS_TPM_EVENTLOG_V2_SIGNATURE "Spec ID Event03" > + > +/* define from tpm2-tss */ > +#define TPM2_SHA_DIGEST_SIZE 20 > +#define TPM2_SHA1_DIGEST_SIZE 20 > +#define TPM2_SHA256_DIGEST_SIZE 32 > +#define TPM2_SHA384_DIGEST_SIZE 48 > +#define TPM2_SHA512_DIGEST_SIZE 64 > + > +typedef uint16_t TPM2_ALG_ID; > +#define TPM2_ALG_ERROR ((TPM2_ALG_ID) 0x0000) > +#define TPM2_ALG_RSA ((TPM2_ALG_ID) 0x0001) > +#define TPM2_ALG_TDES ((TPM2_ALG_ID) 0x0003) > +#define TPM2_ALG_SHA ((TPM2_ALG_ID) 0x0004) > +#define TPM2_ALG_SHA1 ((TPM2_ALG_ID) 0x0004) > +#define TPM2_ALG_HMAC ((TPM2_ALG_ID) 0x0005) > +#define TPM2_ALG_AES ((TPM2_ALG_ID) 0x0006) > +#define TPM2_ALG_MGF1 ((TPM2_ALG_ID) 0x0007) > +#define TPM2_ALG_KEYEDHASH ((TPM2_ALG_ID) 0x0008) > +#define TPM2_ALG_XOR ((TPM2_ALG_ID) 0x000A) > +#define TPM2_ALG_SHA256 ((TPM2_ALG_ID) 0x000B) > +#define TPM2_ALG_SHA384 ((TPM2_ALG_ID) 0x000C) > +#define TPM2_ALG_SHA512 ((TPM2_ALG_ID) 0x000D) > +#define TPM2_ALG_NULL ((TPM2_ALG_ID) 0x0010) > +#define TPM2_ALG_SM3_256 ((TPM2_ALG_ID) 0x0012) > +#define TPM2_ALG_SM4 ((TPM2_ALG_ID) 0x0013) > +#define TPM2_ALG_RSASSA ((TPM2_ALG_ID) 0x0014) > +#define TPM2_ALG_RSAES ((TPM2_ALG_ID) 0x0015) > +#define TPM2_ALG_RSAPSS ((TPM2_ALG_ID) 0x0016) > +#define TPM2_ALG_OAEP ((TPM2_ALG_ID) 0x0017) > +#define TPM2_ALG_ECDSA ((TPM2_ALG_ID) 0x0018) > +#define TPM2_ALG_ECDH ((TPM2_ALG_ID) 0x0019) > +#define TPM2_ALG_ECDAA ((TPM2_ALG_ID) 0x001A) > +#define TPM2_ALG_SM2 ((TPM2_ALG_ID) 0x001B) > +#define TPM2_ALG_ECSCHNORR ((TPM2_ALG_ID) 0x001C) > +#define TPM2_ALG_ECMQV ((TPM2_ALG_ID) 0x001D) > +#define TPM2_ALG_KDF1_SP800_56A ((TPM2_ALG_ID) 0x0020) > +#define TPM2_ALG_KDF2 ((TPM2_ALG_ID) 0x0021) > +#define TPM2_ALG_KDF1_SP800_108 ((TPM2_ALG_ID) 0x0022) > +#define TPM2_ALG_ECC ((TPM2_ALG_ID) 0x0023) > +#define TPM2_ALG_SYMCIPHER ((TPM2_ALG_ID) 0x0025) > +#define TPM2_ALG_CAMELLIA ((TPM2_ALG_ID) 0x0026) > +#define TPM2_ALG_CMAC ((TPM2_ALG_ID) 0x003F) > +#define TPM2_ALG_CTR ((TPM2_ALG_ID) 0x0040) > +#define TPM2_ALG_SHA3_256 ((TPM2_ALG_ID) 0x0027) > +#define TPM2_ALG_SHA3_384 ((TPM2_ALG_ID) 0x0028) > +#define TPM2_ALG_SHA3_512 ((TPM2_ALG_ID) 0x0029) > +#define TPM2_ALG_OFB ((TPM2_ALG_ID) 0x0041) > +#define TPM2_ALG_CBC ((TPM2_ALG_ID) 0x0042) > +#define TPM2_ALG_CFB ((TPM2_ALG_ID) 0x0043) > +#define TPM2_ALG_ECB ((TPM2_ALG_ID) 0x0044) > + > +/* > + * define from TCG PC Client Platform Firmware Profile Specification > + * https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ > + */ > + > +typedef enum { > + EV_PREBOOT_CERT = 0x00000000, > + EV_POST_CODE = 0x00000001, > + EV_UNUSED = 0x00000002, > + EV_NO_ACTION = 0x00000003, > + EV_SEPARATOR = 0x00000004, > + EV_ACTION = 0x00000005, > + EV_EVENT_TAG = 0x00000006, > + EV_S_CRTM_CONTENTS = 0x00000007, > + EV_S_CRTM_VERSION = 0x00000008, > + EV_CPU_MICROCODE = 0x00000009, > + EV_PLATFORM_CONFIG_FLAGS = 0x0000000a, > + EV_TABLE_OF_DEVICES = 0x0000000b, > + EV_COMPACT_HASH = 0x0000000c, > + EV_IPL = 0x0000000d, > + EV_IPL_PARTITION_DATA = 0x0000000e, > + EV_NONHOST_CODE = 0x0000000f, > + EV_NONHOST_CONFIG = 0x00000010, > + EV_NONHOST_INFO = 0x00000011, > + EV_OMIT_BOOT_DEVICE_EVENTS = 0x00000012, > + EV_EFI_EVENT_BASE = 0x80000000, > + EV_EFI_VARIABLE_DRIVER_CONFIG = 0x80000001, > + EV_EFI_VARIABLE_BOOT = 0x80000002, > + EV_EFI_BOOT_SERVICES_APPLICATION = 0x80000003, > + EV_EFI_BOOT_SERVICES_DRIVER = 0x80000004, > + EV_EFI_RUNTIME_SERVICES_DRIVER = 0x80000005, > + EV_EFI_GPT_EVENT = 0x80000006, > + EV_EFI_ACTION = 0x80000007, > + EV_EFI_PLATFORM_FIRMWARE_BLOB = 0x80000008, > + EV_EFI_HANDOFF_TABLES = 0x80000009, > + EV_EFI_HCRTM_EVENT = 0x80000010, > + EV_EFI_VARIABLE_AUTHORITY = 0x800000e0 > +} fwts_tpmlog_event_type; > + > + > +typedef struct { > + uint32_t pcr_index; > + uint32_t event_type; > + uint8_t digest[20]; > + uint32_t event_data_size; > + uint8_t event[0]; > +} __attribute__ ((packed)) fwts_pc_client_pcr_event; > + > +typedef struct { > +uint16_t algorithm_id; > +uint16_t digest_size; > +} __attribute__ ((packed)) fwts_spec_id_event_alg_sz; > + > +typedef struct { > + 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 number_of_alg; > +/* > + * Below items are not fix sizes, skip to define them > + * but it should be calculated when evaluate the > + * struct size. > + */ > +// fwts_spec_id_event_alg_sz digest_sizes[0]; > +// uint8_t vendor_info_size; > +// uint8_t vendor_info[0]; > +} __attribute__ ((packed)) fwts_efi_spec_id_event; > + I'd rather not have // comments in fwts if that's OK > + > +typedef struct { > + uint32_t pcr_index; > + uint32_t event_type; > + uint32_t digests_count; > +/* > + * Below items are not fix size, skip to define them > + * but it should be calculated when evaluate the > + * struct size. > + */ > +// uint8_t digests[0]; > +// uint32_t event_size; > +// uint8_t event[eventSize] missing ; after event[eventSize], and no // comments please > +} __attribute__ ((packed)) fwts_tcg_pcr_event2; > + > +PRAGMA_POP > + > +#endif > diff --git a/src/tpm/tpmevlogdump/tpmevlogdump.c b/src/tpm/tpmevlogdump/tpmevlogdump.c > new file mode 100644 > index 0000000..cd515fd > --- /dev/null > +++ b/src/tpm/tpmevlogdump/tpmevlogdump.c > @@ -0,0 +1,408 @@ > +/* > + * Copyright (C) 2020 Canonical > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > +#include "fwts.h" > + > +#include <sys/types.h> > +#include <dirent.h> > +#include <errno.h> > +#include <sys/stat.h> > +#include <fcntl.h> > + > +#include "fwts_tpm.h" > + > +#define FWTS_TPM_LOG_DIR_PATH "/sys/kernel/security" > + > +static void tpmevlogdump_data_hexdump(fwts_framework *fw, uint8_t *data, size_t size, char *str) > +{ > + size_t i; > + > + fwts_log_info_verbatim(fw, "%s: ", str); > + for (i = 0; i < size; i += 16) { > + char buffer[128]; > + size_t left = size - i; > + > + fwts_dump_raw_data(buffer, sizeof(buffer), data + i, i, left > 16 ? 16 : left); > + fwts_log_info_verbatim(fw, "%s", buffer+2); spaces between better and + and 2, buffer + 2 is preferred > + } > +} > + > +static char *tpmevlogdump_evtype_to_string (fwts_tpmlog_event_type event_type) > +{ A switch() statement is preferred > + if (event_type == EV_PREBOOT_CERT) > + return "EV_PREBOOT_CERT"; > + if (event_type == EV_POST_CODE) > + return "EV_POST_CODE"; > + if (event_type == EV_UNUSED) > + return "EV_UNUSED"; > + if (event_type == EV_NO_ACTION) > + return "EV_NO_ACTION"; > + if (event_type == EV_SEPARATOR) > + return "EV_SEPARATOR"; > + if (event_type == EV_ACTION) > + return "EV_ACTION"; > + if (event_type == EV_EVENT_TAG) > + return "EV_EVENT_TAG"; > + if (event_type == EV_S_CRTM_CONTENTS) > + return "EV_S_CRTM_CONTENTS"; > + if (event_type == EV_S_CRTM_VERSION) > + return "EV_S_CRTM_VERSION"; > + if (event_type == EV_CPU_MICROCODE) > + return "EV_CPU_MICROCODE"; > + if (event_type == EV_PLATFORM_CONFIG_FLAGS) > + return "EV_PLATFORM_CONFIG_FLAGS"; > + if (event_type == EV_TABLE_OF_DEVICES) > + return "EV_TABLE_OF_DEVICES"; > + if (event_type == EV_COMPACT_HASH) > + return "EV_COMPACT_HASH"; > + if (event_type == EV_IPL) > + return "EV_IPL"; > + if (event_type == EV_IPL_PARTITION_DATA) > + return "EV_IPL_PARTITION_DATA"; > + if (event_type == EV_NONHOST_CODE) > + return "EV_NONHOST_CODE"; > + if (event_type == EV_NONHOST_CONFIG) > + return "EV_NONHOST_CONFIG"; > + if (event_type == EV_NONHOST_INFO) > + return "EV_NONHOST_INFO"; > + if (event_type == EV_OMIT_BOOT_DEVICE_EVENTS) > + return "EV_OMIT_BOOT_DEVICE_EVENTS"; > + if (event_type == EV_EFI_EVENT_BASE) > + return "EV_EFI_EVENT_BASE"; > + if (event_type == EV_EFI_VARIABLE_DRIVER_CONFIG) > + return "EV_EFI_VARIABLE_DRIVER_CONFIG"; > + if (event_type == EV_EFI_VARIABLE_BOOT) > + return "EV_EFI_VARIABLE_BOOT"; > + if (event_type == EV_EFI_BOOT_SERVICES_APPLICATION) > + return "EV_BOOT_SERVICES_APPLICATION"; > + if (event_type == EV_EFI_BOOT_SERVICES_DRIVER) > + return "EV_EFI_BOOT_SERVICES_DRIVER"; > + if (event_type == EV_EFI_RUNTIME_SERVICES_DRIVER) > + return "EV_EFI_RUNTIME_SERVICES_DRIVER"; > + if (event_type == EV_EFI_GPT_EVENT) > + return "EV_EFI_GPT_EVENT"; > + if (event_type == EV_EFI_ACTION) > + return "EV_EFI_ACTION"; > + if (event_type == EV_EFI_PLATFORM_FIRMWARE_BLOB) > + return "EV_EFI_PLATFORM_FIRMWARE_BLOB"; > + if (event_type == EV_EFI_HANDOFF_TABLES) > + return "EV_EFI_HANDOFF_TABLES"; > + if (event_type == EV_EFI_HCRTM_EVENT) > + return "EV_EFI_HCRTM_EVENT"; > + if (event_type == EV_EFI_VARIABLE_AUTHORITY) > + return "EV_EFI_EFI_VARIABLE_AUTHORITY"; > + return "Unknown"; > +} > + > +static char *tpmevlogdump_hash_to_string (TPM2_ALG_ID hash) > +{ switch statement here > + if (hash == TPM2_ALG_SHA1) > + return "SHA1"; > + if (hash == TPM2_ALG_SHA256) > + return "SHA256"; > + if (hash == TPM2_ALG_SHA384) > + return "SHA384"; > + if (hash == TPM2_ALG_SHA512) > + return "SHA512"; > + return "Unknown"; > +} > + > +static uint8_t tpmevlogdump_get_hash_size (TPM2_ALG_ID hash) > +{ switch statement here too > + if (hash == TPM2_ALG_SHA1) > + return TPM2_SHA1_DIGEST_SIZE; > + if (hash == TPM2_ALG_SHA256) > + return TPM2_SHA256_DIGEST_SIZE; > + if (hash == TPM2_ALG_SHA384) > + return TPM2_SHA384_DIGEST_SIZE; > + if (hash == TPM2_ALG_SHA512) > + return TPM2_SHA512_DIGEST_SIZE; > + return 0; > +} > + > +static size_t tpmevlogdump_specid_event_dump(fwts_framework *fw, uint8_t *data, size_t len) > +{ > + > + uint32_t i; > + size_t len_remain = len; > + uint8_t *pdata = data; > + char *str_info; > + > + /* check the data length for dumping */ > + if (len_remain < sizeof(fwts_pc_client_pcr_event)) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + fwts_pc_client_pcr_event *pc_event = (fwts_pc_client_pcr_event *)pdata; > + fwts_log_info_verbatim(fw, "PCRIndex: 0x%8.8" PRIx32, pc_event->pcr_index); > + str_info = tpmevlogdump_evtype_to_string(pc_event->event_type); > + fwts_log_info_verbatim(fw, "EventType: 0x%8.8" PRIx32 "(%s)", pc_event->event_type, str_info); > + tpmevlogdump_data_hexdump(fw, pc_event->digest, sizeof(pc_event->digest), "Digest"); > + fwts_log_info_verbatim(fw, "EventSize: 0x%8.8" PRIx32, pc_event->event_data_size); > + > + pdata += sizeof(fwts_pc_client_pcr_event); > + len_remain -= sizeof(fwts_pc_client_pcr_event); > + > + /* check the data length for dumping */ > + if (len_remain < sizeof(fwts_efi_spec_id_event)) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + fwts_efi_spec_id_event *specid_evcent = (fwts_efi_spec_id_event *)pdata; > + fwts_log_info_verbatim(fw, "EfiSpecIdEvent:"); > + fwts_log_info_verbatim(fw, " Signature: %s", (char *)specid_evcent->signature); > + fwts_log_info_verbatim(fw, " platformClass: 0x%8.8" PRIx32, specid_evcent->platform_class); > + fwts_log_info_verbatim(fw, " specVersionMinor: 0x%" PRIx8, specid_evcent->spec_version_minor); > + fwts_log_info_verbatim(fw, " specVersionMajor: 0x%" PRIx8, specid_evcent->platform_class); > + fwts_log_info_verbatim(fw, " specErrata: 0x%" PRIx8, specid_evcent->spec_errata); > + fwts_log_info_verbatim(fw, " uintnSize: 0x%" PRIx8, specid_evcent->uintn_size); > + fwts_log_info_verbatim(fw, " NumberOfAlgorithms: 0x%8.8" PRIx32, specid_evcent->number_of_alg); Minor output formatting nitpick, is it possible to have all the : lined up so the output something like: Signature: sometext platformClass: 0x01234567 specVersionMajor: 0x23 ... NumberOfAlgorithmns: 0x01 > + > + pdata += sizeof(fwts_efi_spec_id_event); > + len_remain -= sizeof(fwts_efi_spec_id_event); > + fwts_spec_id_event_alg_sz *alg_sz = (fwts_spec_id_event_alg_sz *)pdata; > + for (i = 0; i < specid_evcent->number_of_alg; i++) > + { ^^ for (i = 0; i < specid_evcent->number_of_alg; i++) { > + /* check the data length for dumping */ > + if (len_remain < sizeof(fwts_spec_id_event_alg_sz)) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + str_info = tpmevlogdump_hash_to_string(alg_sz->algorithm_id); > + fwts_log_info_verbatim(fw, " digestSizes[%d].AlgId: 0x%4.4" PRIx16 "(%s)", i, alg_sz->algorithm_id, str_info); > + fwts_log_info_verbatim(fw, " digestSizes[%d].DigestSize: %" PRIu16, i, alg_sz->digest_size); > + pdata += sizeof(fwts_spec_id_event_alg_sz); > + len_remain -= sizeof(fwts_spec_id_event_alg_sz); > + alg_sz = (fwts_spec_id_event_alg_sz *)pdata; > + } > + > + uint8_t vendor_info_size = *(uint8_t *)pdata; > + fwts_log_info_verbatim(fw, " vendorInfoSize: 0x%" PRIx8, vendor_info_size); > + pdata += sizeof(vendor_info_size); > + len_remain -= sizeof(vendor_info_size); > + if (vendor_info_size > 0) { > + /* check the data length for dumping */ > + if (len_remain < vendor_info_size) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + tpmevlogdump_data_hexdump(fw, pdata, vendor_info_size, " vendorInfo"); > + pdata += vendor_info_size; > + len_remain -= vendor_info_size; I understand the idea of updating pdata here, but it is effectively dead code as pdata is not referenced any more, so can the pdata += event_size be removed? > + } > + > + return len_remain; > +} > + > +static size_t tpmevlogdump_event_v2_dump(fwts_framework *fw, uint8_t *data, size_t len) > +{ > + uint32_t i; > + uint8_t *pdata = data; > + size_t len_remain = len; > + char *str_info; > + > + /* check the data length for dumping */ > + if (len_remain < sizeof(fwts_tcg_pcr_event2)) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + fwts_tcg_pcr_event2 *pcr_event2 = (fwts_tcg_pcr_event2 *)pdata; > + fwts_log_info_verbatim(fw, "PCRIndex: 0x%8.8" PRIx32, pcr_event2->pcr_index); > + str_info = tpmevlogdump_evtype_to_string(pcr_event2->event_type); > + fwts_log_info_verbatim(fw, "EventType: 0x%8.8" PRIx32 "(%s)", pcr_event2->event_type, str_info); > + fwts_log_info_verbatim(fw, "Digests Count : 0x%8.8" PRIx32, pcr_event2->digests_count); > + pdata += sizeof(fwts_tcg_pcr_event2); > + len_remain -= sizeof(fwts_tcg_pcr_event2); > + for (i = 0; i < pcr_event2->digests_count; i++) { > + uint8_t hash_size = 0; add a blank line after the declaration > + TPM2_ALG_ID alg_id = *(TPM2_ALG_ID *)pdata; > + /* check the data length for dumping */ > + if (len_remain < sizeof(TPM2_ALG_ID)) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + str_info = tpmevlogdump_hash_to_string(alg_id); > + fwts_log_info_verbatim(fw, " Digests[%d].AlgId: 0x%4.4" PRIx16 "(%s)", i, alg_id, str_info); > + hash_size = tpmevlogdump_get_hash_size(alg_id); > + if (!hash_size) { > + fwts_log_info(fw, "Unknown hash algorithm. Aborted."); > + return 0; > + } > + pdata += sizeof(TPM2_ALG_ID); > + len_remain -= sizeof(TPM2_ALG_ID); > + /* check the data length for dumping */ > + if (len_remain < sizeof(TPM2_ALG_ID)) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + tpmevlogdump_data_hexdump(fw, pdata, hash_size, " Digest"); > + pdata += hash_size; > + len_remain -= hash_size; > + } > + > + uint32_t event_size = *(uint32_t *)pdata; > + /* check the data length for dumping */ > + if (len_remain < event_size + sizeof(event_size)) { > + fwts_log_info(fw, "Cannot get enough length for dumping data."); > + return 0; > + } > + pdata += sizeof(event_size); > + len_remain -= sizeof(event_size); > + > + fwts_log_info_verbatim(fw, " EventSize: %" PRIu32, event_size); > + if (event_size > 0) { > + tpmevlogdump_data_hexdump(fw, pdata, event_size, " Event"); > + pdata += event_size; I understand the idea of updating pdata here, but it is effectively dead code as pdata is not referenced any more, so can the pdata += event_size be removed? > + len_remain -= event_size; > + } > + > + return len_remain; > +} > + > +static void tpmevlogdump_parser(fwts_framework *fw, uint8_t *data, size_t len) > +{ > + size_t t_len = len; > + size_t len_remain = 0; > + uint8_t *pdata = data; add a blank line here > + len_remain = tpmevlogdump_specid_event_dump(fw, pdata, t_len); > + fwts_log_nl(fw); > + pdata += (t_len - len_remain); > + while (len_remain > 0) { > + t_len = len_remain; > + len_remain = tpmevlogdump_event_v2_dump(fw, pdata, t_len); > + pdata += (t_len - len_remain); > + fwts_log_nl(fw); > + } > + return; > +} > + > +static uint8_t *tpmevlogdump_load_file(const int fd, size_t *length) > +{ > + uint8_t *ptr = NULL, *tmp; > + size_t size = 0; > + char buffer[4096]; > + > + *length = 0; > + > + for (;;) { > + ssize_t n = read(fd, buffer, sizeof(buffer)); > + > + if (n == 0) > + break; > + if (n < 0) { > + if (errno != EINTR && errno != EAGAIN) { > + fwts_low_free(ptr); should be free(ptr); > + return NULL; > + } > + continue; > + } > + if (n > (ssize_t)sizeof(buffer)) > + goto err; > + if (size + n > 0xffffffff) > + goto err; > + > + if ((tmp = (uint8_t*)realloc(ptr, size + n + 1)) == NULL) { > + free(ptr); > + return NULL; > + } > + ptr = tmp; > + memcpy(ptr + size, buffer, n); > + size += n; > + } > + > + if (!ptr || !size) > + goto err_no_data; > + > + *length = size; > + return ptr; > + > +err: > + free(ptr); > +err_no_data: > + *length = 0; > + return NULL; > +} > + > +static int tpmevlogdump_test1(fwts_framework *fw) > +{ > + DIR *dir; > + struct dirent *tpmdir; > + bool tpm_logfile_found = false; > + > + if (!(dir = opendir(FWTS_TPM_LOG_DIR_PATH))) { > + fwts_log_info(fw, "Cannot find the tpm event log. Aborted."); > + return FWTS_ABORTED; > + } > + > + do { > + tpmdir = readdir(dir); > + if (tpmdir && strstr(tpmdir->d_name, "tpm")) { > + char path[PATH_MAX]; > + uint8_t *data; > + int fd; > + size_t length; > + > + fwts_log_nl(fw); > + fwts_log_info_verbatim(fw, "%s", tpmdir->d_name); > + > + snprintf(path, sizeof(path), FWTS_TPM_LOG_DIR_PATH "/%s/binary_bios_measurements", tpmdir->d_name); > + > + if ((fd = open(path, O_RDONLY)) >= 0) { > + data = tpmevlogdump_load_file(fd, &length); > + tpm_logfile_found = true; > + if (data == NULL) { > + fwts_log_info(fw, "Cannot load the tpm event logs. Aborted."); > + closedir(dir); > + return FWTS_ABORTED; > + } else { > + /* check if the TPM2 eventlog */ > + if (strstr((char *)(data + sizeof(fwts_pc_client_pcr_event)), FWTS_TPM_EVENTLOG_V2_SIGNATURE)) > + tpmevlogdump_parser(fw, data, length); > + else { > + fwts_log_info(fw, "Cannot find the tpm2 event log. Aborted."); > + free(data); > + closedir(dir); > + return FWTS_ABORTED; > + } > + free(data); > + } > + } we need a close(fd) otherwise we leak an open file descriptor > + } > + } while (tpmdir); > + > + if (!tpm_logfile_found) { > + fwts_log_info(fw, "Cannot find the tpm event log. Aborted."); > + closedir(dir); > + return FWTS_ABORTED; > + } > + > + closedir(dir); > + return FWTS_OK; > +} > + > +static fwts_framework_minor_test tpmevlogdump_tests[] = { > + { tpmevlogdump_test1, "Dump Tpm2 Event Log." }, > + { NULL, NULL } > +}; > + > +static fwts_framework_ops tpmevlogdump_ops = { > + .description = "Dump Tpm2 Event Log.", > + .minor_tests = tpmevlogdump_tests > +}; > + > +FWTS_REGISTER("tpmevlogdump", &tpmevlogdump_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UTILS | FWTS_FLAG_ROOT_PRIV) >
diff --git a/src/Makefile.am b/src/Makefile.am index b0e51dd..19ae7a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -183,6 +183,7 @@ fwts_SOURCES = main.c \ pci/aspm/aspm.c \ pci/crs/crs.c \ pci/maxreadreq/maxreadreq.c \ + tpm/tpmevlogdump/tpmevlogdump.c \ uefi/csm/csm.c \ uefi/uefidump/uefidump.c \ uefi/uefirttime/uefirttime.c \ diff --git a/src/lib/include/fwts_tpm.h b/src/lib/include/fwts_tpm.h new file mode 100644 index 0000000..baeb5cc --- /dev/null +++ b/src/lib/include/fwts_tpm.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 Canonical + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef __FWTS_TPM_H__ +#define __FWTS_TPM_H__ + +PRAGMA_PUSH +PRAGMA_PACK_WARN_OFF + +#define FWTS_TPM_EVENTLOG_V2_SIGNATURE "Spec ID Event03" + +/* define from tpm2-tss */ +#define TPM2_SHA_DIGEST_SIZE 20 +#define TPM2_SHA1_DIGEST_SIZE 20 +#define TPM2_SHA256_DIGEST_SIZE 32 +#define TPM2_SHA384_DIGEST_SIZE 48 +#define TPM2_SHA512_DIGEST_SIZE 64 + +typedef uint16_t TPM2_ALG_ID; +#define TPM2_ALG_ERROR ((TPM2_ALG_ID) 0x0000) +#define TPM2_ALG_RSA ((TPM2_ALG_ID) 0x0001) +#define TPM2_ALG_TDES ((TPM2_ALG_ID) 0x0003) +#define TPM2_ALG_SHA ((TPM2_ALG_ID) 0x0004) +#define TPM2_ALG_SHA1 ((TPM2_ALG_ID) 0x0004) +#define TPM2_ALG_HMAC ((TPM2_ALG_ID) 0x0005) +#define TPM2_ALG_AES ((TPM2_ALG_ID) 0x0006) +#define TPM2_ALG_MGF1 ((TPM2_ALG_ID) 0x0007) +#define TPM2_ALG_KEYEDHASH ((TPM2_ALG_ID) 0x0008) +#define TPM2_ALG_XOR ((TPM2_ALG_ID) 0x000A) +#define TPM2_ALG_SHA256 ((TPM2_ALG_ID) 0x000B) +#define TPM2_ALG_SHA384 ((TPM2_ALG_ID) 0x000C) +#define TPM2_ALG_SHA512 ((TPM2_ALG_ID) 0x000D) +#define TPM2_ALG_NULL ((TPM2_ALG_ID) 0x0010) +#define TPM2_ALG_SM3_256 ((TPM2_ALG_ID) 0x0012) +#define TPM2_ALG_SM4 ((TPM2_ALG_ID) 0x0013) +#define TPM2_ALG_RSASSA ((TPM2_ALG_ID) 0x0014) +#define TPM2_ALG_RSAES ((TPM2_ALG_ID) 0x0015) +#define TPM2_ALG_RSAPSS ((TPM2_ALG_ID) 0x0016) +#define TPM2_ALG_OAEP ((TPM2_ALG_ID) 0x0017) +#define TPM2_ALG_ECDSA ((TPM2_ALG_ID) 0x0018) +#define TPM2_ALG_ECDH ((TPM2_ALG_ID) 0x0019) +#define TPM2_ALG_ECDAA ((TPM2_ALG_ID) 0x001A) +#define TPM2_ALG_SM2 ((TPM2_ALG_ID) 0x001B) +#define TPM2_ALG_ECSCHNORR ((TPM2_ALG_ID) 0x001C) +#define TPM2_ALG_ECMQV ((TPM2_ALG_ID) 0x001D) +#define TPM2_ALG_KDF1_SP800_56A ((TPM2_ALG_ID) 0x0020) +#define TPM2_ALG_KDF2 ((TPM2_ALG_ID) 0x0021) +#define TPM2_ALG_KDF1_SP800_108 ((TPM2_ALG_ID) 0x0022) +#define TPM2_ALG_ECC ((TPM2_ALG_ID) 0x0023) +#define TPM2_ALG_SYMCIPHER ((TPM2_ALG_ID) 0x0025) +#define TPM2_ALG_CAMELLIA ((TPM2_ALG_ID) 0x0026) +#define TPM2_ALG_CMAC ((TPM2_ALG_ID) 0x003F) +#define TPM2_ALG_CTR ((TPM2_ALG_ID) 0x0040) +#define TPM2_ALG_SHA3_256 ((TPM2_ALG_ID) 0x0027) +#define TPM2_ALG_SHA3_384 ((TPM2_ALG_ID) 0x0028) +#define TPM2_ALG_SHA3_512 ((TPM2_ALG_ID) 0x0029) +#define TPM2_ALG_OFB ((TPM2_ALG_ID) 0x0041) +#define TPM2_ALG_CBC ((TPM2_ALG_ID) 0x0042) +#define TPM2_ALG_CFB ((TPM2_ALG_ID) 0x0043) +#define TPM2_ALG_ECB ((TPM2_ALG_ID) 0x0044) + +/* + * define from TCG PC Client Platform Firmware Profile Specification + * https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ + */ + +typedef enum { + EV_PREBOOT_CERT = 0x00000000, + EV_POST_CODE = 0x00000001, + EV_UNUSED = 0x00000002, + EV_NO_ACTION = 0x00000003, + EV_SEPARATOR = 0x00000004, + EV_ACTION = 0x00000005, + EV_EVENT_TAG = 0x00000006, + EV_S_CRTM_CONTENTS = 0x00000007, + EV_S_CRTM_VERSION = 0x00000008, + EV_CPU_MICROCODE = 0x00000009, + EV_PLATFORM_CONFIG_FLAGS = 0x0000000a, + EV_TABLE_OF_DEVICES = 0x0000000b, + EV_COMPACT_HASH = 0x0000000c, + EV_IPL = 0x0000000d, + EV_IPL_PARTITION_DATA = 0x0000000e, + EV_NONHOST_CODE = 0x0000000f, + EV_NONHOST_CONFIG = 0x00000010, + EV_NONHOST_INFO = 0x00000011, + EV_OMIT_BOOT_DEVICE_EVENTS = 0x00000012, + EV_EFI_EVENT_BASE = 0x80000000, + EV_EFI_VARIABLE_DRIVER_CONFIG = 0x80000001, + EV_EFI_VARIABLE_BOOT = 0x80000002, + EV_EFI_BOOT_SERVICES_APPLICATION = 0x80000003, + EV_EFI_BOOT_SERVICES_DRIVER = 0x80000004, + EV_EFI_RUNTIME_SERVICES_DRIVER = 0x80000005, + EV_EFI_GPT_EVENT = 0x80000006, + EV_EFI_ACTION = 0x80000007, + EV_EFI_PLATFORM_FIRMWARE_BLOB = 0x80000008, + EV_EFI_HANDOFF_TABLES = 0x80000009, + EV_EFI_HCRTM_EVENT = 0x80000010, + EV_EFI_VARIABLE_AUTHORITY = 0x800000e0 +} fwts_tpmlog_event_type; + + +typedef struct { + uint32_t pcr_index; + uint32_t event_type; + uint8_t digest[20]; + uint32_t event_data_size; + uint8_t event[0]; +} __attribute__ ((packed)) fwts_pc_client_pcr_event; + +typedef struct { +uint16_t algorithm_id; +uint16_t digest_size; +} __attribute__ ((packed)) fwts_spec_id_event_alg_sz; + +typedef struct { + 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 number_of_alg; +/* + * Below items are not fix sizes, skip to define them + * but it should be calculated when evaluate the + * struct size. + */ +// fwts_spec_id_event_alg_sz digest_sizes[0]; +// uint8_t vendor_info_size; +// uint8_t vendor_info[0]; +} __attribute__ ((packed)) fwts_efi_spec_id_event; + + +typedef struct { + uint32_t pcr_index; + uint32_t event_type; + uint32_t digests_count; +/* + * Below items are not fix size, skip to define them + * but it should be calculated when evaluate the + * struct size. + */ +// uint8_t digests[0]; +// uint32_t event_size; +// uint8_t event[eventSize] +} __attribute__ ((packed)) fwts_tcg_pcr_event2; + +PRAGMA_POP + +#endif diff --git a/src/tpm/tpmevlogdump/tpmevlogdump.c b/src/tpm/tpmevlogdump/tpmevlogdump.c new file mode 100644 index 0000000..cd515fd --- /dev/null +++ b/src/tpm/tpmevlogdump/tpmevlogdump.c @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2020 Canonical + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "fwts.h" + +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "fwts_tpm.h" + +#define FWTS_TPM_LOG_DIR_PATH "/sys/kernel/security" + +static void tpmevlogdump_data_hexdump(fwts_framework *fw, uint8_t *data, size_t size, char *str) +{ + size_t i; + + fwts_log_info_verbatim(fw, "%s: ", str); + for (i = 0; i < size; i += 16) { + char buffer[128]; + size_t left = size - i; + + fwts_dump_raw_data(buffer, sizeof(buffer), data + i, i, left > 16 ? 16 : left); + fwts_log_info_verbatim(fw, "%s", buffer+2); + } +} + +static char *tpmevlogdump_evtype_to_string (fwts_tpmlog_event_type event_type) +{ + if (event_type == EV_PREBOOT_CERT) + return "EV_PREBOOT_CERT"; + if (event_type == EV_POST_CODE) + return "EV_POST_CODE"; + if (event_type == EV_UNUSED) + return "EV_UNUSED"; + if (event_type == EV_NO_ACTION) + return "EV_NO_ACTION"; + if (event_type == EV_SEPARATOR) + return "EV_SEPARATOR"; + if (event_type == EV_ACTION) + return "EV_ACTION"; + if (event_type == EV_EVENT_TAG) + return "EV_EVENT_TAG"; + if (event_type == EV_S_CRTM_CONTENTS) + return "EV_S_CRTM_CONTENTS"; + if (event_type == EV_S_CRTM_VERSION) + return "EV_S_CRTM_VERSION"; + if (event_type == EV_CPU_MICROCODE) + return "EV_CPU_MICROCODE"; + if (event_type == EV_PLATFORM_CONFIG_FLAGS) + return "EV_PLATFORM_CONFIG_FLAGS"; + if (event_type == EV_TABLE_OF_DEVICES) + return "EV_TABLE_OF_DEVICES"; + if (event_type == EV_COMPACT_HASH) + return "EV_COMPACT_HASH"; + if (event_type == EV_IPL) + return "EV_IPL"; + if (event_type == EV_IPL_PARTITION_DATA) + return "EV_IPL_PARTITION_DATA"; + if (event_type == EV_NONHOST_CODE) + return "EV_NONHOST_CODE"; + if (event_type == EV_NONHOST_CONFIG) + return "EV_NONHOST_CONFIG"; + if (event_type == EV_NONHOST_INFO) + return "EV_NONHOST_INFO"; + if (event_type == EV_OMIT_BOOT_DEVICE_EVENTS) + return "EV_OMIT_BOOT_DEVICE_EVENTS"; + if (event_type == EV_EFI_EVENT_BASE) + return "EV_EFI_EVENT_BASE"; + if (event_type == EV_EFI_VARIABLE_DRIVER_CONFIG) + return "EV_EFI_VARIABLE_DRIVER_CONFIG"; + if (event_type == EV_EFI_VARIABLE_BOOT) + return "EV_EFI_VARIABLE_BOOT"; + if (event_type == EV_EFI_BOOT_SERVICES_APPLICATION) + return "EV_BOOT_SERVICES_APPLICATION"; + if (event_type == EV_EFI_BOOT_SERVICES_DRIVER) + return "EV_EFI_BOOT_SERVICES_DRIVER"; + if (event_type == EV_EFI_RUNTIME_SERVICES_DRIVER) + return "EV_EFI_RUNTIME_SERVICES_DRIVER"; + if (event_type == EV_EFI_GPT_EVENT) + return "EV_EFI_GPT_EVENT"; + if (event_type == EV_EFI_ACTION) + return "EV_EFI_ACTION"; + if (event_type == EV_EFI_PLATFORM_FIRMWARE_BLOB) + return "EV_EFI_PLATFORM_FIRMWARE_BLOB"; + if (event_type == EV_EFI_HANDOFF_TABLES) + return "EV_EFI_HANDOFF_TABLES"; + if (event_type == EV_EFI_HCRTM_EVENT) + return "EV_EFI_HCRTM_EVENT"; + if (event_type == EV_EFI_VARIABLE_AUTHORITY) + return "EV_EFI_EFI_VARIABLE_AUTHORITY"; + return "Unknown"; +} + +static char *tpmevlogdump_hash_to_string (TPM2_ALG_ID hash) +{ + if (hash == TPM2_ALG_SHA1) + return "SHA1"; + if (hash == TPM2_ALG_SHA256) + return "SHA256"; + if (hash == TPM2_ALG_SHA384) + return "SHA384"; + if (hash == TPM2_ALG_SHA512) + return "SHA512"; + return "Unknown"; +} + +static uint8_t tpmevlogdump_get_hash_size (TPM2_ALG_ID hash) +{ + if (hash == TPM2_ALG_SHA1) + return TPM2_SHA1_DIGEST_SIZE; + if (hash == TPM2_ALG_SHA256) + return TPM2_SHA256_DIGEST_SIZE; + if (hash == TPM2_ALG_SHA384) + return TPM2_SHA384_DIGEST_SIZE; + if (hash == TPM2_ALG_SHA512) + return TPM2_SHA512_DIGEST_SIZE; + return 0; +} + +static size_t tpmevlogdump_specid_event_dump(fwts_framework *fw, uint8_t *data, size_t len) +{ + + uint32_t i; + size_t len_remain = len; + uint8_t *pdata = data; + char *str_info; + + /* check the data length for dumping */ + if (len_remain < sizeof(fwts_pc_client_pcr_event)) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + fwts_pc_client_pcr_event *pc_event = (fwts_pc_client_pcr_event *)pdata; + fwts_log_info_verbatim(fw, "PCRIndex: 0x%8.8" PRIx32, pc_event->pcr_index); + str_info = tpmevlogdump_evtype_to_string(pc_event->event_type); + fwts_log_info_verbatim(fw, "EventType: 0x%8.8" PRIx32 "(%s)", pc_event->event_type, str_info); + tpmevlogdump_data_hexdump(fw, pc_event->digest, sizeof(pc_event->digest), "Digest"); + fwts_log_info_verbatim(fw, "EventSize: 0x%8.8" PRIx32, pc_event->event_data_size); + + pdata += sizeof(fwts_pc_client_pcr_event); + len_remain -= sizeof(fwts_pc_client_pcr_event); + + /* check the data length for dumping */ + if (len_remain < sizeof(fwts_efi_spec_id_event)) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + fwts_efi_spec_id_event *specid_evcent = (fwts_efi_spec_id_event *)pdata; + fwts_log_info_verbatim(fw, "EfiSpecIdEvent:"); + fwts_log_info_verbatim(fw, " Signature: %s", (char *)specid_evcent->signature); + fwts_log_info_verbatim(fw, " platformClass: 0x%8.8" PRIx32, specid_evcent->platform_class); + fwts_log_info_verbatim(fw, " specVersionMinor: 0x%" PRIx8, specid_evcent->spec_version_minor); + fwts_log_info_verbatim(fw, " specVersionMajor: 0x%" PRIx8, specid_evcent->platform_class); + fwts_log_info_verbatim(fw, " specErrata: 0x%" PRIx8, specid_evcent->spec_errata); + fwts_log_info_verbatim(fw, " uintnSize: 0x%" PRIx8, specid_evcent->uintn_size); + fwts_log_info_verbatim(fw, " NumberOfAlgorithms: 0x%8.8" PRIx32, specid_evcent->number_of_alg); + + pdata += sizeof(fwts_efi_spec_id_event); + len_remain -= sizeof(fwts_efi_spec_id_event); + fwts_spec_id_event_alg_sz *alg_sz = (fwts_spec_id_event_alg_sz *)pdata; + for (i = 0; i < specid_evcent->number_of_alg; i++) + { + /* check the data length for dumping */ + if (len_remain < sizeof(fwts_spec_id_event_alg_sz)) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + str_info = tpmevlogdump_hash_to_string(alg_sz->algorithm_id); + fwts_log_info_verbatim(fw, " digestSizes[%d].AlgId: 0x%4.4" PRIx16 "(%s)", i, alg_sz->algorithm_id, str_info); + fwts_log_info_verbatim(fw, " digestSizes[%d].DigestSize: %" PRIu16, i, alg_sz->digest_size); + pdata += sizeof(fwts_spec_id_event_alg_sz); + len_remain -= sizeof(fwts_spec_id_event_alg_sz); + alg_sz = (fwts_spec_id_event_alg_sz *)pdata; + } + + uint8_t vendor_info_size = *(uint8_t *)pdata; + fwts_log_info_verbatim(fw, " vendorInfoSize: 0x%" PRIx8, vendor_info_size); + pdata += sizeof(vendor_info_size); + len_remain -= sizeof(vendor_info_size); + if (vendor_info_size > 0) { + /* check the data length for dumping */ + if (len_remain < vendor_info_size) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + tpmevlogdump_data_hexdump(fw, pdata, vendor_info_size, " vendorInfo"); + pdata += vendor_info_size; + len_remain -= vendor_info_size; + } + + return len_remain; +} + +static size_t tpmevlogdump_event_v2_dump(fwts_framework *fw, uint8_t *data, size_t len) +{ + uint32_t i; + uint8_t *pdata = data; + size_t len_remain = len; + char *str_info; + + /* check the data length for dumping */ + if (len_remain < sizeof(fwts_tcg_pcr_event2)) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + fwts_tcg_pcr_event2 *pcr_event2 = (fwts_tcg_pcr_event2 *)pdata; + fwts_log_info_verbatim(fw, "PCRIndex: 0x%8.8" PRIx32, pcr_event2->pcr_index); + str_info = tpmevlogdump_evtype_to_string(pcr_event2->event_type); + fwts_log_info_verbatim(fw, "EventType: 0x%8.8" PRIx32 "(%s)", pcr_event2->event_type, str_info); + fwts_log_info_verbatim(fw, "Digests Count : 0x%8.8" PRIx32, pcr_event2->digests_count); + pdata += sizeof(fwts_tcg_pcr_event2); + len_remain -= sizeof(fwts_tcg_pcr_event2); + for (i = 0; i < pcr_event2->digests_count; i++) { + uint8_t hash_size = 0; + TPM2_ALG_ID alg_id = *(TPM2_ALG_ID *)pdata; + /* check the data length for dumping */ + if (len_remain < sizeof(TPM2_ALG_ID)) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + str_info = tpmevlogdump_hash_to_string(alg_id); + fwts_log_info_verbatim(fw, " Digests[%d].AlgId: 0x%4.4" PRIx16 "(%s)", i, alg_id, str_info); + hash_size = tpmevlogdump_get_hash_size(alg_id); + if (!hash_size) { + fwts_log_info(fw, "Unknown hash algorithm. Aborted."); + return 0; + } + pdata += sizeof(TPM2_ALG_ID); + len_remain -= sizeof(TPM2_ALG_ID); + /* check the data length for dumping */ + if (len_remain < sizeof(TPM2_ALG_ID)) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + tpmevlogdump_data_hexdump(fw, pdata, hash_size, " Digest"); + pdata += hash_size; + len_remain -= hash_size; + } + + uint32_t event_size = *(uint32_t *)pdata; + /* check the data length for dumping */ + if (len_remain < event_size + sizeof(event_size)) { + fwts_log_info(fw, "Cannot get enough length for dumping data."); + return 0; + } + pdata += sizeof(event_size); + len_remain -= sizeof(event_size); + + fwts_log_info_verbatim(fw, " EventSize: %" PRIu32, event_size); + if (event_size > 0) { + tpmevlogdump_data_hexdump(fw, pdata, event_size, " Event"); + pdata += event_size; + len_remain -= event_size; + } + + return len_remain; +} + +static void tpmevlogdump_parser(fwts_framework *fw, uint8_t *data, size_t len) +{ + size_t t_len = len; + size_t len_remain = 0; + uint8_t *pdata = data; + len_remain = tpmevlogdump_specid_event_dump(fw, pdata, t_len); + fwts_log_nl(fw); + pdata += (t_len - len_remain); + while (len_remain > 0) { + t_len = len_remain; + len_remain = tpmevlogdump_event_v2_dump(fw, pdata, t_len); + pdata += (t_len - len_remain); + fwts_log_nl(fw); + } + return; +} + +static uint8_t *tpmevlogdump_load_file(const int fd, size_t *length) +{ + uint8_t *ptr = NULL, *tmp; + size_t size = 0; + char buffer[4096]; + + *length = 0; + + for (;;) { + ssize_t n = read(fd, buffer, sizeof(buffer)); + + if (n == 0) + break; + if (n < 0) { + if (errno != EINTR && errno != EAGAIN) { + fwts_low_free(ptr); + return NULL; + } + continue; + } + if (n > (ssize_t)sizeof(buffer)) + goto err; + if (size + n > 0xffffffff) + goto err; + + if ((tmp = (uint8_t*)realloc(ptr, size + n + 1)) == NULL) { + free(ptr); + return NULL; + } + ptr = tmp; + memcpy(ptr + size, buffer, n); + size += n; + } + + if (!ptr || !size) + goto err_no_data; + + *length = size; + return ptr; + +err: + free(ptr); +err_no_data: + *length = 0; + return NULL; +} + +static int tpmevlogdump_test1(fwts_framework *fw) +{ + DIR *dir; + struct dirent *tpmdir; + bool tpm_logfile_found = false; + + if (!(dir = opendir(FWTS_TPM_LOG_DIR_PATH))) { + fwts_log_info(fw, "Cannot find the tpm event log. Aborted."); + return FWTS_ABORTED; + } + + do { + tpmdir = readdir(dir); + if (tpmdir && strstr(tpmdir->d_name, "tpm")) { + char path[PATH_MAX]; + uint8_t *data; + int fd; + size_t length; + + fwts_log_nl(fw); + fwts_log_info_verbatim(fw, "%s", tpmdir->d_name); + + snprintf(path, sizeof(path), FWTS_TPM_LOG_DIR_PATH "/%s/binary_bios_measurements", tpmdir->d_name); + + if ((fd = open(path, O_RDONLY)) >= 0) { + data = tpmevlogdump_load_file(fd, &length); + tpm_logfile_found = true; + if (data == NULL) { + fwts_log_info(fw, "Cannot load the tpm event logs. Aborted."); + closedir(dir); + return FWTS_ABORTED; + } else { + /* check if the TPM2 eventlog */ + if (strstr((char *)(data + sizeof(fwts_pc_client_pcr_event)), FWTS_TPM_EVENTLOG_V2_SIGNATURE)) + tpmevlogdump_parser(fw, data, length); + else { + fwts_log_info(fw, "Cannot find the tpm2 event log. Aborted."); + free(data); + closedir(dir); + return FWTS_ABORTED; + } + free(data); + } + } + } + } while (tpmdir); + + if (!tpm_logfile_found) { + fwts_log_info(fw, "Cannot find the tpm event log. Aborted."); + closedir(dir); + return FWTS_ABORTED; + } + + closedir(dir); + return FWTS_OK; +} + +static fwts_framework_minor_test tpmevlogdump_tests[] = { + { tpmevlogdump_test1, "Dump Tpm2 Event Log." }, + { NULL, NULL } +}; + +static fwts_framework_ops tpmevlogdump_ops = { + .description = "Dump Tpm2 Event Log.", + .minor_tests = tpmevlogdump_tests +}; + +FWTS_REGISTER("tpmevlogdump", &tpmevlogdump_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UTILS | FWTS_FLAG_ROOT_PRIV)
The tpm event log define in "TCG PC Client Specific Platform Firmware Profile Specification" chapter 9. https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ Signed-off-by: Ivan Hu <ivan.hu@canonical.com> --- src/Makefile.am | 1 + src/lib/include/fwts_tpm.h | 166 +++++++++++++++ src/tpm/tpmevlogdump/tpmevlogdump.c | 408 ++++++++++++++++++++++++++++++++++++ 3 files changed, 575 insertions(+) create mode 100644 src/lib/include/fwts_tpm.h create mode 100644 src/tpm/tpmevlogdump/tpmevlogdump.c