| /* SPDX-License-Identifier: BSD-2-Clause */ |
| /******************************************************************************* |
| * Copyright 2018-2019, Fraunhofer SIT sponsored by Infineon Technologies AG |
| * All rights reserved. |
| *******************************************************************************/ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "tss2_common.h" |
| |
| #include "ifapi_profiles.h" |
| |
| #include "tpm_json_deserialize.h" |
| #include "ifapi_policy_json_deserialize.h" |
| #include "ifapi_json_deserialize.h" |
| #include "ifapi_helpers.h" |
| #define LOGMODULE fapi |
| #include "util/log.h" |
| #include "util/aux_util.h" |
| #include "ifapi_macros.h" |
| |
| #define PROFILES_EXTENSION ".json" |
| #define PROFILES_PREFIX "P_" |
| |
| static TSS2_RC |
| ifapi_profile_json_deserialize( |
| json_object *jso, |
| IFAPI_PROFILE *profile); |
| |
| static TSS2_RC |
| ifapi_profile_checkpcrs(const TPML_PCR_SELECTION *pcr_profile); |
| |
| /** Initialize the profiles information in the context in an asynchronous way |
| * |
| * Load the profile information from disk, fill the dictionary of loaded profiles and fill |
| * the default profile information into the context. |
| * |
| * Call ifapi_profiles_initialize_finish to complete the operation. |
| * |
| * @param[in,out] profiles The context for the profiles information. |
| * @param[in,out] io The input/output context being used for file I/O. |
| * @param[in] profilesdir The directory to load profile information from. |
| * @param[in] defaultprofile The name of the default profile to use. |
| * @retval TSS2_RC_SUCCESS on success. |
| * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in. |
| * @retval TSS2_FAPI_RC_BAD_VALUE if the profilesdir does not exist or is empty. |
| * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable. |
| * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed. |
| */ |
| TSS2_RC |
| ifapi_profiles_initialize_async( |
| IFAPI_PROFILES *profiles, |
| IFAPI_IO *io, |
| const char *profilesdir, |
| const char *defaultprofile) |
| { |
| TSS2_RC r; |
| char *tmp; |
| size_t i, j; |
| check_not_null(profiles); |
| check_not_null(profilesdir); |
| |
| memset(profiles, 0, sizeof(*profiles)); |
| |
| profiles->default_name = strdup(defaultprofile); |
| check_oom(profiles->default_name); |
| |
| r = ifapi_io_dirfiles(profilesdir, &profiles->filenames, &profiles->num_profiles); |
| return_if_error(r, "Reading profiles from profiles dir"); |
| |
| profiles->profiles = calloc(profiles->num_profiles, sizeof(profiles->profiles[0])); |
| check_oom(profiles->profiles); |
| |
| /* Clean up list of files to only include those that match our filename pattern |
| Expand the filenames with the directory |
| Set the names in the dictionary */ |
| for (i = 0; i < profiles->num_profiles; ) { |
| char *ext = strstr(profiles->filenames[i], PROFILES_EXTENSION); |
| /* Path the filename with the expected pattern */ |
| if (ext != NULL && strlen(ext) == strlen(PROFILES_EXTENSION) && |
| strncmp(profiles->filenames[i], PROFILES_PREFIX, strlen(PROFILES_PREFIX)) == 0) |
| { |
| LOG_TRACE("Using file %s in profiles directory", profiles->filenames[i]); |
| /* Add the profile name */ |
| profiles->profiles[i].name = strndup(profiles->filenames[i], |
| ext - profiles->filenames[i]); |
| check_oom(profiles->profiles[i].name); |
| /* Expand the filename with the directory */ |
| tmp = profiles->filenames[i]; |
| r = ifapi_asprintf(&profiles->filenames[i], "%s/%s", profilesdir, tmp); |
| return_if_error(r, "Out of memory"); |
| |
| LOG_TRACE("Added profile-entry %s for file %s based on direntry %s", |
| profiles->profiles[i].name, profiles->filenames[i], tmp); |
| |
| /* Cleanup and continue */ |
| free(tmp); |
| i++; |
| } else { |
| LOG_TRACE("Skipping file %s in profiles directory", profiles->filenames[i]); |
| free(profiles->filenames[i]); |
| profiles->num_profiles -= 1; |
| for (j = i; j < profiles->num_profiles; j++) { |
| profiles->filenames[j] = profiles->filenames[j + 1]; |
| } |
| } |
| } |
| |
| if (profiles->num_profiles == 0) { |
| LOG_ERROR("No files found in profile dir %s that match the pattern %s*%s", |
| profilesdir, PROFILES_PREFIX, PROFILES_EXTENSION); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| #ifdef HAVE_REALLOCARRAY |
| profiles->profiles = reallocarray(profiles->profiles, profiles->num_profiles, |
| sizeof(profiles->profiles[0])); |
| profiles->filenames = reallocarray(profiles->filenames, profiles->num_profiles, |
| sizeof(profiles->filenames[0])); |
| #else /* HAVE_REALLOCARRAY */ |
| profiles->profiles = realloc(profiles->profiles, profiles->num_profiles * |
| sizeof(profiles->profiles[0])); |
| profiles->filenames = realloc(profiles->filenames, profiles->num_profiles * |
| sizeof(profiles->filenames[0])); |
| #endif /* HAVE_REALLOCARRAY */ |
| /* No need for OOM checks, since num_profiles may only have become smaller */ |
| |
| r = ifapi_io_read_async(io, profiles->filenames[profiles->profiles_idx]); |
| return_if_error2(r, "Reading profile %s", profiles->filenames[profiles->profiles_idx]); |
| |
| return TSS2_RC_SUCCESS; |
| } |
| |
| /** Initialize the profiles information in the context in an asynchronous way |
| * |
| * Call after ifapi_profiles_initialize_async to complete the operation. |
| * |
| * @param[in,out] profiles The context for the profiles information. |
| * @param[in,out] io The input/output context being used for file I/O. |
| * @retval TSS2_RC_SUCCESS on success. |
| * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in. |
| * @retval TSS2_FAPI_RC_BAD_VALUE if a profile could not be loaded. |
| * @retval TSS2_FAPI_RC_IO_ERROR if creation of log_dir failed or log_dir is not writable. |
| * @retval TSS2_FAPI_RC_MEMORY if memory allocation failed. |
| * @retval TSS2_FAPI_RC_TRY_AGAIN if the I/O operation is not finished yet and this function needs |
| * to be called again. |
| */ |
| TSS2_RC |
| ifapi_profiles_initialize_finish( |
| IFAPI_PROFILES *profiles, |
| IFAPI_IO *io) |
| { |
| TSS2_RC r; |
| uint8_t *buffer; |
| size_t i; |
| json_object *jso; |
| check_not_null(profiles); |
| check_not_null(io); |
| |
| r = ifapi_io_read_finish(io, &buffer, NULL); |
| return_if_error(r, "Reading profile failed"); |
| |
| jso = json_tokener_parse((char *) buffer); |
| free(buffer); |
| if (jso == NULL) { |
| LOG_ERROR("Failed to parse profile %s", profiles->filenames[profiles->profiles_idx]); |
| r = TSS2_FAPI_RC_BAD_VALUE; |
| goto error; |
| } |
| |
| r = ifapi_profile_json_deserialize(jso, |
| &profiles->profiles[profiles->profiles_idx].profile); |
| json_object_put(jso); |
| goto_if_error2(r, "Parsing profile %s failed", error, |
| profiles->filenames[profiles->profiles_idx]); |
| |
| r = ifapi_profile_checkpcrs(&profiles->profiles[profiles->profiles_idx].profile.pcr_selection); |
| goto_if_error2(r, "Malformed profile pcr selection for profile %s", error, |
| profiles->filenames[profiles->profiles_idx]); |
| |
| profiles->profiles_idx += 1; |
| |
| if (profiles->profiles_idx < profiles->num_profiles) { |
| r = ifapi_io_read_async(io, profiles->filenames[profiles->profiles_idx]); |
| goto_if_error2(r, "Reading profile %s", error, |
| profiles->filenames[profiles->profiles_idx]); |
| |
| return TSS2_FAPI_RC_TRY_AGAIN; |
| } |
| |
| /* Get the data of the default profile into the respective variable */ |
| for (i = 0; i < profiles->num_profiles; i++) { |
| if (strcmp(profiles->default_name, profiles->profiles[i].name) == 0) { |
| profiles->default_profile = profiles->profiles[i].profile; |
| break; |
| } |
| } |
| if (i == profiles->num_profiles) { |
| LOG_ERROR("Default profile %s not in the list of loaded profiles", |
| profiles->default_name); |
| r = TSS2_FAPI_RC_BAD_VALUE; |
| goto error; |
| } |
| |
| for (i = 0; i < profiles->num_profiles; i++) { |
| free(profiles->filenames[i]); |
| } |
| SAFE_FREE(profiles->filenames); |
| |
| return TSS2_RC_SUCCESS; |
| |
| error: |
| for (i = 0; i < profiles->num_profiles; i++) { |
| SAFE_FREE(profiles->filenames[i]); |
| } |
| SAFE_FREE(profiles->filenames); |
| ifapi_profiles_finalize(profiles); |
| return r; |
| } |
| |
| /** Return the profile data for a given profile name. |
| * |
| * Returns a (const, not to be free'd) pointer to the profile data for a requested profile. |
| * If a NULL profile is requesten, then the default profile is returned. |
| * If a keypath is passed in, then the prefix is analysed. If that keypath starts with a profile |
| * then this profile is returned. Otherwise the default profile is returned. |
| * |
| * @param[in] profiles The profiles context |
| * @param[in] name The name of the profile or the keypath |
| * @param[out] profile The pointer to the profile data. |
| * @retval TSS2_RC_SUCCESS on success. |
| * @retval TSS2_FAPI_RC_BAD_REFERENCE if NULL pointers were passed in. |
| * @retval TSS2_FAPI_RC_BAD_VALUE if a profile is not found. |
| */ |
| TSS2_RC |
| ifapi_profiles_get( |
| const IFAPI_PROFILES *profiles, |
| const char *name, |
| const IFAPI_PROFILE **profile) |
| { |
| check_not_null(profiles); |
| check_not_null(name); |
| check_not_null(profile); |
| char *split; |
| size_t len; |
| |
| /* if no name or nor profile prefix is given, use the default profile */ |
| if (!name || strncmp(name, "P_", 2) != 0 || strncmp(name, "/P_", 2) != 0) { |
| *profile = &profiles->default_profile; |
| return TSS2_RC_SUCCESS; |
| } |
| |
| /* Search for path delimiter */ |
| split = index(name, IFAPI_FILE_DELIM_CHAR); |
| |
| /* If the path beging with delimiters, skip over those */ |
| if (name == split) { |
| name += 1; |
| split = index(name, IFAPI_FILE_DELIM_CHAR); |
| } |
| if (split == NULL) |
| len = strlen(name); |
| else |
| len = split - name; |
| |
| for (size_t i = 0; i < profiles->num_profiles; i++) { |
| if (len == strlen(profiles->profiles[i].name) && |
| strncmp(name, profiles->profiles[i].name, len) == 0) { |
| *profile = &profiles->profiles[i].profile; |
| return TSS2_RC_SUCCESS; |
| } |
| } |
| LOG_ERROR("Profile %s not in the list of loaded profiles", name); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| |
| /** Sanitizes and frees internal data structures of loaded profiles' information. |
| * |
| * @param[in,out] profiles The context for the profiles information. |
| */ |
| void |
| ifapi_profiles_finalize( |
| IFAPI_PROFILES *profiles) |
| { |
| size_t i; |
| if (!profiles) { |
| LOG_ERROR("Called with bad reference"); |
| return; |
| } |
| |
| SAFE_FREE(profiles->default_name); |
| |
| for (i = 0; i < profiles->num_profiles; i++) { |
| IFAPI_PROFILE_ENTRY * entry = &profiles->profiles[i]; |
| SAFE_FREE(profiles->profiles[i].name); |
| |
| IFAPI_PROFILE * profile = &entry->profile; |
| |
| SAFE_FREE(profile->srk_template); |
| SAFE_FREE(profile->ek_template); |
| |
| SAFE_FREE(profile->srk_description); |
| SAFE_FREE(profile->ek_description); |
| |
| ifapi_cleanup_policy(profile->eh_policy); |
| SAFE_FREE(profile->eh_policy); |
| |
| ifapi_cleanup_policy(profile->ek_policy); |
| SAFE_FREE(profile->ek_policy); |
| |
| ifapi_cleanup_policy(profile->sh_policy); |
| SAFE_FREE(profile->sh_policy); |
| } |
| SAFE_FREE(profiles->profiles); |
| |
| memset(profiles, 0, sizeof(*profiles)); |
| } |
| |
| /** Deserialize a IFAPI_KEY_PROFILE json object. |
| * |
| * @param[in] jso the json object to be deserialized. |
| * @param[out] out the deserialzed binary object. |
| * @retval TSS2_RC_SUCCESS if the function call was a success. |
| * @retval TSS2_FAPI_RC_BAD_VALUE if the json object can't be deserialized. |
| * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed. |
| * @retval TSS2_FAPI_RC_IO_ERROR if an error occurred while accessing the |
| * object store. |
| * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. |
| */ |
| static TSS2_RC |
| ifapi_profile_json_deserialize( |
| json_object *jso, |
| IFAPI_PROFILE *out) |
| { |
| json_object *jso2; |
| TSS2_RC r; |
| |
| const TPMT_SYM_DEF session_symmetric_default = { |
| .algorithm = TPM2_ALG_AES, |
| .keyBits = {.aes = 128}, |
| .mode = {.aes = TPM2_ALG_CFB} |
| }; |
| |
| LOG_TRACE("call"); |
| memset(out, 0, sizeof(IFAPI_PROFILE)); |
| return_if_null(out, "Bad reference.", TSS2_FAPI_RC_BAD_REFERENCE); |
| |
| if (!ifapi_get_sub_object(jso, "type", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_TPMI_ALG_PUBLIC_deserialize(jso2, &out->type); |
| return_if_error(r, "BAD VALUE"); |
| |
| if (!ifapi_get_sub_object(jso, "srk_template", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| out->srk_template = strdup(json_object_get_string(jso2)); |
| return_if_null(out->srk_template, "Out of memory.", TSS2_FAPI_RC_MEMORY); |
| |
| if (!ifapi_get_sub_object(jso, "srk_description", &jso2)) { |
| out->srk_description = NULL; |
| } else { |
| out->srk_description = strdup(json_object_get_string(jso2)); |
| return_if_null(out->srk_description, "Out of memory.", TSS2_FAPI_RC_MEMORY); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "ek_template", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| out->ek_template = strdup(json_object_get_string(jso2)); |
| return_if_null(out->ek_template, "Out of memory.", TSS2_FAPI_RC_MEMORY); |
| |
| if (!ifapi_get_sub_object(jso, "ek_description", &jso2)) { |
| out->ek_description = NULL; |
| } else { |
| out->ek_description = strdup(json_object_get_string(jso2)); |
| return_if_null(out->ek_description, "Out of memory.", TSS2_FAPI_RC_MEMORY); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "ecc_signing_scheme", &jso2)) { |
| memset(&out->ecc_signing_scheme, 0, sizeof(TPMT_SIG_SCHEME)); |
| } else { |
| r = ifapi_json_TPMT_SIG_SCHEME_deserialize(jso2, &out->ecc_signing_scheme); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "rsa_signing_scheme", &jso2)) { |
| memset(&out->rsa_signing_scheme, 0, sizeof(TPMT_SIG_SCHEME)); |
| } else { |
| r = ifapi_json_TPMT_SIG_SCHEME_deserialize(jso2, &out->rsa_signing_scheme); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "rsa_decrypt_scheme", &jso2)) { |
| memset(&out->rsa_decrypt_scheme, 0, sizeof(TPMT_RSA_DECRYPT)); |
| } else { |
| r = ifapi_json_TPMT_RSA_DECRYPT_deserialize(jso2, &out->rsa_decrypt_scheme); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "sym_mode", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_TPMI_ALG_SYM_MODE_deserialize(jso2, &out->sym_mode); |
| return_if_error(r, "BAD VALUE"); |
| |
| if (!ifapi_get_sub_object(jso, "sym_parameters", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_TPMT_SYM_DEF_OBJECT_deserialize(jso2, &out->sym_parameters); |
| return_if_error(r, "BAD VALUE"); |
| |
| if (!ifapi_get_sub_object(jso, "sym_block_size", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_UINT16_deserialize(jso2, &out->sym_block_size); |
| return_if_error(r, "BAD VALUE"); |
| |
| if (!ifapi_get_sub_object(jso, "pcr_selection", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_TPML_PCR_SELECTION_deserialize(jso2, &out->pcr_selection); |
| return_if_error(r, "BAD VALUE"); |
| |
| if (!ifapi_get_sub_object(jso, "nameAlg", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_TPMI_ALG_HASH_deserialize(jso2, &out->nameAlg); |
| return_if_error(r, "BAD VALUE"); |
| |
| if (out->type == TPM2_ALG_RSA) { |
| if (!ifapi_get_sub_object(jso, "exponent", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_UINT32_deserialize(jso2, &out->exponent); |
| return_if_error(r, "BAD VALUE"); |
| if (!ifapi_get_sub_object(jso, "keyBits", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| |
| } |
| r = ifapi_json_TPMI_RSA_KEY_BITS_deserialize(jso2, &out->keyBits); |
| return_if_error(r, "BAD VALUE"); |
| |
| } else if (out->type == TPM2_ALG_ECC) { |
| if (!ifapi_get_sub_object(jso, "curveID", &jso2)) { |
| LOG_ERROR("Bad value"); |
| return TSS2_FAPI_RC_BAD_VALUE; |
| } |
| r = ifapi_json_TPMI_ECC_CURVE_deserialize(jso2, &out->curveID); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "session_symmetric", &jso2)) { |
| out->session_symmetric = session_symmetric_default; |
| } else { |
| r = ifapi_json_TPMT_SYM_DEF_deserialize(jso2, &out->session_symmetric); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| if (ifapi_get_sub_object(jso, "eh_policy", &jso2)) { |
| out->eh_policy = calloc(1, sizeof(TPMS_POLICY)); |
| goto_if_null2(out->eh_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, |
| cleanup); |
| |
| r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->eh_policy); |
| goto_if_error(r, "Deserialize policy.", cleanup); |
| } |
| |
| if (ifapi_get_sub_object(jso, "sh_policy", &jso2)) { |
| out->sh_policy = calloc(1, sizeof(TPMS_POLICY)); |
| goto_if_null2(out->sh_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, |
| cleanup); |
| |
| r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->sh_policy); |
| goto_if_error(r, "Deserialize policy.", cleanup); |
| } |
| |
| if (ifapi_get_sub_object(jso, "ek_policy", &jso2)) { |
| out->ek_policy = calloc(1, sizeof(TPMS_POLICY)); |
| goto_if_null2(out->ek_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, |
| cleanup); |
| |
| r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->ek_policy); |
| goto_if_error(r, "Deserialize policy.", cleanup); |
| } |
| |
| if (ifapi_get_sub_object(jso, "srk_policy", &jso2)) { |
| out->srk_policy = calloc(1, sizeof(TPMS_POLICY)); |
| goto_if_null2(out->srk_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, |
| cleanup); |
| |
| r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->srk_policy); |
| goto_if_error(r, "Deserialize policy.", cleanup); |
| } |
| |
| if (ifapi_get_sub_object(jso, "lockout_policy", &jso2)) { |
| out->lockout_policy = calloc(1, sizeof(TPMS_POLICY)); |
| goto_if_null2(out->lockout_policy, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, |
| cleanup); |
| |
| r = ifapi_json_TPMS_POLICY_deserialize(jso2, out->lockout_policy); |
| goto_if_error(r, "Deserialize policy.", cleanup); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "newMaxTries", &jso2)) { |
| out->newMaxTries = 5; |
| } else { |
| r = ifapi_json_UINT32_deserialize(jso2, &out->newMaxTries); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "newRecoveryTime", &jso2)) { |
| out->newRecoveryTime = 1000; |
| } else { |
| r = ifapi_json_UINT32_deserialize(jso2, &out->newRecoveryTime); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| if (!ifapi_get_sub_object(jso, "lockoutRecovery", &jso2)) { |
| out->lockoutRecovery = 1000; |
| } else { |
| r = ifapi_json_UINT32_deserialize(jso2, &out->lockoutRecovery); |
| return_if_error(r, "BAD VALUE"); |
| } |
| |
| LOG_TRACE("true"); |
| return TSS2_RC_SUCCESS; |
| |
| cleanup: |
| SAFE_FREE(out->eh_policy); |
| return r; |
| } |
| |
| /** |
| * Check whether PCRs with muliple banks are defined in profile. |
| * |
| * This case is not allowed by FAPI. |
| */ |
| static TSS2_RC |
| ifapi_profile_checkpcrs(const TPML_PCR_SELECTION *pcr_profile) |
| { |
| size_t i, j, byte_idx; |
| |
| for (i = 0; i < pcr_profile->count - 1; i++) { |
| for (j = i + 1; j < pcr_profile->count; j++) { |
| for (byte_idx = 0; byte_idx < 3; byte_idx++) { |
| /* Check whether a PCR register flag does occur in two different banks. */ |
| if (pcr_profile->pcrSelections[i].pcrSelect[byte_idx] & |
| pcr_profile->pcrSelections[j].pcrSelect[byte_idx]) { |
| return_error2(TSS2_FAPI_RC_BAD_VALUE, |
| "More than one bank selected for a PCR register."); |
| } |
| } |
| } |
| } |
| return TSS2_RC_SUCCESS; |
| } |