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