xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/api/Fapi_NvIncrement.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 <string.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <errno.h>
15 
16 #include "tss2_fapi.h"
17 #include "fapi_int.h"
18 #include "fapi_util.h"
19 #include "tss2_esys.h"
20 #define LOGMODULE fapi
21 #include "util/log.h"
22 #include "util/aux_util.h"
23 
24 /** One-Call function for Fapi_NvIncrement
25  *
26  * Increments an NV index that is a counter by 1.
27  *
28  * @param[in,out] context The FAPI_CONTEXT
29  * @param[in] nvPath The path to the NV index that is incremented.
30  *
31  * @retval TSS2_RC_SUCCESS: if the function call was a success.
32  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or nvPath is NULL.
33  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
34  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath is not found.
35  * @retval TSS2_FAPI_RC_NV_WRONG_TYPE: if the NV index type is not
36  *         TPM2_NT_COUNTER.
37  * @retval TSS2_FAPI_RC_NV_NOT_WRITEABLE: if the NV index is not writeable.
38  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN: if the policy is unknown.
39  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
40  *         operation already pending.
41  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
42  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
43  *         internal operations or return parameters.
44  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
45  *         config file.
46  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
47  *         during authorization.
48  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
49  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
50  *         the function.
51  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
52  *         this function needs to be called again.
53  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
54  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
55  *         is not set.
56  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
57  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
58  */
59 TSS2_RC
Fapi_NvIncrement(FAPI_CONTEXT * context,char const * nvPath)60 Fapi_NvIncrement(
61     FAPI_CONTEXT *context,
62     char   const *nvPath)
63 {
64     LOG_TRACE("called for context:%p", context);
65 
66     TSS2_RC r, r2;
67 
68     /* Check for NULL parameters */
69     check_not_null(context);
70     check_not_null(nvPath);
71 
72     /* Check whether TCTI and ESYS are initialized */
73     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
74                    TSS2_FAPI_RC_NO_TPM);
75 
76     /* If the async state automata of FAPI shall be tested, then we must not set
77        the timeouts of ESYS to blocking mode.
78        During testing, the mssim tcti will ensure multiple re-invocations.
79        Usually however the synchronous invocations of FAPI shall instruct ESYS
80        to block until a result is available. */
81 #ifndef TEST_FAPI_ASYNC
82     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
83     return_if_error_reset_state(r, "Set Timeout to blocking");
84 #endif /* TEST_FAPI_ASYNC */
85 
86     r = Fapi_NvIncrement_Async(context, nvPath);
87     return_if_error_reset_state(r, "NV_Increment");
88 
89     do {
90         /* We wait for file I/O to be ready if the FAPI state automata
91            are in a file I/O state. */
92         r = ifapi_io_poll(&context->io);
93         return_if_error(r, "Something went wrong with IO polling");
94 
95         /* Repeatedly call the finish function, until FAPI has transitioned
96            through all execution stages / states of this invocation. */
97         r = Fapi_NvIncrement_Finish(context);
98     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
99 
100     /* Reset the ESYS timeout to non-blocking, immediate response. */
101     r2 = Esys_SetTimeout(context->esys, 0);
102     return_if_error(r2, "Set Timeout to non-blocking");
103 
104     return_if_error_reset_state(r, "NV_Increment");
105 
106     LOG_TRACE("finished");
107     return TSS2_RC_SUCCESS;
108 }
109 
110 /** Asynchronous function for Fapi_NvIncrement
111  *
112  * Increments an NV index that is a counter by 1.
113  *
114  * Call Fapi_NvIncrement_Finish to finish the execution of this command.
115  *
116  * @param[in,out] context The FAPI_CONTEXT
117  * @param[in] nvPath The path to the NV index that is incremented.
118  *
119  * @retval TSS2_RC_SUCCESS: if the function call was a success.
120  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or nvPath is NULL.
121  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
122  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath is not found.
123  * @retval TSS2_FAPI_RC_NV_WRONG_TYPE: if the NV index type is not
124  *         TPM2_NT_COUNTER.
125  * @retval TSS2_FAPI_RC_NV_NOT_WRITEABLE: if the NV index is not writeable.
126  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN: if the policy is unknown.
127  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
128  *         operation already pending.
129  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
130  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
131  *         internal operations or return parameters.
132  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
133  *         config file.
134  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
135  *         during authorization.
136  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
137  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
138  *         the function.
139  */
140 TSS2_RC
Fapi_NvIncrement_Async(FAPI_CONTEXT * context,char const * nvPath)141 Fapi_NvIncrement_Async(
142     FAPI_CONTEXT *context,
143     char   const *nvPath)
144 {
145     LOG_TRACE("called for context:%p", context);
146     LOG_TRACE("nvPath: %s", nvPath);
147 
148     TSS2_RC r;
149 
150     /* Check for NULL parameters */
151     check_not_null(context);
152     check_not_null(nvPath);
153 
154     /* Helpful alias pointers */
155     IFAPI_NV_Cmds * command = &context->nv_cmd;
156 
157     /* Reset all context-internal session state information. */
158     r = ifapi_session_init(context);
159     return_if_error(r, "Initialize NV_Increment");
160 
161     /* Copy parameters to context for use during _Finish. */
162     memset(&context->nv_cmd, 0, sizeof(IFAPI_NV_Cmds));
163     strdup_check(command->nvPath, nvPath, r, error_cleanup);
164 
165     command->rdata = NULL;
166 
167     /* Load the NV index metadata from keystore. */
168     r = ifapi_keystore_load_async(&context->keystore, &context->io, command->nvPath);
169     goto_if_error2(r, "Could not open: %s", error_cleanup, command->nvPath);
170 
171     /* Initialize the context state for this operation. */
172     context->state = NV_INCREMENT_READ;
173     LOG_TRACE("finished");
174     return TSS2_RC_SUCCESS;
175 
176 error_cleanup:
177     /* Cleanup duplicated input parameters that were copied before. */
178     SAFE_FREE(command->nvPath);
179     return r;
180 }
181 
182 /** Asynchronous finish function for Fapi_NvIncrement
183  *
184  * This function should be called after a previous Fapi_NvIncrement_Async.
185  *
186  * @param[in,out] context The FAPI_CONTEXT
187  *
188  * @retval TSS2_RC_SUCCESS: if the function call was a success.
189  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
190  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
191  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
192  *         operation already pending.
193  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
194  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
195  *         internal operations or return parameters.
196  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
197  *         complete. Call this function again later.
198  * @retval TSS2_FAPI_RC_BAD_PATH if the used path in inappropriate-
199  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
200  *         the function.
201  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
202  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
203  *         during authorization.
204  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
205  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
206  *         is not set.
207  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
208  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
209  *         was not successful.
210  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
211  */
212 TSS2_RC
Fapi_NvIncrement_Finish(FAPI_CONTEXT * context)213 Fapi_NvIncrement_Finish(
214     FAPI_CONTEXT *context)
215 {
216     LOG_TRACE("called for context:%p", context);
217 
218     TSS2_RC r;
219     json_object *jso = NULL;
220     ESYS_TR authIndex;
221     ESYS_TR auth_session;
222 
223     /* Check for NULL parameters */
224     check_not_null(context);
225 
226     /* Helpful alias pointers */
227     IFAPI_NV_Cmds * command = &context->nv_cmd;
228     IFAPI_OBJECT *object = &command->nv_object;
229     ESYS_TR nvIndex = command->esys_handle;
230     IFAPI_OBJECT *authObject = &command->auth_object;
231 
232     switch (context->state) {
233     statecase(context->state, NV_INCREMENT_READ)
234         /* First check whether the file in object store can be updated. */
235         r = ifapi_keystore_check_writeable(&context->keystore, &context->io, command->nvPath);
236         goto_if_error_reset_state(r, "Check whether update object store is possible.", error_cleanup);
237 
238         r = ifapi_keystore_load_finish(&context->keystore, &context->io, object);
239         return_try_again(r);
240         return_if_error_reset_state(r, "read_finish failed");
241 
242         if (object->objectType != IFAPI_NV_OBJ)
243             goto_error(r, TSS2_FAPI_RC_BAD_PATH, "%s is no NV object.", error_cleanup,
244                        command->nvPath);
245 
246         /* Initialize the NV index object for use with ESYS. */
247         r = ifapi_initialize_object(context->esys, object);
248         goto_if_error_reset_state(r, "Initialize NV object", error_cleanup);
249 
250         nvIndex = command->nv_object.handle;
251         command->esys_handle = context->nv_cmd.nv_object.handle;
252         command->nv_obj = object->misc.nv;
253 
254         /* Determine auth object */
255         if (object->misc.nv.public.nvPublic.attributes & TPMA_NV_PPREAD) {
256             ifapi_init_hierarchy_object(authObject, ESYS_TR_RH_PLATFORM);
257             authIndex = ESYS_TR_RH_PLATFORM;
258         } else {
259             if (object->misc.nv.public.nvPublic.attributes & TPMA_NV_OWNERREAD) {
260                 ifapi_init_hierarchy_object(authObject, ESYS_TR_RH_OWNER);
261                 authIndex = ESYS_TR_RH_OWNER;
262             } else {
263                 authIndex = nvIndex;
264             }
265             *authObject = *object;
266         }
267         command->auth_index = authIndex;
268         context->primary_state = PRIMARY_INIT;
269 
270         /* Prepare the session for authorization */
271         r = ifapi_get_sessions_async(context,
272             IFAPI_SESSION_GENEK | IFAPI_SESSION1,
273             0, 0);
274         goto_if_error_reset_state(r, "Create sessions", error_cleanup);
275 
276         fallthrough;
277 
278     statecase(context->state, NV_INCREMENT_WAIT_FOR_SESSION)
279         r = ifapi_get_sessions_finish(context, &context->profiles.default_profile,
280                                       object->misc.nv.public.nvPublic.nameAlg);
281         return_try_again(r);
282         goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
283 
284         fallthrough;
285 
286     statecase(context->state, NV_INCREMENT_AUTHORIZE)
287         /* Authorize the session for accessing the NV-index. */
288         r = ifapi_authorize_object(context, authObject, &auth_session);
289         return_try_again(r);
290         goto_if_error(r, "Authorize NV object.", error_cleanup);
291 
292         /* Prepare increment */
293         r = Esys_NV_Increment_Async(context->esys,  command->auth_index,
294                                     nvIndex,
295                                     auth_session,
296                                     ESYS_TR_NONE, ESYS_TR_NONE);
297         goto_if_error_reset_state(r, " Fapi_NvIncrement_Async", error_cleanup);
298 
299         fallthrough;
300 
301     statecase(context->state, NV_INCREMENT_AUTH_SENT)
302         r = Esys_NV_Increment_Finish(context->esys);
303         return_try_again(r);
304         goto_if_error_reset_state(r, "FAPI NV_Increment_Finish", error_cleanup);
305 
306         /* Perform esys serialization if necessary */
307         r = ifapi_esys_serialize_object(context->esys, &command->nv_object);
308         goto_if_error(r, "Prepare serialization", error_cleanup);
309 
310         /* Start writing the NV object to the key store */
311         r = ifapi_keystore_store_async(&context->keystore, &context->io,
312                                        command->nvPath,
313                                        &command->nv_object);
314         goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
315                                   command->nvPath);
316 
317         fallthrough;
318 
319     statecase(context->state, NV_INCREMENT_WRITE)
320         /* Finish writing the NV object to the key store */
321         r = ifapi_keystore_store_finish(&context->keystore, &context->io);
322         return_try_again(r);
323         return_if_error_reset_state(r, "write_finish failed");
324         fallthrough;
325 
326     statecase(context->state, NV_INCREMENT_CLEANUP)
327         /* Cleanup the authorization session. */
328         r = ifapi_cleanup_session(context);
329         try_again_or_error_goto(r, "Cleanup", error_cleanup);
330 
331         context->state = _FAPI_STATE_INIT;
332         break;
333 
334     statecasedefault(context->state);
335     }
336 
337 error_cleanup:
338     /* Cleanup any intermediate results and state stored in the context. */
339     ifapi_cleanup_ifapi_object(&command->nv_object);
340     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
341     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
342     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
343     SAFE_FREE(command->nvPath);
344     SAFE_FREE(jso);
345     ifapi_session_clean(context);
346     LOG_TRACE("finished");
347     return r;
348 }
349