/* SPDX-License-Identifier: LGPL-2.1+ */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * */ #if ENABLE_TPM #include #include #include "measure.h" #define EFI_TCG_PROTOCOL_GUID { 0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd} } typedef struct _TCG_VERSION { UINT8 Major; UINT8 Minor; UINT8 RevMajor; UINT8 RevMinor; } TCG_VERSION; typedef struct tdEFI_TCG2_VERSION { UINT8 Major; UINT8 Minor; } EFI_TCG2_VERSION; typedef struct _TCG_BOOT_SERVICE_CAPABILITY { UINT8 Size; struct _TCG_VERSION StructureVersion; struct _TCG_VERSION ProtocolSpecVersion; UINT8 HashAlgorithmBitmap; BOOLEAN TPMPresentFlag; BOOLEAN TPMDeactivatedFlag; } TCG_BOOT_SERVICE_CAPABILITY; typedef struct tdTREE_BOOT_SERVICE_CAPABILITY { UINT8 Size; EFI_TCG2_VERSION StructureVersion; EFI_TCG2_VERSION ProtocolVersion; UINT32 HashAlgorithmBitmap; UINT32 SupportedEventLogs; BOOLEAN TrEEPresentFlag; UINT16 MaxCommandSize; UINT16 MaxResponseSize; UINT32 ManufacturerID; } TREE_BOOT_SERVICE_CAPABILITY; typedef UINT32 TCG_ALGORITHM_ID; #define TCG_ALG_SHA 0x00000004 // The SHA1 algorithm #define SHA1_DIGEST_SIZE 20 typedef struct _TCG_DIGEST { UINT8 Digest[SHA1_DIGEST_SIZE]; } TCG_DIGEST; #define EV_IPL 13 typedef struct _TCG_PCR_EVENT { UINT32 PCRIndex; UINT32 EventType; struct _TCG_DIGEST digest; UINT32 EventSize; UINT8 Event[1]; } TCG_PCR_EVENT; INTERFACE_DECL(_EFI_TCG); typedef EFI_STATUS(EFIAPI * EFI_TCG_STATUS_CHECK) (IN struct _EFI_TCG * This, OUT struct _TCG_BOOT_SERVICE_CAPABILITY * ProtocolCapability, OUT UINT32 * TCGFeatureFlags, OUT EFI_PHYSICAL_ADDRESS * EventLogLocation, OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry); typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_ALL) (IN struct _EFI_TCG * This, IN UINT8 * HashData, IN UINT64 HashDataLen, IN TCG_ALGORITHM_ID AlgorithmId, IN OUT UINT64 * HashedDataLen, IN OUT UINT8 ** HashedDataResult); typedef EFI_STATUS(EFIAPI * EFI_TCG_LOG_EVENT) (IN struct _EFI_TCG * This, IN struct _TCG_PCR_EVENT * TCGLogData, IN OUT UINT32 * EventNumber, IN UINT32 Flags); typedef EFI_STATUS(EFIAPI * EFI_TCG_PASS_THROUGH_TO_TPM) (IN struct _EFI_TCG * This, IN UINT32 TpmInputParameterBlockSize, IN UINT8 * TpmInputParameterBlock, IN UINT32 TpmOutputParameterBlockSize, IN UINT8 * TpmOutputParameterBlock); typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_LOG_EXTEND_EVENT) (IN struct _EFI_TCG * This, IN EFI_PHYSICAL_ADDRESS HashData, IN UINT64 HashDataLen, IN TCG_ALGORITHM_ID AlgorithmId, IN struct _TCG_PCR_EVENT * TCGLogData, IN OUT UINT32 * EventNumber, OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry); typedef struct _EFI_TCG { EFI_TCG_STATUS_CHECK StatusCheck; EFI_TCG_HASH_ALL HashAll; EFI_TCG_LOG_EVENT LogEvent; EFI_TCG_PASS_THROUGH_TO_TPM PassThroughToTPM; EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; } EFI_TCG; #define EFI_TCG2_PROTOCOL_GUID {0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }} typedef struct tdEFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL; typedef UINT32 EFI_TCG2_EVENT_LOG_BITMAP; typedef UINT32 EFI_TCG2_EVENT_LOG_FORMAT; typedef UINT32 EFI_TCG2_EVENT_ALGORITHM_BITMAP; #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x00000001 #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002 typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY { UINT8 Size; EFI_TCG2_VERSION StructureVersion; EFI_TCG2_VERSION ProtocolVersion; EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap; EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs; BOOLEAN TPMPresentFlag; UINT16 MaxCommandSize; UINT16 MaxResponseSize; UINT32 ManufacturerID; UINT32 NumberOfPCRBanks; EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks; } EFI_TCG2_BOOT_SERVICE_CAPABILITY; #define EFI_TCG2_EVENT_HEADER_VERSION 1 typedef struct { UINT32 HeaderSize; UINT16 HeaderVersion; UINT32 PCRIndex; UINT32 EventType; } __attribute__ ((packed)) EFI_TCG2_EVENT_HEADER; typedef struct tdEFI_TCG2_EVENT { UINT32 Size; EFI_TCG2_EVENT_HEADER Header; UINT8 Event[1]; } __attribute__ ((packed)) EFI_TCG2_EVENT; typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This, IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability); typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_EVENT_LOG) (IN EFI_TCG2_PROTOCOL * This, IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, OUT EFI_PHYSICAL_ADDRESS * EventLogLocation, OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry, OUT BOOLEAN * EventLogTruncated); typedef EFI_STATUS(EFIAPI * EFI_TCG2_HASH_LOG_EXTEND_EVENT) (IN EFI_TCG2_PROTOCOL * This, IN UINT64 Flags, IN EFI_PHYSICAL_ADDRESS DataToHash, IN UINT64 DataToHashLen, IN EFI_TCG2_EVENT * EfiTcgEvent); typedef EFI_STATUS(EFIAPI * EFI_TCG2_SUBMIT_COMMAND) (IN EFI_TCG2_PROTOCOL * This, IN UINT32 InputParameterBlockSize, IN UINT8 * InputParameterBlock, IN UINT32 OutputParameterBlockSize, IN UINT8 * OutputParameterBlock); typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, OUT UINT32 * ActivePcrBanks); typedef EFI_STATUS(EFIAPI * EFI_TCG2_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, IN UINT32 ActivePcrBanks); typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, OUT UINT32 * OperationPresent, OUT UINT32 * Response); typedef struct tdEFI_TCG2_PROTOCOL { EFI_TCG2_GET_CAPABILITY GetCapability; EFI_TCG2_GET_EVENT_LOG GetEventLog; EFI_TCG2_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; EFI_TCG2_SUBMIT_COMMAND SubmitCommand; EFI_TCG2_GET_ACTIVE_PCR_BANKS GetActivePcrBanks; EFI_TCG2_SET_ACTIVE_PCR_BANKS SetActivePcrBanks; EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS GetResultOfSetActivePcrBanks; } EFI_TCG2; static EFI_STATUS tpm1_measure_to_pcr_and_event_log(const EFI_TCG *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { EFI_STATUS status; TCG_PCR_EVENT *tcg_event; UINT32 event_number; EFI_PHYSICAL_ADDRESS event_log_last; UINTN desc_len; desc_len = (StrLen(description) + 1) * sizeof(CHAR16); tcg_event = AllocateZeroPool(desc_len + sizeof(TCG_PCR_EVENT)); if (!tcg_event) return EFI_OUT_OF_RESOURCES; tcg_event->EventSize = desc_len; CopyMem((VOID *) & tcg_event->Event[0], (VOID *) description, desc_len); tcg_event->PCRIndex = pcrindex; tcg_event->EventType = EV_IPL; event_number = 1; status = uefi_call_wrapper(tcg->HashLogExtendEvent, 7, (EFI_TCG *) tcg, buffer, buffer_size, TCG_ALG_SHA, tcg_event, &event_number, &event_log_last); if (EFI_ERROR(status)) return status; uefi_call_wrapper(BS->FreePool, 1, tcg_event); return EFI_SUCCESS; } /* * 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(const EFI_TCG2 *tcg, EFI_TCG2_EVENT_LOG_FORMAT log_fmt) { EFI_PHYSICAL_ADDRESS loc; EFI_PHYSICAL_ADDRESS last_loc; BOOLEAN truncated; return uefi_call_wrapper(tcg->GetEventLog, 5, (EFI_TCG2 *) tcg, log_fmt, &loc, &last_loc, &truncated); } static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINT64 buffer_size, const CHAR16 *description, EFI_TCG2_EVENT_LOG_FORMAT log_fmt) { EFI_STATUS status; EFI_TCG2_EVENT *tcg_event; UINTN desc_len; static BOOLEAN triggered = FALSE; if (triggered == FALSE) { status = trigger_tcg2_final_events_table(tcg, log_fmt); if (EFI_ERROR(status)) return status; triggered = TRUE; } desc_len = StrLen(description) * sizeof(CHAR16); tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1); if (!tcg_event) return EFI_OUT_OF_RESOURCES; tcg_event->Size = sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1; tcg_event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); tcg_event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; tcg_event->Header.PCRIndex = pcrindex; tcg_event->Header.EventType = EV_IPL; CopyMem((VOID *) tcg_event->Event, (VOID *) description, desc_len); status = uefi_call_wrapper(tcg->HashLogExtendEvent, 5, (EFI_TCG2 *) tcg, 0, buffer, (UINT64) buffer_size, tcg_event); uefi_call_wrapper(BS->FreePool, 1, tcg_event); if (EFI_ERROR(status)) return status; return EFI_SUCCESS; } static EFI_TCG * tcg1_interface_check(void) { EFI_GUID tpm_guid = EFI_TCG_PROTOCOL_GUID; EFI_STATUS status; EFI_TCG *tcg; TCG_BOOT_SERVICE_CAPABILITY capability; UINT32 features; EFI_PHYSICAL_ADDRESS event_log_location; EFI_PHYSICAL_ADDRESS event_log_last_entry; status = LibLocateProtocol(&tpm_guid, (void **) &tcg); if (EFI_ERROR(status)) return NULL; capability.Size = (UINT8) sizeof(capability); status = uefi_call_wrapper(tcg->StatusCheck, 5, tcg, &capability, &features, &event_log_location, &event_log_last_entry); if (EFI_ERROR(status)) return NULL; if (capability.TPMDeactivatedFlag) return NULL; if (!capability.TPMPresentFlag) return NULL; return tcg; } static EFI_TCG2 * tcg2_interface_check(EFI_TCG2_BOOT_SERVICE_CAPABILITY *caps) { EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID; EFI_STATUS status; EFI_TCG2 *tcg; status = LibLocateProtocol(&tpm2_guid, (void **) &tcg); if (EFI_ERROR(status)) return NULL; caps->Size = (UINT8) sizeof(EFI_TCG2_BOOT_SERVICE_CAPABILITY); status = uefi_call_wrapper(tcg->GetCapability, 2, tcg, caps); if (EFI_ERROR(status)) return NULL; if (caps->StructureVersion.Major == 1 && caps->StructureVersion.Minor == 0) { TCG_BOOT_SERVICE_CAPABILITY *caps_1_0; caps_1_0 = (TCG_BOOT_SERVICE_CAPABILITY *)caps; if (caps_1_0->TPMPresentFlag) return tcg; } if (!caps->TPMPresentFlag) return NULL; return tcg; } EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { EFI_TCG *tpm1; EFI_TCG2 *tpm2; EFI_TCG2_BOOT_SERVICE_CAPABILITY caps; tpm2 = tcg2_interface_check(&caps); if (tpm2) { EFI_TCG2_EVENT_LOG_BITMAP supported_logs; EFI_TCG2_EVENT_LOG_FORMAT log_fmt; if (caps.StructureVersion.Major == 1 && caps.StructureVersion.Minor == 0) supported_logs = ((TREE_BOOT_SERVICE_CAPABILITY *)&caps)->SupportedEventLogs; else supported_logs = caps.SupportedEventLogs; if (supported_logs & EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) log_fmt = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; else log_fmt = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; uefi_call_wrapper(BS->Stall, 1, 2000 * 1000); return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description, log_fmt); } tpm1 = tcg1_interface_check(); if (tpm1) return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description); /* No active TPM found, so don't return an error */ return EFI_SUCCESS; } #endif