xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/api/Fapi_PcrExtend.c (revision 758e9fba6fc9adbf15340f70c73baee7b168b1c9)
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