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 #include "fapi_policy.h"
21 #define LOGMODULE fapi
22 #include "util/log.h"
23 #include "util/aux_util.h"
24 
25 /** One-Call function for Fapi_NvWrite
26  *
27  * Writes data to a "regular" (not pin, extend or counter) NV index.
28  *
29  * @param[in,out] context The FAPI_CONTEXT
30  * @param[in] nvPath The path of the NV index to write
31  * @param[in] data The data to write to the NV index
32  * @param[in] size The size of data in bytes
33  *
34  * @retval TSS2_RC_SUCCESS: if the function call was a success.
35  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, nvPath, or data is NULL.
36  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
37  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath is not found.
38  * @retval TSS2_FAPI_RC_NV_EXCEEDED: if the NV is not large enough for the data
39  *         to be written.
40  * @retval TSS2_FAPI_RC_NV_WRONG_TYPE: if the NV index is not a "regular" one.
41  * @retval TSS2_FAPI_RC_NV_NOT_WRITEABLE: if the NV is not a writeable index.
42  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN: if the policy is unknown.
43  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
44  *         operation already pending.
45  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
46  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
47  *         internal operations or return parameters.
48  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
49  *         config file.
50  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
51  *         this function needs to be called again.
52  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
53  *         the function.
54  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
55  *         during authorization.
56  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
57  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
58  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
59  *         is not set.
60  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
61  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
62  */
63 TSS2_RC
Fapi_NvWrite(FAPI_CONTEXT * context,char const * nvPath,uint8_t const * data,size_t size)64 Fapi_NvWrite(
65     FAPI_CONTEXT  *context,
66     char    const *nvPath,
67     uint8_t const *data,
68     size_t         size)
69 {
70     LOG_TRACE("called for context:%p", context);
71 
72     TSS2_RC r, r2;
73 
74     /* Check for NULL parameters */
75     check_not_null(context);
76     check_not_null(nvPath);
77     check_not_null(data);
78 
79     /* Check whether TCTI and ESYS are initialized */
80     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
81                    TSS2_FAPI_RC_NO_TPM);
82 
83     /* If the async state automata of FAPI shall be tested, then we must not set
84        the timeouts of ESYS to blocking mode.
85        During testing, the mssim tcti will ensure multiple re-invocations.
86        Usually however the synchronous invocations of FAPI shall instruct ESYS
87        to block until a result is available. */
88 #ifndef TEST_FAPI_ASYNC
89     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
90     return_if_error_reset_state(r, "Set Timeout to blocking");
91 #endif /* TEST_FAPI_ASYNC */
92 
93     r = Fapi_NvWrite_Async(context, nvPath, data, size);
94     return_if_error_reset_state(r, "NV_Write");
95 
96     do {
97         /* We wait for file I/O to be ready if the FAPI state automata
98            are in a file I/O state. */
99         r = ifapi_io_poll(&context->io);
100         return_if_error(r, "Something went wrong with IO polling");
101 
102         /* Repeatedly call the finish function, until FAPI has transitioned
103            through all execution stages / states of this invocation. */
104         r = Fapi_NvWrite_Finish(context);
105     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
106 
107     /* Reset the ESYS timeout to non-blocking, immediate response. */
108     r2 = Esys_SetTimeout(context->esys, 0);
109     return_if_error(r2, "Set Timeout to non-blocking");
110 
111     return_if_error_reset_state(r, "NV_Write");
112 
113     LOG_TRACE("finished");
114     return TSS2_RC_SUCCESS;
115 }
116 
117 /** Asynchronous function for Fapi_NvWrite
118  *
119  * Writes data to a "regular" (not pin, extend or counter) NV index.
120  *
121  * Call Fapi_NvWrite_Finish to finish the execution of this command.
122  *
123  * @param[in,out] context The FAPI_CONTEXT
124  * @param[in] nvPath The path of the NV index to write
125  * @param[in] data The data to write to the NV index
126  * @param[in] size The size of data in bytes
127  *
128  * @retval TSS2_RC_SUCCESS: if the function call was a success.
129  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, nvPath, or data is NULL.
130  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
131  * @retval TSS2_FAPI_RC_BAD_PATH: if nvPath is not found.
132  * @retval TSS2_FAPI_RC_NV_EXCEEDED: if the NV is not large enough for the data
133  *         to be written.
134  * @retval TSS2_FAPI_RC_NV_WRONG_TYPE: if the NV index is not a "regular" one.
135  * @retval TSS2_FAPI_RC_NV_NOT_WRITEABLE: if the NV is not a writeable index.
136  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN: if the policy is unknown.
137  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
138  *         operation already pending.
139  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
140  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
141  *         internal operations or return parameters.
142  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
143  *         config file.
144  */
145 TSS2_RC
Fapi_NvWrite_Async(FAPI_CONTEXT * context,char const * nvPath,uint8_t const * data,size_t size)146 Fapi_NvWrite_Async(
147     FAPI_CONTEXT  *context,
148     char    const *nvPath,
149     uint8_t const *data,
150     size_t         size)
151 {
152     LOG_TRACE("called for context:%p", context);
153     LOG_TRACE("nvPath: %s", nvPath);
154     if (data) {
155         LOGBLOB_TRACE(data, size, "data");
156     } else {
157         LOG_TRACE("data: (null) size: %zi", size);
158     }
159 
160     TSS2_RC r;
161 
162     /* Check for NULL parameters */
163     check_not_null(context);
164     check_not_null(nvPath);
165     check_not_null(data);
166 
167     /* Helpful alias pointers */
168     IFAPI_NV_Cmds * command = &context->nv_cmd;
169 
170     /* Reset all context-internal session state information. */
171     r = ifapi_session_init(context);
172     return_if_error(r, "Initialize NV_Write");
173 
174     /* Initialize the command */
175     uint8_t * commandData = NULL;
176     memset(&context->nv_cmd, 0, sizeof(IFAPI_NV_Cmds));
177     command->offset = 0;
178     command->data = NULL;
179 
180 
181     /* Copy parameters to context for use during _Finish. */
182     strdup_check(command->nvPath, nvPath, r, error_cleanup);
183 
184     commandData = malloc(size);
185     goto_if_null2(commandData, "Out of memory", r, TSS2_FAPI_RC_MEMORY,
186             error_cleanup);
187     memcpy(commandData, data, size);
188     command->data = commandData;
189 
190     context->primary_state = PRIMARY_INIT;
191     command->numBytes = size;
192 
193     /* Initialize the context state for this operation. */
194     context->state = NV_WRITE_READ;
195     LOG_TRACE("finished");
196     return TSS2_RC_SUCCESS;
197 
198 error_cleanup:
199     /* Cleanup duplicated input parameters that were copied before. */
200     SAFE_FREE(command->nvPath);
201     SAFE_FREE(command->data);
202     return r;
203 }
204 
205 /** Asynchronous finish function for Fapi_NvWrite
206  *
207  * This function should be called after a previous Fapi_NvWrite.
208  *
209  * @param[in,out] context The FAPI_CONTEXT
210  *
211  * @retval TSS2_RC_SUCCESS: if the function call was a success.
212  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
213  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
214  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
215  *         operation already pending.
216  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
217  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
218  *         internal operations or return parameters.
219  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
220  *         complete. Call this function again later.
221  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
222  *         the function.
223  * @retval TSS2_FAPI_RC_BAD_PATH if the used path in inappropriate-
224  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
225  *         during authorization.
226  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
227  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
228  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
229  *         is not set.
230  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
231  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
232  *         was not successful.
233  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
234  */
235 TSS2_RC
Fapi_NvWrite_Finish(FAPI_CONTEXT * context)236 Fapi_NvWrite_Finish(
237     FAPI_CONTEXT  *context)
238 {
239     LOG_TRACE("called for context:%p", context);
240 
241     TSS2_RC r;
242     json_object *jso = NULL;
243 
244     /* Check for NULL parameters */
245     check_not_null(context);
246 
247     /* Helpful alias pointers */
248     IFAPI_NV_Cmds * command = &context->nv_cmd;
249 
250     switch (context->state) {
251     statecase(context->state, NV_WRITE_READ);
252         /* First check whether the file in object store can be updated. */
253         r = ifapi_keystore_check_writeable(&context->keystore, &context->io, command->nvPath);
254         goto_if_error_reset_state(r, "Check whether update object store is possible.", error_cleanup);
255 
256         /* Write to the NV index. */
257         r = ifapi_nv_write(context, command->nvPath, command->offset,
258                            command->data, command->numBytes);
259 
260         return_try_again(r);
261         goto_if_error_reset_state(r, " FAPI NV Write", error_cleanup);
262 
263 
264         /* Perform esys serialization if necessary */
265         r = ifapi_esys_serialize_object(context->esys, &command->nv_object);
266         goto_if_error(r, "Prepare serialization", error_cleanup);
267 
268         /* Start writing the NV object to the key store */
269         r = ifapi_keystore_store_async(&context->keystore, &context->io,
270                                        command->nvPath,
271                                        &command->nv_object);
272         goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
273                                   command->nvPath);
274 
275         fallthrough;
276 
277     statecase(context->state, NV_WRITE_WRITE);
278         /* Finish writing the NV object to the key store */
279         r = ifapi_keystore_store_finish(&context->keystore, &context->io);
280         return_try_again(r);
281         return_if_error_reset_state(r, "write_finish failed");
282 
283         fallthrough;
284 
285     statecase(context->state, NV_WRITE_CLEANUP)
286         /* Cleanup the authorization session. */
287         r = ifapi_cleanup_session(context);
288         try_again_or_error_goto(r, "Cleanup", error_cleanup);
289 
290         context->state = _FAPI_STATE_INIT;
291         break;
292 
293     statecasedefault(context->state);
294     }
295 
296 error_cleanup:
297     /* Cleanup any intermediate results and state stored in the context. */
298     ifapi_cleanup_ifapi_object(&command->nv_object);
299     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
300     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
301     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
302     SAFE_FREE(context->nv_cmd.write_data);
303     SAFE_FREE(command->nvPath);
304     SAFE_FREE(command->data);
305     SAFE_FREE(jso);
306     ifapi_session_clean(context);
307 
308     LOG_TRACE("finished");
309     return r;
310 }
311