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