/* SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "log.h" #include "tpm2.h" #include "tpm2_capability.h" #define APPEND_CAPABILITY_INFORMATION(capability, field, subfield, max_count) \ if (fetched_data->data.capability.count > max_count - property_count) { \ fetched_data->data.capability.count = max_count - property_count; \ } \ \ memmove(&(*capability_data)->data.capability.field[property_count], \ fetched_data->data.capability.field, \ fetched_data->data.capability.count * sizeof(fetched_data->data.capability.field[0])); \ property_count += fetched_data->data.capability.count; \ \ (*capability_data)->data.capability.count = property_count; \ \ if (more_data && property_count < count && fetched_data->data.capability.count) { \ property = (*capability_data)->data.capability.field[property_count - 1]subfield + 1; \ } else { \ more_data = false; \ } tool_rc tpm2_capability_get(ESYS_CONTEXT *ectx, TPM2_CAP capability, UINT32 property, UINT32 count, TPMS_CAPABILITY_DATA **capability_data) { TPMI_YES_NO more_data; UINT32 property_count = 0; *capability_data = NULL; do { /* fetch capability info */ TPMS_CAPABILITY_DATA *fetched_data = NULL; tool_rc rc = tpm2_get_capability(ectx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, capability, property, count - property_count, &more_data, &fetched_data); LOG_INFO("GetCapability: capability: 0x%x, property: 0x%x", capability, property); if (rc != tool_rc_success) { if (*capability_data) { free(*capability_data); *capability_data = NULL; } return rc; } if (fetched_data->capability != capability) { LOG_ERR("TPM returned different capability than requested: 0x%x != " "0x%x", fetched_data->capability, capability); free(fetched_data); if (*capability_data) { free(*capability_data); *capability_data = NULL; } return tool_rc_general_error; } if (*capability_data == NULL) { /* reuse the TPM's result structure */ *capability_data = fetched_data; if (!more_data) { /* there won't be another iteration of the loop, just return the result unmodified */ return tool_rc_success; } } /* append the TPM's results to the initial structure, as long as there is still space left */ switch (capability) { case TPM2_CAP_ALGS: APPEND_CAPABILITY_INFORMATION(algorithms, algProperties, .alg, TPM2_MAX_CAP_ALGS); break; case TPM2_CAP_HANDLES: APPEND_CAPABILITY_INFORMATION(handles, handle,, TPM2_MAX_CAP_HANDLES); break; case TPM2_CAP_COMMANDS: APPEND_CAPABILITY_INFORMATION(command, commandAttributes,, TPM2_MAX_CAP_CC); /* workaround because tpm2-tss does not implement attribute commandIndex for TPMA_CC */ property &= TPMA_CC_COMMANDINDEX_MASK; break; case TPM2_CAP_PP_COMMANDS: APPEND_CAPABILITY_INFORMATION(ppCommands, commandCodes,, TPM2_MAX_CAP_CC); break; case TPM2_CAP_AUDIT_COMMANDS: APPEND_CAPABILITY_INFORMATION(auditCommands, commandCodes,, TPM2_MAX_CAP_CC); break; case TPM2_CAP_PCRS: APPEND_CAPABILITY_INFORMATION(assignedPCR, pcrSelections, .hash, TPM2_NUM_PCR_BANKS); break; case TPM2_CAP_TPM_PROPERTIES: APPEND_CAPABILITY_INFORMATION(tpmProperties, tpmProperty, .property, TPM2_MAX_TPM_PROPERTIES); break; case TPM2_CAP_PCR_PROPERTIES: APPEND_CAPABILITY_INFORMATION(pcrProperties, pcrProperty, .tag, TPM2_MAX_PCR_PROPERTIES); break; case TPM2_CAP_ECC_CURVES: APPEND_CAPABILITY_INFORMATION(eccCurves, eccCurves,, TPM2_MAX_ECC_CURVES); break; case TPM2_CAP_VENDOR_PROPERTY: APPEND_CAPABILITY_INFORMATION(intelPttProperty, property,, TPM2_MAX_PTT_PROPERTIES); break; default: LOG_ERR("Unsupported capability: 0x%x\n", capability); if (fetched_data != *capability_data) { free(fetched_data); } free(*capability_data); *capability_data = NULL; return tool_rc_general_error; } if (fetched_data != *capability_data) { free(fetched_data); } } while (more_data); return tool_rc_success; } tool_rc tpm2_capability_find_vacant_persistent_handle(ESYS_CONTEXT *ctx, bool is_platform, TPMI_DH_PERSISTENT *vacant) { TPMS_CAPABILITY_DATA *capability_data; bool handle_found = false; tool_rc rc = tpm2_capability_get(ctx, TPM2_CAP_HANDLES, TPM2_PERSISTENT_FIRST, TPM2_MAX_CAP_HANDLES, &capability_data); if (rc != tool_rc_success) { return rc; } UINT32 count = capability_data->data.handles.count; if (count == 0) { /* There aren't any persistent handles, so use the first */ *vacant = is_platform ? TPM2_PLATFORM_PERSISTENT : TPM2_PERSISTENT_FIRST; handle_found = true; } else if (count == TPM2_MAX_CAP_HANDLES) { /* All persistent handles are already in use */ goto out; } else if (count < TPM2_MAX_CAP_HANDLES) { /* * iterate over used handles to ensure we're selecting * the next available handle. * * Platform handles start at a higher hange */ UINT32 i; for (i = is_platform ? TPM2_PLATFORM_PERSISTENT : TPM2_PERSISTENT_FIRST; i <= (UINT32) TPM2_PERSISTENT_LAST; ++i) { bool inuse = false; UINT32 c; for (c = 0; c < count; ++c) { if (capability_data->data.handles.handle[c] == i) { inuse = true; break; } } if (!is_platform && i >= TPM2_PLATFORM_PERSISTENT) { break; } if (!inuse) { *vacant = i; handle_found = true; break; } } } out: free(capability_data); return handle_found ? tool_rc_success : tool_rc_general_error; }