summaryrefslogtreecommitdiff
path: root/include/linux/tpm_eventlog.h
blob: 64356b199e9454fbd6bc05d2ab6ce419c78daafc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef __LINUX_TPM_EVENTLOG_H__
#define __LINUX_TPM_EVENTLOG_H__

#include <linux/tpm.h>

#define TCG_EVENT_NAME_LEN_MAX	255
#define MAX_TEXT_EVENT		1000	/* Max event string length */
#define ACPI_TCPA_SIG		"TCPA"	/* 0x41504354 /'TCPA' */

#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x1
#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2   0x2

#ifdef CONFIG_PPC64
#define do_endian_conversion(x) be32_to_cpu(x)
#else
#define do_endian_conversion(x) x
#endif

enum bios_platform_class {
	BIOS_CLIENT = 0x00,
	BIOS_SERVER = 0x01,
};

struct tcpa_event {
	u32 pcr_index;
	u32 event_type;
	u8 pcr_value[20];	/* SHA1 */
	u32 event_size;
	u8 event_data[];
};

enum tcpa_event_types {
	PREBOOT = 0,
	POST_CODE,
	UNUSED,
	NO_ACTION,
	SEPARATOR,
	ACTION,
	EVENT_TAG,
	SCRTM_CONTENTS,
	SCRTM_VERSION,
	CPU_MICROCODE,
	PLATFORM_CONFIG_FLAGS,
	TABLE_OF_DEVICES,
	COMPACT_HASH,
	IPL,
	IPL_PARTITION_DATA,
	NONHOST_CODE,
	NONHOST_CONFIG,
	NONHOST_INFO,
};

struct tcpa_pc_event {
	u32 event_id;
	u32 event_size;
	u8 event_data[];
};

enum tcpa_pc_event_ids {
	SMBIOS = 1,
	BIS_CERT,
	POST_BIOS_ROM,
	ESCD,
	CMOS,
	NVRAM,
	OPTION_ROM_EXEC,
	OPTION_ROM_CONFIG,
	OPTION_ROM_MICROCODE = 10,
	S_CRTM_VERSION,
	S_CRTM_CONTENTS,
	POST_CONTENTS,
	HOST_TABLE_OF_DEVICES,
};

/* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */

struct tcg_efi_specid_event_algs {
	u16 alg_id;
	u16 digest_size;
} __packed;

#define TCG_SPECID_SIG "Spec ID Event03"

struct tcg_efi_specid_event_head {
	u8 signature[16];
	u32 platform_class;
	u8 spec_version_minor;
	u8 spec_version_major;
	u8 spec_errata;
	u8 uintnsize;
	u32 num_algs;
	struct tcg_efi_specid_event_algs digest_sizes[];
} __packed;

struct tcg_pcr_event {
	u32 pcr_idx;
	u32 event_type;
	u8 digest[20];
	u32 event_size;
	u8 event[];
} __packed;

struct tcg_event_field {
	u32 event_size;
	u8 event[];
} __packed;

struct tcg_pcr_event2_head {
	u32 pcr_idx;
	u32 event_type;
	u32 count;
	struct tpm_digest digests[];
} __packed;

struct tcg_algorithm_size {
	u16 algorithm_id;
	u16 algorithm_size;
};

struct tcg_algorithm_info {
	u8 signature[16];
	u32 platform_class;
	u8 spec_version_minor;
	u8 spec_version_major;
	u8 spec_errata;
	u8 uintn_size;
	u32 number_of_algorithms;
	struct tcg_algorithm_size digest_sizes[];
};

#ifndef TPM_MEMREMAP
#define TPM_MEMREMAP(start, size) NULL
#endif

#ifndef TPM_MEMUNMAP
#define TPM_MEMUNMAP(start, size) do{} while(0)
#endif

