1fd3ec366SThiebaud Weksteen /* SPDX-License-Identifier: GPL-2.0 */
2fd3ec366SThiebaud Weksteen
3fd3ec366SThiebaud Weksteen #ifndef __LINUX_TPM_EVENTLOG_H__
4fd3ec366SThiebaud Weksteen #define __LINUX_TPM_EVENTLOG_H__
5fd3ec366SThiebaud Weksteen
6aa042475SRoberto Sassu #include <linux/tpm.h>
7fd3ec366SThiebaud Weksteen
8fd3ec366SThiebaud Weksteen #define TCG_EVENT_NAME_LEN_MAX 255
9fd3ec366SThiebaud Weksteen #define MAX_TEXT_EVENT 1000 /* Max event string length */
10fd3ec366SThiebaud Weksteen #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
11fd3ec366SThiebaud Weksteen
124d01d29dSThiebaud Weksteen #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x1
134d01d29dSThiebaud Weksteen #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x2
144d01d29dSThiebaud Weksteen
15fd3ec366SThiebaud Weksteen #ifdef CONFIG_PPC64
16fd3ec366SThiebaud Weksteen #define do_endian_conversion(x) be32_to_cpu(x)
17fd3ec366SThiebaud Weksteen #else
18fd3ec366SThiebaud Weksteen #define do_endian_conversion(x) x
19fd3ec366SThiebaud Weksteen #endif
20fd3ec366SThiebaud Weksteen
21fd3ec366SThiebaud Weksteen enum bios_platform_class {
22fd3ec366SThiebaud Weksteen BIOS_CLIENT = 0x00,
23fd3ec366SThiebaud Weksteen BIOS_SERVER = 0x01,
24fd3ec366SThiebaud Weksteen };
25fd3ec366SThiebaud Weksteen
26fd3ec366SThiebaud Weksteen struct tcpa_event {
27fd3ec366SThiebaud Weksteen u32 pcr_index;
28fd3ec366SThiebaud Weksteen u32 event_type;
29fd3ec366SThiebaud Weksteen u8 pcr_value[20]; /* SHA1 */
30fd3ec366SThiebaud Weksteen u32 event_size;
3106ccf63dSGustavo A. R. Silva u8 event_data[];
32fd3ec366SThiebaud Weksteen };
33fd3ec366SThiebaud Weksteen
34fd3ec366SThiebaud Weksteen enum tcpa_event_types {
35fd3ec366SThiebaud Weksteen PREBOOT = 0,
36fd3ec366SThiebaud Weksteen POST_CODE,
37fd3ec366SThiebaud Weksteen UNUSED,
38fd3ec366SThiebaud Weksteen NO_ACTION,
39fd3ec366SThiebaud Weksteen SEPARATOR,
40fd3ec366SThiebaud Weksteen ACTION,
41fd3ec366SThiebaud Weksteen EVENT_TAG,
42fd3ec366SThiebaud Weksteen SCRTM_CONTENTS,
43fd3ec366SThiebaud Weksteen SCRTM_VERSION,
44fd3ec366SThiebaud Weksteen CPU_MICROCODE,
45fd3ec366SThiebaud Weksteen PLATFORM_CONFIG_FLAGS,
46fd3ec366SThiebaud Weksteen TABLE_OF_DEVICES,
47fd3ec366SThiebaud Weksteen COMPACT_HASH,
48fd3ec366SThiebaud Weksteen IPL,
49fd3ec366SThiebaud Weksteen IPL_PARTITION_DATA,
50fd3ec366SThiebaud Weksteen NONHOST_CODE,
51fd3ec366SThiebaud Weksteen NONHOST_CONFIG,
52fd3ec366SThiebaud Weksteen NONHOST_INFO,
53fd3ec366SThiebaud Weksteen };
54fd3ec366SThiebaud Weksteen
55fd3ec366SThiebaud Weksteen struct tcpa_pc_event {
56fd3ec366SThiebaud Weksteen u32 event_id;
57fd3ec366SThiebaud Weksteen u32 event_size;
5806ccf63dSGustavo A. R. Silva u8 event_data[];
59fd3ec366SThiebaud Weksteen };
60fd3ec366SThiebaud Weksteen
61fd3ec366SThiebaud Weksteen enum tcpa_pc_event_ids {
62fd3ec366SThiebaud Weksteen SMBIOS = 1,
63fd3ec366SThiebaud Weksteen BIS_CERT,
64fd3ec366SThiebaud Weksteen POST_BIOS_ROM,
65fd3ec366SThiebaud Weksteen ESCD,
66fd3ec366SThiebaud Weksteen CMOS,
67fd3ec366SThiebaud Weksteen NVRAM,
68fd3ec366SThiebaud Weksteen OPTION_ROM_EXEC,
69fd3ec366SThiebaud Weksteen OPTION_ROM_CONFIG,
70fd3ec366SThiebaud Weksteen OPTION_ROM_MICROCODE = 10,
71fd3ec366SThiebaud Weksteen S_CRTM_VERSION,
72fd3ec366SThiebaud Weksteen S_CRTM_CONTENTS,
73fd3ec366SThiebaud Weksteen POST_CONTENTS,
74fd3ec366SThiebaud Weksteen HOST_TABLE_OF_DEVICES,
75fd3ec366SThiebaud Weksteen };
76fd3ec366SThiebaud Weksteen
77fd3ec366SThiebaud Weksteen /* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */
78fd3ec366SThiebaud Weksteen
79fd3ec366SThiebaud Weksteen struct tcg_efi_specid_event_algs {
80fd3ec366SThiebaud Weksteen u16 alg_id;
81fd3ec366SThiebaud Weksteen u16 digest_size;
82fd3ec366SThiebaud Weksteen } __packed;
83fd3ec366SThiebaud Weksteen
847dfc06a0SFabian Vogt #define TCG_SPECID_SIG "Spec ID Event03"
857dfc06a0SFabian Vogt
86c8faabfcSRoberto Sassu struct tcg_efi_specid_event_head {
87fd3ec366SThiebaud Weksteen u8 signature[16];
88fd3ec366SThiebaud Weksteen u32 platform_class;
89fd3ec366SThiebaud Weksteen u8 spec_version_minor;
90fd3ec366SThiebaud Weksteen u8 spec_version_major;
91fd3ec366SThiebaud Weksteen u8 spec_errata;
92fd3ec366SThiebaud Weksteen u8 uintnsize;
93fd3ec366SThiebaud Weksteen u32 num_algs;
94c8faabfcSRoberto Sassu struct tcg_efi_specid_event_algs digest_sizes[];
95fd3ec366SThiebaud Weksteen } __packed;
96fd3ec366SThiebaud Weksteen
97fd3ec366SThiebaud Weksteen struct tcg_pcr_event {
98fd3ec366SThiebaud Weksteen u32 pcr_idx;
99fd3ec366SThiebaud Weksteen u32 event_type;
100fd3ec366SThiebaud Weksteen u8 digest[20];
101fd3ec366SThiebaud Weksteen u32 event_size;
102ab91c2a8SGustavo A. R. Silva u8 event[];
103fd3ec366SThiebaud Weksteen } __packed;
104fd3ec366SThiebaud Weksteen
105fd3ec366SThiebaud Weksteen struct tcg_event_field {
106fd3ec366SThiebaud Weksteen u32 event_size;
10706ccf63dSGustavo A. R. Silva u8 event[];
108fd3ec366SThiebaud Weksteen } __packed;
109fd3ec366SThiebaud Weksteen
110c8faabfcSRoberto Sassu struct tcg_pcr_event2_head {
111fd3ec366SThiebaud Weksteen u32 pcr_idx;
112fd3ec366SThiebaud Weksteen u32 event_type;
113fd3ec366SThiebaud Weksteen u32 count;
114aa042475SRoberto Sassu struct tpm_digest digests[];
115fd3ec366SThiebaud Weksteen } __packed;
116fd3ec366SThiebaud Weksteen
117c46f3405SMatthew Garrett struct tcg_algorithm_size {
118c46f3405SMatthew Garrett u16 algorithm_id;
119c46f3405SMatthew Garrett u16 algorithm_size;
120c46f3405SMatthew Garrett };
121c46f3405SMatthew Garrett
122c46f3405SMatthew Garrett struct tcg_algorithm_info {
123c46f3405SMatthew Garrett u8 signature[16];
124c46f3405SMatthew Garrett u32 platform_class;
125c46f3405SMatthew Garrett u8 spec_version_minor;
126c46f3405SMatthew Garrett u8 spec_version_major;
127c46f3405SMatthew Garrett u8 spec_errata;
128c46f3405SMatthew Garrett u8 uintn_size;
129c46f3405SMatthew Garrett u32 number_of_algorithms;
130c46f3405SMatthew Garrett struct tcg_algorithm_size digest_sizes[];
131c46f3405SMatthew Garrett };
132c46f3405SMatthew Garrett
133c46f3405SMatthew Garrett #ifndef TPM_MEMREMAP
134c46f3405SMatthew Garrett #define TPM_MEMREMAP(start, size) NULL
135c46f3405SMatthew Garrett #endif
136c46f3405SMatthew Garrett
137c46f3405SMatthew Garrett #ifndef TPM_MEMUNMAP
138c46f3405SMatthew Garrett #define TPM_MEMUNMAP(start, size) do{} while(0)
139c46f3405SMatthew Garrett #endif
140c46f3405SMatthew Garrett
14144038bc5SMatthew Garrett /**
14244038bc5SMatthew Garrett * __calc_tpm2_event_size - calculate the size of a TPM2 event log entry
14344038bc5SMatthew Garrett * @event: Pointer to the event whose size should be calculated
14444038bc5SMatthew Garrett * @event_header: Pointer to the initial event containing the digest lengths
145c46f3405SMatthew Garrett * @do_mapping: Whether or not the event needs to be mapped
14644038bc5SMatthew Garrett *
14744038bc5SMatthew Garrett * The TPM2 event log format can contain multiple digests corresponding to
14844038bc5SMatthew Garrett * separate PCR banks, and also contains a variable length of the data that
14944038bc5SMatthew Garrett * was measured. This requires knowledge of how long each digest type is,
15044038bc5SMatthew Garrett * and this information is contained within the first event in the log.
15144038bc5SMatthew Garrett *
15244038bc5SMatthew Garrett * We calculate the length by examining the number of events, and then looking
15344038bc5SMatthew Garrett * at each event in turn to determine how much space is used for events in
15444038bc5SMatthew Garrett * total. Once we've done this we know the offset of the data length field,
15544038bc5SMatthew Garrett * and can calculate the total size of the event.
15644038bc5SMatthew Garrett *
157e658c82bSJerry Snitselaar * Return: size of the event on success, 0 on failure
15844038bc5SMatthew Garrett */
15944038bc5SMatthew Garrett
__calc_tpm2_event_size(struct tcg_pcr_event2_head * event,struct tcg_pcr_event * event_header,bool do_mapping)160bed45936SHuacai Chen static __always_inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
161c46f3405SMatthew Garrett struct tcg_pcr_event *event_header,
162c46f3405SMatthew Garrett bool do_mapping)
16344038bc5SMatthew Garrett {
16444038bc5SMatthew Garrett struct tcg_efi_specid_event_head *efispecid;
16544038bc5SMatthew Garrett struct tcg_event_field *event_field;
166c46f3405SMatthew Garrett void *mapping = NULL;
167c46f3405SMatthew Garrett int mapping_size;
16844038bc5SMatthew Garrett void *marker;
16944038bc5SMatthew Garrett void *marker_start;
17044038bc5SMatthew Garrett u32 halg_size;
17144038bc5SMatthew Garrett size_t size;
17244038bc5SMatthew Garrett u16 halg;
17344038bc5SMatthew Garrett int i;
17444038bc5SMatthew Garrett int j;
175047d50aeSPeter Jones u32 count, event_type;
1767dfc06a0SFabian Vogt const u8 zero_digest[sizeof(event_header->digest)] = {0};
17744038bc5SMatthew Garrett
17844038bc5SMatthew Garrett marker = event;
17944038bc5SMatthew Garrett marker_start = marker;
18044038bc5SMatthew Garrett marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
18144038bc5SMatthew Garrett + sizeof(event->count);
18244038bc5SMatthew Garrett
183c46f3405SMatthew Garrett /* Map the event header */
184c46f3405SMatthew Garrett if (do_mapping) {
185c46f3405SMatthew Garrett mapping_size = marker - marker_start;
186c46f3405SMatthew Garrett mapping = TPM_MEMREMAP((unsigned long)marker_start,
187c46f3405SMatthew Garrett mapping_size);
188c46f3405SMatthew Garrett if (!mapping) {
189c46f3405SMatthew Garrett size = 0;
190c46f3405SMatthew Garrett goto out;
191c46f3405SMatthew Garrett }
192c46f3405SMatthew Garrett } else {
193c46f3405SMatthew Garrett mapping = marker_start;
194c46f3405SMatthew Garrett }
195c46f3405SMatthew Garrett
196c46f3405SMatthew Garrett event = (struct tcg_pcr_event2_head *)mapping;
197047d50aeSPeter Jones /*
198047d50aeSPeter Jones * The loop below will unmap these fields if the log is larger than
199047d50aeSPeter Jones * one page, so save them here for reference:
200047d50aeSPeter Jones */
201*d3f45053SArd Biesheuvel count = event->count;
202*d3f45053SArd Biesheuvel event_type = event->event_type;
203c46f3405SMatthew Garrett
2047dfc06a0SFabian Vogt /* Verify that it's the log header */
2057dfc06a0SFabian Vogt if (event_header->pcr_idx != 0 ||
2067dfc06a0SFabian Vogt event_header->event_type != NO_ACTION ||
2077dfc06a0SFabian Vogt memcmp(event_header->digest, zero_digest, sizeof(zero_digest))) {
2087dfc06a0SFabian Vogt size = 0;
2097dfc06a0SFabian Vogt goto out;
2107dfc06a0SFabian Vogt }
2117dfc06a0SFabian Vogt
21244038bc5SMatthew Garrett efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
21344038bc5SMatthew Garrett
2147f3d176fSTyler Hicks /*
2157f3d176fSTyler Hicks * Perform validation of the event in order to identify malformed
2167f3d176fSTyler Hicks * events. This function may be asked to parse arbitrary byte sequences
2177f3d176fSTyler Hicks * immediately following a valid event log. The caller expects this
2187f3d176fSTyler Hicks * function to recognize that the byte sequence is not a valid event
2197f3d176fSTyler Hicks * and to return an event size of 0.
2207f3d176fSTyler Hicks */
2217dfc06a0SFabian Vogt if (memcmp(efispecid->signature, TCG_SPECID_SIG,
2227f3d176fSTyler Hicks sizeof(TCG_SPECID_SIG)) ||
2237f3d176fSTyler Hicks !efispecid->num_algs || count != efispecid->num_algs) {
224c46f3405SMatthew Garrett size = 0;
225c46f3405SMatthew Garrett goto out;
226c46f3405SMatthew Garrett }
22744038bc5SMatthew Garrett
228047d50aeSPeter Jones for (i = 0; i < count; i++) {
22944038bc5SMatthew Garrett halg_size = sizeof(event->digests[i].alg_id);
230c46f3405SMatthew Garrett
231c46f3405SMatthew Garrett /* Map the digest's algorithm identifier */
232c46f3405SMatthew Garrett if (do_mapping) {
233c46f3405SMatthew Garrett TPM_MEMUNMAP(mapping, mapping_size);
234c46f3405SMatthew Garrett mapping_size = halg_size;
235c46f3405SMatthew Garrett mapping = TPM_MEMREMAP((unsigned long)marker,
236c46f3405SMatthew Garrett mapping_size);
237c46f3405SMatthew Garrett if (!mapping) {
238c46f3405SMatthew Garrett size = 0;
239c46f3405SMatthew Garrett goto out;
240c46f3405SMatthew Garrett }
241c46f3405SMatthew Garrett } else {
242c46f3405SMatthew Garrett mapping = marker;
243c46f3405SMatthew Garrett }
244c46f3405SMatthew Garrett
245c46f3405SMatthew Garrett memcpy(&halg, mapping, halg_size);
24644038bc5SMatthew Garrett marker = marker + halg_size;
247c46f3405SMatthew Garrett
24844038bc5SMatthew Garrett for (j = 0; j < efispecid->num_algs; j++) {
24944038bc5SMatthew Garrett if (halg == efispecid->digest_sizes[j].alg_id) {
25044038bc5SMatthew Garrett marker +=
25144038bc5SMatthew Garrett efispecid->digest_sizes[j].digest_size;
25244038bc5SMatthew Garrett break;
25344038bc5SMatthew Garrett }
25444038bc5SMatthew Garrett }
25544038bc5SMatthew Garrett /* Algorithm without known length. Such event is unparseable. */
256c46f3405SMatthew Garrett if (j == efispecid->num_algs) {
257c46f3405SMatthew Garrett size = 0;
258c46f3405SMatthew Garrett goto out;
259c46f3405SMatthew Garrett }
26044038bc5SMatthew Garrett }
26144038bc5SMatthew Garrett
262c46f3405SMatthew Garrett /*
263c46f3405SMatthew Garrett * Map the event size - we don't read from the event itself, so
264c46f3405SMatthew Garrett * we don't need to map it
265c46f3405SMatthew Garrett */
266c46f3405SMatthew Garrett if (do_mapping) {
267c46f3405SMatthew Garrett TPM_MEMUNMAP(mapping, mapping_size);
268c46f3405SMatthew Garrett mapping_size += sizeof(event_field->event_size);
269c46f3405SMatthew Garrett mapping = TPM_MEMREMAP((unsigned long)marker,
270c46f3405SMatthew Garrett mapping_size);
271c46f3405SMatthew Garrett if (!mapping) {
272c46f3405SMatthew Garrett size = 0;
273c46f3405SMatthew Garrett goto out;
274c46f3405SMatthew Garrett }
275c46f3405SMatthew Garrett } else {
276c46f3405SMatthew Garrett mapping = marker;
277c46f3405SMatthew Garrett }
278c46f3405SMatthew Garrett
279c46f3405SMatthew Garrett event_field = (struct tcg_event_field *)mapping;
280c46f3405SMatthew Garrett
28144038bc5SMatthew Garrett marker = marker + sizeof(event_field->event_size)
28244038bc5SMatthew Garrett + event_field->event_size;
28344038bc5SMatthew Garrett size = marker - marker_start;
28444038bc5SMatthew Garrett
285047d50aeSPeter Jones if (event_type == 0 && event_field->event_size == 0)
286c46f3405SMatthew Garrett size = 0;
287047d50aeSPeter Jones
288c46f3405SMatthew Garrett out:
289c46f3405SMatthew Garrett if (do_mapping)
290c46f3405SMatthew Garrett TPM_MEMUNMAP(mapping, mapping_size);
29144038bc5SMatthew Garrett return size;
29244038bc5SMatthew Garrett }
293c46f3405SMatthew Garrett
294fd3ec366SThiebaud Weksteen #endif
295