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 <stdlib.h>
12 #include <string.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 "ifapi_json_serialize.h"
21 #include "ifapi_json_deserialize.h"
22 #define LOGMODULE fapi
23 #include "util/log.h"
24 #include "util/aux_util.h"
25
26
27 /** One-Call function for Fapi_Delete
28 *
29 * Deletes a given key, policy or NV index from the system.
30 *
31 * @param[in,out] context The ESAPI_CONTEXT
32 * @param[in] path The path to the entity that is to be deleted
33 *
34 * @retval TSS2_RC_SUCCESS: if the function call was a success.
35 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
36 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
37 * @retval TSS2_FAPI_RC_BAD_PATH: if path does not map to a FAPI entity.
38 * @retval TSS2_FAPI_RC_NOT_DELETABLE: if the entity is not deletable or the
39 * path is read-only.
40 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
41 * operation already pending.
42 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
43 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
44 * internal operations or return parameters.
45 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
46 * config file.
47 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
48 * during authorization.
49 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
50 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
51 * the function.
52 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
53 * this function needs to be called again.
54 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
55 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
56 * is not set.
57 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
58 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
59 * was not successful.
60 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
61 */
62 TSS2_RC
Fapi_Delete(FAPI_CONTEXT * context,char const * path)63 Fapi_Delete(
64 FAPI_CONTEXT *context,
65 char const *path)
66 {
67 LOG_TRACE("called for context:%p", context);
68
69 TSS2_RC r;
70
71 /* Check for NULL parameters */
72 check_not_null(context);
73 check_not_null(path);
74
75 r = Fapi_Delete_Async(context, path);
76 return_if_error_reset_state(r, "Entity_Delete");
77
78 do {
79 /* We wait for file I/O to be ready if the FAPI state automata
80 are in a file I/O state. */
81 r = ifapi_io_poll(&context->io);
82 return_if_error(r, "Something went wrong with IO polling");
83
84 /* Repeatedly call the finish function, until FAPI has transitioned
85 through all execution stages / states of this invocation. */
86 r = Fapi_Delete_Finish(context);
87 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
88
89 return_if_error_reset_state(r, "Entity_Delete");
90
91 return TSS2_RC_SUCCESS;
92 }
93
94 /** Asynchronous function for Fapi_Delete
95 *
96 * Deletes a given key, policy or NV index from the system.
97
98 * Call Fapi_Delete_Finish to finish the execution of this command.
99 *
100 * @param[in,out] context The ESAPI_CONTEXT
101 * @param[in] path The path to the entity that is to be deleted
102 *
103 * @retval TSS2_RC_SUCCESS: if the function call was a success.
104 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
105 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
106 * @retval TSS2_FAPI_RC_BAD_PATH: if path does not map to a FAPI entity.
107 * @retval TSS2_FAPI_RC_NOT_DELETABLE: if the entity is not deletable or the
108 * path is read-only.
109 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
110 * operation already pending.
111 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
112 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
113 * internal operations or return parameters.
114 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
115 * config file.
116 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
117 * during authorization.
118 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
119 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
120 * the function.
121 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
122 */
123 TSS2_RC
Fapi_Delete_Async(FAPI_CONTEXT * context,char const * path)124 Fapi_Delete_Async(
125 FAPI_CONTEXT *context,
126 char const *path)
127 {
128 LOG_TRACE("called for context:%p", context);
129 LOG_TRACE("path: %s", path);
130
131 TSS2_RC r;
132
133 /* Check for NULL parameters */
134 check_not_null(context);
135 check_not_null(path);
136
137 /* Helpful alias pointers */
138 IFAPI_Entity_Delete * command = &(context->cmd.Entity_Delete);
139 IFAPI_OBJECT *object = &command->object;
140 IFAPI_OBJECT *authObject = &command->auth_object;
141
142 /* Copy parameters to context for use during _Finish. */
143 strdup_check(command->path, path, r, error_cleanup);
144
145 /* List all keystore elements in the path hierarchy of the provided
146 path. The last of these is the object to be deleted. */
147 r = ifapi_keystore_list_all(&context->keystore, path, &command->pathlist,
148 &command->numPaths);
149 return_if_error(r, "get entities.");
150
151 command->path_idx = command->numPaths;
152
153 if (command->numPaths == 0) {
154 goto_error(r, TSS2_FAPI_RC_BAD_PATH, "No objects found.", error_cleanup);
155 }
156
157 object->objectType = IFAPI_OBJ_NONE;
158 authObject->objectType = IFAPI_OBJ_NONE;
159
160 if (ifapi_path_type_p(path, IFAPI_EXT_PATH) ||
161 (ifapi_path_type_p(path, IFAPI_POLICY_PATH))) {
162 /* No session will be needed these files can be deleted without
163 interaction with the TPM */
164 r = ifapi_non_tpm_mode_init(context);
165 return_if_error(r, "Initialize Entity_Delete");
166
167 context->state = ENTITY_DELETE_GET_FILE;
168 } else {
169 /* Check whether TCTI and ESYS are initialized */
170 return_if_null(context->esys, "Command can't be executed in none TPM mode.",
171 TSS2_FAPI_RC_NO_TPM);
172
173 /* If the async state automata of FAPI shall be tested, then we must not set
174 the timeouts of ESYS to blocking mode.
175 During testing, the mssim tcti will ensure multiple re-invocations.
176 Usually however the synchronous invocations of FAPI shall instruct ESYS
177 to block until a result is available. */
178 #ifndef TEST_FAPI_ASYNC
179 r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
180 return_if_error_reset_state(r, "Set Timeout to blocking");
181 #endif /* TEST_FAPI_ASYNC */
182
183 /* A TPM session will be created to enable object authorization */
184 r = ifapi_session_init(context);
185 return_if_error(r, "Initialize Entity_Delete");
186
187 r = ifapi_get_sessions_async(context,
188 IFAPI_SESSION_GENEK | IFAPI_SESSION1,
189 0, 0);
190 goto_if_error_reset_state(r, "Create sessions", error_cleanup);
191
192 context->state = ENTITY_DELETE_WAIT_FOR_SESSION;
193 }
194
195 LOG_TRACE("finished");
196 return TSS2_RC_SUCCESS;
197
198 error_cleanup:
199 /* Cleanup any intermediate results and state stored in the context. */
200 SAFE_FREE(command->path);
201 if (Esys_FlushContext(context->esys, context->session1) != TSS2_RC_SUCCESS) {
202 LOG_ERROR("Cleanup session failed.");
203 }
204 return r;
205 }
206
207
208 /** Asynchronous finish function for Fapi_Delete
209 *
210 * This function should be called after a previous Fapi_Delete_Async.
211 *
212 * @param[in,out] context The FAPI_CONTEXT
213 *
214 * @retval TSS2_RC_SUCCESS: if the function call was a success.
215 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
216 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
217 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
218 * operation already pending.
219 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
220 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
221 * internal operations or return parameters.
222 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
223 * complete. Call this function again later.
224 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
225 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
226 * the function.
227 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
228 * during authorization.
229 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
230 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
231 * is not set.
232 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
233 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
234 * was not successful.
235 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
236 */
237 TSS2_RC
Fapi_Delete_Finish(FAPI_CONTEXT * context)238 Fapi_Delete_Finish(
239 FAPI_CONTEXT *context)
240 {
241 LOG_TRACE("called for context:%p", context);
242
243 TSS2_RC r;
244 ESYS_TR authIndex;
245 ESYS_TR auth_session;
246 char *path;
247
248 /* Check for NULL parameters */
249 check_not_null(context);
250
251 /* Helpful alias pointers */
252 IFAPI_Entity_Delete * command = &(context->cmd.Entity_Delete);
253 IFAPI_OBJECT *object = &command->object;
254 IFAPI_OBJECT *authObject = &command->auth_object;
255
256 switch (context->state) {
257 statecase(context->state, ENTITY_DELETE_WAIT_FOR_SESSION);
258 /* If a TPM object (e.g. a persistent key) was referenced, then this
259 is the entry point. */
260 r = ifapi_get_sessions_finish(context, &context->profiles.default_profile,
261 context->profiles.default_profile.nameAlg);
262 return_try_again(r);
263 goto_if_error(r, "Create FAPI session.", error_cleanup);
264
265 fallthrough;
266
267 statecase(context->state, ENTITY_DELETE_GET_FILE);
268 /* If a non-TPM object (e.g. a policy) was referenced, then this is the
269 entry point. */
270 /* Use last path in the path list */
271 command->path_idx -= 1;
272 path = command->pathlist[command->path_idx];
273 LOG_TRACE("Delete object: %s %zu", path, command->path_idx);
274
275 if (ifapi_path_type_p(path, IFAPI_EXT_PATH)) {
276 /* External keyfile can be deleted directly without TPM operations. */
277 context->state = ENTITY_DELETE_FILE;
278 return TSS2_FAPI_RC_TRY_AGAIN;
279 }
280
281 if (ifapi_path_type_p(path, IFAPI_POLICY_PATH)) {
282 /* Policy file can be deleted directly without TPM operations. */
283 context->state = ENTITY_DELETE_POLICY;
284 return TSS2_FAPI_RC_TRY_AGAIN;
285 }
286
287 /* Load the object metadata from the keystore. */
288 r = ifapi_keystore_load_async(&context->keystore, &context->io, path);
289 return_if_error2(r, "Could not open: %s", path);
290
291 fallthrough;
292
293 statecase(context->state, ENTITY_DELETE_READ);
294 /* We only end up in this path, if the referenced object requires
295 TPM operations; e.g. persistent key or NV index. */
296 r = ifapi_keystore_load_finish(&context->keystore, &context->io, object);
297 return_try_again(r);
298 return_if_error_reset_state(r, "read_finish failed");
299
300 /* Initialize the ESYS object for the persistent key or NV Index. */
301 r = ifapi_initialize_object(context->esys, object);
302 goto_if_error_reset_state(r, "Initialize NV object", error_cleanup);
303
304 if (object->objectType == IFAPI_KEY_OBJ) {
305 /* If the object is a key, we jump over to ENTITY_DELETE_KEY. */
306 command->is_key = true;
307 context->state = ENTITY_DELETE_KEY;
308 return TSS2_FAPI_RC_TRY_AGAIN;
309
310 } else if (object->objectType == IFAPI_NV_OBJ) {
311 /* Prepare for the deletion of an NV index. */
312 command->is_key = false;
313
314 if (object->misc.nv.hierarchy == ESYS_TR_RH_OWNER) {
315 authIndex = ESYS_TR_RH_OWNER;
316 ifapi_init_hierarchy_object(authObject, authIndex);
317 } else {
318 *authObject = *object;
319 authIndex = object->handle;
320 }
321 command->auth_index = authIndex;
322 context->state = ENTITY_DELETE_AUTHORIZE_NV;
323 } else {
324 context->state = ENTITY_DELETE_FILE;
325 return TSS2_FAPI_RC_TRY_AGAIN;
326 }
327 fallthrough;
328
329 statecase(context->state, ENTITY_DELETE_AUTHORIZE_NV);
330 /* Authorize with the storage hierarhcy / "owner" to delete the NV index. */
331 r = ifapi_authorize_object(context, authObject, &auth_session);
332 return_try_again(r);
333 goto_if_error(r, "Authorize NV object.", error_cleanup);
334
335 /* Delete the NV index. */
336 r = Esys_NV_UndefineSpace_Async(context->esys,
337 command->auth_index,
338 object->handle,
339 auth_session,
340 ESYS_TR_NONE,
341 ESYS_TR_NONE);
342 goto_if_error_reset_state(r, " Fapi_NV_UndefineSpace_Async", error_cleanup);
343
344 context->state = ENTITY_DELETE_NULL_AUTH_SENT_FOR_NV;
345 return TSS2_FAPI_RC_TRY_AGAIN;
346
347 statecase(context->state, ENTITY_DELETE_KEY);
348 if (object->misc.key.persistent_handle) {
349 /* Delete the persistent handle from the TPM. */
350 r = Esys_EvictControl_Async(context->esys, ESYS_TR_RH_OWNER,
351 object->handle,
352 context->session1,
353 ESYS_TR_NONE, ESYS_TR_NONE,
354 object->misc.key.persistent_handle);
355 goto_if_error(r, "Evict Control", error_cleanup);
356 context->state = ENTITY_DELETE_NULL_AUTH_SENT_FOR_KEY;
357 } else {
358 context->state = ENTITY_DELETE_FILE;
359 return TSS2_FAPI_RC_TRY_AGAIN;
360 }
361 fallthrough;
362
363 statecase(context->state, ENTITY_DELETE_AUTH_SENT_FOR_KEY);
364 fallthrough;
365 statecase(context->state, ENTITY_DELETE_NULL_AUTH_SENT_FOR_KEY);
366 r = Esys_EvictControl_Finish(context->esys,
367 &command->new_object_handle);
368 return_try_again(r);
369 if ((r & ~TPM2_RC_N_MASK) == TPM2_RC_BAD_AUTH) {
370 /* If evict control failed, we know that an owner password was set
371 and we need to re-issue the command with a password being set. */
372 if (context->state == ENTITY_DELETE_NULL_AUTH_SENT_FOR_KEY) {
373 ifapi_init_hierarchy_object(authObject,
374 TPM2_RH_OWNER);
375 r = ifapi_set_auth(context, authObject,
376 "Owner Authorization");
377 goto_if_error_reset_state(r, "Set owner authorization", error_cleanup);
378
379 context->state = ENTITY_DELETE_AUTH_SENT_FOR_KEY;
380 return TSS2_FAPI_RC_TRY_AGAIN;
381 }
382 }
383 goto_if_error_reset_state(r, "FAPI Entity_Delete", error_cleanup);
384
385 context->state = ENTITY_DELETE_FILE;
386 return TSS2_FAPI_RC_TRY_AGAIN;
387 break;
388
389 statecase(context->state, ENTITY_DELETE_AUTH_SENT_FOR_NV);
390 fallthrough;
391 statecase(context->state, ENTITY_DELETE_NULL_AUTH_SENT_FOR_NV);
392 r = Esys_NV_UndefineSpace_Finish(context->esys);
393 return_try_again(r);
394
395 if ((r & ~TPM2_RC_N_MASK) == TPM2_RC_BAD_AUTH) {
396 /* If undefine space failed, we know that an owner password was set
397 and we need to re-issue the command with a password being set. */
398 if (context->state == ENTITY_DELETE_NULL_AUTH_SENT_FOR_NV) {
399 r = ifapi_set_auth(context, authObject, "Entity Delete object");
400 goto_if_error_reset_state(r, " Fapi_NV_UndefineSpace", error_cleanup);
401
402 r = Esys_NV_UndefineSpace_Async(context->esys,
403 command->auth_index,
404 object->handle,
405 context->session1,
406 context->session2,
407 ESYS_TR_NONE);
408 goto_if_error_reset_state(r, "FAPI Entity_Delete", error_cleanup);
409
410 context->state = ENTITY_DELETE_AUTH_SENT_FOR_NV;
411 return TSS2_FAPI_RC_TRY_AGAIN;
412 }
413 }
414 goto_if_error_reset_state(r, "FAPI NV_UndefineSpace", error_cleanup);
415
416 LOG_TRACE("NV Object undefined.");
417 context->state = ENTITY_DELETE_FILE;
418 return TSS2_FAPI_RC_TRY_AGAIN;
419 break;
420
421 statecase(context->state, ENTITY_DELETE_POLICY);
422 /* This is the simple case of deleting a policy from the keystore. */
423 path = command->pathlist[command->path_idx];
424 LOG_TRACE("Delete: %s", path);
425
426 r = ifapi_policy_delete(&context->pstore, path);
427 goto_if_error_reset_state(r, "Could not delete: %s", error_cleanup, path);
428
429 if (command->path_idx > 0)
430 context->state = ENTITY_DELETE_GET_FILE;
431 else
432 context->state = ENTITY_DELETE_REMOVE_DIRS;
433 return TSS2_FAPI_RC_TRY_AGAIN;
434
435 statecase(context->state, ENTITY_DELETE_FILE);
436 /* This is the simple case of deleting an external (pub)key from the keystore
437 or we enter here after the TPM operation for the persistent key or NV index
438 deletion have been performed. */
439 path = command->pathlist[command->path_idx];
440 LOG_TRACE("Delete: %s", path);
441 ifapi_cleanup_ifapi_object(object);
442 ifapi_cleanup_ifapi_object(authObject);
443
444 /* Delete all the object's data from the keystore. */
445 r = ifapi_keystore_delete(&context->keystore, path);
446 goto_if_error_reset_state(r, "Could not delete: %s", error_cleanup, path);
447
448 if (command->path_idx > 0) {
449 context->state = ENTITY_DELETE_GET_FILE;
450 return TSS2_FAPI_RC_TRY_AGAIN;
451 }
452
453 fallthrough;
454
455 statecase(context->state, ENTITY_DELETE_REMOVE_DIRS);
456 /* For some cases, we need to remove the directory that contained the
457 meta data as well. */
458 r = ifapi_keystore_remove_directories(&context->keystore, command->path);
459 goto_if_error(r, "Error while removing directories", error_cleanup);
460
461 context->state = _FAPI_STATE_INIT;
462
463 LOG_DEBUG("success");
464 r = TSS2_RC_SUCCESS;
465 break;
466
467 statecasedefault(context->state);
468 }
469
470 /* Reset the ESYS timeout to non-blocking, immediate response. */
471 if (context->esys) {
472 r = Esys_SetTimeout(context->esys, 0);
473 goto_if_error(r, "Set Timeout to non-blocking", error_cleanup);
474 }
475
476 /* Cleanup intermediate state stored in the context. */
477 SAFE_FREE(command->path);
478 ifapi_cleanup_ifapi_object(authObject);
479 ifapi_cleanup_ifapi_object(object);
480 for (size_t i = 0; i < command->numPaths; i++) {
481 SAFE_FREE(command->pathlist[i]);
482 }
483 SAFE_FREE(command->pathlist);
484 ifapi_session_clean(context);
485 ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
486 ifapi_cleanup_ifapi_object(context->loadKey.key_object);
487 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
488
489 LOG_TRACE("finished");
490 return r;
491
492 error_cleanup:
493 /* Cleanup any intermediate results and state stored in the context. */
494 Esys_SetTimeout(context->esys, 0);
495 ifapi_cleanup_ifapi_object(object);
496 SAFE_FREE(command->path);
497 for (size_t i = 0; i < command->numPaths; i++) {
498 SAFE_FREE(command->pathlist[i]);
499 }
500 SAFE_FREE(command->pathlist);
501 ifapi_session_clean(context);
502 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
503 return r;
504 }
505