/**
 * __calc_tpm2_event_size - calculate the size of a TPM2 event log entry
 * @event:        Pointer to the event whose size should be calculated
 * @event_header: Pointer to the initial event containing the digest lengths
 * @do_mapping:   Whether or not the event needs to be mapped
 *
 * The TPM2 event log format can contain multiple digests corresponding to
 * separate PCR banks, and also contains a variable length of the data that
 * was measured. This requires knowledge of how long each digest type is,
 * and this information is contained within the first event in the log.
 *
 * We calculate the length by examining the number of events, and then looking
 * at each event in turn to determine how much space is used for events in
 * total. Once we've done this we know the offset of the data length field,
 * and can calculate the total size of the event.
 *
 * Return: size of the event on success, 0 on failure
 */

static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
					 struct tcg_pcr_event *event_header,
					 bool do_mapping)
{
	struct tcg_efi_specid_event_head *efispecid;
	struct tcg_event_field *event_field;
	void *mapping = NULL;
	int mapping_size;
	void *marker;
	void *marker_start;
	u32 halg_size;
	size_t size;
	u16 halg;
	int i;
	int j;
	u32 count, event_type;
	const u8 zero_digest[sizeof(event_header->digest)] = {0};

	marker = event;
	marker_start = marker;
	marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
		+ sizeof(event->count);

	/* Map the event header */
	if (do_mapping) {
		mapping_size = marker - marker_start;
		mapping = TPM_MEMREMAP((unsigned long)marker_start,
				       mapping_size);
		if (!mapping) {
			size = 0;
			goto out;
		}
	} else {
		mapping = marker_start;
	}

	event = (struct tcg_pcr_event2_head *)mapping;
	/*
	 * The loop below will unmap these fields if the log is larger than
	 * one page, so save them here for reference:
	 */
	count = READ_ONCE(event->count);
	event_type = READ_ONCE(event->event_type);

	/* Verify that it's the log header */
	if (event_header->pcr_idx != 0 ||
	    event_header->event_type != NO_ACTION ||
	    memcmp(event_header->digest, zero_digest, sizeof(zero_digest))) {
		size = 0;
		goto out;
	}

	efispecid = (struct tcg_efi_specid_event_head *)event_header->event;

	/* Check if event is malformed. */
	if (memcmp(efispecid->signature, TCG_SPECID_SIG,
		   sizeof(TCG_SPECID_SIG)) || count > efispecid->num_algs) {
		size = 0;
		goto out;
	}

	for (i = 0; i < count; i++) {
		halg_size = sizeof(event->digests[i].alg_id);

		/* Map the digest's algorithm identifier */
		if (do_mapping) {
			TPM_MEMUNMAP(mapping, mapping_size);
			mapping_size = halg_size;
			mapping = TPM_MEMREMAP((unsigned long)marker,
					     mapping_size);
			if (!mapping) {
				size = 0;
				goto out;
			}
		} else {
			mapping = marker;
		}

		memcpy(&halg, mapping, halg_size);
		marker = marker + halg_size;

		for (j = 0; j < efispecid->num_algs; j++) {
			if (halg == efispecid->digest_sizes[j].alg_id) {
				marker +=
					efispecid->digest_sizes[j].digest_size;
				break;
			}
		}
		/* Algorithm without known length. Such event is unparseable. */
		if (j == efispecid->num_algs) {
			size = 0;
			goto out;
		}
	}

	/*
	 * Map the event size - we don't read from the event itself, so
	 * we don't need to map it
	 */
	if (do_mapping) {
		TPM_MEMUNMAP(mapping, mapping_size);
		mapping_size += sizeof(event_field->event_size);
		mapping = TPM_MEMREMAP((unsigned long)marker,
				       mapping_size);
		if (!mapping) {
			size = 0;
			goto out;
		}
	} else {
		mapping = marker;
	}

	event_field = (struct tcg_event_field *)mapping;

	marker = marker + sizeof(event_field->event_size)
		+ event_field->event_size;
	size = marker - marker_start;

	if (event_type == 0 && event_field->event_size == 0)
		size = 0;

out:
	if (do_mapping)
		TPM_MEMUNMAP(mapping, mapping_size);
	return size;
}

#endif