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