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