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