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 "tss2_fapi.h"
12 #include "fapi_int.h"
13 #include "fapi_util.h"
14 #include "tss2_esys.h"
15 #include "ifapi_json_serialize.h"
16 #include "fapi_crypto.h"
17 #define LOGMODULE fapi
18 #include "util/log.h"
19 #include "util/aux_util.h"
20
21 /** One-Call function for Fapi_PcrExtend
22 *
23 * Performs an extend operation on a given PCR.
24 *
25 * @param[in,out] context The FAPI_CONTEXT
26 * @param[in] pcr The PCR to extend
27 * @param[in] data The data that is to be extended on the PCR
28 * @param[in] dataSize The size of data in bytes
29 * @param[in] logData A JSON representation of data to be written to the PCR's
30 * event log. May be NULL
31 *
32 * @retval TSS2_RC_SUCCESS: if the function call was a success.
33 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or data is NULL.
34 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
35 * @retval TSS2_FAPI_RC_NO_PCR: if no such PCR exists on this TPM.
36 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
37 * operation already pending.
38 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
39 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
40 * internal operations or return parameters.
41 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
42 * config file.
43 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
44 * the function.
45 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
46 * this function needs to be called again.
47 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
48 * during authorization.
49 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
50 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
51 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
52 * is not set.
53 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
54 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
55 * was not successful.
56 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
57 */
58 TSS2_RC
Fapi_PcrExtend(FAPI_CONTEXT * context,uint32_t pcr,uint8_t const * data,size_t dataSize,char const * logData)59 Fapi_PcrExtend(
60 FAPI_CONTEXT *context,
61 uint32_t pcr,
62 uint8_t const *data,
63 size_t dataSize,
64 char const *logData)
65 {
66 LOG_TRACE("called for context:%p", context);
67
68 TSS2_RC r, r2;
69
70 /* Check for NULL parameters */
71 check_not_null(context);
72 check_not_null(data);
73
74 /* Check whether TCTI and ESYS are initialized */
75 return_if_null(context->esys, "Command can't be executed in none TPM mode.",
76 TSS2_FAPI_RC_NO_TPM);
77
78 /* If the async state automata of FAPI shall be tested, then we must not set
79 the timeouts of ESYS to blocking mode.
80 During testing, the mssim tcti will ensure multiple re-invocations.
81 Usually however the synchronous invocations of FAPI shall instruct ESYS
82 to block until a result is available. */
83 #ifndef TEST_FAPI_ASYNC
84 r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
85 return_if_error_reset_state(r, "Set Timeout to blocking");
86 #endif /* TEST_FAPI_ASYNC */
87
88 r = Fapi_PcrExtend_Async(context, pcr, data, dataSize, logData);
89 return_if_error_reset_state(r, "PcrExtend");
90
91 do {
92 /* We wait for file I/O to be ready if the FAPI state automata
93 are in a file I/O state. */
94 r = ifapi_io_poll(&context->io);
95 return_if_error(r, "Something went wrong with IO polling");
96
97 /* Repeatedly call the finish function, until FAPI has transitioned
98 through all execution stages / states of this invocation. */
99 r = Fapi_PcrExtend_Finish(context);
100 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
101
102 /* Reset the ESYS timeout to non-blocking, immediate response. */
103 r2 = Esys_SetTimeout(context->esys, 0);
104 return_if_error(r2, "Set Timeout to non-blocking");
105
106 return_if_error_reset_state(r, "PcrExtend");
107
108 LOG_TRACE("finished");
109 return TSS2_RC_SUCCESS;
110 }
111
112 /** Asynchronous function for Fapi_PcrExtend
113 *
114 * Performs an extend operation on a given PCR.
115 *
116 * Call Fapi_PcrExtend_Finish to finish the execution of this command.
117 *
118 * @param[in,out] context The FAPI_CONTEXT
119 * @param[in] pcr The PCR to extend
120 * @param[in] data The data that is to be extended on the PCR
121 * @param[in] dataSize The size of data in bytes
122 * @param[in] logData A JSON representation of data to be written to the PCR's
123 * event log. May be NULL
124 *
125 * @retval TSS2_RC_SUCCESS: if the function call was a success.
126 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or data is NULL.
127 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
128 * @retval TSS2_FAPI_RC_NO_PCR: if no such PCR exists on this TPM.
129 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
130 * operation already pending.
131 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
132 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
133 * internal operations or return parameters.
134 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
135 * the function.
136 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
137 * config file.
138 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
139 */
140 TSS2_RC
Fapi_PcrExtend_Async(FAPI_CONTEXT * context,uint32_t pcr,uint8_t const * data,size_t dataSize,char const * logData)141 Fapi_PcrExtend_Async(
142 FAPI_CONTEXT *context,
143 uint32_t pcr,
144 uint8_t const *data,
145 size_t dataSize,
146 char const *logData)
147 {
148 LOG_TRACE("called for context:%p", context);
149 LOG_TRACE("pcr: %u", pcr);
150 if (data) {
151 LOGBLOB_TRACE(data, dataSize, "data");
152 } else {
153 LOG_TRACE("data: (null) dataSize: %zi", dataSize);
154 }
155 LOG_TRACE("logData: %s", logData);
156
157 TSS2_RC r;
158
159 /* Check for NULL parameters */
160 check_not_null(context);
161 check_not_null(data);
162
163 /* Helpful alias pointers */
164 IFAPI_PCR * command = &context->cmd.pcr;
165
166 /* Reset all context-internal session state information. */
167 r = ifapi_session_init(context);
168 goto_if_error(r, "Initialize PcrExtend", error_cleanup);
169
170 /* Perform some sanity checks on the input. */
171 if (dataSize > 1024 || dataSize == 0) {
172 goto_error(r, TSS2_FAPI_RC_BAD_VALUE,
173 "Event size must be > 1024 and != 0", error_cleanup);
174 }
175
176 /* Copy parameters to context for use during _Finish. */
177 strdup_check(command->logData, logData, r, error_cleanup);
178 command->event.size = dataSize;
179 memcpy(&command->event.buffer[0], data, dataSize);
180 command->pcrIndex = pcr;
181
182 r = Esys_GetCapability_Async(context->esys,
183 ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
184 TPM2_CAP_PCRS, 0, 1);
185 goto_if_error(r, "Esys_GetCapability_Async", error_cleanup);
186
187 /* Initialize the context state for this operation. */
188 context->state = PCR_EXTEND_WAIT_FOR_GET_CAP;
189 LOG_TRACE("finished");
190 return TSS2_RC_SUCCESS;
191
192 error_cleanup:
193 /* Cleanup duplicated input parameters that were copied before. */
194 SAFE_FREE(command->logData);
195 return r;
196 }
197
198 /** Asynchronous finish function for Fapi_PcrExtend
199 *
200 * This function should be called after a previous Fapi_PcrExtend_Async.
201 *
202 * @param[in,out] context The FAPI_CONTEXT
203 *
204 * @retval TSS2_RC_SUCCESS: if the function call was a success.
205 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
206 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
207 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
208 * operation already pending.
209 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
210 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
211 * internal operations or return parameters.
212 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
213 * complete. Call this function again later.
214 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
215 * during authorization.
216 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
217 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
218 * the function.
219 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
220 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
221 * is not set.
222 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
223 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
224 * was not successful.
225 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
226 */
227 TSS2_RC
Fapi_PcrExtend_Finish(FAPI_CONTEXT * context)228 Fapi_PcrExtend_Finish(
229 FAPI_CONTEXT *context)
230 {
231 LOG_TRACE("called for context:%p", context);
232
233 TSS2_RC r;
234 TPMI_YES_NO moreData;
235
236 /* Check for NULL parameters */
237 check_not_null(context);
238
239 /* Helpful alias pointers */
240 IFAPI_PCR * command = &context->cmd.pcr;
241 TPMS_CAPABILITY_DATA **capabilityData = &command->capabilityData;
242 IFAPI_EVENT * pcrEvent = &command->pcr_event;
243 IFAPI_TSS_EVENT * subEvent = &pcrEvent->sub_event.tss_event;
244
245 switch (context->state) {
246 statecase(context->state, PCR_EXTEND_WAIT_FOR_GET_CAP);
247 r = Esys_GetCapability_Finish(context->esys, &moreData, capabilityData);
248 return_try_again(r);
249 goto_if_error_reset_state(r, "GetCapablity_Finish", error_cleanup);
250
251 /* Prepare session used for integrity protecting the PCR Event operation. */
252 r = ifapi_get_sessions_async(context,
253 IFAPI_SESSION_GENEK | IFAPI_SESSION1,
254 0, 0);
255 goto_if_error_reset_state(r, "Create sessions", error_cleanup);
256
257 fallthrough;
258
259 statecase(context->state, PCR_EXTEND_WAIT_FOR_SESSION);
260 r = ifapi_get_sessions_finish(context, &context->profiles.default_profile,
261 context->profiles.default_profile.nameAlg);
262 return_try_again(r);
263 goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
264
265 /* Call PCR Event on the TPM, which performs an extend to all banks. */
266 r = Esys_PCR_Event_Async(context->esys, command->pcrIndex,
267 context->session1, ESYS_TR_NONE, ESYS_TR_NONE,
268 &command->event);
269 return_if_error(r, "Esys_PCR_Event_Async");
270 command->event_digests = NULL;
271
272 fallthrough;
273
274 statecase(context->state, PCR_EXTEND_FINISH);
275 r = Esys_PCR_Event_Finish(context->esys, &command->event_digests);
276 return_try_again(r);
277 goto_if_error_reset_state(r, "PCR_Extend_Finish", error_cleanup);
278
279 /* Construct the eventLog entry. */
280 pcrEvent->digests = *command->event_digests;
281 pcrEvent->pcr = command->pcrIndex;
282 pcrEvent->type = IFAPI_TSS_EVENT_TAG;
283 subEvent->data = command->event;
284 if (command->logData) {
285 strdup_check(subEvent->event,
286 command->logData, r, error_cleanup);
287 } else {
288 subEvent->event = NULL;
289 }
290
291 /* Append the eventLog entry to the event log. */
292 r = ifapi_eventlog_append_async(&context->eventlog, &context->io,
293 &command->pcr_event);
294 goto_if_error(r, "Error ifapi_eventlog_append_async", error_cleanup);
295
296 fallthrough;
297
298 statecase(context->state, PCR_EXTEND_APPEND_EVENT_LOG);
299 r = ifapi_eventlog_append_finish(&context->eventlog, &context->io);
300 return_try_again(r);
301 goto_if_error(r, "ifapi_eventlog_append_async", error_cleanup);
302
303 SAFE_FREE(command->event_digests);
304 fallthrough;
305
306 statecase(context->state, PCR_EXTEND_CLEANUP)
307 /* Cleanup the session used for integrity checking. */
308 r = ifapi_cleanup_session(context);
309 try_again_or_error_goto(r, "Cleanup", error_cleanup);
310
311 context->state = _FAPI_STATE_INIT;
312 break;
313
314 statecasedefault(context->state);
315 }
316
317 error_cleanup:
318 /* Cleanup any intermediate results and state stored in the context. */
319 SAFE_FREE(*capabilityData);
320 SAFE_FREE(command->event_digests);
321 SAFE_FREE(command->logData);
322 ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
323 ifapi_cleanup_ifapi_object(context->loadKey.key_object);
324 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
325 ifapi_cleanup_event(pcrEvent);
326 ifapi_session_clean(context);
327 LOG_TRACE("finished");
328 return r;
329 }
330