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 <stdio.h>
12 #include <string.h>
13 #include <stdarg.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <ctype.h>
20 #include <dirent.h>
21 
22 #include "tss2_mu.h"
23 #include "fapi_util.h"
24 #include "fapi_crypto.h"
25 #include "ifapi_helpers.h"
26 #include "ifapi_json_serialize.h"
27 #include "ifapi_json_deserialize.h"
28 #include "tpm_json_deserialize.h"
29 #include "fapi_policy.h"
30 #include "ifapi_policyutil_execute.h"
31 #define LOGMODULE fapi
32 #include "util/log.h"
33 #include "util/aux_util.h"
34 
35 /** State machine for flushing objects.
36  *
37  * @param[in] context The FAPI_CONTEXT.
38  * @param[in] handle of the object to be flushed.
39  *
40  * @retval TSS2_RC_SUCCESS on success.
41  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
42  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
43  *         this function needs to be called again.
44  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
45  *         operation already pending.
46  */
47 TSS2_RC
ifapi_flush_object(FAPI_CONTEXT * context,ESYS_TR handle)48 ifapi_flush_object(FAPI_CONTEXT *context, ESYS_TR handle)
49 {
50     TSS2_RC r = TSS2_RC_SUCCESS;
51 
52     if (handle == ESYS_TR_NONE)
53         return r;
54 
55     switch (context->flush_object_state) {
56     statecase(context->flush_object_state, FLUSH_INIT);
57         r = Esys_FlushContext_Async(context->esys, handle);
58         return_if_error(r, "Flush Object");
59         fallthrough;
60 
61     statecase(context->flush_object_state, WAIT_FOR_FLUSH);
62         r = Esys_FlushContext_Finish(context->esys);
63         if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
64             return TSS2_FAPI_RC_TRY_AGAIN;
65 
66         return_if_error(r, "FlushContext");
67 
68         context->flush_object_state = FLUSH_INIT;
69         return TSS2_RC_SUCCESS;
70 
71     statecasedefault(context->flush_object_state);
72     }
73 }
74 
75 /** Preparation for getting a session handle.
76  *
77  * The corresponding async call be executed and a session secret for encryption
78  * TPM2B parameters will be created.
79  *
80  * @param[in] esys The ESYS_CONTEXT.
81  * @param[in] saltkey The key which will be used for the encryption of the session
82  *            secret.
83  * @param[in] profile The FAPI profile will be used to adjust the sessions symmetric
84  *            parameters.
85  * @param[in] hashAlg The hash algorithm used for the session.
86  *
87  * @retval TSS2_RC_SUCCESS on success.
88  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
89  */
90 TSS2_RC
ifapi_get_session_async(ESYS_CONTEXT * esys,ESYS_TR saltkey,const IFAPI_PROFILE * profile,TPMI_ALG_HASH hashAlg)91 ifapi_get_session_async(ESYS_CONTEXT *esys, ESYS_TR saltkey, const IFAPI_PROFILE *profile,
92                         TPMI_ALG_HASH hashAlg)
93 {
94     TSS2_RC r;
95 
96     r = Esys_StartAuthSession_Async(esys, saltkey,
97                                     ESYS_TR_NONE,
98                                     ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
99                                     NULL,
100                                     TPM2_SE_HMAC, &profile->session_symmetric,
101                                     hashAlg);
102     return_if_error(r, "Creating session.");
103 
104     return TSS2_RC_SUCCESS;
105 }
106 
107 /**  Call for getting a session handle and adjust session parameters.
108  *
109  * @param[in] esys The ESYS_CONTEXT.
110  * @param[out] session The session handle.
111  * @param[in] flags The flags to adjust the session attributes.
112  *
113  * @retval TSS2_RC_SUCCESS on success.
114  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
115  */
116 TSS2_RC
ifapi_get_session_finish(ESYS_CONTEXT * esys,ESYS_TR * session,TPMA_SESSION flags)117 ifapi_get_session_finish(ESYS_CONTEXT *esys, ESYS_TR *session,
118                          TPMA_SESSION flags)
119 {
120     TSS2_RC r;
121     TPMA_SESSION sessionAttributes = 0;
122 
123     /* Check whether authorization callback is defined */
124 
125     r = Esys_StartAuthSession_Finish(esys, session);
126     if (r != TSS2_RC_SUCCESS)
127         return r;
128 
129     sessionAttributes |= flags;
130     sessionAttributes |= TPMA_SESSION_CONTINUESESSION;
131 
132     r = Esys_TRSess_SetAttributes(esys, *session, sessionAttributes,
133                                   0xff);
134     return_if_error(r, "Set session attributes.");
135 
136     return TSS2_RC_SUCCESS;
137 }
138 
139 /** Get the digest size of the policy of a FAPI object.
140  *
141  * @param[in] object The object with the correspodning policy.
142  *
143  * @retval The size of policy digest.
144  * @retval 0 if The object does not have a policy.
145  */
146 static size_t
policy_digest_size(IFAPI_OBJECT * object)147 policy_digest_size(IFAPI_OBJECT *object)
148 {
149     switch (object->objectType) {
150     case IFAPI_KEY_OBJ:
151         return object->misc.key.public.publicArea.authPolicy.size;
152     case IFAPI_NV_OBJ:
153         return object->misc.nv.public.nvPublic.authPolicy.size;
154     case IFAPI_HIERARCHY_OBJ:
155         return object->misc.hierarchy.authPolicy.size;
156     default:
157         return 0;
158     }
159 }
160 
161 /** Add a object together with size as first element to a linked list.
162  *
163  * This function can e.g. used to add byte arrays together with their size
164  * to a linked list.
165  *
166  * @param[in] object The object to be added.
167  * @param[in] size The size of the object to be added.
168  * @param[in,out] object_list The linked list to be extended.
169  *
170  * @retval TSS2_RC_SUCCESS if the object was added.
171  * @retval TSS2_FAPI_RC_MEMORY If memory for the list extension cannot
172  *         be allocated.
173  */
174 static TSS2_RC
push_object_with_size_to_list(void * object,size_t size,NODE_OBJECT_T ** object_list)175 push_object_with_size_to_list(void *object, size_t size, NODE_OBJECT_T **object_list)
176 {
177     TSS2_RC r;
178     r = push_object_to_list(object, object_list);
179     return_if_error(r, "Push object with size.");
180 
181     (*object_list)->size = size;
182     return TSS2_RC_SUCCESS;
183 }
184 
185 /** Initialize and expand the linked list representing a FAPI key path.
186  *
187  * From a passed key path the explicit key path will be determined. The
188  * profile and the hierarchy will be added if necessary and the extension
189  * is possible.
190  *
191  * @param[in]  context_profile The profile used for extension of no profile is
192  *             part of the path.
193  * @param[in]  ipath The implicit pathname which has to be extended.
194  * @param[out] list_node1 The linked list for the passed key path without
195  *             extensions.
196  * @param[out] current_list_node The current node in the list list_node1,
197  *             which represent the tail not processed.
198  * @param[out] result The part of the new list which had been extended
199  *             without the tail not processed.
200  *
201  * @retval TSS2_RC_SUCCESS: If the initialization was successful.
202  * @retval TSS2_FAPI_RC_BAD_VALUE If an invalid path was passed.
203  * @retval TSS2_FAPI_RC_MEMORY: if not enough memory can be allocated.
204  */
205 static TSS2_RC
init_explicit_key_path(const char * context_profile,const char * ipath,NODE_STR_T ** list_node1,NODE_STR_T ** current_list_node,NODE_STR_T ** result)206 init_explicit_key_path(
207     const char *context_profile,
208     const char *ipath,
209     NODE_STR_T **list_node1,
210     NODE_STR_T **current_list_node,
211     NODE_STR_T **result)
212 {
213     *list_node1 = split_string(ipath, IFAPI_FILE_DELIM);
214     NODE_STR_T *list_node = *list_node1;
215     char const *profile;
216     char *hierarchy;
217     TSS2_RC r = TSS2_RC_SUCCESS;
218 
219     *result = NULL;
220     if (list_node == NULL) {
221         LOG_ERROR("Invalid path");
222         free_string_list(*list_node1);
223         return TSS2_FAPI_RC_BAD_VALUE;
224     }
225 
226     /* Processing of the profile. */
227     if (strncmp("P_", list_node->str, 2) == 0) {
228         profile = list_node->str;
229         list_node = list_node->next;
230     } else {
231         profile = context_profile;
232     }
233     *result = init_string_list(profile);
234     if (*result == NULL) {
235         free_string_list(*list_node1);
236         LOG_ERROR("Out of memory");
237         return TSS2_FAPI_RC_MEMORY;
238     }
239     if (list_node == NULL) {
240         /* extend default hierarchy. */
241         hierarchy = "HS";
242     } else {
243         if (strcmp(list_node->str, "HS") == 0 ||
244                 strcmp(list_node->str, "HE") == 0 ||
245                 strcmp(list_node->str, "HP") == 0 ||
246                 strcmp(list_node->str, "HN") == 0 ||
247                 strcmp(list_node->str, "HP") == 0) {
248             hierarchy = list_node->str;
249             list_node = list_node->next;
250         }
251         /* Extend hierarchy. */
252         else if (strcmp(list_node->str, "EK") == 0) {
253             hierarchy = "HE";
254         } else if (list_node->next != NULL &&
255                    (strcmp(list_node->str, "SRK") == 0 ||
256                     strcmp(list_node->str, "SDK") == 0 ||
257                     strcmp(list_node->str, "UNK") == 0 ||
258                     strcmp(list_node->str, "UDK") == 0)) {
259             hierarchy = "HS";
260         } else {
261             hierarchy = "HS";
262         }
263     }
264 
265     /* Extend the current result. */
266     if (!add_string_to_list(*result, hierarchy)) {
267         LOG_ERROR("Out of memory");
268         r = TSS2_FAPI_RC_MEMORY;
269         goto error;
270     }
271     if (list_node == NULL) {
272         goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Explicit path can't be determined.",
273                    error);
274     }
275     if (!add_string_to_list(*result, list_node->str)) {
276         LOG_ERROR("Out of memory");
277         r = TSS2_FAPI_RC_MEMORY;
278         goto error;
279     }
280     *current_list_node = list_node->next;
281     return TSS2_RC_SUCCESS;
282 
283 error:
284     free_string_list(*result);
285     *result = NULL;
286     free_string_list(*list_node1);
287     *list_node1 = NULL;
288     return r;
289 }
290 
291 /** Free first object of a linked list.
292  *
293  * Note: Referenced objects of the list have to be freed before.
294  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
295  */
296 static TSS2_RC
pop_object_from_list(FAPI_CONTEXT * context,NODE_OBJECT_T ** object_list)297 pop_object_from_list(FAPI_CONTEXT *context, NODE_OBJECT_T **object_list)
298 {
299     return_if_null(*object_list, "Pop from list.", TSS2_FAPI_RC_BAD_REFERENCE);
300 
301     NODE_OBJECT_T *head = *object_list;
302     NODE_OBJECT_T *next = head->next;
303     *object_list = next;
304     ifapi_free_object(context, (void *)&head->object);
305     free(head);
306     return TSS2_RC_SUCCESS;
307 }
308 
309 /** Set authorization value for a FAPI object.
310  *
311  * The callback which provides the auth value must be defined.
312  *
313  * @param[in,out] context The FAPI_CONTEXT.
314  * @param[in]     auth_object The auth value will be assigned to this object.
315  * @param[in]     description The description will be passed to the callback
316  *                which delivers the auth value.
317  *
318  * @retval TSS2_RC_SUCCESS on success.
319  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN If the callback for getting
320  *         the auth value is not defined.
321  */
322 TSS2_RC
ifapi_set_auth(FAPI_CONTEXT * context,IFAPI_OBJECT * auth_object,const char * description)323 ifapi_set_auth(
324     FAPI_CONTEXT *context,
325     IFAPI_OBJECT *auth_object,
326     const char *description)
327 {
328     TSS2_RC r;
329     char *auth = NULL;
330     TPM2B_AUTH authValue = {.size = 0,.buffer = {0} };
331     char *obj_description;
332 
333     obj_description = get_description(auth_object);
334 
335     if (obj_description)
336         description = obj_description;
337 
338     /* Check whether callback is defined. */
339     if (context->callbacks.auth) {
340         r = context->callbacks.auth(context, description, &auth,
341                                         context->callbacks.authData);
342         return_if_error(r, "policyAuthCallback");
343         if (auth != NULL) {
344             authValue.size = strlen(auth);
345             memcpy(&authValue.buffer[0], auth, authValue.size);
346         }
347         SAFE_FREE(auth);
348         /* Store auth value in the ESYS object. */
349         r = Esys_TR_SetAuth(context->esys, auth_object->handle, &authValue);
350         return_if_error(r, "Set auth value.");
351 
352         return TSS2_RC_SUCCESS;
353     }
354     SAFE_FREE(auth);
355     return TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN;
356 }
357 
358 /** Preparation for getting a free handle after a start handle number.
359  *
360  * @param[in] fctx The FAPI_CONTEXT.
361  * @param[in] handle The start value for handle search.
362  *
363  * @retval TSS2_RC_SUCCESS on success.
364  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
365  */
366 TSS2_RC
ifapi_get_free_handle_async(FAPI_CONTEXT * fctx,TPM2_HANDLE * handle)367 ifapi_get_free_handle_async(FAPI_CONTEXT *fctx, TPM2_HANDLE *handle)
368 {
369     TSS2_RC r = Esys_GetCapability_Async(fctx->esys,
370                                          ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
371                                          TPM2_CAP_HANDLES, *handle, 1);
372     return_if_error(r, "GetCapability");
373     return r;
374 }
375 
376 /** Execution of get capability until a free handle is found.
377  *
378  * The get capability method is called until a free handle is found
379  * or the max number of trials passe to the function is exeeded.
380  *
381  * @param[in] fctx The FAPI_CONTEXT.
382  * @param[out] handle The free handle.
383  * @param[in] max The maximal number of trials.
384  *
385  * @retval TSS2_RC_SUCCESS on success.
386  * @retval TSS2_FAPI_RC_NV_TOO_SMALL if too many NV handles are defined.
387  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
388  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
389  *         this function needs to be called again.
390  */
391 TSS2_RC
ifapi_get_free_handle_finish(FAPI_CONTEXT * fctx,TPM2_HANDLE * handle,TPM2_HANDLE max)392 ifapi_get_free_handle_finish(FAPI_CONTEXT *fctx, TPM2_HANDLE *handle,
393                              TPM2_HANDLE max)
394 {
395     TPMI_YES_NO moreData;
396     TPMS_CAPABILITY_DATA *capabilityData = NULL;
397     TSS2_RC r = Esys_GetCapability_Finish(fctx->esys,
398                                           &moreData, &capabilityData);
399 
400     if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
401         return TSS2_FAPI_RC_TRY_AGAIN;
402 
403     return_if_error(r, "GetCapability");
404 
405     if (capabilityData->data.handles.count == 0 ||
406             capabilityData->data.handles.handle[0] != *handle) {
407         SAFE_FREE(capabilityData);
408         return TSS2_RC_SUCCESS;
409     }
410     SAFE_FREE(capabilityData);
411     *handle += 1;
412     if (*handle > max) {
413         return_error(TSS2_FAPI_RC_NV_TOO_SMALL, "No NV index free.");
414     }
415 
416     r = ifapi_get_free_handle_async(fctx, handle);
417     return_if_error(r, "GetCapability");
418 
419     return TSS2_FAPI_RC_TRY_AGAIN;
420 }
421 
422 /** Create a linked list of directories in the key store.
423  *
424  * If the absolute path in key store is not defined the list will
425  * be extended if possible.
426  *
427  * @param[out] keystore The used keystore.
428  * @param[in] ipath The implicit pathname, which might be extended.
429  * @param[out] The linked list of directories in the explicit pathname.
430  *
431  * @retval TSS2_RC_SUCCESS If the keystore can be initialized.
432  * @retval TSS2_FAPI_RC_IO_ERROR If the user part of the keystore can't be
433  *         initialized.
434  * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated.
435  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
436  *         the function.
437  */
438 static TSS2_RC
get_explicit_key_path(IFAPI_KEYSTORE * keystore,const char * ipath,NODE_STR_T ** result)439 get_explicit_key_path(
440     IFAPI_KEYSTORE *keystore,
441     const char *ipath,
442     NODE_STR_T **result)
443 {
444     NODE_STR_T *list_node1 = NULL;
445     NODE_STR_T *list_node = NULL;
446 
447     /* Extend the first part of the list if necessary. */
448     TSS2_RC r = init_explicit_key_path(keystore->defaultprofile, ipath,
449                                        &list_node1, &list_node, result);
450     goto_if_error(r, "init_explicit_key_path", error);
451 
452     /* Extend the list with the tail of the initial unmodified list. */
453     while (list_node != NULL) {
454         if (!add_string_to_list(*result, list_node->str)) {
455             LOG_ERROR("Out of memory");
456             r = TSS2_FAPI_RC_MEMORY;
457             goto error;
458         }
459         list_node = list_node->next;
460     }
461     free_string_list(list_node1);
462     return TSS2_RC_SUCCESS;
463 
464 error:
465     if (*result)
466         free_string_list(*result);
467     if (list_node1)
468         free_string_list(list_node1);
469     return r;
470 }
471 
472 /** Prepare the creation of a primary key.
473  *
474  * Depending on the parameters the creation of an endorsement or storage root key
475  * will be prepared.
476  *
477  * @param[in] context The FAPI_CONTEXT.
478  * @param[in] ktype The type of key TSS2_EK or TSS2_SRK.
479  * @retval TSS2_RC_SUCCESS on success.
480  * @retval TSS2_FAPI_RC_BAD_VALUE if a wrong type was passed.
481  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
482  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
483  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
484  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
485  *         this function needs to be called again.
486  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
487  *         operation already pending.
488  * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the
489  *         object store.
490  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
491  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
492  *         during authorization.
493  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
494  */
495 TSS2_RC
ifapi_init_primary_async(FAPI_CONTEXT * context,TSS2_KEY_TYPE ktype)496 ifapi_init_primary_async(FAPI_CONTEXT *context, TSS2_KEY_TYPE ktype)
497 {
498     TSS2_RC r;
499     IFAPI_OBJECT *hierarchy;
500     hierarchy = &context->cmd.Provision.hierarchy;
501     TPMS_POLICY *policy;
502 
503     if (ktype == TSS2_EK) {
504         /* Values set according to EK credential profile. */
505         if (context->cmd.Provision.public_templ.public.publicArea.type == TPM2_ALG_RSA) {
506             context->cmd.Provision.public_templ.public.publicArea.unique.rsa.size = 256;
507         } else if (context->cmd.Provision.public_templ.public.publicArea.type == TPM2_ALG_ECC) {
508             context->cmd.Provision.public_templ.public.publicArea.unique.ecc.x.size = 32;
509             context->cmd.Provision.public_templ.public.publicArea.unique.ecc.y.size = 32;
510         }
511         ifapi_init_hierarchy_object(hierarchy, ESYS_TR_RH_ENDORSEMENT);
512         policy = context->profiles.default_profile.ek_policy;
513     } else if (ktype == TSS2_SRK) {
514         policy = context->profiles.default_profile.srk_policy;
515         ifapi_init_hierarchy_object(hierarchy, ESYS_TR_RH_OWNER);
516     } else {
517         return_error(TSS2_FAPI_RC_BAD_VALUE,
518                      "Invalid key type. Only EK or SRK allowed");
519     }
520 
521     if (policy) {
522         /* Duplicate policy to prevent profile policy from cleanup. */
523         policy = ifapi_copy_policy(policy);
524         return_if_null(policy, "Out of memory.", TSS2_FAPI_RC_MEMORY);
525 
526         r = ifapi_calculate_tree(context, NULL, /**< no path needed */
527                                  policy,
528                                  context->profiles.default_profile.nameAlg,
529                                  &context->cmd.Provision.digest_idx,
530                                  &context->cmd.Provision.hash_size);
531         if (r) {
532             LOG_ERROR("Policy calculation");
533             free(policy);
534             return r;
535         }
536 
537         context->cmd.Provision.public_templ.public.publicArea.authPolicy.size =
538             context->cmd.Provision.hash_size;
539         memcpy(&context->cmd.Provision.public_templ.public.publicArea.authPolicy.buffer[0],
540                &policy->policyDigests.digests[context->policy.digest_idx].digest,
541                context->cmd.Provision.hash_size);
542     }
543     context->createPrimary.pkey_object.policy = policy;
544 
545     memset(&context->cmd.Provision.inSensitive, 0, sizeof(TPM2B_SENSITIVE_CREATE));
546     memset(&context->cmd.Provision.outsideInfo, 0, sizeof(TPM2B_DATA));
547     memset(&context->cmd.Provision.creationPCR, 0, sizeof(TPML_PCR_SELECTION));
548 
549     r = Esys_CreatePrimary_Async(context->esys, hierarchy->handle,
550                                  ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
551                                  &context->cmd.Provision.inSensitive,
552                                  &context->cmd.Provision.public_templ.public,
553                                  &context->cmd.Provision.outsideInfo,
554                                  &context->cmd.Provision.creationPCR);
555     return r;
556 }
557 
558 /** Finalize the creation of a primary key.
559  *
560  * Depending on the parameters the creation of an endorsement key or a storage root key
561  * will be finalized. The created object with the all information needed by FAPI will
562  * be stored in the FAPI context.
563  *
564  * @param[in] context The FAPI_CONTEXT.
565  * @param[in] ktype The type of key TSS2_EK or TSS2_SRK.
566  *
567  * @retval TSS2_RC_SUCCESS on success.
568  * @retval TSS2_FAPI_RC_TRY_AGAIN if the execution cannot be completed.
569  * @retval TSS2_FAPI_RC_BAD_VALUE if a wrong type was passed.
570  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
571  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
572  *         is not set.
573  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
574  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
575  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
576  */
577 TSS2_RC
ifapi_init_primary_finish(FAPI_CONTEXT * context,TSS2_KEY_TYPE ktype)578 ifapi_init_primary_finish(FAPI_CONTEXT *context, TSS2_KEY_TYPE ktype)
579 {
580     TSS2_RC r;
581     ESYS_TR primaryHandle;
582     IFAPI_OBJECT *hierarchy;
583     TPM2B_PUBLIC *outPublic = NULL;
584     TPM2B_CREATION_DATA *creationData = NULL;
585     TPM2B_DIGEST *creationHash = NULL;
586     TPMT_TK_CREATION *creationTicket = NULL;
587     IFAPI_KEY *pkey = &context->createPrimary.pkey_object.misc.key;
588     NODE_STR_T *k_sub_path = NULL;
589 
590     hierarchy = &context->cmd.Provision.hierarchy;
591 
592     r = Esys_CreatePrimary_Finish(context->esys,
593                                   &primaryHandle, &outPublic, &creationData, &creationHash,
594                                   &creationTicket);
595     if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
596         return TSS2_FAPI_RC_TRY_AGAIN;
597 
598     /* Retry with authorization callback after trial with null auth */
599     if ((((r & ~TPM2_RC_N_MASK) == TPM2_RC_BAD_AUTH))
600             && (context->state == PROVISION_AUTH_EK_NO_AUTH_SENT ||
601                 context->state == PROVISION_AUTH_SRK_NO_AUTH_SENT)) {
602         r = ifapi_set_auth(context, hierarchy, "CreatePrimary");
603         goto_if_error_reset_state(r, "CreatePrimary", error_cleanup);
604 
605         r = Esys_CreatePrimary_Async(context->esys, hierarchy->handle,
606                                      ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
607                                      &context->cmd.Provision.inSensitive,
608                                      &context->cmd.Provision.public,
609                                      &context->cmd.Provision.outsideInfo,
610                                      &context->cmd.Provision.creationPCR);
611         goto_if_error_reset_state(r, "CreatePrimary", error_cleanup);
612 
613         if (ktype == TSS2_EK)
614             context->state = PROVISION_AUTH_EK_AUTH_SENT;
615         else
616             context->state = PROVISION_AUTH_SRK_AUTH_SENT;
617         return TSS2_FAPI_RC_TRY_AGAIN;
618 
619     } else {
620         goto_if_error_reset_state(r, "FAPI Provision", error_cleanup);
621     }
622     /* Set EK or SRK handle in context. */
623     if (ktype == TSS2_EK) {
624         context->ek_handle = primaryHandle;
625     } else if (ktype == TSS2_SRK) {
626         context->srk_handle = primaryHandle;
627     } else {
628         return_error(TSS2_FAPI_RC_BAD_VALUE,
629                      "Invalid key type. Only EK or SRK allowed");
630     }
631 
632     /* Prepare serialization of pkey to key store. */
633 
634     SAFE_FREE(pkey->serialization.buffer);
635     r = Esys_TR_Serialize(context->esys, primaryHandle, &pkey->serialization.buffer,
636                           &pkey->serialization.size);
637     goto_if_error(r, "Error serialize esys object", error_cleanup);
638 
639     r = ifapi_get_name(&outPublic->publicArea, &pkey->name);
640     goto_if_error(r, "Get primary name", error_cleanup);
641 
642     pkey->public = *outPublic;
643     pkey->policyInstance = NULL;
644     pkey->creationData = *creationData;
645     pkey->creationTicket = *creationTicket;
646     pkey->description = NULL;
647     pkey->certificate = NULL;
648 
649     /* Cleanup unused information */
650     SAFE_FREE(outPublic);
651     SAFE_FREE(creationData);
652     SAFE_FREE(creationHash);
653     SAFE_FREE(creationTicket);
654 
655     if (pkey->public.publicArea.type == TPM2_ALG_RSA)
656         pkey->signing_scheme = context->profiles.default_profile.rsa_signing_scheme;
657     else
658         pkey->signing_scheme = context->profiles.default_profile.ecc_signing_scheme;
659     context->createPrimary.pkey_object.handle = primaryHandle;
660     SAFE_FREE(pkey->serialization.buffer);
661     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
662     return TSS2_RC_SUCCESS;
663 
664 error_cleanup:
665     free_string_list(k_sub_path);
666     SAFE_FREE(pkey->serialization.buffer);
667     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
668     return r;
669 }
670 
671 /** Prepare the loading of a primary key from key store.
672  *
673  * The asynchronous loading or the key from keystore will be prepared and
674  * the path will be stored in the FAPI context.
675  *
676  * @param[in] context The FAPI_CONTEXT.
677  * @param[in] path The FAPI path of the primary key.
678  *
679  * @retval TSS2_RC_SUCCESS on success.
680  * @retval TSS2_FAPI_RC_BAD_VALUE if a wrong type was passed.
681  * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error was encountered.
682  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if the file does not exist.
683  * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated for path names.
684  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
685  */
686 TSS2_RC
ifapi_load_primary_async(FAPI_CONTEXT * context,char * path)687 ifapi_load_primary_async(FAPI_CONTEXT *context, char *path)
688 {
689 
690     TSS2_RC r;
691 
692     memset(&context->createPrimary.pkey_object, 0, sizeof(IFAPI_OBJECT));
693     context->createPrimary.path = path;
694     r = ifapi_keystore_load_async(&context->keystore, &context->io, path);
695     return_if_error2(r, "Could not open: %s", path);
696     context->primary_state = PRIMARY_READ_KEY;
697     return TSS2_RC_SUCCESS;
698 
699 }
700 
701 /** State machine to finalize the loading of a primary key from key store.
702  *
703  * The asynchronous loading or the key from keystore will be finalized.
704  * Afterwards the hierarchy object, which will be used for authorization will
705  * be loaded and the ESAPI functions for primary generation will be called
706  * if the primary is not persistent.
707  *
708  * @param[in] context The FAPI_CONTEXT.
709  * @param[out] handle The object handle of the primary key.
710  *
711  * @retval TSS2_RC_SUCCESS on success.
712  * @retval TSS2_FAPI_RC_BAD_VALUE if a wrong type was passed.
713  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if the hierarchy file does not exist.
714  * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error was encountered.
715  * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated for path names.
716  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
717  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
718  *         this function needs to be called again.
719  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
720  *         operation already pending.
721  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
722  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
723  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
724  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
725  *         is not set.
726  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
727  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
728  *         was not successful.
729  */
730 TSS2_RC
ifapi_load_primary_finish(FAPI_CONTEXT * context,ESYS_TR * handle)731 ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle)
732 {
733     TSS2_RC r;
734     IFAPI_OBJECT *hierarchy = &context->createPrimary.hierarchy;
735 
736     TPM2B_PUBLIC *outPublic = NULL;
737     TPM2B_CREATION_DATA *creationData = NULL;
738     TPM2B_DIGEST *creationHash = NULL;
739     TPMT_TK_CREATION *creationTicket = NULL;
740     IFAPI_OBJECT *pkey_object = &context->createPrimary.pkey_object;
741     IFAPI_KEY *pkey = &context->createPrimary.pkey_object.misc.key;
742     ESYS_TR auth_session;
743 
744     LOG_TRACE("call");
745 
746     switch (context->primary_state) {
747     statecase(context->primary_state, PRIMARY_READ_KEY);
748         /* Read the primary key from keystore. */
749         r = ifapi_keystore_load_finish(&context->keystore, &context->io,
750                                        pkey_object);
751         return_try_again(r);
752         return_if_error(r, "read_finish failed");
753 
754         r = ifapi_initialize_object(context->esys, pkey_object);
755         goto_if_error_reset_state(r, "Initialize key object", error_cleanup);
756 
757         /* Check whether a persistent key was loaded.
758            In this case the handle has already been set. */
759         if (pkey_object->handle != ESYS_TR_NONE) {
760             if (pkey->creationTicket.hierarchy == TPM2_RH_EK) {
761                 context->ek_persistent = true;
762             } else {
763                 context->srk_persistent = true;
764             }
765             /* Persistent handle will be used. */
766             *handle = pkey_object->handle;
767             break;
768         } else {
769             if (pkey->creationTicket.hierarchy == TPM2_RH_EK) {
770                 context->ek_persistent = false;
771             } else {
772                 context->srk_persistent = false;
773             }
774         }
775         fallthrough;
776 
777     statecase(context->primary_state, PRIMARY_READ_HIERARCHY);
778         /* The hierarchy object ussed for auth_session will be loaded from key store. */
779         if (pkey->creationTicket.hierarchy == TPM2_RH_EK) {
780             r = ifapi_keystore_load_async(&context->keystore, &context->io, "/HE");
781             return_if_error2(r, "Could not open hierarchy /HE");
782         } else {
783             r = ifapi_keystore_load_async(&context->keystore, &context->io, "/HS");
784             return_if_error2(r, "Could not open hierarchy /HS");
785         }
786         fallthrough;
787 
788     statecase(context->primary_state, PRIMARY_READ_HIERARCHY_FINISH);
789         r = ifapi_keystore_load_finish(&context->keystore, &context->io, hierarchy);
790         return_try_again(r);
791         return_if_error(r, "read_finish failed");
792 
793         r = ifapi_initialize_object(context->esys, hierarchy);
794         goto_if_error_reset_state(r, "Initialize hierarchy object", error_cleanup);
795 
796         if (pkey->creationTicket.hierarchy == TPM2_RH_EK) {
797             hierarchy->handle = ESYS_TR_RH_ENDORSEMENT;
798         } else {
799             hierarchy->handle = ESYS_TR_RH_OWNER;
800         }
801         fallthrough;
802 
803     statecase(context->primary_state, PRIMARY_AUTHORIZE_HIERARCHY);
804         /* The asynchronous authorization of the hierarchy needed for primary. */
805         r = ifapi_authorize_object(context, hierarchy, &auth_session);
806         FAPI_SYNC(r, "Authorize hierarchy.", error_cleanup);
807 
808         memset(&context->createPrimary.inSensitive, 0, sizeof(TPM2B_SENSITIVE_CREATE));
809         memset(&context->createPrimary.outsideInfo, 0, sizeof(TPM2B_DATA));
810         memset(&context->createPrimary.creationPCR, 0, sizeof(TPML_PCR_SELECTION));
811 
812         /* Prepare primary creation. */
813         r = Esys_CreatePrimary_Async(context->esys, hierarchy->handle,
814                                      auth_session, ESYS_TR_NONE, ESYS_TR_NONE,
815                                      &context->createPrimary.inSensitive,
816                                      &pkey->public,
817                                      &context->createPrimary.outsideInfo,
818                                      &context->createPrimary.creationPCR);
819         return_if_error(r, "CreatePrimary");
820         fallthrough;
821 
822     statecase(context->primary_state, PRIMARY_HAUTH_SENT);
823         if (context->createPrimary.handle) {
824             *handle = context->createPrimary.handle;
825             context->primary_state = PRIMARY_CREATED;
826             return TSS2_FAPI_RC_TRY_AGAIN;
827         } else {
828             r = Esys_CreatePrimary_Finish(context->esys,
829                                           &pkey_object->handle, &outPublic,
830                                           &creationData, &creationHash,
831                                           &creationTicket);
832             return_try_again(r);
833             goto_if_error_reset_state(r, "FAPI regenerate primary", error_cleanup);
834         }
835         *handle = pkey_object->handle;
836         context->primary_state = PRIMARY_INIT;
837         break;
838 
839     statecasedefault(context->primary_state);
840     }
841     SAFE_FREE(outPublic);
842     SAFE_FREE(creationData);
843     SAFE_FREE(creationHash);
844     SAFE_FREE(creationTicket);
845     ifapi_cleanup_ifapi_object(&context->createPrimary.hierarchy);
846     return TSS2_RC_SUCCESS;
847 
848 error_cleanup:
849     SAFE_FREE(outPublic);
850     SAFE_FREE(creationData);
851     SAFE_FREE(creationHash);
852     SAFE_FREE(creationTicket);
853     ifapi_cleanup_ifapi_object(&context->createPrimary.hierarchy);
854     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
855     return r;
856 }
857 
858 /** Prepare session for FAPI command execution.
859  *
860  * It will be checked whether the context of FAPI and ESAPI is initialized
861  * and whether no other FAPI command session is running.
862  * Also some handle variables in the context are initialized.
863  *
864  * @param[in] context The FAPI_CONTEXT.
865  *
866  * @retval TSS2_RC_SUCCESS on success.
867  * @retval TSS2_FAPI_RC_BAD_REFERENCE if the context is not initialized.
868  * @retval TSS2_FAPI_RC_BAD_SEQUENCE If a FAPI command session is active.
869  * @retval TSS2_FAPI_RC_NO_TPM if the ESAPI context is not initialized.
870  */
871 TSS2_RC
ifapi_session_init(FAPI_CONTEXT * context)872 ifapi_session_init(FAPI_CONTEXT *context)
873 {
874     LOG_TRACE("call");
875     return_if_null(context, "No context", TSS2_FAPI_RC_BAD_REFERENCE);
876 
877     return_if_null(context->esys, "No context", TSS2_FAPI_RC_NO_TPM);
878 
879     if (context->state != _FAPI_STATE_INIT) {
880         return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State");
881     }
882 
883     context->session1 = ESYS_TR_NONE;
884     context->session2 = ESYS_TR_NONE;
885     context->policy.session = ESYS_TR_NONE;
886     context->srk_handle = ESYS_TR_NONE;
887     return TSS2_RC_SUCCESS;
888 }
889 
890 /** Prepare session for FAPI command execution without TPM.
891  *
892  * It will be checked whether the context of FAPI is initialized
893  * and whether no other FAPI command session is running.
894  * Also some handle variables in the context are initialized.
895  *
896  * @param[in] context The FAPI_CONTEXT.
897  *
898  * @retval TSS2_RC_SUCCESS on success.
899  * @retval TSS2_FAPI_RC_BAD_REFERENCE if the context is not initialized.
900  * @retval TSS2_FAPI_RC_BAD_SEQUENCE If a FAPI command session is active.
901  */
902 TSS2_RC
ifapi_non_tpm_mode_init(FAPI_CONTEXT * context)903 ifapi_non_tpm_mode_init(FAPI_CONTEXT *context)
904 {
905     LOG_TRACE("call");
906     return_if_null(context, "No context", TSS2_FAPI_RC_BAD_REFERENCE);
907 
908     if (context->state != _FAPI_STATE_INIT) {
909         return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State");
910     }
911 
912     context->session1 = ESYS_TR_NONE;
913     context->session2 = ESYS_TR_NONE;
914     context->policy.session = ESYS_TR_NONE;
915     context->srk_handle = ESYS_TR_NONE;
916     return TSS2_RC_SUCCESS;
917 }
918 
919 /** Cleanup FAPI sessions in error cases.
920  *
921  * The uses sessions and the SRK (if not persistent) will be flushed
922  * non asynchronous in error cases.
923  *
924  * @param[in,out] context The FAPI_CONTEXT.
925  */
926 void
ifapi_session_clean(FAPI_CONTEXT * context)927 ifapi_session_clean(FAPI_CONTEXT *context)
928 {
929     if (context->session1 != ESYS_TR_NONE) {
930         if (Esys_FlushContext(context->esys, context->session1) != TSS2_RC_SUCCESS) {
931             LOG_ERROR("Cleanup session failed.");
932         }
933         context->session1 = ESYS_TR_NONE;
934     }
935     if (context->session2 != ESYS_TR_NONE) {
936         if (Esys_FlushContext(context->esys, context->session2) != TSS2_RC_SUCCESS) {
937             LOG_ERROR("Cleanup session failed.");
938             context->session2 = ESYS_TR_NONE;
939         }
940     }
941     if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) {
942         if (Esys_FlushContext(context->esys, context->srk_handle) != TSS2_RC_SUCCESS) {
943             LOG_ERROR("Cleanup Policy Session  failed.");
944         }
945         context->srk_handle = ESYS_TR_NONE;
946     }
947     context->srk_persistent = false;
948 }
949 
950 /** State machine for asynchronous cleanup of a FAPI session.
951  *
952  * Used sessions and the SRK will be flushed.
953  *
954  * @param[in] context The FAPI_CONTEXT storing the used handles.
955  *
956  * @retval TSS2_RC_SUCCESS on success.
957  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
958  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
959  *         this function needs to be called again.
960  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
961  *         operation already pending.
962  */
963 TSS2_RC
ifapi_cleanup_session(FAPI_CONTEXT * context)964 ifapi_cleanup_session(FAPI_CONTEXT *context)
965 {
966     TSS2_RC r;
967 
968     switch (context->cleanup_state) {
969         statecase(context->cleanup_state, CLEANUP_INIT);
970             if (context->session1 != ESYS_TR_NONE) {
971                 r = Esys_FlushContext_Async(context->esys, context->session1);
972                 try_again_or_error(r, "Flush session.");
973             }
974             fallthrough;
975 
976         statecase(context->cleanup_state, CLEANUP_SESSION1);
977             if (context->session1 != ESYS_TR_NONE) {
978                 r = Esys_FlushContext_Finish(context->esys);
979                 try_again_or_error(r, "Flush session.");
980             }
981             context->session1 = ESYS_TR_NONE;
982 
983             if (context->session2 != ESYS_TR_NONE) {
984                 r = Esys_FlushContext_Async(context->esys, context->session2);
985                 try_again_or_error(r, "Flush session.");
986             }
987             fallthrough;
988 
989         statecase(context->cleanup_state, CLEANUP_SESSION2);
990             if (context->session2 != ESYS_TR_NONE) {
991                 r = Esys_FlushContext_Finish(context->esys);
992                 try_again_or_error(r, "Flush session.");
993             }
994             context->session2 = ESYS_TR_NONE;
995 
996             if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) {
997                 r = Esys_FlushContext_Async(context->esys, context->srk_handle);
998                 try_again_or_error(r, "Flush SRK.");
999             }
1000             fallthrough;
1001 
1002         statecase(context->cleanup_state, CLEANUP_SRK);
1003             if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) {
1004                 r = Esys_FlushContext_Finish(context->esys);
1005                 try_again_or_error(r, "Flush SRK.");
1006 
1007                 context->srk_handle = ESYS_TR_NONE;
1008                 context->srk_persistent = false;
1009             }
1010             context->cleanup_state = CLEANUP_INIT;
1011             return TSS2_RC_SUCCESS;
1012 
1013         statecasedefault(context->state);
1014     }
1015 }
1016 
1017 /** Cleanup primary keys in error cases (non asynchronous).
1018  *
1019  * @param[in] context The FAPI_CONTEXT storing the used handles.
1020  *
1021  * @retval TSS2_RC_SUCCESS on success.
1022  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
1023  */
1024 void
ifapi_primary_clean(FAPI_CONTEXT * context)1025 ifapi_primary_clean(FAPI_CONTEXT *context)
1026 {
1027     if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) {
1028         if (Esys_FlushContext(context->esys, context->srk_handle) != TSS2_RC_SUCCESS) {
1029             LOG_ERROR("Cleanup session failed.");
1030         }
1031         context->srk_handle = ESYS_TR_NONE;
1032     }
1033     if (!context->ek_persistent && context->ek_handle != ESYS_TR_NONE) {
1034         if (Esys_FlushContext(context->esys, context->ek_handle) != TSS2_RC_SUCCESS) {
1035             LOG_ERROR("Cleanup EK failed.");
1036         }
1037         context->ek_handle = ESYS_TR_NONE;
1038     }
1039     context->srk_persistent = false;
1040 }
1041 
1042 /** Prepare the session creation of a FAPI command.
1043  *
1044  * The initial state of the state machine for session creation will be determined.
1045  * Depending of the session_flags creation of a primary for the encryption of
1046  * the session secret can be adjusted.
1047  * The session passed session attributes will be used for the ESAPI command
1048  * Esys_TRSess_SetAttributes.
1049  *
1050  * @param[in] context The FAPI_CONTEXT storing the used handles.
1051  * @param[in] session_flags The flags to adjust used session and encryption
1052  *            key. With IFAPI_SESSION1 and IFAPI_SESSION2 the session creation
1053  *            for sesion1 and session2 can be activated, IFAPI_SESSION_GENEK
1054  *            triggers the creation of the primary for session secret encryption.
1055  * @param[in] attribute_flags1 The attributes used for session1.
1056  * @param[in] attribute_flags2 The attributes used for session2.
1057  *
1058  * @retval TSS2_RC_SUCCESS on success.
1059  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if the hierarchy file or the primary key file
1060  *         does not exist.
1061  * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated for path names.
1062  *         of the primary.
1063  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
1064  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
1065  *         the function.
1066  * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the
1067  *         object store.
1068  */
1069 TSS2_RC
ifapi_get_sessions_async(FAPI_CONTEXT * context,IFAPI_SESSION_TYPE session_flags,TPMA_SESSION attribute_flags1,TPMA_SESSION attribute_flags2)1070 ifapi_get_sessions_async(FAPI_CONTEXT *context,
1071                          IFAPI_SESSION_TYPE session_flags,
1072                          TPMA_SESSION attribute_flags1,
1073                          TPMA_SESSION attribute_flags2)
1074 {
1075     TSS2_RC r;
1076 
1077     LOG_TRACE("call");
1078     context->session_flags = session_flags;
1079     context->session1_attribute_flags = attribute_flags1;
1080     context->session2_attribute_flags = attribute_flags2;
1081     char *file = NULL;
1082 
1083     if (!(session_flags & IFAPI_SESSION_GENEK)) {
1084         context->srk_handle = ESYS_TR_NONE;
1085         context->session_state = SESSION_CREATE_SESSION;
1086         return TSS2_RC_SUCCESS;
1087     }
1088 
1089     context->primary_state = PRIMARY_INIT;
1090     r = ifapi_asprintf(&file, "%s/%s", context->config.profile_name,
1091                        IFAPI_SRK_KEY_PATH);
1092     goto_if_error(r, "Error ifapi_asprintf", error_cleanup);
1093 
1094     r = ifapi_load_primary_async(context, file);
1095     return_if_error_reset_state(r, "Load EK");
1096     free(file);
1097 
1098     context->session_state = SESSION_WAIT_FOR_PRIMARY;
1099     return TSS2_RC_SUCCESS;
1100 
1101 error_cleanup:
1102     SAFE_FREE(file);
1103     return r;
1104 }
1105 
1106 /** State machine for the session creation of a FAPI command.
1107  *
1108  * The sessions needed for a FAPI command will be created. If needed also the
1109  * primary key for session encryption will be created.
1110  *
1111  * @param[in] context The FAPI_CONTEXT storing the used handles.
1112  * @param[in] profile The FAPI profile will be used to adjust session parameters.
1113  * @param[in] hash_alg The hash algorithm used for the session.
1114  *
1115  * @retval TSS2_RC_SUCCESS on success.
1116  * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error was encountered.
1117  * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated for path names.
1118  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
1119  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
1120  *         this function needs to be called again.
1121  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
1122  *         operation already pending.
1123  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
1124  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
1125  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
1126  *         the function.
1127  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
1128  *         during authorization.
1129  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
1130  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
1131  *         is not set.
1132  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
1133  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
1134  *         was not successful.
1135  */
1136 TSS2_RC
ifapi_get_sessions_finish(FAPI_CONTEXT * context,const IFAPI_PROFILE * profile,TPMI_ALG_HASH hash_alg)1137 ifapi_get_sessions_finish(
1138     FAPI_CONTEXT *context,
1139     const IFAPI_PROFILE *profile,
1140     TPMI_ALG_HASH hash_alg)
1141 {
1142     TSS2_RC r;
1143 
1144     switch (context->session_state) {
1145     statecase(context->session_state, SESSION_WAIT_FOR_PRIMARY);
1146         LOG_TRACE("**STATE** SESSION_WAIT_FOR_PRIMARY");
1147         r = ifapi_load_primary_finish(context, &context->srk_handle);
1148         return_try_again(r);
1149         return_if_error(r, "Load primary.");
1150         fallthrough;
1151 
1152     statecase(context->session_state, SESSION_CREATE_SESSION);
1153         LOG_TRACE("**STATE** SESSION_CREATE_SESSION");
1154         if (!(context->session_flags & IFAPI_SESSION1)) {
1155             LOG_TRACE("finished");
1156             return TSS2_RC_SUCCESS;
1157         }
1158 
1159         /* Initializing the first session for the caller */
1160 
1161         r = ifapi_get_session_async(context->esys, context->srk_handle, profile,
1162                                     hash_alg);
1163         return_if_error_reset_state(r, "Create FAPI session async");
1164         fallthrough;
1165 
1166     statecase(context->session_state, SESSION_WAIT_FOR_SESSION1);
1167         LOG_TRACE("**STATE** SESSION_WAIT_FOR_SESSION1");
1168         r = ifapi_get_session_finish(context->esys, &context->session1,
1169                                      context->session1_attribute_flags);
1170         return_try_again(r);
1171         return_if_error_reset_state(r, "Create FAPI session finish");
1172 
1173         if (!(context->session_flags & IFAPI_SESSION2)) {
1174             LOG_TRACE("finished");
1175             return TSS2_RC_SUCCESS;
1176         }
1177 
1178         /* Initializing the second session for the caller */
1179 
1180         r = ifapi_get_session_async(context->esys, context->srk_handle, profile,
1181                                     profile->nameAlg);
1182         return_if_error_reset_state(r, "Create FAPI session async");
1183         fallthrough;
1184 
1185     statecase(context->session_state, SESSION_WAIT_FOR_SESSION2);
1186         LOG_TRACE("**STATE** SESSION_WAIT_FOR_SESSION2");
1187         r = ifapi_get_session_finish(context->esys, &context->session2,
1188                                      context->session2_attribute_flags);
1189         return_try_again(r);
1190 
1191         return_if_error_reset_state(r, "Create FAPI session finish");
1192         break;
1193 
1194     statecasedefault(context->session_state);
1195     }
1196 
1197     return TSS2_RC_SUCCESS;
1198 }
1199 
1200 /** Merge profile already stored in FAPI context into a NV object template.
1201  *
1202  * The defaults for NV creation which are stored in the FAPI default profile
1203  * will be merged in the passed templates default values.
1204  *
1205  * @param[in] context The FAPI_CONTEXT with the default profile.
1206  * @param[in] template The template with the default values for the NV object.
1207  *
1208  * @retval TSS2_RC_SUCCESS on success.
1209  */
1210 TSS2_RC
ifapi_merge_profile_into_nv_template(FAPI_CONTEXT * context,IFAPI_NV_TEMPLATE * template)1211 ifapi_merge_profile_into_nv_template(
1212     FAPI_CONTEXT *context,
1213     IFAPI_NV_TEMPLATE *template)
1214 {
1215     const TPMA_NV extend_mask = TPM2_NT_EXTEND << TPMA_NV_TPM2_NT_SHIFT;
1216     const TPMA_NV counter_mask = TPM2_NT_COUNTER << TPMA_NV_TPM2_NT_SHIFT;
1217     const TPMA_NV bitfield_mask = TPM2_NT_BITS << TPMA_NV_TPM2_NT_SHIFT;
1218     const IFAPI_PROFILE *profile = &context->profiles.default_profile;
1219     size_t hash_size;
1220 
1221     template->public.nameAlg = profile->nameAlg;
1222     if ((template->public.attributes & extend_mask) == extend_mask) {
1223         /* The size of the NV ram to be extended must be read from the
1224            profile */
1225         hash_size = ifapi_hash_get_digest_size(profile->nameAlg);
1226         template->public.dataSize = hash_size;
1227     } else if ((template->public.attributes & counter_mask) == counter_mask ||
1228                (template->public.attributes & bitfield_mask) == bitfield_mask) {
1229         /* For bit fields and counters only size 8 is possible */
1230         template->public.dataSize = 8;
1231     } else {
1232         /* For normal NV ram the passed size will be used. */
1233         template->public.dataSize = context->nv_cmd.numBytes;
1234     }
1235 
1236     return TSS2_RC_SUCCESS;
1237 }
1238 
1239 /** Merge profile already stored in FAPI context into a key template.
1240  *
1241  * The defaults for key creation which are stored in the FAPI default profile
1242  * will be merged in the passed templates default values.
1243  *
1244  * @param[in] profile The profile which will be used to adjust the template.
1245  * @param[in] template The template with the default values for the key object.
1246  *
1247  * @retval TSS2_RC_SUCCESS on success.
1248  */
1249 TSS2_RC
ifapi_merge_profile_into_template(const IFAPI_PROFILE * profile,IFAPI_KEY_TEMPLATE * template)1250 ifapi_merge_profile_into_template(
1251     const IFAPI_PROFILE *profile,
1252     IFAPI_KEY_TEMPLATE *template)
1253 {
1254     /* Merge profile parameters */
1255     template->public.publicArea.type = profile->type;
1256     template->public.publicArea.nameAlg = profile->nameAlg;
1257     if (profile->type == TPM2_ALG_RSA) {
1258         template->public.publicArea.parameters.rsaDetail.keyBits = profile->keyBits;
1259         template->public.publicArea.parameters.rsaDetail.exponent = profile->exponent;
1260     } else if (profile->type == TPM2_ALG_ECC) {
1261         template->public.publicArea.parameters.eccDetail.curveID = profile->curveID;
1262         template->public.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG_NULL;
1263     }
1264 
1265     /* Set remaining parameters depending on key type */
1266     if (template->public.publicArea.objectAttributes & TPMA_OBJECT_RESTRICTED) {
1267         if (template->public.publicArea.objectAttributes & TPMA_OBJECT_DECRYPT) {
1268             template->public.publicArea.parameters.asymDetail.symmetric =
1269             profile->sym_parameters;
1270         } else {
1271             template->public.publicArea.parameters.asymDetail.symmetric.algorithm =
1272             TPM2_ALG_NULL;
1273         }
1274         if (profile->type == TPM2_ALG_RSA) {
1275             if (template->public.publicArea.objectAttributes & TPMA_OBJECT_SIGN_ENCRYPT) {
1276                 template->public.publicArea.parameters.rsaDetail.scheme.scheme =
1277                 profile->rsa_signing_scheme.scheme;
1278                 memcpy(&template->public.publicArea.parameters.rsaDetail.scheme.details,
1279                        &profile->rsa_signing_scheme.details, sizeof(TPMU_ASYM_SCHEME));
1280             } else {
1281                 template->public.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG_NULL;
1282             }
1283         } else if (profile->type == TPM2_ALG_ECC) {
1284             if (template->public.publicArea.objectAttributes & TPMA_OBJECT_SIGN_ENCRYPT) {
1285                 template->public.publicArea.parameters.eccDetail.scheme.scheme =
1286                 profile->ecc_signing_scheme.scheme;
1287                 memcpy(&template->public.publicArea.parameters.eccDetail.scheme.details,
1288                        &profile->ecc_signing_scheme.details, sizeof(TPMU_ASYM_SCHEME));
1289             } else {
1290                 template->public.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG_NULL;
1291             }
1292         } else {
1293             template->public.publicArea.parameters.asymDetail.scheme.scheme = TPM2_ALG_NULL;
1294         }
1295     } else {
1296         /* Non restricted key */
1297         template->public.publicArea.parameters.asymDetail.symmetric.algorithm =
1298         TPM2_ALG_NULL;
1299         template->public.publicArea.parameters.asymDetail.scheme.scheme = TPM2_ALG_NULL;
1300     }
1301     return TSS2_RC_SUCCESS;
1302 }
1303 
1304 /** Convert absolute path to FAPI path which can be used as parameter for FAPI commands.
1305  *
1306  * Function converts the absolute path to a FAPI path.
1307  *
1308  * @param[in] keystore The used keystore.
1309  * @param[out] path FAPI key path.
1310  */
1311 static void
full_path_to_fapi_path(IFAPI_KEYSTORE * keystore,char * path)1312 full_path_to_fapi_path(IFAPI_KEYSTORE *keystore, char *path)
1313 {
1314     unsigned int start_pos, end_pos, i;
1315     const unsigned int path_length = strlen(path);
1316     size_t keystore_length = strlen(keystore->userdir);
1317     char fapi_path_delim;
1318 
1319     start_pos = 0;
1320 
1321     /* Check key store part of the path */
1322     if (strncmp(&path[0], keystore->userdir, keystore_length) == 0) {
1323         start_pos = strlen(keystore->userdir);
1324     } else {
1325         keystore_length = strlen(keystore->systemdir);
1326         if (strncmp(&path[0], keystore->systemdir, keystore_length) == 0)
1327             start_pos = strlen(keystore->systemdir);
1328     }
1329     if (!start_pos)
1330         return;
1331 
1332     /* Shift FAPI path to the beginning. */
1333     end_pos = path_length - start_pos;
1334     memmove(&path[0], &path[start_pos], end_pos);
1335     size_t ip = 0;
1336     size_t lp = strlen(path);
1337 
1338     /* Special handling for // */
1339     while (ip < lp) {
1340         if (strncmp(&path[ip], "//", 2) == 0) {
1341             memmove(&path[ip], &path[ip + 1], lp - ip);
1342             lp -= 1;
1343         } else {
1344             ip += 1;
1345         }
1346     }
1347 
1348     /* Special handling for policy path were the name of the object file
1349        is part of the path. */
1350     if (ifapi_path_type_p(path, IFAPI_POLICY_PATH))
1351         fapi_path_delim = '.';
1352     else
1353         fapi_path_delim = IFAPI_FILE_DELIM_CHAR;
1354 
1355     for (i = end_pos - 1; i > 0; i--) {
1356         if (path[i] == fapi_path_delim) {
1357             path[i] = '\0';
1358             break;
1359         }
1360     }
1361 }
1362 
1363 /** Asynchronous preparation for loading a key and parent keys.
1364  *
1365  * The key loading is prepared. The pathname will be extended if possible and
1366  * a linked list with the directories will be created.
1367  *
1368  * @param[in,out] context The FAPI_CONTEXT.
1369  * @param[in]     keyPath the key path without the parent directories
1370  *                of the key store. (e.g. HE/EK, HS/SRK/mykey)
1371  *
1372  * @retval TSS2_RC_SUCCESS If the preparation is successful.
1373  * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated for path names.
1374  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
1375  *         the function.
1376  */
1377 TSS2_RC
ifapi_load_keys_async(FAPI_CONTEXT * context,char const * keyPath)1378 ifapi_load_keys_async(FAPI_CONTEXT *context, char const *keyPath)
1379 {
1380     TSS2_RC r;
1381     NODE_STR_T *path_list;
1382     size_t path_length;
1383     char *fapi_key_path = NULL;
1384 
1385     LOG_TRACE("Load key: %s", keyPath);
1386     fapi_key_path = strdup(keyPath);
1387     check_oom(fapi_key_path);
1388     full_path_to_fapi_path(&context->keystore, fapi_key_path);
1389     r = get_explicit_key_path(&context->keystore, fapi_key_path, &path_list);
1390     SAFE_FREE(fapi_key_path);
1391     return_if_error(r, "Compute explicit path.");
1392 
1393     context->loadKey.path_list = path_list;
1394     path_length = ifapi_path_length(path_list);
1395     r = ifapi_load_key_async(context, path_length);
1396     return_if_error(r, "Load key async.");
1397 
1398     return TSS2_RC_SUCCESS;
1399 }
1400 
1401 /** Asynchronous finish function for loading a key.
1402   *
1403  * @param[in,out] context The FAPI_CONTEXT.
1404  * @param[in]     flush_parent If false the parent of the key to be loaded
1405  *                will not be flushed.
1406  * @param[out]    handle The ESYS handle of the key.
1407  * @param[out]    key_object The object which will be used for the
1408  *                authorization of the loaded key.
1409  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
1410  *         this function needs to be called again.
1411  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
1412  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
1413  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
1414  *         the function.
1415  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
1416  *         operation already pending.
1417  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
1418  *         during authorization.
1419  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
1420  * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the
1421  *         object store.
1422  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
1423  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
1424  *         is not set.
1425  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
1426  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
1427  *         was not successful.
1428  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
1429  */
1430 TSS2_RC
ifapi_load_keys_finish(FAPI_CONTEXT * context,bool flush_parent,ESYS_TR * handle,IFAPI_OBJECT ** key_object)1431 ifapi_load_keys_finish(
1432     FAPI_CONTEXT *context,
1433     bool flush_parent,
1434     ESYS_TR *handle,
1435     IFAPI_OBJECT **key_object)
1436 {
1437     TSS2_RC r;
1438 
1439     r = ifapi_load_key_finish(context, flush_parent);
1440     if (r == TSS2_FAPI_RC_TRY_AGAIN)
1441         return r;
1442 
1443     return_if_error(r, "Load keys");
1444 
1445     *handle = context->loadKey.auth_object.handle;
1446     /* The current authorization object is the last key loaded and
1447        will be used. */
1448     *key_object = &context->loadKey.auth_object;
1449     free_string_list(context->loadKey.path_list);
1450     return TSS2_RC_SUCCESS;
1451 }
1452 
1453 /** Initialize state machine for loading a key.
1454  *
1455  * @param[in,out] context for storing all state information.
1456  * @param[in] position the position of the key in path list stored in
1457  *            context->loadKey.path_list.
1458  *
1459  * @retval TSS2_RC_SUCCESS on success.
1460  * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated for path names.
1461  */
1462 TSS2_RC
ifapi_load_key_async(FAPI_CONTEXT * context,size_t position)1463 ifapi_load_key_async(FAPI_CONTEXT *context, size_t position)
1464 {
1465     context->loadKey.state = LOAD_KEY_GET_PATH;
1466     context->loadKey.position = position;
1467     context->loadKey.key_list = NULL;
1468     context->loadKey.parent_handle = ESYS_TR_NONE;
1469     // context->loadKey.auth_object = NULL;
1470 
1471     return TSS2_RC_SUCCESS;
1472 }
1473 
1474 /** State machine for loading a key.
1475  *
1476  * A stack with all sup keys will be created and decremented during
1477  * the loading auf all keys.
1478  * The object of the loaded key will be stored in:
1479  * context->loadKey.auth_object
1480  *
1481  * @param[in,out] context for storing all state information.
1482  * @param[in]     flush_parent If flush_parent is false parent is
1483                   only flushed if a new parent is available.
1484  *
1485  * @retval TSS2_RC_SUCCESS If the loading of the key was successful.
1486  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
1487  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
1488  * @retval TSS2_FAPI_RC_GENERAL_FAILURE If an internal error occurs, which is
1489  *         not covered by other return codes.
1490  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
1491  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the policy
1492  *         store.
1493  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND If an object needed for loading or
1494  *         authentication was not found.
1495  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
1496  *         not successful.
1497  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for loading
1498  *         fails.
1499  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a needed authorization callback
1500  *         is not defined.
1501  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
1502  *         this function needs to be called again.
1503  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
1504  *         operation already pending.
1505  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
1506  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
1507  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
1508  */
1509 TSS2_RC
ifapi_load_key_finish(FAPI_CONTEXT * context,bool flush_parent)1510 ifapi_load_key_finish(FAPI_CONTEXT *context, bool flush_parent)
1511 {
1512     TSS2_RC r;
1513     NODE_STR_T *path_list = context->loadKey.path_list;
1514     size_t *position = &context->loadKey.position;
1515     IFAPI_OBJECT *key_object = NULL;
1516     IFAPI_KEY *key = NULL;
1517     ESYS_TR auth_session;
1518 
1519     switch (context->loadKey.state) {
1520     statecase(context->loadKey.state, LOAD_KEY_GET_PATH);
1521         context->loadKey.key_path = NULL;
1522         /* Compute path name of key to be loaded. */
1523         r = ifapi_path_string_n(&context->loadKey.key_path, NULL, path_list, NULL,
1524                                 *position);
1525         return_if_error(r, "Compute key path.");
1526 
1527         context->loadKey.key_object = ifapi_allocate_object(context);
1528         goto_if_null2(context->loadKey.key_object, "Allocating key", r,
1529                       TSS2_FAPI_RC_MEMORY, error_cleanup);
1530 
1531         goto_if_null2(context->loadKey.key_path, "Invalid path", r,
1532                       TSS2_FAPI_RC_GENERAL_FAILURE,
1533                       error_cleanup); /**< to avoid scan-build errors. */
1534 
1535         /* Prepare key loading. */
1536         r = ifapi_keystore_load_async(&context->keystore, &context->io,
1537                                       context->loadKey.key_path);
1538         return_if_error2(r, "Could not open: %s", context->loadKey.key_path);
1539         fallthrough;
1540 
1541     statecase(context->loadKey.state, LOAD_KEY_READ_KEY);
1542         goto_if_null2(context->loadKey.key_path, "Invalid path", r,
1543                       TSS2_FAPI_RC_GENERAL_FAILURE,
1544                       error_cleanup); /**< to avoid scan-build errors. */
1545 
1546         key = &context->loadKey.key_object->misc.key;
1547 
1548         r = ifapi_keystore_load_finish(&context->keystore, &context->io,
1549                                        context->loadKey.key_object);
1550         if (r != TSS2_RC_SUCCESS) {
1551             ifapi_cleanup_ifapi_object(context->loadKey.key_object);
1552         }
1553         return_try_again(r);
1554         return_if_error(r, "read_finish failed");
1555 
1556         if (context->loadKey.key_object->objectType != IFAPI_KEY_OBJ)
1557             goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "%s is no key", error_cleanup,
1558                        context->loadKey.key_path);
1559 
1560         r = ifapi_initialize_object(context->esys, context->loadKey.key_object);
1561         goto_if_error_reset_state(r, "Initialize key object", error_cleanup);
1562 
1563         SAFE_FREE(context->loadKey.key_path);
1564         context->loadKey.handle = context->loadKey.key_object->handle;
1565         if (context->loadKey.handle != ESYS_TR_NONE) {
1566             /* Persistent key could be desearialized keys can be loaded */
1567             r = ifapi_copy_ifapi_key_object(&context->loadKey.auth_object,
1568                 context->loadKey.key_object);
1569             goto_if_error(r, "Could not copy key object", error_cleanup);
1570             ifapi_cleanup_ifapi_object(context->loadKey.key_object);            context->loadKey.state = LOAD_KEY_LOAD_KEY;
1571 
1572             return TSS2_FAPI_RC_TRY_AGAIN;
1573         }
1574 
1575         if (key->private.size == 0) {
1576             /* Create a deep copy of the primary key */
1577             ifapi_cleanup_ifapi_key(key);
1578             r = ifapi_copy_ifapi_key(key, &context->createPrimary.pkey_object.misc.key);
1579             goto_if_error(r, "Could not copy primary key", error_cleanup);
1580             context->primary_state = PRIMARY_READ_HIERARCHY;
1581             context->loadKey.state = LOAD_KEY_WAIT_FOR_PRIMARY;
1582             return TSS2_FAPI_RC_TRY_AGAIN;
1583         }
1584         IFAPI_OBJECT * copyToPush = malloc(sizeof(IFAPI_OBJECT));
1585         goto_if_null(copyToPush, "Out of memory", TSS2_FAPI_RC_MEMORY, error_cleanup);
1586         r = ifapi_copy_ifapi_key_object(copyToPush, context->loadKey.key_object);
1587         if (r) {
1588             free(copyToPush);
1589             LOG_ERROR("Could not create a copy to push");
1590             goto error_cleanup;
1591         }
1592         /* Add object to the list of keys to be loaded. */
1593         r = push_object_to_list(copyToPush, &context->loadKey.key_list);
1594         if (r) {
1595             free(copyToPush);
1596             LOG_ERROR("Out of memory");
1597             goto error_cleanup;
1598         }
1599 
1600         ifapi_cleanup_ifapi_object(context->loadKey.key_object);
1601 
1602         *position -= 1;
1603         context->loadKey.state = LOAD_KEY_GET_PATH;
1604         return TSS2_FAPI_RC_TRY_AGAIN;
1605 
1606     statecase(context->loadKey.state, LOAD_KEY_LOAD_KEY);
1607         if (!(context->loadKey.key_list)) {
1608             LOG_TRACE("All keys loaded.");
1609             return TSS2_RC_SUCCESS;
1610         }
1611 
1612         /* if flush_parent is false parent is only flushed if a new parent
1613            is available */
1614         if (!flush_parent && context->loadKey.parent_handle != ESYS_TR_NONE) {
1615             r = Esys_FlushContext(context->esys, context->loadKey.parent_handle);
1616             goto_if_error_reset_state(r, "Flush object", error_cleanup);
1617         }
1618         fallthrough;
1619 
1620     statecase(context->loadKey.state, LOAD_KEY_AUTHORIZE);
1621         key_object = context->loadKey.key_list->object;
1622         key = &key_object->misc.key;
1623         r = ifapi_authorize_object(context, &context->loadKey.auth_object, &auth_session);
1624         FAPI_SYNC(r, "Authorize key.", error_cleanup);
1625 
1626         /* Store parent handle in context for usage in ChangeAuth if not persistent */
1627         context->loadKey.parent_handle = context->loadKey.handle;
1628         if (context->loadKey.auth_object.misc.key.persistent_handle)
1629             context->loadKey.parent_handle_persistent = true;
1630         else
1631             context->loadKey.parent_handle_persistent = false;
1632 
1633         TPM2B_PRIVATE private;
1634 
1635         private.size = key->private.size;
1636         memcpy(&private.buffer[0], key->private.buffer, key->private.size);
1637 
1638         r = Esys_Load_Async(context->esys, context->loadKey.handle,
1639                             auth_session,
1640                             ESYS_TR_NONE, ESYS_TR_NONE,
1641                             &private, &key->public);
1642         goto_if_error(r, "Load async", error_cleanup);
1643         fallthrough;
1644 
1645     statecase(context->loadKey.state, LOAD_KEY_AUTH);
1646         r = Esys_Load_Finish(context->esys, &context->loadKey.handle);
1647         return_try_again(r);
1648         goto_if_error_reset_state(r, "Load", error_cleanup);
1649 
1650         /* The current parent is flushed if not prohibited by flush parent */
1651         if (flush_parent && context->loadKey.auth_object.objectType == IFAPI_KEY_OBJ &&
1652             ! context->loadKey.auth_object.misc.key.persistent_handle) {
1653             r = Esys_FlushContext(context->esys, context->loadKey.auth_object.handle);
1654             goto_if_error_reset_state(r, "Flush object", error_cleanup);
1655 
1656         }
1657         LOG_TRACE("New key used as auth object.");
1658         ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
1659         r = ifapi_copy_ifapi_key_object(&context->loadKey.auth_object,
1660                 context->loadKey.key_list->object);
1661         goto_if_error(r, "Could not copy loaded key", error_cleanup);
1662         context->loadKey.auth_object.handle = context->loadKey.handle;
1663         IFAPI_OBJECT *top_obj = context->loadKey.key_list->object;
1664         ifapi_cleanup_ifapi_object(top_obj);
1665         SAFE_FREE(context->loadKey.key_list->object);
1666         r = pop_object_from_list(context, &context->loadKey.key_list);
1667         goto_if_error_reset_state(r, "Pop key failed.", error_cleanup);
1668 
1669         if (context->loadKey.key_list) {
1670             /* Object can be cleaned if it's not the last */
1671             ifapi_free_object(context, &top_obj);
1672         }
1673 
1674         context->loadKey.state = LOAD_KEY_LOAD_KEY;
1675         return TSS2_FAPI_RC_TRY_AGAIN;
1676 
1677     statecase(context->loadKey.state, LOAD_KEY_WAIT_FOR_PRIMARY);
1678         r = ifapi_load_primary_finish(context, &context->loadKey.handle);
1679         return_try_again(r);
1680         goto_if_error(r, "CreatePrimary", error_cleanup);
1681 
1682         /* Save the primary object for authorization */
1683         r = ifapi_copy_ifapi_key_object(&context->loadKey.auth_object,
1684                 &context->createPrimary.pkey_object);
1685         goto_if_error(r, "Could not copy primary key", error_cleanup);
1686 
1687         if (context->loadKey.key_list) {
1688             context->loadKey.state = LOAD_KEY_LOAD_KEY;
1689             return TSS2_FAPI_RC_TRY_AGAIN;
1690         } else {
1691             LOG_TRACE("success");
1692             ifapi_cleanup_ifapi_object(context->loadKey.key_object);
1693             ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
1694             return TSS2_RC_SUCCESS;
1695         }
1696         break;
1697 
1698     statecasedefault(context->loadKey.state);
1699     }
1700 
1701 error_cleanup:
1702     ifapi_free_object_list(context->loadKey.key_list);
1703     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
1704     SAFE_FREE(context->loadKey.key_path);
1705     return r;
1706 }
1707 
1708 /** Get the name alg corresponding to a FAPI object.
1709  *
1710  * @param[in] context The context with the default profile.
1711  * @param[in] object The object to be checked.
1712  * @retval TPMI_ALG_HASH The hash algorithm.
1713  * @retval 0 If no name alg can be assigned to the object.
1714  */
1715 static size_t
get_name_alg(FAPI_CONTEXT * context,IFAPI_OBJECT * object)1716 get_name_alg(FAPI_CONTEXT *context, IFAPI_OBJECT *object)
1717 {
1718     switch (object->objectType) {
1719     case IFAPI_KEY_OBJ:
1720         return object->misc.key.public.publicArea.nameAlg;
1721     case IFAPI_NV_OBJ:
1722         return object->misc.nv.public.nvPublic.nameAlg;
1723     case IFAPI_HIERARCHY_OBJ:
1724         return context->profiles.default_profile.nameAlg;
1725     default:
1726         return 0;
1727     }
1728 }
1729 
1730 /** Check whether policy session has to be flushed.
1731  *
1732  * Policy sessions with cleared continue session flag are not flushed in error
1733  * cases. Therefore the return code will be checked and if a policy session was
1734  * used the session will be flushed if the command was not executed successfully.
1735  *
1736  * @param[in,out] context for storing all state information.
1737  * @param[in] session the session to be checked whether flush is needed.
1738  * @param[in] r The return code of the command using the session.
1739  */
1740 void
ifapi_flush_policy_session(FAPI_CONTEXT * context,ESYS_TR session,TSS2_RC r)1741 ifapi_flush_policy_session(FAPI_CONTEXT *context, ESYS_TR session, TSS2_RC r)
1742 {
1743     if (session != context->session1) {
1744         /* A policy session was used instead auf the default session. */
1745         if (r != TSS2_RC_SUCCESS) {
1746             Esys_FlushContext(context->esys, session);
1747         }
1748     }
1749 }
1750 
1751 /** State machine to authorize a key, a NV object of a hierarchy.
1752  *
1753  * @param[in,out] context for storing all state information.
1754  * @param[in] object The FAPI object.
1755  * @param[out] session The session which can be used for object authorization.
1756  *
1757  * @retval TSS2_RC_SUCCESS If the authorization is successful
1758  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
1759  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
1760  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the policy
1761  *         store.
1762  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND If a policy for a certain path was not found.
1763  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
1764  *         not successful.
1765  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for the policy
1766  *         execution fails.
1767  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a needed authorization callback
1768            is not defined.
1769  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
1770  *         this function needs to be called again.
1771  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
1772  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
1773  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
1774  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
1775  */
1776 TSS2_RC
ifapi_authorize_object(FAPI_CONTEXT * context,IFAPI_OBJECT * object,ESYS_TR * session)1777 ifapi_authorize_object(FAPI_CONTEXT *context, IFAPI_OBJECT *object, ESYS_TR *session)
1778 {
1779     TSS2_RC r;
1780     TPMI_YES_NO auth_required;
1781 
1782     LOG_DEBUG("Authorize object: %x", object->handle);
1783     switch (object->authorization_state) {
1784         statecase(object->authorization_state, AUTH_INIT)
1785             LOG_TRACE("**STATE** AUTH_INIT");
1786 
1787             if (!policy_digest_size(object)) {
1788                 /* No policy used authorization callbacks have to be called if necessary. */
1789                 if (object_with_auth(object)) {
1790                     r = ifapi_set_auth(context, object, "Authorize object");
1791                     return_if_error(r, "Set auth value");
1792                 }
1793                 /* No policy session needed current fapi session can be used */
1794                 if (context->session1 && context->session1 != ESYS_TR_NONE)
1795                     *session = context->session1;
1796                 else
1797                     /* Use password session if session1 had not been created */
1798                     *session = ESYS_TR_PASSWORD;
1799                 break;
1800             }
1801             r = ifapi_policyutil_execute_prepare(context, get_name_alg(context, object)
1802                                                  ,object->policy);
1803             return_if_error(r, "Prepare policy execution.");
1804 
1805             /* Next state will switch from prev context to next context. */
1806             context->policy.util_current_policy = context->policy.util_current_policy->prev;
1807             object->authorization_state = AUTH_EXEC_POLICY;
1808             fallthrough;
1809 
1810         statecase(object->authorization_state, AUTH_EXEC_POLICY)
1811             *session = ESYS_TR_NONE;
1812             r = ifapi_policyutil_execute(context, session);
1813             if (r == TSS2_FAPI_RC_TRY_AGAIN)
1814                 return r;
1815 
1816             return_if_error(r, "Execute policy.");
1817 
1818             r = Esys_TRSess_GetAuthRequired(context->esys, *session,
1819                                             &auth_required);
1820             return_if_error(r, "GetAuthRequired");
1821 
1822             /* Check whether PolicyCommand requiring authorization was executed */
1823             if (auth_required == TPM2_YES) {
1824                 r = ifapi_set_auth(context, object, "Authorize object");
1825                 goto_if_error(r, "Set auth value", error);
1826             }
1827             /* Clear continue session flag, so policy session will be flushed after authorization */
1828             r = Esys_TRSess_SetAttributes(context->esys, *session, 0, TPMA_SESSION_CONTINUESESSION);
1829             goto_if_error(r, "Esys_TRSess_SetAttributes", error);
1830             break;
1831 
1832         general_failure(object->authorization_state)
1833     }
1834 
1835     object->authorization_state = AUTH_INIT;
1836     return TSS2_RC_SUCCESS;
1837 
1838 error:
1839     /* No policy call was executed session can be flushed */
1840     Esys_FlushContext(context->esys, *session);
1841     return r;
1842 }
1843 
1844 /** State machine to write data to the NV ram of the TPM.
1845  *
1846  * The NV object will be read from object store and the data will be
1847  * written by one, or more than one if necessary, ESAPI calls to the NV ram of
1848  * the TPM.
1849  * The sub context nv_cmd will be prepared:
1850  * - data The buffer for the data which has to be written
1851  * - offset The current offset for writing
1852  * - numBytes The number of bytes which have to be written.
1853  *
1854  * @param[in,out] context for storing all state information.
1855  * @param[in] nvPath The fapi path of the NV object.
1856  * @param[in] param_offset The offset in the NV memory (will be stored in context).
1857  * @param[in] data The pointer to the data to be written.
1858  * @param[in] size The number of bytes to be written.
1859  *
1860  * @retval TSS2_RC_SUCCESS If data can be written.
1861  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
1862  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
1863  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
1864  * @retval TSS2_FAPI_RC_GENERAL_FAILURE If an internal error occurs, which is
1865  +         not covered by other return codes.
1866  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the object
1867  *         store.
1868  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND The nv object or an object needed for
1869  *         authentication was not found.
1870  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
1871  *          not successful.
1872  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for the
1873  *         command execution fails.
1874  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a needed authorization callback
1875  *         is not defined.
1876  * @retval TSS2_FAPI_RC_BAD_PATH if the used path in inappropriate-
1877  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
1878  *         this function needs to be called again.
1879  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
1880  *         operation already pending.
1881  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
1882  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
1883  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
1884  */
1885 TSS2_RC
ifapi_nv_write(FAPI_CONTEXT * context,char * nvPath,size_t param_offset,uint8_t const * data,size_t size)1886 ifapi_nv_write(
1887     FAPI_CONTEXT *context,
1888     char         *nvPath,
1889     size_t         param_offset,
1890     uint8_t const *data,
1891     size_t         size)
1892 {
1893     TSS2_RC r = TSS2_RC_SUCCESS;
1894     ESYS_TR auth_index;
1895     ESYS_TR nv_index = context->nv_cmd.esys_handle;
1896     IFAPI_OBJECT *object = &context->nv_cmd.nv_object;
1897     IFAPI_OBJECT *auth_object = &context->nv_cmd.auth_object;
1898     TPM2B_MAX_NV_BUFFER *aux_data = (TPM2B_MAX_NV_BUFFER *)&context->aux_data;
1899     char *nv_file_name = NULL;
1900     ESYS_TR auth_session;
1901 
1902     switch (context->nv_cmd.nv_write_state) {
1903     statecase(context->nv_cmd.nv_write_state, NV2_WRITE_INIT);
1904         memset(&context->nv_cmd.nv_object, 0, sizeof(IFAPI_OBJECT));
1905         context->nv_cmd.nvPath = nvPath;
1906         context->nv_cmd.offset = param_offset;
1907         context->nv_cmd.numBytes = size;
1908         context->nv_cmd.data = data;
1909         if (context->nv_cmd.numBytes > context->nv_buffer_max)
1910             aux_data->size = context->nv_buffer_max;
1911         else
1912             aux_data->size = context->nv_cmd.numBytes;
1913         context->nv_cmd.data_idx = 0;
1914 
1915         /* Use calloc to ensure zero padding for write buffer. */
1916         context->nv_cmd.write_data = calloc(size, 1);
1917         goto_if_null2(context->nv_cmd.write_data, "Out of memory.", r,
1918                       TSS2_FAPI_RC_MEMORY,
1919                       error_cleanup);
1920         memcpy(context->nv_cmd.write_data, data, size);
1921         memcpy(&aux_data->buffer[0], &context->nv_cmd.data[0], aux_data->size);
1922 
1923         /* Prepare reading of the key from keystore. */
1924         r = ifapi_keystore_load_async(&context->keystore, &context->io,
1925                                       context->nv_cmd.nvPath);
1926         return_if_error2(r, "Could not open: %s", context->nv_cmd.nvPath);
1927         fallthrough;
1928 
1929     statecase(context->nv_cmd.nv_write_state, NV2_WRITE_READ);
1930         r = ifapi_keystore_load_finish(&context->keystore, &context->io, object);
1931         return_try_again(r);
1932         return_if_error(r, "read_finish failed");
1933 
1934         if (object->objectType != IFAPI_NV_OBJ)
1935             goto_error(r, TSS2_FAPI_RC_BAD_PATH, "%s is no NV object.", error_cleanup,
1936                        context->nv_cmd.nvPath);
1937 
1938         r = ifapi_initialize_object(context->esys, object);
1939         goto_if_error_reset_state(r, "Initialize NV object", error_cleanup);
1940 
1941         /* Store object info in context */
1942         nv_index = context->nv_cmd.nv_object.handle;
1943         context->nv_cmd.esys_handle = nv_index;
1944         context->nv_cmd.nv_obj = object->misc.nv;
1945 
1946         /* Determine the object which will be uses for authorization. */
1947         if (object->misc.nv.public.nvPublic.attributes & TPMA_NV_PPWRITE) {
1948             ifapi_init_hierarchy_object(auth_object, ESYS_TR_RH_PLATFORM);
1949             auth_index = ESYS_TR_RH_PLATFORM;
1950         } else {
1951             if (object->misc.nv.public.nvPublic.attributes & TPMA_NV_OWNERWRITE) {
1952                 ifapi_init_hierarchy_object(auth_object, ESYS_TR_RH_OWNER);
1953                 auth_index = ESYS_TR_RH_OWNER;
1954             } else {
1955                 auth_index = nv_index;
1956             }
1957             *auth_object = *object;
1958         }
1959         context->nv_cmd.auth_index = auth_index;
1960 
1961         /* Get A session for authorizing the NV write operation. */
1962         r = ifapi_get_sessions_async(context, IFAPI_SESSION_GENEK | IFAPI_SESSION1,
1963                                          TPMA_SESSION_DECRYPT, 0);
1964         goto_if_error(r, "Create sessions", error_cleanup);
1965 
1966         fallthrough;
1967 
1968     statecase(context->nv_cmd.nv_write_state, NV2_WRITE_WAIT_FOR_SESSSION);
1969         r = ifapi_get_sessions_finish(context, &context->profiles.default_profile,
1970                                       object->misc.nv.public.nvPublic.nameAlg);
1971         return_try_again(r);
1972         goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
1973 
1974         fallthrough;
1975 
1976     statecase(context->nv_cmd.nv_write_state, NV2_WRITE_AUTHORIZE);
1977         r = ifapi_authorize_object(context, auth_object, &auth_session);
1978         FAPI_SYNC(r, "Authorize NV object.", error_cleanup);
1979 
1980         /* Prepare the writing to NV ram. */
1981         r = Esys_NV_Write_Async(context->esys,
1982                                 context->nv_cmd.auth_index,
1983                                 nv_index,
1984                                 auth_session,
1985                                 context->session2,
1986                                 ESYS_TR_NONE,
1987                                 aux_data,
1988                                 context->nv_cmd.data_idx);
1989         goto_if_error_reset_state(r, " Fapi_NvWrite_Async", error_cleanup);
1990 
1991         if (!(object->misc.nv.public.nvPublic.attributes & TPMA_NV_NO_DA))
1992             context->nv_cmd.nv_write_state = NV2_WRITE_AUTH_SENT;
1993         else
1994             context->nv_cmd.nv_write_state = NV2_WRITE_NULL_AUTH_SENT;
1995 
1996         context->nv_cmd.bytesRequested = aux_data->size;
1997 
1998         fallthrough;
1999 
2000     case NV2_WRITE_AUTH_SENT:
2001     case NV2_WRITE_NULL_AUTH_SENT:
2002         r = Esys_NV_Write_Finish(context->esys);
2003         return_try_again(r);
2004 
2005         if ((r & ~TPM2_RC_N_MASK) == TPM2_RC_BAD_AUTH) {
2006             if (context->nv_cmd.nv_write_state == NV2_WRITE_NULL_AUTH_SENT) {
2007                 IFAPI_OBJECT *auth_object = &context->nv_cmd.auth_object;
2008                 r = ifapi_set_auth(context, auth_object, "NV Write");
2009                 goto_if_error_reset_state(r, " Fapi_NvWrite_Finish", error_cleanup);
2010 
2011                 /* Prepare the writing to NV ram. */
2012                 r = Esys_NV_Write_Async(context->esys,
2013                                         context->nv_cmd.auth_index,
2014                                         nv_index,
2015                                         (!context->policy.session
2016                                          || context->policy.session == ESYS_TR_NONE) ? context->session1 :
2017                                         context->policy.session,
2018                                         context->session2,
2019                                         ESYS_TR_NONE,
2020                                         aux_data,
2021                                         context->nv_cmd.data_idx);
2022                 goto_if_error_reset_state(r, "FAPI NV_Write_Async", error_cleanup);
2023 
2024                 context->nv_cmd.nv_write_state = NV2_WRITE_AUTH_SENT;
2025                 return TSS2_FAPI_RC_TRY_AGAIN;
2026             }
2027         }
2028         goto_if_error_reset_state(r, "FAPI NV_Write_Finish", error_cleanup);
2029 
2030         context->nv_cmd.numBytes -= context->nv_cmd.bytesRequested;
2031 
2032         if (context->nv_cmd.numBytes > 0) {
2033             /* Increment data idx with number of transmitted bytes. */
2034             context->nv_cmd.data_idx += aux_data->size;
2035             if (context->nv_cmd.numBytes > context->nv_buffer_max)
2036                 aux_data->size = context->nv_buffer_max;
2037             else
2038                 aux_data->size = context->nv_cmd.numBytes;
2039             memcpy(&aux_data->buffer[0],
2040                    &context->nv_cmd.write_data[context->nv_cmd.data_idx],
2041                    aux_data->size);
2042 
2043             statecase(context->nv_cmd.nv_write_state, NV2_WRITE_AUTHORIZE2);
2044                 r = ifapi_authorize_object(context, auth_object, &auth_session);
2045                 FAPI_SYNC(r, "Authorize NV object.", error_cleanup);
2046 
2047             /* Prepare the writing to NV ram */
2048             r = Esys_NV_Write_Async(context->esys,
2049                                     context->nv_cmd.auth_index,
2050                                     nv_index,
2051                                     auth_session,
2052                                     context->session2,
2053                                     ESYS_TR_NONE,
2054                                     aux_data,
2055                                     context->nv_cmd.data_idx);
2056             goto_if_error_reset_state(r, "FAPI NV_Write", error_cleanup);
2057 
2058             context->nv_cmd.bytesRequested = aux_data->size;
2059             context->nv_cmd.nv_write_state = NV2_WRITE_AUTH_SENT;
2060             return TSS2_FAPI_RC_TRY_AGAIN;
2061 
2062         }
2063         fallthrough;
2064 
2065     statecase(context->nv_cmd.nv_write_state, NV2_WRITE_WRITE_PREPARE);
2066         /* Set written bit in keystore */
2067         context->nv_cmd.nv_object.misc.nv.public.nvPublic.attributes |= TPMA_NV_WRITTEN;
2068         /* Perform esys serialization if necessary */
2069         r = ifapi_esys_serialize_object(context->esys, &context->nv_cmd.nv_object);
2070         goto_if_error(r, "Prepare serialization", error_cleanup);
2071 
2072         /* Start writing the NV object to the key store */
2073         r = ifapi_keystore_store_async(&context->keystore, &context->io,
2074                                        context->nv_cmd.nvPath,
2075                                        &context->nv_cmd.nv_object);
2076         goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
2077                                   context->nv_cmd.nvPath);
2078         context->nv_cmd.nv_write_state = NV2_WRITE_WRITE;
2079         fallthrough;
2080 
2081     statecase(context->nv_cmd.nv_write_state, NV2_WRITE_WRITE);
2082         /* Finish writing the NV object to the key store */
2083         r = ifapi_keystore_store_finish(&context->keystore, &context->io);
2084         return_try_again(r);
2085         return_if_error_reset_state(r, "write_finish failed");
2086 
2087         LOG_DEBUG("success");
2088         r = TSS2_RC_SUCCESS;
2089 
2090         context->nv_cmd.nv_write_state = NV2_WRITE_INIT;
2091         break;
2092 
2093     statecasedefault(context->nv_cmd.nv_write_state);
2094     }
2095 
2096 error_cleanup:
2097     SAFE_FREE(nv_file_name);
2098     SAFE_FREE(context->nv_cmd.write_data);
2099     return r;
2100 }
2101 
2102 /** State machine to read data from the NV ram of the TPM.
2103  *
2104  * Context nv_cmd has to be prepared before the call of this function:
2105  * - auth_index The ESAPI handle of the authorization object.
2106  * - numBytes The number of bytes which should be read.
2107  * - esys_handle The ESAPI handle of the NV object.
2108  *
2109  * @param[in,out] context for storing all state information.
2110  * @param[out] data the data fetched from TPM.
2111  * @param[in,out] size The number of bytes requested and fetched.
2112  *
2113  * @retval TSS2_RC_SUCCESS If the data was read successfully.
2114  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
2115  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2116  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
2117  * @retval TSS2_FAPI_RC_GENERAL_FAILURE If an internal error occurs, which is
2118  +         not covered by other return codes.
2119  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the object
2120  *         store.
2121  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND If a policy for a certain path was not found.
2122  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
2123  *         not successful.
2124  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for the
2125  *         execution fails.
2126  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a needed authorization callback
2127  *         is not defined.
2128  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
2129  *         this function needs to be called again.
2130  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2131  *         operation already pending.
2132  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
2133  */
2134 TSS2_RC
ifapi_nv_read(FAPI_CONTEXT * context,uint8_t ** data,size_t * size)2135 ifapi_nv_read(
2136     FAPI_CONTEXT *context,
2137     uint8_t     **data,
2138     size_t       *size)
2139 {
2140     TSS2_RC r;
2141     UINT16 aux_size;
2142     TPM2B_MAX_NV_BUFFER *aux_data;
2143     UINT16 bytesRequested = context->nv_cmd.bytesRequested;
2144     size_t *numBytes = &context->nv_cmd.numBytes;
2145     ESYS_TR nv_index = context->nv_cmd.esys_handle;
2146     IFAPI_OBJECT *auth_object = &context->nv_cmd.auth_object;
2147     ESYS_TR session;
2148 
2149     switch (context->nv_cmd.nv_read_state) {
2150     statecase(context->nv_cmd.nv_read_state, NV_READ_INIT);
2151         LOG_TRACE("NV_READ_INIT");
2152         context->nv_cmd.rdata = NULL;
2153         fallthrough;
2154 
2155     statecase(context->nv_cmd.nv_read_state, NV_READ_AUTHORIZE);
2156         LOG_TRACE("NV_READ_AUTHORIZE");
2157         r = ifapi_authorize_object(context, auth_object, &session);
2158         FAPI_SYNC(r, "Authorize NV object.", error_cleanup);
2159 
2160         if (*numBytes > context->nv_buffer_max)
2161             aux_size = context->nv_buffer_max;
2162         else
2163             aux_size = *numBytes;
2164 
2165         /* Prepare the reading from NV ram. */
2166         r = Esys_NV_Read_Async(context->esys,
2167                                context->nv_cmd.auth_index,
2168                                nv_index,
2169                                session,
2170                                ESYS_TR_NONE,
2171                                ESYS_TR_NONE,
2172                                aux_size,
2173                                0);
2174         goto_if_error_reset_state(r, " Fapi_NvRead_Async", error_cleanup);
2175 
2176         context->nv_cmd.nv_read_state = NV_READ_AUTH_SENT;
2177         context->nv_cmd.bytesRequested = aux_size;
2178 
2179         return TSS2_FAPI_RC_TRY_AGAIN;
2180 
2181     statecase(context->nv_cmd.nv_read_state, NV_READ_AUTH_SENT);
2182         LOG_TRACE("NV_READ_NULL_AUTH_SENT");
2183         if (context->nv_cmd.rdata == NULL) {
2184             /* Allocate the data buffer if not already initialized. */
2185             LOG_TRACE("Allocate %zu bytes", *numBytes);
2186             context->nv_cmd.rdata = malloc(*numBytes);
2187         }
2188         *data = context->nv_cmd.rdata;
2189         goto_if_null(*data, "Malloc failed", TSS2_FAPI_RC_MEMORY, error_cleanup);
2190 
2191         r = Esys_NV_Read_Finish(context->esys, &aux_data);
2192 
2193         if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN)
2194             return TSS2_FAPI_RC_TRY_AGAIN;
2195 
2196         goto_if_error_reset_state(r, "FAPI NV_Read_Finish", error_cleanup);
2197 
2198         if (aux_data->size < bytesRequested)
2199             *numBytes = 0;
2200         else
2201             *numBytes -= aux_data->size;
2202         memcpy(*data + context->nv_cmd.data_idx, &aux_data->buffer[0],
2203                aux_data->size);
2204         context->nv_cmd.data_idx += aux_data->size;
2205         free(aux_data);
2206         if (*numBytes > 0) {
2207             statecase(context->nv_cmd.nv_read_state, NV_READ_AUTHORIZE2);
2208                 r = ifapi_authorize_object(context, auth_object, &session);
2209                 FAPI_SYNC(r, "Authorize NV object.", error_cleanup);
2210 
2211             /* The reading of the NV data is not completed. The next
2212             reading will be prepared. */
2213             if (*numBytes > context->nv_buffer_max)
2214                 aux_size = context->nv_buffer_max;
2215             else
2216                 aux_size = *numBytes;
2217 
2218             r = Esys_NV_Read_Async(context->esys,
2219                                    context->nv_cmd.auth_index,
2220                                    nv_index,
2221                                    session,
2222                                    ESYS_TR_NONE,
2223                                    ESYS_TR_NONE,
2224                                    aux_size,
2225                                    context->nv_cmd.data_idx);
2226             goto_if_error_reset_state(r, "FAPI NV_Read", error_cleanup);
2227             context->nv_cmd.bytesRequested = aux_size;
2228             context->nv_cmd.nv_read_state = NV_READ_AUTH_SENT;
2229             return TSS2_FAPI_RC_TRY_AGAIN;
2230         } else {
2231             *size = context->nv_cmd.data_idx;
2232             context->nv_cmd.nv_read_state = NV_READ_INIT;
2233             LOG_DEBUG("success");
2234             r = TSS2_RC_SUCCESS;
2235             break;
2236         }
2237     statecasedefault(context->nv_cmd.nv_read_state);
2238     }
2239 
2240 error_cleanup:
2241     return r;
2242 }
2243 
2244 #define min(X,Y) (X>Y)?Y:X
2245 
2246 /** State machine to retrieve random data from TPM.
2247  *
2248  * If the buffer size exceeds the maximum size, several ESAPI calls are made.
2249  *
2250  * @param[in,out] context for storing all state information.
2251  * @param[in] numBytes Number of random bytes to be computed.
2252  * @param[out] data The random data.
2253  *
2254  * @retval TSS2_RC_SUCCESS If random data can be computed.
2255  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
2256  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2257  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
2258  *         the function.
2259  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
2260  *         this function needs to be called again.
2261  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2262  *         operation already pending.
2263  */
2264 TSS2_RC
ifapi_get_random(FAPI_CONTEXT * context,size_t numBytes,uint8_t ** data)2265 ifapi_get_random(FAPI_CONTEXT *context, size_t numBytes, uint8_t **data)
2266 {
2267     TSS2_RC r;
2268     TPM2B_DIGEST *aux_data = NULL;
2269 
2270     switch (context->get_random_state) {
2271     statecase(context->get_random_state, GET_RANDOM_INIT);
2272         context->get_random.numBytes = numBytes;
2273         context->get_random.data = calloc(context->get_random.numBytes, 1);
2274         context->get_random.idx = 0;
2275         return_if_null(context->get_random.data, "FAPI out of memory.",
2276                        TSS2_FAPI_RC_MEMORY);
2277 
2278         /* Prepare the creation of random data. */
2279         r = Esys_GetRandom_Async(context->esys,
2280                                  context->session1,
2281                                  ESYS_TR_NONE, ESYS_TR_NONE,
2282                                  min(context->get_random.numBytes, sizeof(TPMU_HA)));
2283         goto_if_error_reset_state(r, "FAPI GetRandom", error_cleanup);
2284         fallthrough;
2285 
2286     statecase(context->get_random_state, GET_RANDOM_SENT);
2287         r = Esys_GetRandom_Finish(context->esys, &aux_data);
2288         return_try_again(r);
2289         goto_if_error_reset_state(r, "FAPI GetRandom_Finish", error_cleanup);
2290 
2291         if (aux_data -> size > context->get_random.numBytes) {
2292             goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "TPM returned too many bytes",
2293                        error_cleanup);
2294         }
2295 
2296         /* Save created random data. */
2297         memcpy(context->get_random.data + context->get_random.idx, &aux_data->buffer[0],
2298                aux_data->size);
2299         context->get_random.numBytes -= aux_data->size;
2300         context->get_random.idx += aux_data->size;
2301         Esys_Free(aux_data);
2302         aux_data = NULL;
2303         if (context->get_random.numBytes > 0) {
2304 
2305             /* Continue creaion of random data if needed. */
2306             r = Esys_GetRandom_Async(context->esys, context->session1, ESYS_TR_NONE,
2307                                      ESYS_TR_NONE, min(context->get_random.numBytes, sizeof(TPMU_HA)));
2308             goto_if_error_reset_state(r, "FAPI GetRandom", error_cleanup);
2309 
2310             return TSS2_FAPI_RC_TRY_AGAIN;
2311         }
2312         break;
2313 
2314     statecasedefault(context->get_random_state);
2315     }
2316 
2317     *data = context->get_random.data;
2318 
2319     LOG_DEBUG("success");
2320     context->get_random_state = GET_RANDOM_INIT;
2321     return TSS2_RC_SUCCESS;
2322 
2323 error_cleanup:
2324     if (aux_data)
2325         Esys_Free(aux_data);
2326     context->get_random_state = GET_RANDOM_INIT;
2327     if (context->get_random.data != NULL)
2328         SAFE_FREE(context->get_random.data);
2329     return r;
2330 }
2331 
2332 /** Load a key and initialize profile and session for ESAPI execution.
2333  *
2334  * This state machine prepares the session for key loading. Some
2335  * session related parameters will be taken from profile.
2336  *
2337  * @param[in,out] context The FAPI_CONTEXT.
2338  * @param[in]     keyPath the key path without the parent directories
2339  *                of the key store. (e.g. HE/EK, HS/SRK/mykey)
2340  * @param[out]    key_object The callee allocated internal representation
2341  *                of a key object.
2342  *
2343  * @retval TSS2_RC_SUCCESS If the key was loaded successfully.
2344  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
2345  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2346  * @retval TSS2_FAPI_RC_GENERAL_FAILURE If an internal error occurs, which is
2347  *         not covered by other return codes.
2348  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
2349  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the object
2350  *         store.
2351  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND If a policy or key was not found.
2352  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
2353  *         not successful.
2354  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for policy
2355  *         execution fails.
2356  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a needed authorization callback
2357            is not defined.
2358  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
2359  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
2360  *         this function needs to be called again.
2361  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2362  *         operation already pending.
2363  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
2364  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
2365  */
2366 TSS2_RC
ifapi_load_key(FAPI_CONTEXT * context,char const * keyPath,IFAPI_OBJECT ** key_object)2367 ifapi_load_key(
2368     FAPI_CONTEXT  *context,
2369     char    const *keyPath,
2370     IFAPI_OBJECT **key_object)
2371 {
2372     TSS2_RC r;
2373     const IFAPI_PROFILE *profile;
2374 
2375     return_if_null(keyPath, "Bad reference for key path.",
2376                    TSS2_FAPI_RC_BAD_REFERENCE);
2377 
2378     switch (context->Key_Sign.state) {
2379     statecase(context->Key_Sign.state, SIGN_INIT);
2380         context->Key_Sign.keyPath = keyPath;
2381 
2382         /* Prepare the session creation. */
2383         r = ifapi_get_sessions_async(context,
2384                                      IFAPI_SESSION_GENEK | IFAPI_SESSION1,
2385                                      TPMA_SESSION_DECRYPT, 0);
2386         goto_if_error_reset_state(r, "Create sessions", error_cleanup);
2387         fallthrough;
2388 
2389     statecase(context->Key_Sign.state, SIGN_WAIT_FOR_SESSION);
2390         r = ifapi_profiles_get(&context->profiles, context->Key_Sign.keyPath, &profile);
2391         goto_if_error_reset_state(r, "Reading profile data", error_cleanup);
2392 
2393         r = ifapi_get_sessions_finish(context, profile, profile->nameAlg);
2394         return_try_again(r);
2395         goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
2396 
2397         /* Prepare the key loading. */
2398         r = ifapi_load_keys_async(context, context->Key_Sign.keyPath);
2399         goto_if_error(r, "Load keys.", error_cleanup);
2400         fallthrough;
2401 
2402     statecase(context->Key_Sign.state, SIGN_WAIT_FOR_KEY);
2403         r = ifapi_load_keys_finish(context, IFAPI_FLUSH_PARENT,
2404                                    &context->Key_Sign.handle,
2405                                    key_object);
2406         return_try_again(r);
2407         goto_if_error_reset_state(r, " Load key.", error_cleanup);
2408 
2409         context->Key_Sign.state = SIGN_INIT;
2410         break;
2411 
2412     statecasedefault(context->Key_Sign.state);
2413     }
2414 
2415 error_cleanup:
2416     return r;
2417 }
2418 
2419 /** State machine for signing operation.
2420  *
2421  * The key used for signing will be authorized and the signing of the passed data
2422  * will be executed.
2423  *
2424  * @param[in,out] context The FAPI_CONTEXT.
2425  * @param[in]     sig_key_object The Fapi key object which will be used to
2426  *                sign the passed digest.
2427  * @param[in]     padding is the padding algorithm used. Possible values are RSA_SSA,
2428  *                RSA_PPSS (case insensitive). padding MAY be NULL.
2429  * @param[in]     digest is the data to be signed, already hashed.
2430  *                digest MUST NOT be NULL.
2431  * @param[out]    tpm_signature returns the signature in binary form (DER format).
2432  *                tpm_signature MUST NOT be NULL (callee-allocated).
2433  * @param[out]    publicKey is the public key of the signing key in PEM format.
2434  *                publicKey is callee allocated and MAY be NULL.
2435  * @param[out]    certificate is the certificate associated with the signing key
2436  *                in PEM format. certificate MAY be NULL.
2437  *
2438  * @retval TSS2_RC_SUCCESS If the signing was successful.
2439  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
2440  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2441  * @retval TSS2_FAPI_RC_GENERAL_FAILURE If an internal error occurs, which is
2442  *         not covered by other return codes.
2443  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
2444  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the policy
2445  *         store.
2446  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND If a policy for a certain path was not found.
2447  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
2448  *         not successful.
2449  * @retval TSS2_FAPI_RC_BAD_TEMPLATE In a invalid policy is loaded during execution.
2450  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for policy
2451  *         execution fails.
2452  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a needed authorization callback
2453  *         is not defined.
2454  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
2455  *         this function needs to be called again.
2456  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2457  *         operation already pending.
2458  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
2459  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
2460  */
2461 TSS2_RC
ifapi_key_sign(FAPI_CONTEXT * context,IFAPI_OBJECT * sig_key_object,char const * padding,TPM2B_DIGEST * digest,TPMT_SIGNATURE ** tpm_signature,char ** publicKey,char ** certificate)2462 ifapi_key_sign(
2463     FAPI_CONTEXT     *context,
2464     IFAPI_OBJECT     *sig_key_object,
2465     char const       *padding,
2466     TPM2B_DIGEST     *digest,
2467     TPMT_SIGNATURE  **tpm_signature,
2468     char            **publicKey,
2469     char            **certificate)
2470 {
2471     TSS2_RC r;
2472     TPMT_SIG_SCHEME sig_scheme;
2473     ESYS_TR session;
2474 
2475     TPMT_TK_HASHCHECK hash_validation = {
2476         .tag = TPM2_ST_HASHCHECK,
2477         .hierarchy = TPM2_RH_OWNER,
2478     };
2479     memset(&hash_validation.digest, 0, sizeof(TPM2B_DIGEST));
2480 
2481     switch (context->Key_Sign.state) {
2482     statecase(context->Key_Sign.state, SIGN_INIT);
2483         sig_key_object = context->Key_Sign.key_object;
2484 
2485         r = ifapi_authorize_object(context, sig_key_object, &session);
2486         FAPI_SYNC(r, "Authorize signature key.", cleanup);
2487 
2488         context->policy.session = session;
2489 
2490         r = ifapi_get_sig_scheme(context, sig_key_object, padding, digest, &sig_scheme);
2491         goto_if_error(r, "Get signature scheme", cleanup);
2492 
2493         /* Prepare the signing operation. */
2494         r = Esys_Sign_Async(context->esys,
2495                             context->Key_Sign.handle,
2496                             session,
2497                             ESYS_TR_NONE, ESYS_TR_NONE,
2498                             digest,
2499                             &sig_scheme,
2500                             &hash_validation);
2501         goto_if_error(r, "Error: Sign", cleanup);
2502         fallthrough;
2503 
2504     statecase(context->Key_Sign.state, SIGN_AUTH_SENT);
2505         context->Key_Sign.signature = NULL;
2506         r = Esys_Sign_Finish(context->esys,
2507                              &context->Key_Sign.signature);
2508         return_try_again(r);
2509         ifapi_flush_policy_session(context, context->policy.session, r);
2510         goto_if_error(r, "Error: Sign", cleanup);
2511 
2512         /* Prepare the flushing of the signing key. */
2513         r = Esys_FlushContext_Async(context->esys, context->Key_Sign.handle);
2514         goto_if_error(r, "Error: FlushContext", cleanup);
2515         fallthrough;
2516 
2517     statecase(context->Key_Sign.state, SIGN_WAIT_FOR_FLUSH);
2518         r = Esys_FlushContext_Finish(context->esys);
2519         return_try_again(r);
2520         goto_if_error(r, "Error: Sign", cleanup);
2521 
2522         int pem_size;
2523         if (publicKey) {
2524             /* Convert internal key object to PEM format. */
2525             r = ifapi_pub_pem_key_from_tpm(&sig_key_object->misc.key.public,
2526                                                 publicKey,
2527                                                 &pem_size);
2528             goto_if_error(r, "Conversion pub key to PEM failed", cleanup);
2529         }
2530         context->Key_Sign.handle = ESYS_TR_NONE;
2531         *tpm_signature = context->Key_Sign.signature;
2532         if (certificate) {
2533             *certificate = strdup(context->Key_Sign.key_object->misc.key.certificate);
2534             goto_if_null(*certificate, "Out of memory.",
2535                     TSS2_FAPI_RC_MEMORY, cleanup);
2536         }
2537         context->Key_Sign.state = SIGN_INIT;
2538         LOG_TRACE("success");
2539         r = TSS2_RC_SUCCESS;
2540         break;
2541 
2542     statecasedefault(context->Key_Sign.state);
2543     }
2544 
2545 cleanup:
2546     if (context->Key_Sign.handle != ESYS_TR_NONE)
2547         Esys_FlushContext(context->esys, context->Key_Sign.handle);
2548     ifapi_cleanup_ifapi_object(context->Key_Sign.key_object);
2549     return r;
2550 }
2551 
2552 /** Get json encoding for FAPI object.
2553  *
2554  * A json representation which can be used for exporting of a FAPI object will
2555  * be created.
2556  *
2557  * @param[in]   context The FAPI_CONTEXT.
2558  * @param[in]   object The object to be serialized.
2559  * @param[out]  json_string The json string created by the deserialzation
2560  *              function (callee-allocated).
2561  *
2562  * @retval TSS2_RC_SUCCESS If the serialization was successful.
2563  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2564  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during
2565  *         serialization.
2566  * @retval TSS2_FAPI_RC_BAD_REFERENCE If a NULL pointer was passed for
2567  *         the object.
2568  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
2569  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
2570  */
2571 TSS2_RC
ifapi_get_json(FAPI_CONTEXT * context,IFAPI_OBJECT * object,char ** json_string)2572 ifapi_get_json(FAPI_CONTEXT *context, IFAPI_OBJECT *object, char **json_string)
2573 {
2574     TSS2_RC r = TSS2_RC_SUCCESS;
2575     json_object *jso = NULL;
2576 
2577     /* Perform esys serialization if necessary */
2578     r = ifapi_esys_serialize_object(context->esys, object);
2579     goto_if_error(r, "Prepare serialization", cleanup);
2580 
2581     r = ifapi_json_IFAPI_OBJECT_serialize(object, &jso);
2582     return_if_error(r, "Serialize duplication object");
2583 
2584     *json_string = strdup(json_object_to_json_string_ext(jso,
2585                           JSON_C_TO_STRING_PRETTY));
2586     goto_if_null2(*json_string, "Converting json to string", r, TSS2_FAPI_RC_MEMORY,
2587                   cleanup);
2588 
2589 cleanup:
2590     if (jso)
2591         json_object_put(jso);
2592     return r;
2593 }
2594 
2595 /** Serialize persistent objects into buffer of keystore object.
2596  *
2597  * NV objects and persistent keys will serialized via the ESYS API to
2598  * enable reconstruction durinng loading from keystore.
2599  *
2600  * @param[in]     ectx The ESAPI context.
2601  * @param[in,out] object  The nv object or the key.
2602  * @retval TSS2_RC_SUCCESS if the function call was a success.
2603  */
2604 TSS2_RC
ifapi_esys_serialize_object(ESYS_CONTEXT * ectx,IFAPI_OBJECT * object)2605 ifapi_esys_serialize_object(ESYS_CONTEXT *ectx, IFAPI_OBJECT *object)
2606 {
2607     TSS2_RC r = TSS2_RC_SUCCESS;
2608     IFAPI_KEY *key_object = NULL;
2609     IFAPI_NV *nv_object;
2610 
2611     switch (object->objectType) {
2612     case IFAPI_NV_OBJ:
2613         nv_object = &object->misc.nv;
2614         if (nv_object->serialization.buffer != NULL) {
2615             /* Cleanup old buffer */
2616             Fapi_Free(nv_object->serialization.buffer);
2617             nv_object->serialization.buffer = NULL;
2618         }
2619         r = Esys_TR_Serialize(ectx, object->handle,
2620                               &nv_object->serialization.buffer,
2621                               &nv_object->serialization.size);
2622         return_if_error(r, "Error serialize esys object");
2623         break;
2624 
2625     case IFAPI_KEY_OBJ:
2626         key_object = &object->misc.key;
2627         key_object->serialization.size = 0;
2628         if (key_object->serialization.buffer != NULL) {
2629             /* Cleanup old buffer */
2630             Fapi_Free(key_object->serialization.buffer);
2631             key_object->serialization.buffer = NULL;
2632         }
2633         if (object->handle != ESYS_TR_NONE && key_object->persistent_handle) {
2634             key_object->serialization.buffer = NULL;
2635             r = Esys_TR_Serialize(ectx, object->handle,
2636                                   &key_object->serialization.buffer,
2637                                   &key_object->serialization.size);
2638             return_if_error(r, "Error serialize esys object");
2639         }
2640         break;
2641 
2642     default:
2643         /* Nothing to be done */
2644         break;
2645     }
2646     return TSS2_RC_SUCCESS;
2647 }
2648 
2649  /** Initialize the part of an IFAPI_OBJECT  which is not serialized.
2650   *
2651   * For persistent objects the correspodning ESYS object will be created.
2652   *
2653   * @param[in,out] ectx The ESYS context.
2654   * @param[out] object the deserialzed binary object.
2655   * @retval TSS2_RC_SUCCESS if the function call was a success.
2656   * @retval TSS2_FAPI_RC_BAD_VALUE if the json object can't be deserialized.
2657   */
2658 TSS2_RC
ifapi_initialize_object(ESYS_CONTEXT * ectx,IFAPI_OBJECT * object)2659 ifapi_initialize_object(
2660     ESYS_CONTEXT *ectx,
2661     IFAPI_OBJECT *object)
2662 {
2663     TSS2_RC r = TSS2_RC_SUCCESS;
2664     ESYS_TR handle;
2665 
2666     switch (object->objectType) {
2667     case IFAPI_NV_OBJ:
2668         if (object->misc.nv.serialization.size > 0) {
2669             r = Esys_TR_Deserialize(ectx, &object->misc.nv.serialization.buffer[0],
2670                                     object->misc.nv.serialization.size, &handle);
2671             goto_if_error(r, "Error dserialize esys object", cleanup);
2672         } else {
2673             handle = ESYS_TR_NONE;
2674         }
2675         object->authorization_state = AUTH_INIT;
2676         object->handle = handle;
2677         break;
2678 
2679     case IFAPI_KEY_OBJ:
2680         if (object->misc.key.serialization.size > 0) {
2681             r = Esys_TR_Deserialize(ectx, &object->misc.key.serialization.buffer[0],
2682                                     object->misc.key.serialization.size, &handle);
2683             goto_if_error(r, "Error deserialize esys object", cleanup);
2684         } else {
2685             handle = ESYS_TR_NONE;
2686         }
2687         object->authorization_state = AUTH_INIT;
2688         object->handle = handle;
2689         break;
2690 
2691     default:
2692         /* Nothing to be done */
2693         break;
2694     }
2695 
2696     return r;
2697 
2698 cleanup:
2699     SAFE_FREE(object->policy);
2700     return r;
2701 }
2702 
2703 /** Prepare key creation with an auth value.
2704  *
2705  * The auth value will be copied int the FAPI context for later use in key creation.
2706  *
2707  * @param[in,out] context The FAPI_CONTEXT.
2708  * @param[in]     keyPath the key path without the parent directories
2709  *                of the key store. (e.g. HE/EK, HS/SRK/mykey)
2710  * @param[in]     policyPath identifies the policy to be associated with the new key.
2711  *                policyPath MAY be NULL. If policyPath is NULL then no policy will
2712  *                be associated with the key.
2713  * @param[in]     authValue The authentication value of the key.
2714  *
2715  * @retval TSS2_RC_SUCCESS If the preparation was successful.
2716  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS If the object with does already exist in
2717  *         keystore.
2718  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2719  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
2720  *         the function.
2721  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
2722  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
2723  *         config file.
2724  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2725  *         operation already pending.
2726  */
2727 TSS2_RC
ifapi_key_create_prepare_auth(FAPI_CONTEXT * context,char const * keyPath,char const * policyPath,char const * authValue)2728 ifapi_key_create_prepare_auth(
2729     FAPI_CONTEXT  *context,
2730     char   const *keyPath,
2731     char   const *policyPath,
2732     char   const *authValue)
2733 {
2734     TSS2_RC r;
2735 
2736     memset(&context->cmd.Key_Create.inSensitive, 0, sizeof(TPM2B_SENSITIVE_CREATE));
2737     if (authValue) {
2738         /* Copy the auth value */
2739         if (strlen(authValue) > sizeof(TPMU_HA)) {
2740             return_error(TSS2_FAPI_RC_BAD_VALUE, "Password too long.");
2741         }
2742         memcpy(&context->cmd.Key_Create.inSensitive.sensitive.userAuth.buffer,
2743                authValue, strlen(authValue));
2744         context->cmd.Key_Create.inSensitive.sensitive.userAuth.size = strlen(authValue);
2745     }
2746     context->cmd.Key_Create.inSensitive.sensitive.data.size = 0;
2747     r = ifapi_key_create_prepare(context, keyPath, policyPath);
2748     return r;
2749 }
2750 
2751 /** Prepare key creation with an auth value and sensitive data.
2752  *
2753  * The auth value and the sensitive data will be copied int the FAPI context
2754  * for later use in key creation.
2755  *
2756  * @param[in,out] context The FAPI_CONTEXT.
2757  * @param[in]     keyPath the key path without the parent directories
2758  *                of the key store. (e.g. HE/EK, HS/SRK/mykey)
2759  * @param[in]     policyPath identifies the policy to be associated with the new key.
2760  *                policyPath MAY be NULL. If policyPath is NULL then no policy will
2761  *                be associated with the key.
2762  * @param[in]     dataSize The size of the sensitive data.
2763  * @param[in]     authValue The authentication value of the key.
2764  * @param[in]     data The sensitive data.
2765  *
2766  * @retval TSS2_RC_SUCCESS If the preparation was successful.
2767  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS If the object with does already exist in
2768  *         keystore.
2769  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2770  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
2771  *         the function.
2772  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
2773  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
2774  *         config file.
2775  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2776  *         operation already pending.
2777  */
2778 TSS2_RC
ifapi_key_create_prepare_sensitive(FAPI_CONTEXT * context,char const * keyPath,char const * policyPath,size_t dataSize,char const * authValue,uint8_t const * data)2779 ifapi_key_create_prepare_sensitive(
2780     FAPI_CONTEXT  *context,
2781     char    const *keyPath,
2782     char    const *policyPath,
2783     size_t         dataSize,
2784     char    const *authValue,
2785     uint8_t const *data)
2786 {
2787     TSS2_RC r;
2788 
2789     memset(&context->cmd.Key_Create.inSensitive, 0, sizeof(TPM2B_SENSITIVE_CREATE));
2790     if (dataSize > sizeof(TPMU_HA) || dataSize == 0) {
2791         return_error(TSS2_FAPI_RC_BAD_VALUE, "Data to big or equal zero.");
2792     }
2793     if (data)
2794         /* Copy the sensitive data */
2795         memcpy(&context->cmd.Key_Create.inSensitive.sensitive.data.buffer,
2796                data, dataSize);
2797     context->cmd.Key_Create.inSensitive.sensitive.data.size = dataSize;
2798     if (authValue) {
2799         /* Copy the auth value. */
2800         if (strlen(authValue) > sizeof(TPMU_HA)) {
2801             return_error(TSS2_FAPI_RC_BAD_VALUE, "Password too long.");
2802         }
2803         memcpy(&context->cmd.Key_Create.inSensitive.sensitive.userAuth.buffer,
2804                authValue, strlen(authValue));
2805         context->cmd.Key_Create.inSensitive.sensitive.userAuth.size = strlen(authValue);
2806     }
2807     r = ifapi_key_create_prepare(context, keyPath, policyPath);
2808     return r;
2809 }
2810 
2811 /** Prepare key creation if possible.
2812  *
2813  * It will be checked whether the object already exists in key store and the FAPI context
2814  * will be initialized appropriate for key creation.
2815  *
2816  * @param[in,out] context The FAPI_CONTEXT.
2817  * @param[in]     keyPath the key path without the parent directories
2818  *                of the key store. (e.g. HE/EK, HS/SRK/mykey)
2819  * @param[in]     policyPath identifies the policy to be associated with the new key.
2820  *                policyPath MAY be NULL. If policyPath is NULL then no policy will
2821  *                be associated with the key.
2822  *
2823  * @retval TSS2_RC_SUCCESS If the preparation was successful.
2824  * @retval TSS2_FAPI_RC_PATH_ALREADY_EXISTS If the object with does already exist in
2825  *         keystore.
2826  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2827  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
2828  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
2829  *         config file.
2830  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2831  *         operation already pending.
2832  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
2833  *         the function.
2834  */
2835 TSS2_RC
ifapi_key_create_prepare(FAPI_CONTEXT * context,char const * keyPath,char const * policyPath)2836 ifapi_key_create_prepare(
2837     FAPI_CONTEXT  *context,
2838     char   const *keyPath,
2839     char   const *policyPath)
2840 {
2841     TSS2_RC r;
2842     IFAPI_OBJECT *object = &context->cmd.Key_Create.object;
2843     NODE_STR_T *path_list = NULL;
2844 
2845     LOG_TRACE("call");
2846     r = ifapi_session_init(context);
2847     return_if_error(r, "Initialize Key_Create");
2848 
2849     /* First check whether an existing object would be overwritten */
2850     r = ifapi_keystore_check_overwrite(&context->keystore, &context->io,
2851                                        keyPath);
2852     return_if_error2(r, "Check overwrite %s", keyPath);
2853 
2854     context->srk_handle = 0;
2855 
2856     /* Clear the memory used for the the new key object */
2857     memset(&context->cmd.Key_Create.outsideInfo, 0, sizeof(TPM2B_DATA));
2858     memset(&context->cmd.Key_Create.creationPCR, 0, sizeof(TPML_PCR_SELECTION));
2859     memset(object, 0, sizeof(IFAPI_OBJECT));
2860 
2861     strdup_check(context->cmd.Key_Create.policyPath, policyPath, r, error);
2862     strdup_check(context->cmd.Key_Create.keyPath, keyPath, r, error);
2863     r = get_explicit_key_path(&context->keystore, keyPath, &path_list);
2864     return_if_error(r, "Compute explicit path.");
2865 
2866     context->loadKey.path_list = path_list;
2867     char *file;
2868     r = ifapi_path_string(&file, NULL, path_list, NULL);
2869     goto_if_error(r, "Compute explicit path.", error);
2870 
2871     LOG_DEBUG("Explicit key path: %s", file);
2872 
2873     free(file);
2874 
2875     context->cmd.Key_Create.state = KEY_CREATE_INIT;
2876 
2877     return TSS2_RC_SUCCESS;
2878 
2879 error:
2880     free_string_list(path_list);
2881     return r;
2882 }
2883 
2884 /** State machine for key creation.
2885  *
2886  * The function for the preparation of the key have to called before the state machine can
2887  * be activated. The linked list for the used directories must be available in the
2888  * FAPI context.
2889  * It will be checked whether the object already exists in key store and the FAPI context
2890  * will be initialized appropriate for key creation.
2891  *
2892  * @param[in,out] context The FAPI_CONTEXT.
2893  * @param[in] template The template which defines the key attributes and whether the
2894  *            key will be persistent.
2895  *
2896  * @retval TSS2_RC_SUCCESS If the key could be generated.
2897  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
2898  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
2899  * @retval TSS2_FAPI_RC_GENERAL_FAILURE If an internal error occurs, which is
2900  *         not covered by other return codes.
2901  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution.
2902  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the policy
2903  *         store.
2904  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND If an object needed for creation or
2905            authentication was not found.
2906  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
2907  *         not successful.
2908  * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for creation
2909  *         fails.
2910  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a needed authorization callback
2911  *         is not defined.
2912  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
2913  *         this function needs to be called again.
2914  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
2915  *         operation already pending.
2916  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
2917  */
2918 TSS2_RC
ifapi_key_create(FAPI_CONTEXT * context,IFAPI_KEY_TEMPLATE * template)2919 ifapi_key_create(
2920     FAPI_CONTEXT *context,
2921     IFAPI_KEY_TEMPLATE *template)
2922 {
2923     TSS2_RC r;
2924     size_t path_length;
2925     NODE_STR_T *path_list = context->loadKey.path_list;
2926     TPM2B_PUBLIC *outPublic = NULL;
2927     TPM2B_PRIVATE *outPrivate = NULL;
2928     TPM2B_CREATION_DATA *creationData = NULL;
2929     TPM2B_DIGEST *creationHash = NULL;
2930     TPMT_TK_CREATION *creationTicket = NULL;
2931     IFAPI_OBJECT *object = &context->cmd.Key_Create.object;
2932     ESYS_TR auth_session;
2933 
2934     LOG_TRACE("call");
2935 
2936     switch (context->cmd.Key_Create.state) {
2937     statecase(context->cmd.Key_Create.state, KEY_CREATE_INIT);
2938         context->cmd.Key_Create.public_templ = *template;
2939 
2940         /* Profile name is first element of the explicit path list */
2941         char *profile_name = context->loadKey.path_list->str;
2942         r = ifapi_profiles_get(&context->profiles, profile_name, &context->cmd.Key_Create.profile);
2943         goto_if_error_reset_state(r, "Retrieving profile data", error_cleanup);
2944 
2945         if (context->cmd.Key_Create.inSensitive.sensitive.data.size > 0) {
2946             /* A keyed hash object sealing sensitive data will be created */
2947             context->cmd.Key_Create.public_templ.public.publicArea.type = TPM2_ALG_KEYEDHASH;
2948             context->cmd.Key_Create.public_templ.public.publicArea.nameAlg =
2949                     context->cmd.Key_Create.profile->nameAlg;
2950             context->cmd.Key_Create.public_templ.public.publicArea.parameters.keyedHashDetail.scheme.scheme =
2951             TPM2_ALG_NULL;
2952         } else {
2953             r = ifapi_merge_profile_into_template(context->cmd.Key_Create.profile,
2954                                                   &context->cmd.Key_Create.public_templ);
2955             goto_if_error_reset_state(r, "Merge profile", error_cleanup);
2956         }
2957 
2958         if (context->cmd.Key_Create.policyPath
2959                 && strcmp(context->cmd.Key_Create.policyPath, "") != 0)
2960             context->cmd.Key_Create.state = KEY_CREATE_CALCULATE_POLICY;
2961         /* else jump over to KEY_CREATE_WAIT_FOR_SESSION below */
2962     /* FALLTHRU */
2963 
2964     case KEY_CREATE_CALCULATE_POLICY:
2965         if (context->cmd.Key_Create.state == KEY_CREATE_CALCULATE_POLICY) {
2966             r = ifapi_calculate_tree(context, context->cmd.Key_Create.policyPath,
2967                                      &context->policy.policy,
2968                                      context->cmd.Key_Create.public_templ.public.publicArea.nameAlg,
2969                                      &context->policy.digest_idx,
2970                                      &context->policy.hash_size);
2971             return_try_again(r);
2972             goto_if_error2(r, "Calculate policy tree %s", error_cleanup,
2973                            context->cmd.Key_Create.policyPath);
2974 
2975             /* Store the calculated policy in the key object */
2976             object->policy = calloc(1, sizeof(TPMS_POLICY));
2977             return_if_null(object->policy, "Out of memory",
2978                     TSS2_FAPI_RC_MEMORY);
2979             *(object->policy) = context->policy.policy;
2980 
2981             context->cmd.Key_Create.public_templ.public.publicArea.authPolicy.size =
2982                 context->policy.hash_size;
2983             memcpy(&context->cmd.Key_Create.public_templ.public.publicArea.authPolicy.buffer[0],
2984                    &context->policy.policy.policyDigests.digests[context->policy.digest_idx].digest,
2985                    context->policy.hash_size);
2986         }
2987         r = ifapi_get_sessions_async(context,
2988                                      IFAPI_SESSION_GENEK | IFAPI_SESSION1,
2989                                      TPMA_SESSION_DECRYPT, 0);
2990         goto_if_error_reset_state(r, "Create sessions", error_cleanup);
2991         fallthrough;
2992 
2993     statecase(context->cmd.Key_Create.state, KEY_CREATE_WAIT_FOR_SESSION);
2994         LOG_TRACE("KEY_CREATE_WAIT_FOR_SESSION");
2995         r = ifapi_get_sessions_finish(context, context->cmd.Key_Create.profile,
2996                                       context->cmd.Key_Create.profile->nameAlg);
2997         return_try_again(r);
2998         goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
2999 
3000         path_length = ifapi_path_length(path_list);
3001         r = ifapi_load_key_async(context, path_length - 1);
3002         goto_if_error(r, "LoadKey async", error_cleanup);
3003         fallthrough;
3004 
3005     statecase(context->cmd.Key_Create.state, KEY_CREATE_WAIT_FOR_PARENT);
3006         LOG_TRACE("KEY_CREATE_WAIT_FOR_PARENT");
3007         r = ifapi_load_key_finish(context, IFAPI_FLUSH_PARENT);
3008         return_try_again(r);
3009         goto_if_error(r, "LoadKey finish", error_cleanup);
3010         fallthrough;
3011 
3012     statecase(context->cmd.Key_Create.state, KEY_CREATE_WAIT_FOR_AUTHORIZATION);
3013         r = ifapi_authorize_object(context, &context->loadKey.auth_object, &auth_session);
3014         FAPI_SYNC(r, "Authorize key.", error_cleanup);
3015 
3016         r = Esys_Create_Async(context->esys, context->loadKey.auth_object.handle,
3017                               auth_session,
3018                               ESYS_TR_NONE, ESYS_TR_NONE,
3019                               &context->cmd.Key_Create.inSensitive,
3020                               &context->cmd.Key_Create.public_templ.public,
3021                               &context->cmd.Key_Create.outsideInfo,
3022                               &context->cmd.Key_Create.creationPCR);
3023         goto_if_error(r, "Create_Async", error_cleanup);
3024         fallthrough;
3025 
3026     statecase(context->cmd.Key_Create.state, KEY_CREATE_AUTH_SENT);
3027         r = Esys_Create_Finish(context->esys, &outPrivate, &outPublic, &creationData,
3028                                &creationHash, &creationTicket);
3029         try_again_or_error_goto(r, "Key create finish", error_cleanup);
3030 
3031         /* Prepare object for serialization */
3032         object->system = context->cmd.Key_Create.public_templ.system;
3033         object->objectType = IFAPI_KEY_OBJ;
3034         object->misc.key.public = *outPublic;
3035         object->misc.key.private.size = outPrivate->size;
3036         object->misc.key.private.buffer = calloc(1, outPrivate->size);
3037         goto_if_null2( object->misc.key.private.buffer, "Out of memory.", r,
3038                        TSS2_FAPI_RC_MEMORY, error_cleanup);
3039 
3040         object->misc.key.private.buffer = memcpy(&object->misc.key.private.buffer[0],
3041                                                  &outPrivate->buffer[0], outPrivate->size);
3042         object->misc.key.policyInstance = NULL;
3043         object->misc.key.creationData = *creationData;
3044         object->misc.key.creationTicket = *creationTicket;
3045         object->misc.key.description = NULL;
3046         object->misc.key.certificate = NULL;
3047         SAFE_FREE(outPrivate);
3048         SAFE_FREE(creationData);
3049         SAFE_FREE(creationTicket);
3050         SAFE_FREE(creationHash);
3051         if (context->cmd.Key_Create.inSensitive.sensitive.userAuth.size > 0)
3052             object->misc.key.with_auth = TPM2_YES;
3053         else
3054             object->misc.key.with_auth = TPM2_NO;;
3055         r = ifapi_get_name(&outPublic->publicArea, &object->misc.key.name);
3056         goto_if_error(r, "Get key name", error_cleanup);
3057 
3058         if (object->misc.key.public.publicArea.type == TPM2_ALG_RSA)
3059             object->misc.key.signing_scheme = context->cmd.Key_Create.profile->rsa_signing_scheme;
3060         else
3061             object->misc.key.signing_scheme = context->cmd.Key_Create.profile->ecc_signing_scheme;
3062         SAFE_FREE(outPublic);
3063         fallthrough;
3064 
3065     statecase(context->cmd.Key_Create.state, KEY_CREATE_WRITE_PREPARE);
3066         /* Perform esys serialization if necessary */
3067         r = ifapi_esys_serialize_object(context->esys, object);
3068         goto_if_error(r, "Prepare serialization", error_cleanup);
3069 
3070         /* Start writing the NV object to the key store */
3071         r = ifapi_keystore_store_async(&context->keystore, &context->io,
3072                                        context->cmd.Key_Create.keyPath, object);
3073         goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
3074                                   context->cmd.Key_Create.keyPath);
3075         ifapi_cleanup_ifapi_object(object);
3076         fallthrough;
3077 
3078     statecase(context->cmd.Key_Create.state, KEY_CREATE_WRITE);
3079         /* Finish writing the key to the key store */
3080         r = ifapi_keystore_store_finish(&context->keystore, &context->io);
3081         return_try_again(r);
3082         return_if_error_reset_state(r, "write_finish failed");
3083 
3084         if (context->loadKey.auth_object.misc.key.persistent_handle) {
3085             context->cmd.Key_Create.state = KEY_CREATE_INIT;
3086             r = TSS2_RC_SUCCESS;
3087             break;
3088         }
3089         /* Prepare Flushing of key used for authorization */
3090         r = Esys_FlushContext_Async(context->esys, context->loadKey.auth_object.handle);
3091         goto_if_error(r, "Flush parent", error_cleanup);
3092         fallthrough;
3093 
3094     statecase(context->cmd.Key_Create.state, KEY_CREATE_FLUSH);
3095         r = Esys_FlushContext_Finish(context->esys);
3096         try_again_or_error_goto(r, "Flush context", error_cleanup);
3097         fallthrough;
3098 
3099     statecase(context->cmd.Key_Create.state, KEY_CREATE_CLEANUP);
3100         r = ifapi_cleanup_session(context);
3101         try_again_or_error_goto(r, "Cleanup", error_cleanup);
3102 
3103         context->cmd.Key_Create.state = KEY_CREATE_INIT;
3104         r = TSS2_RC_SUCCESS;
3105         break;
3106 
3107     statecasedefault(context->cmd.Key_Create.state);
3108     }
3109 error_cleanup:
3110     free_string_list(context->loadKey.path_list);
3111     SAFE_FREE(outPublic);
3112     SAFE_FREE(outPrivate);
3113     SAFE_FREE(creationData);
3114     SAFE_FREE(creationHash);
3115     SAFE_FREE(creationTicket);
3116     SAFE_FREE(context->cmd.Key_Create.policyPath);
3117     SAFE_FREE(context->cmd.Key_Create.keyPath);
3118     ifapi_cleanup_ifapi_object(object);
3119     ifapi_session_clean(context);
3120     return r;
3121 }
3122 
3123 /** Get signature scheme for key.
3124  *
3125  * If padding is passed the scheme will be derived from paddint otherwise
3126  * the scheme form object will be used.
3127  *
3128  * @param[in] context The FAPI_CONTEXT.
3129  * @param[in] object The internal FAPI object of the key.
3130  * @param[in] padding The strings RSA_SSA or RSA_PSS will be converted
3131  *            into the TSS constants used for the signing scheme.
3132  * @param[in] digest The digest size will be used to determine the hashalg
3133  *            for the signature scheme.
3134  * @param[out] sig_scheme The computed signature scheme.
3135  *
3136  * @retval TSS2_FAPI_RC_BAD_VALUE If the digest size is not appropriate.
3137  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
3138  */
3139 TSS2_RC
ifapi_get_sig_scheme(FAPI_CONTEXT * context,IFAPI_OBJECT * object,char const * padding,TPM2B_DIGEST * digest,TPMT_SIG_SCHEME * sig_scheme)3140 ifapi_get_sig_scheme(
3141     FAPI_CONTEXT *context,
3142     IFAPI_OBJECT *object,
3143     char const *padding,
3144     TPM2B_DIGEST *digest,
3145     TPMT_SIG_SCHEME *sig_scheme)
3146 {
3147     TPMI_ALG_HASH hash_alg;
3148     TSS2_RC r;
3149 
3150     if (padding) {
3151         /* Get hash algorithm from digest size */
3152         r = ifapi_get_hash_alg_for_size(digest->size, &hash_alg);
3153         return_if_error2(r, "Invalid digest size.");
3154 
3155         /* Use scheme object from context */
3156         if (strcasecmp("RSA_SSA", padding) == 0) {
3157             context->Key_Sign.scheme.scheme = TPM2_ALG_RSASSA;
3158             context->Key_Sign.scheme.details.rsassa.hashAlg = hash_alg;
3159         }
3160         if (strcasecmp("RSA_PSS", padding) == 0) {
3161             context->Key_Sign.scheme.scheme = TPM2_ALG_RSAPSS;
3162             context->Key_Sign.scheme.details.rsapss.hashAlg = hash_alg;
3163         }
3164         *sig_scheme = context->Key_Sign.scheme;
3165         return TSS2_RC_SUCCESS;
3166     } else {
3167         /* Use scheme defined for object */
3168         *sig_scheme = object->misc.key.signing_scheme;
3169         /* Get hash algorithm from digest size */
3170         r = ifapi_get_hash_alg_for_size(digest->size, &hash_alg);
3171         return_if_error2(r, "Invalid digest size.");
3172 
3173         sig_scheme->details.any.hashAlg = hash_alg;
3174         return TSS2_RC_SUCCESS;
3175     }
3176 }
3177 
3178 /** State machine for changing the hierarchy authorization.
3179  *
3180  * First it will be tried to set the auth value of the hierarchy with a
3181  * "null" authorization. If this trial is not successful it will be tried to
3182  * authorize the hierarchy via a callback.
3183  * If an not null auth value is passed with_auth is set to yes for the
3184  * object otherwise to no. So for later authorizations it will be clear
3185  * whether null authorization is possible or not.
3186  *
3187  * @param[in] context The FAPI_CONTEXT.
3188  * @param[in] handle The ESAPI handle of the hierarchy.
3189  * @param[in,out] hierarchy_object The internal FAPI representation of a
3190  *                hierarchy.
3191  * @param[in] newAuthValue The new authorization for the hierarchy.
3192  *
3193  * @retval TSS2_RC_SUCCESS on success.
3194  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
3195  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
3196  *         this function needs to be called again.
3197  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
3198  *         operation already pending.
3199  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
3200  *         is not set.
3201  */
3202 TSS2_RC
ifapi_change_auth_hierarchy(FAPI_CONTEXT * context,ESYS_TR handle,IFAPI_OBJECT * hierarchy_object,TPM2B_AUTH * newAuthValue)3203 ifapi_change_auth_hierarchy(
3204     FAPI_CONTEXT *context,
3205     ESYS_TR handle,
3206     IFAPI_OBJECT *hierarchy_object,
3207     TPM2B_AUTH *newAuthValue)
3208 {
3209     TSS2_RC r;
3210 
3211     switch (context->hierarchy_state) {
3212     statecase(context->hierarchy_state, HIERARCHY_CHANGE_AUTH_INIT);
3213         if (newAuthValue->size > 0)
3214             hierarchy_object->misc.hierarchy.with_auth = TPM2_YES;
3215         else
3216             hierarchy_object->misc.hierarchy.with_auth = TPM2_NO;
3217         r = Esys_HierarchyChangeAuth_Async(context->esys,
3218                                            handle,
3219                                            (context->session1
3220                                             && context->session1 != ESYS_TR_NONE) ?
3221                                            context->session1 : ESYS_TR_PASSWORD,
3222                                            ESYS_TR_NONE, ESYS_TR_NONE,
3223                                            newAuthValue);
3224         return_if_error(r, "HierarchyChangeAuth");
3225         fallthrough;
3226 
3227     statecase(context->hierarchy_state, HIERARCHY_CHANGE_AUTH_NULL_AUTH_SENT);
3228         r = Esys_HierarchyChangeAuth_Finish(context->esys);
3229         return_try_again(r);
3230 
3231         if ((r & ~TPM2_RC_N_MASK) != TPM2_RC_BAD_AUTH) {
3232             return_if_error(r, "Hierarchy change auth.");
3233             context->hierarchy_state = HIERARCHY_CHANGE_AUTH_INIT;
3234             LOG_TRACE("success");
3235             return TSS2_RC_SUCCESS;
3236         }
3237 
3238         /* Retry after NULL authorization was not successful */
3239         r = ifapi_set_auth(context, hierarchy_object, "Hierarchy object");
3240         return_if_error(r, "HierarchyChangeAuth");
3241 
3242         r = Esys_HierarchyChangeAuth_Async(context->esys,
3243                                            handle,
3244                                            (context->session1
3245                                             && context->session1 != ESYS_TR_NONE) ?
3246                                            context->session1 : ESYS_TR_PASSWORD,
3247                                            ESYS_TR_NONE, ESYS_TR_NONE,
3248                                            newAuthValue);
3249         return_if_error(r, "HierarchyChangeAuth");
3250         fallthrough;
3251 
3252     statecase(context->hierarchy_state, HIERARCHY_CHANGE_AUTH_AUTH_SENT);
3253         r = Esys_HierarchyChangeAuth_Finish(context->esys);
3254         FAPI_SYNC(r, "Hierarchy change auth.", error);
3255 
3256         context->hierarchy_state = HIERARCHY_CHANGE_AUTH_INIT;
3257         return r;
3258 
3259     statecasedefault(context->hierarchy_state);
3260     }
3261 
3262 error:
3263     return r;
3264 }
3265 
3266 /** State machine for changing the policy of a hierarchy.
3267  *
3268  * Based on a passed policy the policy digest will be computed.
3269  * First it will be tried to set the policy of the hierarchy with a
3270  * "null" authorization. If this trial is not successful it will be tried to
3271  * authorize the hierarchy via a callback.
3272  * If an not null auth value is passed with_auth is set to yes for the
3273  * object otherwise to no. So for later authorizations it will be clear
3274  * whether null authorization is possible or not.
3275  *
3276  * @param[in] context The FAPI_CONTEXT.
3277  * @param[in] handle The ESAPI handle of the hierarchy.
3278  * @param[in,out] hierarchy_object The internal FAPI representation of a
3279  *                hierarchy.
3280  * @param[in] policy The new policy assigned to the hierarchy.
3281  *
3282  * @retval TSS2_RC_SUCCESS on success.
3283  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
3284  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
3285  * @retval TSS2_FAPI_RC_GENERAL_FAILURE If an internal error occurs, which is
3286  *         not covered by other return codes.
3287  * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during policy calculation.
3288  * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the policy
3289  *         store.
3290  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND If an object needed for policy calculation was
3291  *         not found.
3292  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was
3293  *         not successful.
3294  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
3295  *         this function needs to be called again.
3296  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
3297  *         operation already pending.
3298  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
3299  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
3300  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
3301  *         is not set.
3302  */
3303 TSS2_RC
ifapi_change_policy_hierarchy(FAPI_CONTEXT * context,ESYS_TR handle,IFAPI_OBJECT * hierarchy_object,TPMS_POLICY * policy)3304 ifapi_change_policy_hierarchy(
3305     FAPI_CONTEXT *context,
3306     ESYS_TR handle,
3307     IFAPI_OBJECT *hierarchy_object,
3308     TPMS_POLICY *policy)
3309 {
3310     TSS2_RC r;
3311 
3312     switch (context->hierarchy_policy_state) {
3313     statecase(context->hierarchy_policy_state, HIERARCHY_CHANGE_POLICY_INIT);
3314         if (! policy || ! policy->policy) {
3315             /* No policy will be used for hierarchy */
3316             return TSS2_RC_SUCCESS;
3317         }
3318 
3319         context->policy.state = POLICY_INIT;
3320 
3321         /* Calculate the policy digest which will be used as hierarchy policy. */
3322         r = ifapi_calculate_tree(context, NULL, /**< no path needed */
3323                                  policy,
3324                                  context->profiles.default_profile.nameAlg,
3325                                  &context->cmd.Provision.digest_idx,
3326                                  &context->cmd.Provision.hash_size);
3327         goto_if_error(r, "Policy calculation", error);
3328 
3329 
3330         /* Policy data will be stored in the provisioning context. */
3331         context->cmd.Provision.policy_digest.size = context->cmd.Provision.hash_size;
3332         memcpy(&context->cmd.Provision.policy_digest.buffer[0],
3333                &policy
3334                ->policyDigests.digests[context->cmd.Provision.digest_idx].digest,
3335                context->cmd.Provision.hash_size);
3336 
3337         hierarchy_object->policy = policy;
3338         hierarchy_object->misc.hierarchy.authPolicy = context->cmd.Provision.policy_digest;
3339 
3340         /* Prepare the setting of the policy. */
3341         r = Esys_SetPrimaryPolicy_Async(context->esys, handle,
3342                                         ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
3343                                         &context->cmd.Provision.policy_digest,
3344                                         context->profiles.default_profile.nameAlg);
3345         return_if_error(r, "Esys_SetPrimaryPolicy_Async");
3346         fallthrough;
3347 
3348     statecase(context->hierarchy_policy_state, HIERARCHY_CHANGE_POLICY_NULL_AUTH_SENT);
3349         r = Esys_SetPrimaryPolicy_Finish(context->esys);
3350         return_try_again(r);
3351         if ((r & ~TPM2_RC_N_MASK) != TPM2_RC_BAD_AUTH) {
3352             return_if_error(r, "SetPrimaryPolicy_Finish");
3353             context->hierarchy_policy_state = HIERARCHY_CHANGE_POLICY_INIT;
3354             return TSS2_RC_SUCCESS;
3355         }
3356 
3357         /* Retry after NULL authorization was not successful */
3358         ifapi_init_hierarchy_object(hierarchy_object, handle);
3359         r = ifapi_set_auth(context, hierarchy_object, "Hierarchy object");
3360         return_if_error(r, "HierarchyChangePolicy");
3361 
3362         r = Esys_SetPrimaryPolicy_Async(context->esys, handle,
3363                                         context->session1, ESYS_TR_NONE, ESYS_TR_NONE,
3364                                         &context->cmd.Provision.policy_digest,
3365                                         context->profiles.default_profile.nameAlg);
3366         return_if_error(r, "Esys_SetPrimaryPolicy_Async");
3367 
3368         fallthrough;
3369 
3370     statecase(context->hierarchy_policy_state, HIERARCHY_CHANGE_POLICY_AUTH_SENT);
3371         r = Esys_SetPrimaryPolicy_Finish(context->esys);
3372         return_try_again(r);
3373         return_if_error(r, "SetPrimaryPolicy_Finish");
3374 
3375         return TSS2_RC_SUCCESS;
3376 
3377     statecasedefault(context->hierarchy_policy_state);
3378     }
3379 
3380 error:
3381     return r;
3382 }
3383 
3384 /** Allocate ifapi object and store the result in a linked list.
3385  *
3386  * Allocated ifapi objects will be recorded in the context.
3387  *
3388  * @param[in,out] context The FAPI_CONTEXT.
3389  *
3390  * @retval The allocated ifapi object.
3391  * @retval NULL if the object cannot be allocated.
3392  */
3393 IFAPI_OBJECT
ifapi_allocate_object(FAPI_CONTEXT * context)3394 *ifapi_allocate_object(FAPI_CONTEXT *context)
3395 {
3396     NODE_OBJECT_T *node = calloc(1, sizeof(NODE_OBJECT_T));
3397     if (!node)
3398         return NULL;
3399 
3400     node->object = calloc(1, sizeof(IFAPI_OBJECT));
3401     if (!node->object) {
3402         free(node);
3403         return NULL;
3404     }
3405     node->next = context->object_list;
3406     context->object_list = node;
3407     return (IFAPI_OBJECT *) node->object;
3408 }
3409 
3410 /** Free all ifapi objects stored in the context.
3411  *
3412  * @param[in,out] context The FAPI_CONTEXT.
3413  */
3414 void
ifapi_free_objects(FAPI_CONTEXT * context)3415 ifapi_free_objects(FAPI_CONTEXT *context)
3416 {
3417     NODE_OBJECT_T *free_node;
3418     NODE_OBJECT_T *node = context->object_list;
3419     while (node) {
3420         free(node->object);
3421         free_node = node;
3422         node = node->next;
3423         free(free_node);
3424     }
3425 }
3426 
3427 /** Free ifapi a object stored in the context.
3428  *
3429  * @param[in,out] context The FAPI_CONTEXT.
3430  * @param[in,out] object The object which should be removed from the
3431  *                the linked list stored in context.
3432  */
3433 void
ifapi_free_object(FAPI_CONTEXT * context,IFAPI_OBJECT ** object)3434 ifapi_free_object(FAPI_CONTEXT *context, IFAPI_OBJECT **object)
3435 {
3436     NODE_OBJECT_T *node;
3437     NODE_OBJECT_T **update_ptr;
3438 
3439     for (node = context->object_list,
3440              update_ptr = &context->object_list;
3441              node != NULL;
3442          update_ptr = &node->next, node = node->next) {
3443         if (node->object == object) {
3444             *update_ptr = node->next;
3445             SAFE_FREE(node->object);
3446             SAFE_FREE(node);
3447             *object = NULL;
3448             return;
3449         }
3450     }
3451 }
3452 
3453 #define ADD_CAPABILITY_INFO(capability, field, subfield, max_count, property_count) \
3454     if (context->cmd.GetInfo.fetched_data->data.capability.count > max_count - property_count) { \
3455         context->cmd.GetInfo.fetched_data->data.capability.count = max_count - property_count; \
3456     } \
3457 \
3458     memmove(&context->cmd.GetInfo.capability_data->data.capability.field[property_count], \
3459             context->cmd.GetInfo.fetched_data->data.capability.field, \
3460             context->cmd.GetInfo.fetched_data->data.capability.count \
3461             * sizeof(context->cmd.GetInfo.fetched_data->data.capability.field[0]));       \
3462     property_count += context->cmd.GetInfo.fetched_data->data.capability.count; \
3463 \
3464     context->cmd.GetInfo.capability_data->data.capability.count = property_count; \
3465 \
3466     if (more_data && property_count < count \
3467         && context->cmd.GetInfo.fetched_data->data.capability.count) {  \
3468         context->cmd.GetInfo.property \
3469             = context->cmd.GetInfo.capability_data->data. \
3470             capability.field[property_count - 1]subfield + 1;   \
3471     } else { \
3472         more_data = false; \
3473     }
3474 
3475 
3476 /** Prepare the receiving of capability data.
3477  *
3478  * @param[in,out] context The FAPI_CONTEXT.
3479  *
3480  * @retval TSS2_RC_SUCCESS.
3481  */
3482 TPM2_RC
ifapi_capability_init(FAPI_CONTEXT * context)3483 ifapi_capability_init(FAPI_CONTEXT *context)
3484 {
3485     context->cmd.GetInfo.capability_data = NULL;
3486     context->cmd.GetInfo.fetched_data = NULL;
3487 
3488     return TSS2_RC_SUCCESS;
3489 
3490 
3491 }
3492 
3493 /** State machine for receiving TPM capability information.
3494  *
3495  * The state machine shares the state with the FAPI function Fapi_GetInfo.
3496  * context->state == GET_INFO_GET_CAP_MORE signals that more capability data can
3497  * be retrieved.
3498  *
3499  * @param[in,out] context The FAPI_CONTEXT.
3500  * @param[in]     capability The capability to be retrieved.
3501  * @param[in]     count The maximal number of items that should be retrieved.
3502  * @param[out]    capability_data The retrieved capability information.
3503  *
3504  * @retval TSS2_RC_SUCCESS If all capability data is retrieved.
3505  * @retval TSS2_FAPI_RC_TRY_AGAIN if more capability data is available.
3506  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
3507  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
3508  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
3509  *         the function.
3510  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
3511  *         operation already pending.
3512  */
3513 TPM2_RC
ifapi_capability_get(FAPI_CONTEXT * context,TPM2_CAP capability,UINT32 count,TPMS_CAPABILITY_DATA ** capability_data)3514 ifapi_capability_get(FAPI_CONTEXT *context, TPM2_CAP capability,
3515                      UINT32 count, TPMS_CAPABILITY_DATA **capability_data) {
3516 
3517     TPMI_YES_NO more_data;
3518     TSS2_RC r = TSS2_RC_SUCCESS;
3519     ESYS_CONTEXT *ectx = context->esys;
3520 
3521     switch (context->state) {
3522     statecase(context->state, GET_INFO_GET_CAP);
3523         /* fetch capability info */
3524         context->cmd.GetInfo.fetched_data = NULL;
3525         context->cmd.GetInfo.capability_data = NULL;
3526         fallthrough;
3527 
3528     statecase(context->state, GET_INFO_GET_CAP_MORE);
3529         r = Esys_GetCapability_Async(ectx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
3530                                      capability, context->cmd.GetInfo.property,
3531                                      count - context->cmd.GetInfo.property_count);
3532         goto_if_error(r, "Error GetCapability", error_cleanup);
3533         fallthrough;
3534 
3535     statecase(context->state, GET_INFO_WAIT_FOR_CAP);
3536         r = Esys_GetCapability_Finish(ectx, &more_data, &context->cmd.GetInfo.fetched_data);
3537         return_try_again(r);
3538         goto_if_error(r, "Error GetCapability", error_cleanup);
3539 
3540         LOG_TRACE("GetCapability: capability: 0x%x, property: 0x%x", capability,
3541                   context->cmd.GetInfo.property);
3542 
3543         if (context->cmd.GetInfo.fetched_data->capability != capability) {
3544             goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE,
3545                        "TPM returned different capability than requested: 0x%x != 0x%x",
3546                        error_cleanup,
3547                        context->cmd.GetInfo.fetched_data->capability, capability);
3548         }
3549 
3550         if (context->cmd.GetInfo.capability_data == NULL) {
3551             /* reuse the TPM's result structure */
3552             context->cmd.GetInfo.capability_data = context->cmd.GetInfo.fetched_data;
3553 
3554             if (!more_data) {
3555                 /* there won't be another iteration of the loop, just return the result unmodified */
3556                 *capability_data = context->cmd.GetInfo.capability_data;
3557                 return TPM2_RC_SUCCESS;
3558             }
3559         }
3560 
3561         /* append the TPM's results to the initial structure, as long as there is still space left */
3562         switch (capability) {
3563         case TPM2_CAP_ALGS:
3564             ADD_CAPABILITY_INFO(algorithms, algProperties, .alg,
3565                                 TPM2_MAX_CAP_ALGS,
3566                                 context->cmd.GetInfo.property_count);
3567             break;
3568         case TPM2_CAP_HANDLES:
3569             ADD_CAPABILITY_INFO(handles, handle,,
3570                                 TPM2_MAX_CAP_HANDLES,
3571                                 context->cmd.GetInfo.property_count);
3572             break;
3573         case TPM2_CAP_COMMANDS:
3574             ADD_CAPABILITY_INFO(command, commandAttributes,,
3575                                 TPM2_MAX_CAP_CC,
3576                                 context->cmd.GetInfo.property_count);
3577             /* workaround because tpm2-tss does not implement attribute commandIndex for TPMA_CC */
3578             context->cmd.GetInfo.property &= TPMA_CC_COMMANDINDEX_MASK;
3579             break;
3580         case TPM2_CAP_PP_COMMANDS:
3581             ADD_CAPABILITY_INFO(ppCommands, commandCodes,,
3582                                 TPM2_MAX_CAP_CC,
3583                                 context->cmd.GetInfo.property_count);
3584             break;
3585         case TPM2_CAP_AUDIT_COMMANDS:
3586             ADD_CAPABILITY_INFO(auditCommands, commandCodes,,
3587                                 TPM2_MAX_CAP_CC,
3588                                 context->cmd.GetInfo.property_count);
3589             break;
3590         case TPM2_CAP_PCRS:
3591             ADD_CAPABILITY_INFO(assignedPCR, pcrSelections, .hash,
3592                                 TPM2_NUM_PCR_BANKS,
3593                                 context->cmd.GetInfo.property_count);
3594             break;
3595         case TPM2_CAP_TPM_PROPERTIES:
3596             ADD_CAPABILITY_INFO(tpmProperties, tpmProperty, .property,
3597                                 TPM2_MAX_TPM_PROPERTIES,
3598                                 context->cmd.GetInfo.property_count);
3599             break;
3600         case TPM2_CAP_PCR_PROPERTIES:
3601             ADD_CAPABILITY_INFO(pcrProperties, pcrProperty, .tag,
3602                                 TPM2_MAX_PCR_PROPERTIES,
3603                                 context->cmd.GetInfo.property_count);
3604             break;
3605         case TPM2_CAP_ECC_CURVES:
3606             ADD_CAPABILITY_INFO(eccCurves, eccCurves,,
3607                                 TPM2_MAX_ECC_CURVES,
3608                                 context->cmd.GetInfo.property_count);
3609             break;
3610         case TPM2_CAP_VENDOR_PROPERTY:
3611             ADD_CAPABILITY_INFO(intelPttProperty, property,,
3612                                 TPM2_MAX_PTT_PROPERTIES,
3613                                 context->cmd.GetInfo.property_count);
3614             break;
3615         default:
3616             LOG_ERROR("Unsupported capability: 0x%x\n", capability);
3617             if (context->cmd.GetInfo.fetched_data != context->cmd.GetInfo.capability_data) {
3618                 free(context->cmd.GetInfo.fetched_data);
3619             }
3620             free(context->cmd.GetInfo.capability_data);
3621             *capability_data = NULL;
3622             return TSS2_FAPI_RC_BAD_VALUE;
3623         }
3624 
3625         if (context->cmd.GetInfo.fetched_data != context->cmd.GetInfo.capability_data) {
3626             free(context->cmd.GetInfo.fetched_data);
3627         }
3628         *capability_data = context->cmd.GetInfo.capability_data;
3629         break;
3630 
3631     statecasedefault(context->state);
3632     }
3633     if (more_data) {
3634         context->state = GET_INFO_GET_CAP_MORE;
3635         return TSS2_FAPI_RC_TRY_AGAIN;
3636     } else {
3637         context->state = _FAPI_STATE_INIT;
3638         return TSS2_RC_SUCCESS;
3639     }
3640 
3641 error_cleanup:
3642     context->state = _FAPI_STATE_INIT;
3643     SAFE_FREE(context->cmd.GetInfo.capability_data);
3644     SAFE_FREE(context->cmd.GetInfo.fetched_data);
3645     return r;
3646 }
3647 
3648 /** Get certificates stored in NV ram.
3649  *
3650  * The NV handles in the certificate range are determined. The corresponding
3651  * certificates are read out and stored in a linked list.
3652  *
3653  * @param[in,out] context The FAPI_CONTEXT. The sub context for NV reading
3654  *                will be used.
3655  * @param[in] min_handle The first possible handle in the handle range.
3656  * @param[in] max_handle Maximal handle to filter out the handles not in the
3657  *            handle range for certificates.
3658  * @param[out] cert_list The callee allocates linked list of certificates.
3659  *
3660  * @retval TSS2_RC_SUCCESS on success.
3661  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
3662  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
3663  *
3664  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
3665  *         this function needs to be called again.
3666  * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous
3667  *         operation already pending.
3668  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
3669  *         is not set.
3670  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
3671  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
3672  * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the
3673  *         object store.
3674  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
3675  *         was not successful.
3676  */
3677 TSS2_RC
ifapi_get_certificates(FAPI_CONTEXT * context,UINT32 min_handle,UINT32 max_handle,NODE_OBJECT_T ** cert_list)3678 ifapi_get_certificates(
3679     FAPI_CONTEXT *context,
3680     UINT32 min_handle,
3681     UINT32 max_handle,
3682     NODE_OBJECT_T **cert_list)
3683 {
3684     TSS2_RC r;
3685     TPMI_YES_NO moreData;
3686     TPMS_CAPABILITY_DATA **capabilityData = &context->cmd.Provision.capabilityData;
3687     TPM2B_NV_PUBLIC *nvPublic;
3688     uint8_t *cert_data;
3689     size_t cert_size;
3690 
3691     context->cmd.Provision.cert_nv_idx = MIN_EK_CERT_HANDLE;
3692     context->cmd.Provision.capabilityData = NULL;
3693 
3694     switch (context->get_cert_state) {
3695     statecase(context->get_cert_state, GET_CERT_INIT);
3696         *cert_list = NULL;
3697         context->cmd.Provision.cert_idx = 0;
3698         /* Prepare the reading of the capability handles in the certificate range */
3699         r = Esys_GetCapability_Async(context->esys,
3700                                      ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
3701                                      TPM2_CAP_HANDLES, min_handle,
3702                                      TPM2_MAX_CAP_HANDLES);
3703         goto_if_error(r, "Esys_GetCapability_Async", error);
3704         fallthrough;
3705 
3706     statecase(context->get_cert_state, GET_CERT_WAIT_FOR_GET_CAP);
3707         r = Esys_GetCapability_Finish(context->esys, &moreData, capabilityData);
3708         return_try_again(r);
3709         goto_if_error_reset_state(r, "GetCapablity_Finish", error);
3710 
3711         if (!*capabilityData || (*capabilityData)->data.handles.count == 0) {
3712             *cert_list = NULL;
3713             return TSS2_RC_SUCCESS;
3714         }
3715         context->cmd.Provision.capabilityData = *capabilityData;
3716         context->cmd.Provision.cert_count = (*capabilityData)->data.handles.count;
3717 
3718         /* Filter out NV handles beyond the EK cert range */
3719         for (size_t i = 0; i < context->cmd.Provision.cert_count; i++) {
3720             if (context->cmd.Provision.capabilityData->data.handles.handle[i] > max_handle) {
3721                 context->cmd.Provision.cert_count = i;
3722                 break;
3723             }
3724         }
3725         fallthrough;
3726 
3727     statecase(context->get_cert_state, GET_CERT_GET_CERT_NV);
3728         goto_if_null(context->cmd.Provision.capabilityData,
3729             "capabilityData is null", TSS2_FAPI_RC_MEMORY, error);
3730         context->cmd.Provision.cert_nv_idx
3731             = context->cmd.Provision.capabilityData
3732             ->data.handles.handle[context->cmd.Provision.cert_idx];
3733 
3734         ifapi_init_hierarchy_object(&context->nv_cmd.auth_object,
3735                                     TPM2_RH_OWNER);
3736 
3737         r = Esys_TR_FromTPMPublic_Async(context->esys,
3738                                         context->cmd.Provision.cert_nv_idx,
3739                                         ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE);
3740         goto_if_error_reset_state(r, "Esys_TR_FromTPMPublic_Async", error);
3741         fallthrough;
3742 
3743     statecase(context->get_cert_state, GET_CERT_GET_CERT_NV_FINISH);
3744         r = Esys_TR_FromTPMPublic_Finish(context->esys,
3745                                          &context->cmd.Provision.esys_nv_cert_handle);
3746         return_try_again(r);
3747         goto_if_error_reset_state(r, "TR_FromTPMPublic_Finish", error);
3748 
3749         /* Read public to get size of certificate */
3750         r = Esys_NV_ReadPublic_Async(context->esys,
3751                                      context->cmd.Provision.esys_nv_cert_handle,
3752                                      ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE);
3753         goto_if_error_reset_state(r, "Esys_NV_ReadPublic_Async", error);
3754         fallthrough;
3755 
3756     statecase(context->get_cert_state, GET_CERT_GET_CERT_READ_PUBLIC);
3757         r = Esys_NV_ReadPublic_Finish(context->esys,
3758                                       &nvPublic,
3759                                       NULL);
3760         return_try_again(r);
3761         goto_if_error(r, "Error: nv read public", error);
3762 
3763         /* TPMA_NV_NO_DA is set for NV certificate */
3764         context->nv_cmd.nv_object.misc.nv.public.nvPublic.attributes = TPMA_NV_NO_DA;
3765 
3766         /* Prepare context for nv read */
3767         context->nv_cmd.data_idx = 0;
3768         context->nv_cmd.auth_index = ESYS_TR_RH_OWNER;
3769         context->nv_cmd.numBytes = nvPublic->nvPublic.dataSize;
3770         context->nv_cmd.esys_handle = context->cmd.Provision.esys_nv_cert_handle;
3771         context->nv_cmd.offset = 0;
3772         context->cmd.Provision.pem_cert = NULL;
3773         context->session1 = ESYS_TR_PASSWORD;
3774         context->session2 = ESYS_TR_NONE;
3775         context->nv_cmd.nv_read_state = NV_READ_INIT;
3776         memset(&context->nv_cmd.nv_object, 0, sizeof(IFAPI_OBJECT));
3777         Esys_Free(nvPublic);
3778         fallthrough;
3779 
3780     statecase(context->get_cert_state, GET_CERT_READ_CERT);
3781         r = ifapi_nv_read(context, &cert_data, &cert_size);
3782         return_try_again(r);
3783         goto_if_error_reset_state(r, " FAPI NV_Read", error);
3784 
3785         context->cmd.Provision.cert_idx += 1;
3786 
3787         /* Add cert to list */
3788         if (context->cmd.Provision.cert_idx == context->cmd.Provision.cert_count) {
3789             context->get_cert_state = GET_CERT_GET_CERT_NV;
3790 
3791             r = push_object_with_size_to_list(cert_data, cert_size, cert_list);
3792             goto_if_error(r, "Store certificate in list.", error);
3793 
3794             return TSS2_RC_SUCCESS;
3795         } else {
3796             context->get_cert_state = GET_CERT_GET_CERT_NV;
3797         }
3798         break;
3799 
3800     statecasedefault(context->get_cert_state);
3801     }
3802 
3803 error:
3804     ifapi_free_object_list(*cert_list);
3805     return r;
3806 }
3807 
3808 
3809 /** Get description of an internal FAPI object.
3810  *
3811  * @param[in] object The object with the description.
3812  * @param[out] description The callee allocated description.
3813  *
3814  * @retval TSS2_RC_SUCCESS If a copy of the description can be returned
3815  *         or if no description exists.
3816  * @retval TSS2_FAPI_RC_MEMORY in the copy cannot be allocated.
3817  */
3818 TSS2_RC
ifapi_get_description(IFAPI_OBJECT * object,char ** description)3819 ifapi_get_description(IFAPI_OBJECT *object, char **description)
3820 {
3821     char *obj_description = NULL;
3822 
3823     switch (object->objectType) {
3824     case IFAPI_KEY_OBJ:
3825         obj_description = object->misc.key.description;
3826         break;
3827     case IFAPI_NV_OBJ:
3828         obj_description = object->misc.nv.description;
3829         break;
3830     case IFAPI_HIERARCHY_OBJ:
3831         obj_description = object->misc.hierarchy.description;
3832         break;
3833     default:
3834         *description = NULL;
3835         return TSS2_RC_SUCCESS;
3836     }
3837     if (obj_description) {
3838         *description = strdup(obj_description);
3839         check_oom(*description);
3840     } else {
3841         *description = NULL;
3842     }
3843     return TSS2_RC_SUCCESS;
3844 }
3845 
3846 /** Set description of an internal FAPI object.
3847  *
3848  * @param[in,out] object The object with the description.
3849  * @param[in] description The description char strint or NULL.
3850  */
3851 void
ifapi_set_description(IFAPI_OBJECT * object,char * description)3852 ifapi_set_description(IFAPI_OBJECT *object, char *description)
3853 {
3854     switch (object->objectType) {
3855     case IFAPI_KEY_OBJ:
3856         SAFE_FREE(object->misc.key.description);
3857         object->misc.key.description = description;
3858         break;
3859     case IFAPI_NV_OBJ:
3860         SAFE_FREE(object->misc.nv.description);
3861         object->misc.nv.description = description;
3862         break;
3863     case IFAPI_HIERARCHY_OBJ:
3864         SAFE_FREE(object->misc.hierarchy.description);
3865         object->misc.hierarchy.description = description;
3866         break;
3867     default:
3868         LOG_WARNING("Description can't be set");
3869         break;
3870     }
3871 }
3872