xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/api/Fapi_WriteAuthorizeNV.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_mu.h"
12 #include "tss2_fapi.h"
13 #include "fapi_int.h"
14 #include "fapi_util.h"
15 #include "tss2_esys.h"
16 #include "fapi_policy.h"
17 #include "fapi_crypto.h"
18 #define LOGMODULE fapi
19 #include "util/log.h"
20 #include "util/aux_util.h"
21 
22 /** One-Call function for Fapi_WriteAuthorizeNv
23  *
24  * Write the policyDigest of a policy to an NV index so it can be used in policies
25  * containing PolicyAuthorizeNV elements.
26  *
27  * @param[in,out] context The FAPI_CONTEXT
28  * @param[in] nvPath The path of the NV index
29  * @param[in] policyPath The path of the new policy
30  *
31  * @retval TSS2_RC_SUCCESS: if the function call was a success.
32  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
33  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
34  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath or policyPath does not map to a
35  *         FAPI policy or NV index.
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_PATH_NOT_FOUND if a FAPI object path was not found
44  *         during authorization.
45  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
46  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
47  *         the function.
48  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
49  *         this function needs to be called again.
50  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
51  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
52  */
53 TSS2_RC
Fapi_WriteAuthorizeNv(FAPI_CONTEXT * context,char const * nvPath,char const * policyPath)54 Fapi_WriteAuthorizeNv(
55     FAPI_CONTEXT  *context,
56     char    const *nvPath,
57     char    const *policyPath)
58 {
59     LOG_TRACE("called for context:%p", context);
60 
61     TSS2_RC r, r2;
62 
63     /* Check for NULL parameters */
64     check_not_null(context);
65     check_not_null(nvPath);
66     check_not_null(policyPath);
67 
68     /* Check whether TCTI and ESYS are initialized */
69     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
70                    TSS2_FAPI_RC_NO_TPM);
71 
72     /* If the async state automata of FAPI shall be tested, then we must not set
73        the timeouts of ESYS to blocking mode.
74        During testing, the mssim tcti will ensure multiple re-invocations.
75        Usually however the synchronous invocations of FAPI shall instruct ESYS
76        to block until a result is available. */
77 #ifndef TEST_FAPI_ASYNC
78     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
79     return_if_error_reset_state(r, "Set Timeout to blocking");
80 #endif /* TEST_FAPI_ASYNC */
81 
82     r = Fapi_WriteAuthorizeNv_Async(context, nvPath, policyPath);
83     return_if_error_reset_state(r, "WriteAuthorizeNV");
84 
85     do {
86         /* We wait for file I/O to be ready if the FAPI state automata
87            are in a file I/O state. */
88         r = ifapi_io_poll(&context->io);
89         return_if_error(r, "Something went wrong with IO polling");
90 
91         /* Repeatedly call the finish function, until FAPI has transitioned
92            through all execution stages / states of this invocation. */
93         r = Fapi_WriteAuthorizeNv_Finish(context);
94     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
95 
96     /* Reset the ESYS timeout to non-blocking, immediate response. */
97     r2 = Esys_SetTimeout(context->esys, 0);
98     return_if_error(r2, "Set Timeout to non-blocking");
99 
100     return_if_error_reset_state(r, "WriteAuthorizeNV");
101 
102     LOG_TRACE("finished");
103     return TSS2_RC_SUCCESS;
104 }
105 
106 /** Asynchronous function for Fapi_WriteAuthorizeNv
107  *
108  * Write the policyDigest of a policy to an NV index so it can be used in policies
109  * containing PolicyAuthorizeNV elements.
110  *
111  * Call Fapi_WriteAuthorizeNv_Finish to finish the execution of this command.
112  *
113  * @param[in,out] context The FAPI_CONTEXT
114  * @param[in] nvPath The path of the NV index
115  * @param[in] policyPath The path of the new policy
116  *
117  * @retval TSS2_RC_SUCCESS: if the function call was a success.
118  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
119  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
120  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath or policyPath does not map to a
121  *         FAPI policy or NV index.
122  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
123  *         operation already pending.
124  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
125  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
126  *         internal operations or return parameters.
127  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
128  *         config file.
129  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
130  *         during authorization.
131  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
132  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
133  *         the function.
134  */
135 TSS2_RC
Fapi_WriteAuthorizeNv_Async(FAPI_CONTEXT * context,char const * nvPath,char const * policyPath)136 Fapi_WriteAuthorizeNv_Async(
137     FAPI_CONTEXT  *context,
138     char    const *nvPath,
139     char    const *policyPath)
140 {
141     LOG_TRACE("called for context:%p", context);
142     LOG_TRACE("nvPath: %s", nvPath);
143     LOG_TRACE("policyPath: %s", policyPath);
144 
145     TSS2_RC r;
146 
147     /* Check for NULL parameters */
148     check_not_null(context);
149     check_not_null(nvPath);
150     check_not_null(policyPath);
151 
152     /* Helpful alias pointers */
153     IFAPI_api_WriteAuthorizeNv * command = &context->cmd.WriteAuthorizeNV;
154     IFAPI_NV_Cmds * nvCmd = &context->nv_cmd;
155 
156     /* Reset all context-internal session state information. */
157     r = ifapi_session_init(context);
158     return_if_error(r, "Initialize WriterAuthorizeNv");
159 
160     /* Copy parameters to context for use during _Finish. */
161     strdup_check(command->policyPath, policyPath, r, error_cleanup);
162     strdup_check(nvCmd->nvPath, nvPath, r, error_cleanup);
163 
164     /* Load the metadata for the NV index to be written to from the keystore. */
165     r = ifapi_keystore_load_async(&context->keystore, &context->io, nvCmd->nvPath);
166     goto_if_error2(r, "Could not open: %s", error_cleanup, nvCmd->nvPath);
167 
168     /* Initialize the context state for this operation. */
169     context->state = WRITE_AUTHORIZE_NV_READ_NV;
170     LOG_TRACE("finished");
171     return TSS2_RC_SUCCESS;
172 
173 error_cleanup:
174     /* Cleanup duplicated input parameters that were copied before. */
175     SAFE_FREE(command->policyPath);
176     SAFE_FREE(nvCmd->nvPath);
177     return r;
178 }
179 
180 /** Asynchronous finish function for Fapi_WriteAuthorizeNv
181  *
182  * This function should be called after a previous Fapi_WriteAuthorizeNv_Async.
183  *
184  * @param[in,out] context The FAPI_CONTEXT
185  *
186  * @retval TSS2_RC_SUCCESS: if the function call was a success.
187  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
188  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
189  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
190  *         operation already pending.
191  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
192  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
193  *         internal operations or return parameters.
194  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
195  *         complete. Call this function again later.
196  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
197  *         the function.
198  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
199  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
200  *         during authorization.
201  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
202  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
203  */
204 TSS2_RC
Fapi_WriteAuthorizeNv_Finish(FAPI_CONTEXT * context)205 Fapi_WriteAuthorizeNv_Finish(
206     FAPI_CONTEXT  *context)
207 {
208     LOG_TRACE("called for context:%p", context);
209 
210     TSS2_RC r;
211     const size_t maxNvSize = sizeof(TPMU_HA) + sizeof(TPMI_ALG_HASH);
212     BYTE nvBuffer[maxNvSize];
213     size_t offset = 0;
214 
215     /* Check for NULL parameters */
216     check_not_null(context);
217 
218     /* Helpful alias pointers */
219     IFAPI_api_WriteAuthorizeNv * command = &context->cmd.WriteAuthorizeNV;
220     IFAPI_NV_Cmds * nvCmd = &context->nv_cmd;
221     IFAPI_OBJECT *object = &nvCmd->nv_object;
222     TPMI_ALG_HASH hashAlg;
223     TPMS_POLICY * policy = &context->policy.policy;
224 
225     switch (context->state) {
226         statecase(context->state, WRITE_AUTHORIZE_NV_READ_NV)
227             /* First check whether the file in object store can be updated. */
228             r = ifapi_keystore_check_writeable(&context->keystore, &context->io,
229                     nvCmd->nvPath);
230             goto_if_error_reset_state(r,
231                     "Check whether update object store is possible.", error_cleanup);
232 
233             r = ifapi_keystore_load_finish(&context->keystore, &context->io, object);
234             return_try_again(r);
235             return_if_error_reset_state(r, "read_finish failed");
236 
237             ifapi_cleanup_ifapi_object(object);
238 
239             /* Initialize the NV index object to be used with esys. */
240             r = ifapi_initialize_object(context->esys, object);
241             goto_if_error_reset_state(r, "Initialize NV object", error_cleanup);
242 
243             fallthrough;
244 
245         statecase(context->state, WRITE_AUTHORIZE_NV_CALCULATE_POLICY)
246             /* Calculate the policy digest for the referenced policy. */
247             hashAlg = object->misc.nv.public.nvPublic.nameAlg;
248             r = ifapi_calculate_tree(context, command->policyPath,
249                     policy, hashAlg, &command->digest_idx,
250                     &command->hash_size);
251             if (r != TSS2_RC_SUCCESS) {
252                 ifapi_cleanup_ifapi_object(object);
253             }
254             return_try_again(r);
255             goto_if_error(r, "Fapi calculate tree.", error_cleanup);
256 
257             fallthrough;
258 
259         statecase(context->state, WRITE_AUTHORIZE_NV_WRITE_NV_RAM_PREPARE)
260 
261             /* Copy hash alg followed by digest into a buffer to be written to NV ram */
262             r = Tss2_MU_TPMI_ALG_HASH_Marshal(
263                     object->misc.nv.public.nvPublic.nameAlg,
264                     &nvBuffer[0], maxNvSize, &offset);
265             goto_if_error_reset_state(r, "FAPI marshal hash alg", error_cleanup);
266 
267             void * currentDigest =
268                 &policy->policyDigests.digests[command->digest_idx].digest;
269             memcpy(&nvBuffer[offset], currentDigest, command->hash_size);
270 
271             /* Store these data in the context to be used for re-entry on nv_write. */
272             nvCmd->data = &nvBuffer[0];
273             nvCmd->numBytes = command->hash_size + sizeof(TPMI_ALG_HASH);
274             fallthrough;
275 
276         statecase(context->state, WRITE_AUTHORIZE_NV_WRITE_NV_RAM)
277             /* Perform the actual NV Write operation. */
278             r = ifapi_nv_write(context, nvCmd->nvPath, 0,
279                     nvCmd->data, context->nv_cmd.numBytes);
280             return_try_again(r);
281             goto_if_error_reset_state(r, " FAPI NV Write", error_cleanup);
282 
283             /* Perform esys serialization if necessary */
284             r = ifapi_esys_serialize_object(context->esys, object);
285             goto_if_error(r, "Prepare serialization", error_cleanup);
286 
287              /* Save NV object to ensure that changed flags are updated. */
288             r = ifapi_keystore_store_async(&context->keystore, &context->io,
289                     nvCmd->nvPath, object);
290             goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
291                     nvCmd->nvPath);
292 
293             fallthrough;
294 
295         statecase(context->state, WRITE_AUTHORIZE_NV_WRITE_OBJCECT)
296             /* Finish writing the NV object to the key store */
297             r = ifapi_keystore_store_finish(&context->keystore, &context->io);
298             return_try_again(r);
299             return_if_error_reset_state(r, "write_finish failed");
300 
301             fallthrough;
302 
303         statecase(context->state, WRITE_AUTHORIZE_NV_WRITE_POLICY_PREPARE)
304             r = ifapi_policy_store_store_async(&context->pstore, &context->io,
305                                                command->policyPath, policy);
306             goto_if_error_reset_state(r, "Could not open: %s", error_cleanup,
307                     command->policyPath);
308             fallthrough;
309 
310         statecase(context->state, WRITE_AUTHORIZE_NV_WRITE_POLICY)
311             /* Save policy with computed digest */
312             r = ifapi_policy_store_store_finish(&context->pstore, &context->io);
313             return_try_again(r);
314             return_if_error_reset_state(r, "write_finish failed");
315 
316             fallthrough;
317 
318         statecase(context->state, WRITE_AUTHORIZE_NV_CLEANUP)
319             /* Cleanup the session used for authorizing access to the NV index. */
320             r = ifapi_cleanup_session(context);
321             try_again_or_error_goto(r, "Cleanup", error_cleanup);
322             context->state = _FAPI_STATE_INIT;
323             break;
324 
325         statecasedefault(context->state);
326     }
327 
328 error_cleanup:
329     /* Cleanup any intermediate results and state stored in the context. */
330     SAFE_FREE(command->policyPath);
331     SAFE_FREE(nvCmd->nvPath);
332     ifapi_session_clean(context);
333     ifapi_cleanup_policy(policy);
334     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
335     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
336     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
337     ifapi_cleanup_ifapi_object(object);
338     LOG_TRACE("finished");
339     return r;
340 }
341