• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3  * Copyright 2018-2019, Fraunhofer SIT sponsored by Infineon Technologies AG
4  * All rights reserved.
5  *******************************************************************************/
6 
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10 
11 #include <string.h>
12 
13 #include "ifapi_helpers.h"
14 #include "ifapi_eventlog.h"
15 #include "ifapi_json_serialize.h"
16 
17 #define LOGMODULE fapi
18 #include "util/log.h"
19 #include "util/aux_util.h"
20 #include "ifapi_macros.h"
21 
22 /** Initialize the eventlog module of FAPI.
23  *
24  * @param[in,out] eventlog The context area for the eventlog.
25  * @param[in] log_dir The directory where to put the eventlog data.
26  * @retval TSS2_RC_SUCCESS on success.
27  * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
28  * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
29  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
30  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
31  *         the function.
32  */
33 TSS2_RC
ifapi_eventlog_initialize(IFAPI_EVENTLOG * eventlog,const char * log_dir)34 ifapi_eventlog_initialize(
35     IFAPI_EVENTLOG *eventlog,
36     const char *log_dir)
37 {
38     check_not_null(eventlog);
39     check_not_null(log_dir);
40 
41     TSS2_RC r;
42 
43     r = ifapi_io_check_create_dir(log_dir);
44     return_if_error2(r, "Directory check/creation failed for %s", log_dir);
45 
46     eventlog->log_dir = strdup(log_dir);
47     return_if_null(eventlog->log_dir, "Out of memory.", TSS2_FAPI_RC_MEMORY);
48 
49     return TSS2_RC_SUCCESS;
50 }
51 
52 /** Retrieve the eventlog for a given list of pcrs using asynchronous io.
53  *
54  * Call ifapi_eventlog_get_finish to retrieve the results.
55  *
56  * @param[in,out] eventlog The context area for the eventlog.
57  * @param[in,out] io The context area for the asynchronous io module.
58  * @param[in] pcrList The list of PCR indices to retrieve the log for.
59  * @param[in] pcrListSize The size of pcrList.
60  * @retval TSS2_RC_SUCCESS on success.
61  * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
62  * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
63  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
64  *         the function.
65  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
66  */
67 TSS2_RC
ifapi_eventlog_get_async(IFAPI_EVENTLOG * eventlog,IFAPI_IO * io,const TPM2_HANDLE * pcrList,size_t pcrListSize)68 ifapi_eventlog_get_async(
69     IFAPI_EVENTLOG *eventlog,
70     IFAPI_IO *io,
71     const TPM2_HANDLE *pcrList,
72     size_t pcrListSize)
73 {
74     check_not_null(eventlog);
75     check_not_null(io);
76     check_not_null(pcrList);
77 
78     if (pcrListSize > TPM2_MAX_PCRS) {
79         LOG_ERROR("pcrList too long %zi > %i", pcrListSize, TPM2_MAX_PCRS);
80         return TSS2_FAPI_RC_BAD_VALUE;
81     }
82 
83     LOG_TRACE("called for pcrListSize=%zi", pcrListSize);
84 
85     memcpy(&eventlog->pcrList, pcrList, pcrListSize * sizeof(TPM2_HANDLE));
86     eventlog->pcrListSize = pcrListSize;
87     eventlog->pcrListIdx = 0;
88 
89     eventlog->log = json_object_new_array();
90     return_if_null(eventlog->log, "Out of memory", TSS2_FAPI_RC_MEMORY);
91 
92     return TSS2_RC_SUCCESS;
93 }
94 
95 /** Retrieve the eventlog for a given list of pcrs using asynchronous io.
96  *
97  * Call after ifapi_eventlog_get_async.
98  *
99  * @param[in,out] eventlog The context area for the eventlog.
100  * @param[in,out] io The context area for the asynchronous io module.
101  * @param[out] log The event log for the requested PCRs in JSON format
102  * @retval TSS2_RC_SUCCESS on success.
103  * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
104  * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
105  * @retval TSS2_FAPI_RC_TRY_AGAIN if the I/O operation is not finished yet and this function needs
106  *         to be called again.
107  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
108  *         the function.
109  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
110  *         operation already pending.
111  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
112  */
113 TSS2_RC
ifapi_eventlog_get_finish(IFAPI_EVENTLOG * eventlog,IFAPI_IO * io,char ** log)114 ifapi_eventlog_get_finish(
115     IFAPI_EVENTLOG *eventlog,
116     IFAPI_IO *io,
117     char **log)
118 {
119     /* eventlog parameter currently not used */
120     check_not_null(eventlog);
121     check_not_null(io);
122     check_not_null(log);
123 
124     TSS2_RC r;
125     char *event_log_file, *logstr;
126     json_object *logpart, *event;
127 
128     LOG_TRACE("called");
129 
130 loop:
131     /* If we're dune with adding all eventlogs to the json array, we can serialize it and return
132        it to the caller. */
133     if (eventlog->pcrListIdx >= eventlog->pcrListSize) {
134         LOG_TRACE("Done reading pcrLog");
135         *log = strdup(json_object_to_json_string_ext(eventlog->log, JSON_C_TO_STRING_PRETTY));
136         check_oom(*log);
137         json_object_put(eventlog->log);
138         eventlog->log = NULL;
139         eventlog->state = IFAPI_EVENTLOG_STATE_INIT;
140         return TSS2_RC_SUCCESS;
141     }
142 
143     switch (eventlog->state) {
144     statecase(eventlog->state, IFAPI_EVENTLOG_STATE_INIT)
145         /* Construct the filename for the eventlog file */
146         r = ifapi_asprintf(&event_log_file, "%s/%s%i",
147                            eventlog->log_dir, IFAPI_PCR_LOG_FILE,
148                            eventlog->pcrList[eventlog->pcrListIdx]);
149         return_if_error(r, "Out of memory.");
150 
151         if (!ifapi_io_path_exists(event_log_file)) {
152             LOG_DEBUG("No event log for pcr %i", eventlog->pcrList[eventlog->pcrListIdx]);
153             SAFE_FREE(event_log_file);
154             eventlog->pcrListIdx += 1;
155             goto loop;
156         }
157 
158         /* Initiate the reading of the eventlog file */
159         r = ifapi_io_read_async(io, event_log_file);
160         free(event_log_file);
161         if (r) {
162             LOG_DEBUG("No event log for pcr %i", eventlog->pcrList[eventlog->pcrListIdx]);
163             eventlog->pcrListIdx += 1;
164             goto loop;
165         }
166         fallthrough;
167 
168     statecase(eventlog->state, IFAPI_EVENTLOG_STATE_READING)
169         /* Finish the reading of the eventlog file and return it directly to the output parameter */
170         r = ifapi_io_read_finish(io, (uint8_t **)&logstr, NULL);
171         return_try_again(r);
172         return_if_error(r, "read_finish failed");
173 
174         logpart = json_tokener_parse(logstr);
175         SAFE_FREE(logstr);
176         return_if_null(log, "JSON parsing error", TSS2_FAPI_RC_BAD_VALUE);
177 
178         /* Append the log-entry from logpart to the eventlog */
179         json_type jso_type = json_object_get_type(logpart);
180         if (jso_type != json_type_array) {
181             /* libjson-c does not deliver an array if array has only one element */
182             json_object_array_add(eventlog->log, logpart);
183         } else {
184             /* Iterate through the array of logpart and add each item to the eventlog */
185             /* The return type of json_object_array_length() was changed, thus the case */
186             for (int i = 0; i < (int)json_object_array_length(logpart); i++) {
187                 event = json_object_array_get_idx(logpart, i);
188                 /* Increment the refcount of event so it does not get freed on put(logpart) below */
189                 json_object_get(event);
190                 json_object_array_add(eventlog->log, event);
191             }
192             json_object_put(logpart);
193         }
194 
195         eventlog->pcrListIdx += 1;
196         eventlog->state = IFAPI_EVENTLOG_STATE_INIT;
197         goto loop;
198 
199     statecasedefault(eventlog->state);
200     }
201     return TSS2_RC_SUCCESS;
202 }
203 
204 /** Append an event to the existing event log.
205  *
206  * Call ifapi_eventlog_append_finish to finalize this operation.
207  *
208  * @param[in,out] eventlog The context area for the eventlog.
209  * @param[in,out] io The context area for the asynchronous io module.
210  * @param[in] event The event to be appended to the eventlog.
211  * @retval TSS2_RC_SUCCESS on success.
212  * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
213  * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
214  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
215  *         operation already pending.
216  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
217  */
218 TSS2_RC
ifapi_eventlog_append_async(IFAPI_EVENTLOG * eventlog,IFAPI_IO * io,const IFAPI_EVENT * event)219 ifapi_eventlog_append_async(
220     IFAPI_EVENTLOG *eventlog,
221     IFAPI_IO *io,
222     const IFAPI_EVENT *event)
223 {
224     check_not_null(eventlog);
225     check_not_null(io);
226     check_not_null(event);
227 
228     TSS2_RC r;
229     char *event_log_file;
230 
231     if (eventlog->state != IFAPI_EVENTLOG_STATE_INIT) {
232         LOG_ERROR("Wrong state: %i", eventlog->state);
233         return TSS2_FAPI_RC_BAD_SEQUENCE;
234     }
235 
236     eventlog->event = *event;
237 
238     /* Construct the filename for the eventlog file */
239     r = ifapi_asprintf(&event_log_file, "%s/%s%i",
240                        eventlog->log_dir, IFAPI_PCR_LOG_FILE, event->pcr);
241     return_if_error(r, "Out of memory.");
242 
243     /* Initiate the reading of the eventlog file */
244     r = ifapi_io_read_async(io, event_log_file);
245     if (r) {
246         LOG_DEBUG("Eventlog file %s could not be opened, creating...", event_log_file);
247         free(event_log_file);
248         eventlog->state = IFAPI_EVENTLOG_STATE_APPENDING;
249         return TSS2_RC_SUCCESS;
250     }
251     free(event_log_file);
252 
253     eventlog->state = IFAPI_EVENTLOG_STATE_READING;
254     return TSS2_RC_SUCCESS;
255 }
256 
257 /** Append an event to the existing event log.
258  *
259  * Call after ifapi_eventlog_get_async.
260  *
261  * @param[in,out] eventlog The context area for the eventlog.
262  * @param[in,out] io The context area for the asynchronous io module.
263  * @retval TSS2_RC_SUCCESS on success.
264  * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
265  * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
266  * @retval TSS2_FAPI_RC_TRY_AGAIN if the I/O operation is not finished yet and this function needs
267  *         to be called again.
268  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
269  *         the function.
270  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
271  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
272  *         operation already pending.
273  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
274  */
275 TSS2_RC
ifapi_eventlog_append_finish(IFAPI_EVENTLOG * eventlog,IFAPI_IO * io)276 ifapi_eventlog_append_finish(
277     IFAPI_EVENTLOG *eventlog,
278     IFAPI_IO *io)
279 {
280     check_not_null(eventlog);
281     check_not_null(io);
282 
283     TSS2_RC r;
284     char *logstr = NULL, *event_log_file;
285     const char *logstr2 = NULL;
286     json_object *log, *event = NULL;
287 
288     switch (eventlog->state) {
289     statecase(eventlog->state, IFAPI_EVENTLOG_STATE_READING)
290         /* Finish the reading of the eventlog file and return it directly to the output parameter */
291         r = ifapi_io_read_finish(io, (uint8_t **)&logstr, NULL);
292         return_try_again(r);
293         return_if_error(r, "read_finish failed");
294         fallthrough;
295 
296     statecase(eventlog->state, IFAPI_EVENTLOG_STATE_APPENDING)
297         /* If a log was read, we deserialize it to JSON. Otherwise we start a new log. */
298         if (logstr) {
299             log = json_tokener_parse(logstr);
300             SAFE_FREE(logstr);
301             return_if_null(log, "JSON parsing error", TSS2_FAPI_RC_BAD_VALUE);
302 
303              /* libjson-c does not deliver an array if array has only one element */
304             json_type jso_type = json_object_get_type(log);
305             if (jso_type != json_type_array) {
306                 json_object *json_array = json_object_new_array();
307                 json_object_array_add(json_array, log);
308                 log = json_array;
309             }
310         } else {
311             log = json_object_new_array();
312             return_if_null(log, "Out of memory", TSS2_FAPI_RC_MEMORY);
313         }
314 
315         /* Extend the eventlog with the data */
316         eventlog->event.recnum = json_object_array_length(log) + 1;
317 
318         r = ifapi_json_IFAPI_EVENT_serialize(&eventlog->event, &event);
319         if (r) {
320             json_object_put(log);
321             LOG_ERROR("Error serializing event data");
322             return TSS2_FAPI_RC_GENERAL_FAILURE;
323         }
324 
325         json_object_array_add(log, event);
326         logstr2 = json_object_to_json_string_ext(log, JSON_C_TO_STRING_PRETTY);
327 
328         /* Construct the filename for the eventlog file */
329         r = ifapi_asprintf(&event_log_file, "%s/%s%i",
330                            eventlog->log_dir, IFAPI_PCR_LOG_FILE, eventlog->event.pcr);
331         return_if_error(r, "Out of memory.");
332 
333         /* Start writing the eventlog back to disk */
334         r = ifapi_io_write_async(io, event_log_file, (uint8_t *) logstr2, strlen(logstr2));
335         free(event_log_file);
336         json_object_put(log); /* this also frees logstr2 */
337         return_if_error(r, "write_async failed");
338         fallthrough;
339 
340     statecase(eventlog->state, IFAPI_EVENTLOG_STATE_WRITING)
341         /* Finish writing the eventlog */
342         r = ifapi_io_write_finish(io);
343         return_try_again(r);
344         return_if_error(r, "read_finish failed");
345 
346         eventlog->state = IFAPI_EVENTLOG_STATE_INIT;
347         break;
348 
349     statecasedefault(eventlog->state);
350     }
351 
352     return TSS2_RC_SUCCESS;
353 }
354 
355 
356 /** Free allocated memory for an ifapi event.
357  *
358  * @param[in,out] event The structure to be cleaned up.
359  */
360 void
ifapi_cleanup_event(IFAPI_EVENT * event)361 ifapi_cleanup_event(IFAPI_EVENT * event) {
362     if (event != NULL) {
363         if (event->type == IFAPI_IMA_EVENT_TAG) {
364             SAFE_FREE(event->sub_event.ima_event.eventName);
365         } else if (event->type == IFAPI_TSS_EVENT_TAG) {
366             SAFE_FREE(event->sub_event.tss_event.event);
367         }
368     }
369 }
370