1 /*
2 * Copyright (c) 2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdbool.h>
8 #include <TpmProfile.h>
9 #include <trace.h>
10 #include <TpmProfile.h>
11 #include <TpmAlgorithmDefines.h>
12 #include <GpMacros.h>
13 #include <fTPM.h>
14 #include <Capabilities.h>
15 #include <fTPM_helpers.h>
16 #include <fTPM_event_log.h>
17 #include <fTPM_event_log_private.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 /*
22 * Global variables.
23 */
24 static bool log_extended = false;
25 static id_event_struct_header_t *event_header_ptr;
26
check_header_digest(const unsigned char * const digest)27 static int check_header_digest(const unsigned char *const digest)
28 {
29 /*
30 * Checks the header digest according to section 5.3 of
31 * TCG EFI Protocol Specification. Family 2.0. Level 00 Revision 00.13
32 * March 30, 2016.
33 */
34
35 unsigned int i;
36
37 for (i = 0U; i < HEADER_DIGEST_SIZE; i++) {
38 if (digest[i] != 0) {
39 return 0;
40 }
41 }
42
43 return 1;
44 }
45
46 /*
47 * Function to process a TPM event log header.
48 *
49 * @buf_index Offset where the header is expected to start in the event log.
50 * @buf Pointer to a buffer where the TPM event log is.
51 * @log_size Size of the TPM event log.
52 *
53 * The function returns the offset on the event log after the header.
54 */
process_header(unsigned int buf_index,const unsigned char * const buf,const size_t log_size)55 static unsigned int process_header(unsigned int buf_index,
56 const unsigned char *const buf,
57 const size_t log_size)
58 {
59 uint32_t event_size;
60 uint32_t digest_size;
61 uint8_t vendor_info_size;
62
63 if (buf_index + sizeof(tcg_pcr_event_t) + sizeof(id_event_struct_header_t)
64 >= log_size) {
65 #ifdef fTPMDebug
66 EMSG("TPM Event log header extends beyond the scope of the event log buffer\n");
67 #endif
68 }
69
70 /*
71 * Check PcrIndex.
72 */
73 if (*((uint32_t *)(buf + buf_index)) != 0U) {
74 /*
75 * PCR Index must be 0 on the header.
76 * Ref. Section 5.3 of TCG EFI Protocol Specification. Family 2.0
77 * Level 00 Revision 00.13. March 30, 2016
78 */
79 return 0U;
80 }
81 buf_index += sizeof(uint32_t);
82
83 /*
84 * Check EventType
85 */
86 if (*((uint32_t *)(buf + buf_index)) != EV_NO_ACTION) {
87 /*
88 * Event type must be EV_NO_ACTION on the header.
89 * Ref. Section 5.3 of TCG EFI Protocol Specification. Family 2.0
90 * Level 00 Revision 00.13. March 30, 2016
91 */
92 return 0U;
93 }
94 buf_index += sizeof(uint32_t);
95
96 if (!check_header_digest(buf + buf_index)) {
97 return 0U;
98 }
99
100 buf_index += HEADER_DIGEST_SIZE;
101
102 memcpy(&event_size, buf + buf_index, sizeof(event_size));
103 buf_index += sizeof(event_size);
104
105 event_header_ptr = (id_event_struct_header_t *)(buf + buf_index);
106
107 buf_index += sizeof(id_event_struct_header_t);
108
109 digest_size = (event_header_ptr->number_of_algorithms *
110 sizeof(id_event_algorithm_size_t));
111
112 if (buf_index + digest_size >= log_size) {
113 #ifdef fTPMDebug
114 EMSG("TPM Event log header extends beyond the scope of the event log buffer\n");
115 #endif
116 event_header_ptr = NULL;
117 return 0U;
118 }
119
120 buf_index += digest_size;
121
122 if (buf_index + sizeof(vendor_info_size) >= log_size) {
123 #ifdef fTPMDebug
124 EMSG("TPM Event log header extends beyond the scope of the event log buffer\n");
125 #endif
126 event_header_ptr = NULL;
127 return 0U;
128 }
129
130 memcpy(&vendor_info_size, buf + buf_index, sizeof(vendor_info_size));
131
132 if (digest_size + vendor_info_size + sizeof(vendor_info_size) +
133 sizeof(id_event_struct_header_t) != event_size) {
134 #ifdef fTPMDebug
135 EMSG("The parsed event size does not match the event size on the header\n");
136 #endif
137 return 0U;
138 }
139
140 buf_index += sizeof(vendor_info_size);
141
142 if (buf_index + vendor_info_size > log_size) {
143 #ifdef fTPMDebug
144 EMSG("Event size larger than the log size\n");
145 #endif
146 event_header_ptr = NULL;
147 return 0U;
148 }
149
150 /*
151 * Skips the vendor info.
152 */
153 buf_index += vendor_info_size;
154
155 return buf_index;
156 }
157
158 /*
159 * Function to proccess (and extend) an event from the TPM event log.
160 *
161 * @buf_index Offset where the event is expected to start in the event log.
162 * @buf Pointer to a buffer where the TPM event log is.
163 * @log_size Size of the TPM event log.
164 *
165 * The function returns the offset of the next event in the TPM event log
166 * or 0 if fails.
167 */
process_event(unsigned int buf_index,const unsigned char * const buf,const size_t log_size)168 static unsigned int process_event(unsigned int buf_index,
169 const unsigned char *const buf,
170 const size_t log_size)
171 {
172 TPM2_PCR_EXTEND_COMMAND cmd;
173 unsigned char *digest_array;
174 uint32_t count;
175 uint32_t event_size;
176 uint16_t alg_id;
177 unsigned int digest_size;
178 unsigned int i;
179 unsigned char *response;
180 uint32_t resplen;
181 event2_header_t event;
182 void *cmd_end = (void *)(&cmd + 1);
183
184 if (buf_index + sizeof(event2_header_t) >= log_size) {
185 #ifdef fTPMDebug
186 EMSG("Event header size larger than the log size\n");
187 #endif
188 return 0U;
189 }
190
191 memcpy(&event, buf + buf_index, sizeof(event2_header_t));
192 buf_index += sizeof(event2_header_t);
193
194 if (event.digests.count > HASH_COUNT) {
195 #ifdef fTPMDebug
196 EMSG("Number of digests on this event exceeds the maximum allowed\n");
197 #endif
198 return 0U;
199 }
200
201 memset(&cmd, 0, sizeof(TPM2_PCR_EXTEND_COMMAND));
202
203 cmd.Header.paramSize = sizeof(cmd.PcrHandle) +
204 sizeof(cmd.AuthorizationSize) +
205 sizeof(cmd.Header);
206
207 cmd.PcrHandle = SwapBytes32(event.pcr_index);
208
209 cmd.Header.commandCode = SwapBytes32(TPM_PCR_EXTEND);
210 cmd.Header.tag = SwapBytes16(TPM_ST_SESS);
211
212 /*
213 * We are not using authorization sessions in this prototype code so
214 * populate the auth session info based on how it is handled in
215 * CopyAuthSessionCommand() with a NULL auth session. See
216 * SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c in EDK2.
217 */
218 cmd.AuthSessionPcr.sessionHandle = SwapBytes32(TPM_RS_PW);
219 cmd.AuthSessionPcr.nonce.b.size = 0U;
220 *((uint8_t *)&cmd.AuthSessionPcr.sessionAttributes) = 0U;
221 cmd.AuthSessionPcr.hmac.b.size = 0U;
222 cmd.AuthorizationSize = SwapBytes32(AUTH_SIZE);
223 cmd.Header.paramSize += (AUTH_SIZE);
224
225 /*
226 * As we are not using authorization sessions for this prototype,
227 * AuthSessionPcr is empty and therefore the digests are allocated
228 * straight after the empty AuthSessionPcr structure, so make the
229 * pointer for the digests to point right after the empty
230 * AuthSessionPcr structure.
231 */
232 digest_array = ((uint8_t *)&cmd.AuthSessionPcr) + AUTH_SIZE;
233
234 /*
235 * Populate the digest.
236 */
237 count = SwapBytes32(event.digests.count);
238 memcpy(digest_array, &count, sizeof(count));
239 digest_array += sizeof(count);
240
241 cmd.Header.paramSize += sizeof(count);
242
243 for (i = 0U; i < event.digests.count; i++) {
244 unsigned int j;
245
246 if (buf_index + sizeof(alg_id) >= log_size) {
247 return 0U;
248 }
249 memcpy(&alg_id, buf + buf_index, sizeof(alg_id));
250 alg_id = SwapBytes16(alg_id);
251 buf_index += sizeof(alg_id);
252 /*
253 * Algorithm ID.
254 */
255 if ((void *)(digest_array + sizeof(alg_id)) >= cmd_end) {
256 #ifdef fTPMDebug
257 EMSG("Not enough space for digest %u of %u\n", i,
258 event.digests.count);
259 #endif
260 return 0U;
261 }
262 memcpy(digest_array, &alg_id, sizeof(alg_id));
263 digest_array += sizeof(alg_id);
264 cmd.Header.paramSize += sizeof(alg_id);
265
266 for (j = 0U; j < event_header_ptr->number_of_algorithms; j++) {
267 if (SwapBytes16(alg_id) ==
268 event_header_ptr->digest_size[i].algorithm_id) {
269 digest_size = event_header_ptr->digest_size[i].digest_size;
270 break;
271 }
272 }
273
274 if (j > event_header_ptr->number_of_algorithms) {
275 #ifdef fTPMDebug
276 EMSG("Algorithm ID %i not found\n", alg_id);
277 #endif
278 return 0U;
279 }
280
281 cmd.Header.paramSize += digest_size;
282
283 if (buf_index + digest_size >= log_size ||
284 digest_size > (sizeof(TPMT_HA) - sizeof(TPMI_ALG_HASH))) {
285 /*
286 * Sanity check: If the log extends beyond the
287 * maximum size of the log buffer or if the digest is
288 * bigger than the allocated space on the command structure, abort.
289 */
290 #ifdef fTPMDebug
291 EMSG("Log extends beyond the maximum size of the log buffer.\n");
292 EMSG("alg_id = %i\n", alg_id);
293 EMSG("log_size = %i\n", log_size);
294 EMSG("buf_index = %i, digest_size = %i\n", buf_index, digest_size);
295 EMSG("TPMH_HA = %i\n", sizeof(TPMT_HA));
296 EMSG("TPMI_ALG_HASH = %i\n", sizeof(TPMI_ALG_HASH));
297 #endif
298 return 0U;
299 }
300 memcpy(digest_array, buf + buf_index, digest_size);
301 digest_array += digest_size;
302 buf_index += digest_size;
303 }
304
305 cmd.Header.paramSize = SwapBytes32(cmd.Header.paramSize);
306
307 if (buf_index + sizeof(event2_data_t) > log_size) {
308 return 0U;
309 }
310 memcpy(&event_size, buf + buf_index, sizeof(event_size));
311 buf_index += sizeof(event_size);
312 buf_index += event_size;
313
314 if (buf_index > log_size) {
315 #ifdef fTPMDebug
316 EMSG("The event log extends beyond the log buffer:");
317 EMSG("\tbuf_index = %i, log_size = %i\n", buf_index, log_size);
318 #endif
319 return 0U;
320 }
321
322 resplen = 1024;
323 response = (unsigned char *)malloc(resplen);
324
325 if (response == NULL) {
326 #ifdef fTPMDebug
327 EMSG("Not enough memory to allocate a response\n");
328 #endif
329 return 0U;
330 }
331
332 memset(response, 0, resplen);
333
334 ExecuteCommand(SwapBytes32(cmd.Header.paramSize), &cmd,
335 &resplen, &response);
336
337 #ifdef fTPMDebug
338 uint16_t ret_tag;
339 uint32_t resp_size;
340 uint32_t tpm_rc;
341
342 memcpy(&ret_tag, response, sizeof(ret_tag));
343 memcpy(&resp_size, response + sizeof(ret_tag), sizeof(resp_size));
344 memcpy(&tpm_rc, response + sizeof(ret_tag) + sizeof(resp_size),
345 sizeof(tpm_rc));
346
347 MSG("TPM2_PCR_EXTEND_COMMAND returned value:\n");
348 MSG("\tret_tag = 0x%.4x, size = 0x%.8x, rc = 0x%.8x\n",
349 SwapBytes16(ret_tag), SwapBytes32(resp_size), SwapBytes32(tpm_rc));
350 #endif
351
352 free(response);
353
354 return buf_index;
355 }
356
process_eventlog(const unsigned char * const buf,const size_t log_size)357 bool process_eventlog(const unsigned char *const buf, const size_t log_size)
358 {
359 unsigned int buf_index = 0U;
360 unsigned int event_count = 0U;
361
362 if (log_extended == true) {
363 #ifdef fTPMDebug
364 MSG("The event log has already been extended. Ignoring\n");
365 #endif
366 return false;
367 }
368
369 log_extended = true;
370 buf_index = process_header(buf_index, buf, log_size);
371 if (buf_index == 0) {
372 #ifdef fTPMDebug
373 EMSG("Fail to process TPM event log header. Skiping.\n");
374 #endif
375 return false;
376 }
377
378 while (buf_index < log_size) {
379 /*
380 * Process the rest of the Event Log.
381 */
382 buf_index = process_event(buf_index, buf, log_size);
383 event_count++;
384 }
385
386 #ifdef fTPMDebug
387 MSG("%i Event logs processed\n", event_count);
388 #endif
389
390 event_header_ptr = NULL;
391
392 return true;
393 }
394