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