• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdint.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "tss2_common.h"
16 
17 #include "ifapi_profiles.h"
18 
19 #include "tpm_json_deserialize.h"
20 #include "ifapi_policy_json_deserialize.h"
21 #include "ifapi_json_deserialize.h"
22 #include "ifapi_helpers.h"
23 #define LOGMODULE fapi
24 #include "util/log.h"
25 #include "util/aux_util.h"
26 #include "ifapi_macros.h"
27 
28 #define PROFILES_EXTENSION ".json"
29 #define PROFILES_PREFIX "P_"
30 
31 static TSS2_RC
32 ifapi_profile_json_deserialize(
33     json_object *jso,
34     IFAPI_PROFILE *profile);
35 
36 static TSS2_RC
37 ifapi_profile_checkpcrs(const TPML_PCR_SELECTION *pcr_profile);
38 
39 /** Initialize the profiles information in the context in an asynchronous way
40  *
41  * Load the profile information from disk, fill the dictionary of loaded profiles and fill
42  * the default profile information into the context.
43  *
44  * Call ifapi_profiles_initialize_finish to complete the operation.
45  *
46  * @param[in,out] profiles The context for the profiles information.
47  * @param[in,out] io The input/output context being used for file I/O.
48  * @param[in] profilesdir The directory to load profile information from.
49  * @param[in] defaultprofile The name of the default profile to use.
50  * @retval TSS2_RC_SUCCESS on success.
51  * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in.
52  * @retval TSS2_FAPI_RC_BAD_VALUE if the profilesdir does not exist or is empty.
53  * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
54  * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
55  */
56 TSS2_RC
ifapi_profiles_initialize_async(IFAPI_PROFILES * profiles,IFAPI_IO * io,const char * profilesdir,const char * defaultprofile)57 ifapi_profiles_initialize_async(
58     IFAPI_PROFILES *profiles,
59     IFAPI_IO *io,
60     const char *profilesdir,
61     const char *defaultprofile)
62 {
63     TSS2_RC r;
64     char *tmp;
65     size_t i, j;
66     check_not_null(profiles);
67     check_not_null(profilesdir);
68 
69     memset(profiles, 0, sizeof(*profiles));
70 
71     profiles->default_name = strdup(defaultprofile);
72     check_oom(profiles->default_name);
73 
74     r = ifapi_io_dirfiles(profilesdir, &profiles->filenames, &profiles->num_profiles);
75     return_if_error(r, "Reading profiles from profiles dir");
76 
77     profiles->profiles = calloc(profiles->num_profiles, sizeof(profiles->profiles[0]));
78     check_oom(profiles->profiles);
79 
80     /* Clean up list of files to only include those that match our filename pattern
81        Expand the filenames with the directory
82        Set the names in the dictionary */
83     for (i = 0; i < profiles->num_profiles; ) {
84         char *ext = strstr(profiles->filenames[i], PROFILES_EXTENSION);
85         /* Path the filename with the expected pattern */
86         if (ext != NULL && strlen(ext) == strlen(PROFILES_EXTENSION) &&
87                 strncmp(profiles->filenames[i], PROFILES_PREFIX, strlen(PROFILES_PREFIX)) == 0)
88         {
89             LOG_TRACE("Using file %s in profiles directory", profiles->filenames[i]);
90             /* Add the profile name */
91             profiles->profiles[i].name = strndup(profiles->filenames[i],
92                                                  ext - profiles->filenames[i]);
93             check_oom(profiles->profiles[i].name);
94             /* Expand the filename with the directory */
95             tmp = profiles->filenames[i];
96             r = ifapi_asprintf(&profiles->filenames[i], "%s/%s", profilesdir, tmp);
97             return_if_error(r, "Out of memory");
98 
99             LOG_TRACE("Added profile-entry %s for file %s based on direntry %s",
100                       profiles->profiles[i].name, profiles->filenames[i], tmp);
101 
102             /* Cleanup and continue */
103             free(tmp);
104             i++;
105         } else {
106             LOG_TRACE("Skipping file %s in profiles directory", profiles->filenames[i]);
107             free(profiles->filenames[i]);
108             profiles->num_profiles -= 1;
109             for (j = i; j < profiles->num_profiles; j++) {
110                 profiles->filenames[j] = profiles->filenames[j + 1];
111             }
112         }
113     }
114 
115     if (profiles->num_profiles == 0) {
116         LOG_ERROR("No files found in profile dir %s that match the pattern %s*%s",
117                   profilesdir, PROFILES_PREFIX, PROFILES_EXTENSION);
118         return TSS2_FAPI_RC_BAD_VALUE;
119     }
120 #ifdef HAVE_REALLOCARRAY
121     profiles->profiles = reallocarray(profiles->profiles, profiles->num_profiles,
122                                       sizeof(profiles->profiles[0]));
123     profiles->filenames = reallocarray(profiles->filenames, profiles->num_profiles,
124                                       sizeof(profiles->filenames[0]));
125 #else /* HAVE_REALLOCARRAY */
126     profiles->profiles = realloc(profiles->profiles, profiles->num_profiles *
127                                       sizeof(profiles->profiles[0]));
128     profiles->filenames = realloc(profiles->filenames, profiles->num_profiles *
129                                       sizeof(profiles->filenames[0]));
130 #endif /* HAVE_REALLOCARRAY */
131     /* No need for OOM checks, since num_profiles may only have become smaller */
132 
133     r = ifapi_io_read_async(io, profiles->filenames[profiles->profiles_idx]);
134     return_if_error2(r, "Reading profile %s", profiles->filenames[profiles->profiles_idx]);
135 
136     return TSS2_RC_SUCCESS;
137 }
138 
139 /** Initialize the profiles information in the context in an asynchronous way
140  *
141  * Call after ifapi_profiles_initialize_async to complete the operation.
142  *
143  * @param[in,out] profiles The context for the profiles information.
144  * @param[in,out] io The input/output context being used for file I/O.
145  * @retval TSS2_RC_SUCCESS on success.
146  * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in.
147  * @retval TSS2_FAPI_RC_BAD_VALUE if a profile could not be loaded.
148  * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable.
149  * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed.
150  * @retval TSS2_FAPI_RC_TRY_AGAIN if the I/O operation is not finished yet and this function needs
151  *         to be called again.
152  */
153 TSS2_RC
ifapi_profiles_initialize_finish(IFAPI_PROFILES * profiles,IFAPI_IO * io)154 ifapi_profiles_initialize_finish(
155     IFAPI_PROFILES *profiles,
156     IFAPI_IO *io)
157 {
158     TSS2_RC r;
159     uint8_t *buffer;
160     size_t i;
161     json_object *jso;
162     check_not_null(profiles);
163     check_not_null(io);
164 
165     r = ifapi_io_read_finish(io, &buffer, NULL);
166     return_if_error(r, "Reading profile failed");
167 
168     jso = json_tokener_parse((char *) buffer);
169     free(buffer);
170     if (jso == NULL) {
171         LOG_ERROR("Failed to parse profile %s", profiles->filenames[profiles->profiles_idx]);
172         return TSS2_FAPI_RC_BAD_VALUE;
173     }
174 
175     r = ifapi_profile_json_deserialize(jso,
176             &profiles->profiles[profiles->profiles_idx].profile);
177     json_object_put(jso);
178     return_if_error2(r, "Parsing profile %s failed",
179                      profiles->filenames[profiles->profiles_idx]);
180 
181     r = ifapi_profile_checkpcrs(&profiles->profiles[profiles->profiles_idx].profile.pcr_selection);
182     return_if_error2(r, "Malformed profile pcr selection for profile %s",
183                      profiles->filenames[profiles->profiles_idx]);
184 
185     profiles->profiles_idx += 1;
186 
187     if (profiles->profiles_idx < profiles->num_profiles) {
188         r = ifapi_io_read_async(io, profiles->filenames[profiles->profiles_idx]);
189         return_if_error2(r, "Reading profile %s", profiles->filenames[profiles->profiles_idx]);
190 
191         return TSS2_FAPI_RC_TRY_AGAIN;
192     }
193 
194     /* Get the data of the default profile into the respective variable */
195     for (i = 0; i < profiles->num_profiles; i++) {
196         if (strcmp(profiles->default_name, profiles->profiles[i].name) == 0) {
197             profiles->default_profile = profiles->profiles[i].profile;
198             break;
199         }
200     }
201     if (i == profiles->num_profiles) {
202         LOG_ERROR("Default profile %s not in the list of loaded profiles",
203                   profiles->default_name);
204         return TSS2_FAPI_RC_BAD_VALUE;
205     }
206 
207     for (i = 0; i < profiles->num_profiles; i++) {
208         free(profiles->filenames[i]);
209     }
210     SAFE_FREE(profiles->filenames);
211 
212     return TSS2_RC_SUCCESS;
213 }
214 
215 /** Return the profile data for a given profile name.
216  *
217  * Returns a (const, not to be free'd) pointer to the profile data for a requested profile.
218  * If a NULL profile is requesten, then the default profile is returned.
219  * If a keypath is passed in, then the prefix is analysed. If that keypath starts with a profile
220  * then this profile is returned. Otherwise the default profile is returned.
221  *
222  * @param[in] profiles The profiles context
223  * @param[in] name The name of the profile or the keypath
224  * @param[out] profile The pointer to the profile data.
225  * @retval TSS2_RC_SUCCESS on success.
226  * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in.
227  * @retval TSS2_FAPI_RC_BAD_VALUE if a profile is not found.
228  */
229 TSS2_RC
ifapi_profiles_get(const IFAPI_PROFILES * profiles,const char * name,const IFAPI_PROFILE ** profile)230 ifapi_profiles_get(
231     const IFAPI_PROFILES *profiles,
232     const char *name,
233     const IFAPI_PROFILE **profile)
234 {
235     check_not_null(profiles);
236     check_not_null(name);
237     check_not_null(profile);
238     char *split;
239     size_t len;
240 
241     /* if no name or nor profile prefix is given, use the default profile */
242     if (!name || strncmp(name, "P_", 2) != 0 || strncmp(name, "/P_", 2) != 0) {
243         *profile = &profiles->default_profile;
244         return TSS2_RC_SUCCESS;
245     }
246 
247     /* Search for path delimiter */
248     split = index(name, IFAPI_FILE_DELIM_CHAR);
249 
250     /* If the path beging with delimiters, skip over those */
251     if (name == split) {
252         name += 1;
253         split = index(name, IFAPI_FILE_DELIM_CHAR);
254     }
255     if (split == NULL)
256         len = strlen(name);
257     else
258         len = split - name;
259 
260     for (size_t i = 0; i < profiles->num_profiles; i++) {
261         if (len == strlen(profiles->profiles[i].name) &&
262                 strncmp(name, profiles->profiles[i].name, len) == 0) {
263             *profile = &profiles->profiles[i].profile;
264             return TSS2_RC_SUCCESS;
265         }
266     }
267     LOG_ERROR("Profile %s not in the list of loaded profiles", name);
268     return TSS2_FAPI_RC_BAD_VALUE;
269 }
270 
271 /** Sanitizes and frees internal data structures of loaded profiles' information.
272  *
273  * @param[in,out] profiles The context for the profiles information.
274  */
275 void
ifapi_profiles_finalize(IFAPI_PROFILES * profiles)276 ifapi_profiles_finalize(
277     IFAPI_PROFILES *profiles)
278 {
279     size_t i;
280     if (!profiles) {
281         LOG_ERROR("Called with bad reference");
282         return;
283     }
284 
285     SAFE_FREE(profiles->default_name);
286 
287     for (i = 0; i < profiles->num_profiles; i++) {
288         IFAPI_PROFILE_ENTRY * entry = &profiles->profiles[i];
289         SAFE_FREE(profiles->profiles[i].name);
290 
291         IFAPI_PROFILE * profile = &entry->profile;
292 
293         SAFE_FREE(profile->srk_template);
294         SAFE_FREE(profile->ek_template);
295 
296         ifapi_cleanup_policy(profile->eh_policy);
297         SAFE_FREE(profile->eh_policy);
298 
299         ifapi_cleanup_policy(profile->ek_policy);
300         SAFE_FREE(profile->ek_policy);
301 
302         ifapi_cleanup_policy(profile->sh_policy);
303         SAFE_FREE(profile->sh_policy);
304     }
305     SAFE_FREE(profiles->profiles);
306 
307     memset(profiles, 0, sizeof(*profiles));
308 }
309 
310 /** Deserialize a IFAPI_KEY_PROFILE json object.
311  *
312  * @param[in]  jso the json object to be deserialized.
313  * @param[out] out the deserialzed binary object.
314  * @retval TSS2_RC_SUCCESS if the function call was a success.
315  * @retval TSS2_FAPI_RC_BAD_VALUE if the json object can't be deserialized.
316  * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
317  * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the
318  *         object store.
319  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
320  */
321 static TSS2_RC
ifapi_profile_json_deserialize(json_object * jso,IFAPI_PROFILE * out)322 ifapi_profile_json_deserialize(
323     json_object *jso,
324     IFAPI_PROFILE *out)
325 {
326     json_object *jso2;
327     TSS2_RC r;
328 
329     const TPMT_SYM_DEF session_symmetric_default = {
330         .algorithm = TPM2_ALG_AES,
331         .keyBits = {.aes = 128},
332         .mode = {.aes = TPM2_ALG_CFB}
333     };
334 
335     LOG_TRACE("call");
336     return_if_null(out, "Bad reference.", TSS2_FAPI_RC_BAD_REFERENCE);
337 
338     if (!ifapi_get_sub_object(jso, "type", &jso2)) {
339         LOG_ERROR("Bad value");
340         return TSS2_FAPI_RC_BAD_VALUE;
341     }
342     r = ifapi_json_TPMI_ALG_PUBLIC_deserialize(jso2, &out->type);
343     return_if_error(r, "BAD VALUE");
344 
345     if (!ifapi_get_sub_object(jso, "srk_template", &jso2)) {
346         LOG_ERROR("Bad value");
347         return TSS2_FAPI_RC_BAD_VALUE;
348     }
349     out->srk_template = strdup(json_object_get_string(jso2));
350     return_if_null(out->srk_template, "Out of memory.", TSS2_FAPI_RC_MEMORY);
351 
352     if (!ifapi_get_sub_object(jso, "ek_template", &jso2)) {
353         LOG_ERROR("Bad value");
354         return TSS2_FAPI_RC_BAD_VALUE;
355     }
356     out->ek_template = strdup(json_object_get_string(jso2));
357     return_if_null(out->ek_template, "Out of memory.", TSS2_FAPI_RC_MEMORY);
358 
359     if (!ifapi_get_sub_object(jso, "ecc_signing_scheme", &jso2)) {
360         memset(&out->ecc_signing_scheme, 0, sizeof(TPMT_SIG_SCHEME));
361     } else {
362         r = ifapi_json_TPMT_SIG_SCHEME_deserialize(jso2, &out->ecc_signing_scheme);
363         return_if_error(r, "BAD VALUE");
364     }
365 
366     if (!ifapi_get_sub_object(jso, "rsa_signing_scheme", &jso2)) {
367         memset(&out->rsa_signing_scheme, 0, sizeof(TPMT_SIG_SCHEME));
368     } else {
369         r = ifapi_json_TPMT_SIG_SCHEME_deserialize(jso2, &out->rsa_signing_scheme);
370         return_if_error(r, "BAD VALUE");
371     }
372 
373     if (!ifapi_get_sub_object(jso, "rsa_decrypt_scheme", &jso2)) {
374         memset(&out->rsa_decrypt_scheme, 0, sizeof(TPMT_RSA_DECRYPT));
375     } else {
376         r = ifapi_json_TPMT_RSA_DECRYPT_deserialize(jso2, &out->rsa_decrypt_scheme);
377         return_if_error(r, "BAD VALUE");
378     }
379 
380     if (!ifapi_get_sub_object(jso, "sym_mode", &jso2)) {
381         LOG_ERROR("Bad value");
382         return TSS2_FAPI_RC_BAD_VALUE;
383     }
384     r = ifapi_json_TPMI_ALG_SYM_MODE_deserialize(jso2, &out->sym_mode);
385     return_if_error(r, "BAD VALUE");
386 
387     if (!ifapi_get_sub_object(jso, "sym_parameters", &jso2)) {
388         LOG_ERROR("Bad value");
389         return TSS2_FAPI_RC_BAD_VALUE;
390     }
391     r = ifapi_json_TPMT_SYM_DEF_OBJECT_deserialize(jso2, &out->sym_parameters);
392     return_if_error(r, "BAD VALUE");
393 
394     if (!ifapi_get_sub_object(jso, "sym_block_size", &jso2)) {
395         LOG_ERROR("Bad value");
396         return TSS2_FAPI_RC_BAD_VALUE;
397     }
398     r = ifapi_json_UINT16_deserialize(jso2, &out->sym_block_size);
399     return_if_error(r, "BAD VALUE");
400 
401     if (!ifapi_get_sub_object(jso, "pcr_selection", &jso2)) {
402         LOG_ERROR("Bad value");
403         return TSS2_FAPI_RC_BAD_VALUE;
404     }
405     r = ifapi_json_TPML_PCR_SELECTION_deserialize(jso2, &out->pcr_selection);
406     return_if_error(r, "BAD VALUE");
407 
408     if (!ifapi_get_sub_object(jso, "nameAlg", &jso2)) {
409         LOG_ERROR("Bad value");
410         return TSS2_FAPI_RC_BAD_VALUE;
411     }
412     r = ifapi_json_TPMI_ALG_HASH_deserialize(jso2, &out->nameAlg);
413     return_if_error(r, "BAD VALUE");
414 
415     if (out->type == TPM2_ALG_RSA) {
416         if (!ifapi_get_sub_object(jso, "exponent", &jso2)) {
417             LOG_ERROR("Bad value");
418             return TSS2_FAPI_RC_BAD_VALUE;
419         }
420         r = ifapi_json_UINT32_deserialize(jso2, &out->exponent);
421         return_if_error(r, "BAD VALUE");
422         if (!ifapi_get_sub_object(jso, "keyBits", &jso2)) {
423             LOG_ERROR("Bad value");
424             return TSS2_FAPI_RC_BAD_VALUE;
425 
426         }
427         r = ifapi_json_TPMI_RSA_KEY_BITS_deserialize(jso2, &out->keyBits);
428         return_if_error(r, "BAD VALUE");
429 
430     } else if (out->type == TPM2_ALG_ECC) {
431         if (!ifapi_get_sub_object(jso, "curveID", &jso2)) {
432             LOG_ERROR("Bad value");
433             return TSS2_FAPI_RC_BAD_VALUE;
434         }
435         r = ifapi_json_TPMI_ECC_CURVE_deserialize(jso2, &out->curveID);
436         return_if_error(r, "BAD VALUE");
437     }
438 
439     if (!ifapi_get_sub_object(jso, "session_symmetric", &jso2)) {
440         out->session_symmetric = session_symmetric_default;
441     } else {
442         r = ifapi_json_TPMT_SYM_DEF_deserialize(jso2, &out->session_symmetric);
443         return_if_error(r, "BAD VALUE");
444     }
445 
446     if (ifapi_get_sub_object(jso, "eh_policy", &jso2)) {
447         out->eh_policy = calloc(1, sizeof(TPMS_POLICY));
448         goto_if_null2(out->eh_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
449                       cleanup);
450 
451         r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->eh_policy);
452         goto_if_error(r, "Deserialize policy.", cleanup);
453     }
454 
455     if (ifapi_get_sub_object(jso, "sh_policy", &jso2)) {
456         out->sh_policy = calloc(1, sizeof(TPMS_POLICY));
457         goto_if_null2(out->sh_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
458                       cleanup);
459 
460         r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->sh_policy);
461         goto_if_error(r, "Deserialize policy.", cleanup);
462     }
463 
464     if (ifapi_get_sub_object(jso, "ek_policy", &jso2)) {
465         out->ek_policy = calloc(1, sizeof(TPMS_POLICY));
466         goto_if_null2(out->ek_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
467                       cleanup);
468 
469         r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->ek_policy);
470         goto_if_error(r, "Deserialize policy.", cleanup);
471     }
472 
473     if (ifapi_get_sub_object(jso, "srk_policy", &jso2)) {
474         out->srk_policy = calloc(1, sizeof(TPMS_POLICY));
475         goto_if_null2(out->srk_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
476                       cleanup);
477 
478         r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->srk_policy);
479         goto_if_error(r, "Deserialize policy.", cleanup);
480     }
481 
482     if (ifapi_get_sub_object(jso, "lockout_policy", &jso2)) {
483         out->lockout_policy = calloc(1, sizeof(TPMS_POLICY));
484         goto_if_null2(out->lockout_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
485                       cleanup);
486 
487         r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->lockout_policy);
488         goto_if_error(r, "Deserialize policy.", cleanup);
489     }
490 
491     if (!ifapi_get_sub_object(jso, "newMaxTries", &jso2)) {
492         out->newMaxTries = 5;
493     } else {
494         r = ifapi_json_UINT32_deserialize(jso2, &out->newMaxTries);
495         return_if_error(r, "BAD VALUE");
496     }
497 
498     if (!ifapi_get_sub_object(jso, "newRecoveryTime", &jso2)) {
499         out->newRecoveryTime = 1000;
500     } else {
501         r = ifapi_json_UINT32_deserialize(jso2, &out->newRecoveryTime);
502         return_if_error(r, "BAD VALUE");
503     }
504 
505     if (!ifapi_get_sub_object(jso, "lockoutRecovery", &jso2)) {
506         out->lockoutRecovery = 1000;
507     } else {
508         r = ifapi_json_UINT32_deserialize(jso2, &out->lockoutRecovery);
509         return_if_error(r, "BAD VALUE");
510     }
511 
512     LOG_TRACE("true");
513     return TSS2_RC_SUCCESS;
514 
515 cleanup:
516     SAFE_FREE(out->eh_policy);
517     return r;
518 }
519 
520 /**
521   * Check whether PCRs with muliple banks are defined in profile.
522   *
523   * This case is not allowed by FAPI.
524   */
525 static TSS2_RC
ifapi_profile_checkpcrs(const TPML_PCR_SELECTION * pcr_profile)526 ifapi_profile_checkpcrs(const TPML_PCR_SELECTION *pcr_profile)
527 {
528     size_t i, j, byte_idx;
529 
530     for (i = 0; i < pcr_profile->count - 1; i++) {
531         for (j = i + 1; j <  pcr_profile->count; j++) {
532             for (byte_idx = 0; byte_idx < 3; byte_idx++) {
533                 /* Check whether a PCR register flag does occur in two different banks. */
534                 if (pcr_profile->pcrSelections[i].pcrSelect[byte_idx] &
535                         pcr_profile->pcrSelections[j].pcrSelect[byte_idx]) {
536                     return_error2(TSS2_FAPI_RC_BAD_VALUE,
537                                   "More than one bank selected for a PCR register.");
538                 }
539             }
540         }
541     }
542     return TSS2_RC_SUCCESS;
543 }
544