#include #include #include #include "tpm.h" extern UINT8 in_protocol; #define perror(fmt, ...) ({ \ UINTN __perror_ret = 0; \ if (!in_protocol) \ __perror_ret = Print((fmt), ##__VA_ARGS__); \ __perror_ret; \ }) EFI_GUID tpm_guid = EFI_TPM_GUID; EFI_GUID tpm2_guid = EFI_TPM2_GUID; static BOOLEAN tpm_present(efi_tpm_protocol_t *tpm) { EFI_STATUS status; TCG_EFI_BOOT_SERVICE_CAPABILITY caps; UINT32 flags; EFI_PHYSICAL_ADDRESS eventlog, lastevent; caps.Size = (UINT8)sizeof(caps); status = uefi_call_wrapper(tpm->status_check, 5, tpm, &caps, &flags, &eventlog, &lastevent); if (status != EFI_SUCCESS || caps.TPMDeactivatedFlag || !caps.TPMPresentFlag) return FALSE; return TRUE; } static BOOLEAN tpm2_present(efi_tpm2_protocol_t *tpm) { EFI_STATUS status; EFI_TCG2_BOOT_SERVICE_CAPABILITY caps; TREE_BOOT_SERVICE_CAPABILITY *caps_1_0; caps.Size = (UINT8)sizeof(caps); status = uefi_call_wrapper(tpm->get_capability, 2, tpm, &caps); if (status != EFI_SUCCESS) return FALSE; if (caps.StructureVersion.Major == 1 && caps.StructureVersion.Minor == 0) { caps_1_0 = (TREE_BOOT_SERVICE_CAPABILITY *)∩︀ if (caps_1_0->TrEEPresentFlag) return TRUE; } else { if (caps.TPMPresentFlag) return TRUE; } return FALSE; } /* * According to TCG EFI Protocol Specification for TPM 2.0 family, * all events generated after the invocation of EFI_TCG2_GET_EVENT_LOG * shall be stored in an instance of an EFI_CONFIGURATION_TABLE aka * EFI TCG 2.0 final events table. Hence, it is necessary to trigger the * internal switch through calling get_event_log() in order to allow * to retrieve the logs from OS runtime. */ static EFI_STATUS trigger_tcg2_final_events_table(efi_tpm2_protocol_t *tpm2) { EFI_PHYSICAL_ADDRESS start; EFI_PHYSICAL_ADDRESS end; BOOLEAN truncated; return uefi_call_wrapper(tpm2->get_event_log, 5, tpm2, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, &start, &end, &truncated); } EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr, const CHAR8 *description) { EFI_STATUS status; efi_tpm_protocol_t *tpm; efi_tpm2_protocol_t *tpm2; status = LibLocateProtocol(&tpm2_guid, (VOID **)&tpm2); /* TPM 2.0 */ if (status == EFI_SUCCESS) { EFI_TCG2_EVENT *event; if (!tpm2_present(tpm2)) return EFI_SUCCESS; status = trigger_tcg2_final_events_table(tpm2); if (EFI_ERROR(status)) { perror(L"Unable to trigger tcg2 final events table: %r\n", status); return status; } event = AllocatePool(sizeof(*event) + strlen(description) + 1); if (!event) { perror(L"Unable to allocate event structure\n"); return EFI_OUT_OF_RESOURCES; } event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); event->Header.HeaderVersion = 1; event->Header.PCRIndex = pcr; event->Header.EventType = 0x0d; event->Size = sizeof(*event) - sizeof(event->Event) + strlen(description) + 1; memcpy(event->Event, description, strlen(description) + 1); status = uefi_call_wrapper(tpm2->hash_log_extend_event, 5, tpm2, 0, buf, (UINT64) size, event); FreePool(event); return status; } else { TCG_PCR_EVENT *event; UINT32 algorithm, eventnum = 0; EFI_PHYSICAL_ADDRESS lastevent; status = LibLocateProtocol(&tpm_guid, (VOID **)&tpm); if (status != EFI_SUCCESS) return EFI_SUCCESS; if (!tpm_present(tpm)) return EFI_SUCCESS; event = AllocatePool(sizeof(*event) + strlen(description) + 1); if (!event) { perror(L"Unable to allocate event structure\n"); return EFI_OUT_OF_RESOURCES; } event->PCRIndex = pcr; event->EventType = 0x0d; event->EventSize = strlen(description) + 1; algorithm = 0x00000004; status = uefi_call_wrapper(tpm->log_extend_event, 7, tpm, buf, (UINT64)size, algorithm, event, &eventnum, &lastevent); FreePool(event); return status; } return EFI_SUCCESS; }