From fe3fd537356e95e52e4fc61e76f474736ffd3112 Mon Sep 17 00:00:00 2001 From: Konst Kolesnichenko Date: Mon, 14 Aug 2023 18:09:08 +0300 Subject: [PATCH] [efi] Add variable with TPM presence information, 0 if none and 1 if it's present and working (TPM 1.X, TPM 2.0 are supported) Signed-off-by: Konst Kolesnichenko --- src/config/config.c | 3 + src/config/defaults/efi.h | 2 + src/include/ipxe/efi/Protocol/Tcg2Protocol.h | 324 +++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/usr/tpm.c | 154 +++++++++ 5 files changed, 484 insertions(+) create mode 100644 src/include/ipxe/efi/Protocol/Tcg2Protocol.h create mode 100644 src/usr/tpm.c diff --git a/src/config/config.c b/src/config/config.c index abb7d16a2..00e13a442 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -358,6 +358,9 @@ REQUIRE_OBJECT ( acpi_settings ); #ifdef EFI_SETTINGS REQUIRE_OBJECT ( efi_settings ); #endif +#ifdef TPM_SETTINGS +REQUIRE_OBJECT ( tpm ); +#endif /* * Drag in selected keyboard map diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index e39d475b7..478755e72 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -50,6 +50,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define EFI_SETTINGS /* EFI variable settings */ +#define TPM_SETTINGS /* EFI TPM settings */ + #if defined ( __i386__ ) || defined ( __x86_64__ ) #define IOAPI_X86 #define NAP_EFIX86 diff --git a/src/include/ipxe/efi/Protocol/Tcg2Protocol.h b/src/include/ipxe/efi/Protocol/Tcg2Protocol.h new file mode 100644 index 000000000..c4e6ed434 --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Tcg2Protocol.h @@ -0,0 +1,324 @@ +/** @file + TPM2 Protocol as defined in TCG PC Client Platform EFI Protocol Specification Family "2.0". + See http://trustedcomputinggroup.org for the latest specification +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#ifndef __TCG2_PROTOCOL_H__ +#define __TCG2_PROTOCOL_H__ + +#include +#include + +#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 struct tdEFI_TCG2_VERSION { + UINT8 Major; + UINT8 Minor; +} EFI_TCG2_VERSION; + +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 { + // + // Allocated size of the structure + // + UINT8 Size; + // + // Version of the EFI_TCG2_BOOT_SERVICE_CAPABILITY structure itself. + // For this version of the protocol, the Major version shall be set to 1 + // and the Minor version shall be set to 1. + // + EFI_TCG2_VERSION StructureVersion; + // + // Version of the EFI TCG2 protocol. + // For this version of the protocol, the Major version shall be set to 1 + // and the Minor version shall be set to 1. + // + EFI_TCG2_VERSION ProtocolVersion; + // + // Supported hash algorithms (this bitmap is determined by the supported PCR + // banks in the TPM and the hashing algorithms supported by the firmware) + // + EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap; + // + // Bitmap of supported event log formats + // + EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs; + // + // False = TPM not present + // + BOOLEAN TPMPresentFlag; + // + // Max size (in bytes) of a command that can be sent to the TPM + // + UINT16 MaxCommandSize; + // + // Max size (in bytes) of a response that can be provided by the TPM + // + UINT16 MaxResponseSize; + // + // 4-byte Vendor ID + // (see TCG Vendor ID registry, Section "TPM Capabilities Vendor ID") + // + UINT32 ManufacturerID; + // + // Maximum number of PCR banks (hashing algorithms) supported. + // No granularity is provided to support a specific set of algorithms. + // Minimum value is 1. + // + UINT32 NumberOfPCRBanks; + // + // A bitmap of currently active PCR banks (hashing algorithms). + // This is a subset of the supported hashing algorithms reported in HashAlgorithmBitMap. + // NumberOfPcrBanks defines the number of bits that are set. + // + EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks; +} EFI_TCG2_BOOT_SERVICE_CAPABILITY; + +#define EFI_TCG2_BOOT_HASH_ALG_SHA1 0x00000001 +#define EFI_TCG2_BOOT_HASH_ALG_SHA256 0x00000002 +#define EFI_TCG2_BOOT_HASH_ALG_SHA384 0x00000004 +#define EFI_TCG2_BOOT_HASH_ALG_SHA512 0x00000008 +#define EFI_TCG2_BOOT_HASH_ALG_SM3_256 0x00000010 + +// +// This bit is shall be set when an event shall be extended but not logged. +// +#define EFI_TCG2_EXTEND_ONLY 0x0000000000000001 +// +// This bit shall be set when the intent is to measure a PE/COFF image. +// +#define PE_COFF_IMAGE 0x0000000000000010 + +#define MAX_PCR_INDEX 23 + +#pragma pack(1) + +#define EFI_TCG2_EVENT_HEADER_VERSION 1 + +typedef struct { + // + // Size of the event header itself (sizeof(EFI_TCG2_EVENT_HEADER)). + // + UINT32 HeaderSize; + // + // Header version. For this version of this specification, the value shall be 1. + // + UINT16 HeaderVersion; + // + // Index of the PCR that shall be extended (0 - 23). + // + TCG_PCRINDEX PCRIndex; + // + // Type of the event that shall be extended (and optionally logged). + // + TCG_EVENTTYPE EventType; +} EFI_TCG2_EVENT_HEADER; + +typedef struct tdEFI_TCG2_EVENT { + // + // Total size of the event including the Size component, the header and the Event data. + // + UINT32 Size; + EFI_TCG2_EVENT_HEADER Header; + UINT8 Event[1]; +} EFI_TCG2_EVENT; + +#pragma pack() + +/** + The EFI_TCG2_PROTOCOL GetCapability function call provides protocol + capability information and state information. + @param[in] This Indicates the calling context + @param[in, out] ProtocolCapability The caller allocates memory for a EFI_TCG2_BOOT_SERVICE_CAPABILITY + structure and sets the size field to the size of the structure allocated. + The callee fills in the fields with the EFI protocol capability information + and the current EFI TCG2 state information up to the number of fields which + fit within the size of the structure passed in. + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + The ProtocolCapability variable will not be populated. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + The ProtocolCapability variable will not be populated. + @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response. + It will be partially populated (required Size field will be set). +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG2_GET_CAPABILITY) ( + IN EFI_TCG2_PROTOCOL *This, + IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY *ProtocolCapability + ); + +/** + The EFI_TCG2_PROTOCOL Get Event Log function call allows a caller to + retrieve the address of a given event log and its last entry. + @param[in] This Indicates the calling context + @param[in] EventLogFormat The type of the event log for which the information is requested. + @param[out] EventLogLocation A pointer to the memory address of the event log. + @param[out] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the + address of the start of the last entry in the event log in memory. + @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would + have exceeded the area allocated for events, this value is set to TRUE. + Otherwise, the value will be FALSE and the Event Log will be complete. + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect + (e.g. asking for an event log whose format is not supported). +**/ +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 + ); + +/** + The EFI_TCG2_PROTOCOL HashLogExtendEvent function call provides callers with + an opportunity to extend and optionally log events without requiring + knowledge of actual TPM commands. + The extend operation will occur even if this function cannot create an event + log entry (e.g. due to the event log being full). + @param[in] This Indicates the calling context + @param[in] Flags Bitmap providing additional information. + @param[in] DataToHash Physical address of the start of the data buffer to be hashed. + @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash. + @param[in] EfiTcgEvent Pointer to data buffer containing information about the event. + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + @retval EFI_UNSUPPORTED The PE/COFF image type is not supported. +**/ +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 + ); + +/** + This service enables the sending of commands to the TPM. + @param[in] This Indicates the calling context + @param[in] InputParameterBlockSize Size of the TPM input parameter block. + @param[in] InputParameterBlock Pointer to the TPM input parameter block. + @param[in] OutputParameterBlockSize Size of the TPM output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM output parameter block. + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +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 + ); + +/** + This service returns the currently active PCR banks. + @param[in] This Indicates the calling context + @param[out] ActivePcrBanks Pointer to the variable receiving the bitmap of currently active PCR banks. + @retval EFI_SUCCESS The bitmap of active PCR banks was stored in the ActivePcrBanks parameter. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG2_GET_ACTIVE_PCR_BANKS) ( + IN EFI_TCG2_PROTOCOL *This, + OUT UINT32 *ActivePcrBanks + ); + +/** + This service sets the currently active PCR banks. + @param[in] This Indicates the calling context + @param[in] ActivePcrBanks Bitmap of the requested active PCR banks. At least one bit SHALL be set. + @retval EFI_SUCCESS The bitmap in ActivePcrBank parameter is already active. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG2_SET_ACTIVE_PCR_BANKS) ( + IN EFI_TCG2_PROTOCOL *This, + IN UINT32 ActivePcrBanks + ); + +/** + This service retrieves the result of a previous invocation of SetActivePcrBanks. + @param[in] This Indicates the calling context + @param[out] OperationPresent Non-zero value to indicate a SetActivePcrBank operation was invoked during the last boot. + @param[out] Response The response from the SetActivePcrBank request. + @retval EFI_SUCCESS The result value could be returned. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS) ( + IN EFI_TCG2_PROTOCOL *This, + OUT UINT32 *OperationPresent, + OUT UINT32 *Response + ); + +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; +}; + +extern EFI_GUID gEfiTcg2ProtocolGuid; + +// +// Log entries after Get Event Log service +// + +#define EFI_TCG2_FINAL_EVENTS_TABLE_GUID \ + {0x1e2ed096, 0x30e2, 0x4254, { 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25 }} + +extern EFI_GUID gEfiTcg2FinalEventsTableGuid; + +typedef struct tdEFI_TCG2_FINAL_EVENTS_TABLE { + // + // The version of this structure. + // + UINT64 Version; + // + // Number of events recorded after invocation of GetEventLog API + // + UINT64 NumberOfEvents; + // + // List of events of type TCG_PCR_EVENT2. + // +//TCG_PCR_EVENT2 Event[1]; +} EFI_TCG2_FINAL_EVENTS_TABLE; + +#define EFI_TCG2_FINAL_EVENTS_TABLE_VERSION 1 + +#endif \ No newline at end of file diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 320835a34..dad3ed43a 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -407,6 +407,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_rng ( ERRFILE_OTHER | 0x005c0000 ) #define ERRFILE_efi_shim ( ERRFILE_OTHER | 0x005d0000 ) #define ERRFILE_efi_settings ( ERRFILE_OTHER | 0x005e0000 ) +#define ERRFILE_tpm ( ERRFILE_OTHER | 0x005f0000 ) /** @} */ diff --git a/src/usr/tpm.c b/src/usr/tpm.c new file mode 100644 index 000000000..fbb58ecf5 --- /dev/null +++ b/src/usr/tpm.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2023 Konst Kolesnichenko . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE(GPL2_OR_LATER_OR_UBDL); + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * TPM Presence information, provides settings variable tpm + * with 0 in case if TPM is absent or disabled + * and 1 if TPM is up and running (regardless of version). + */ + +static BOOLEAN tpm2_present() +{ + EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID; + EFI_TCG2_PROTOCOL *tcg; + EFI_STATUS efirc; + int rc; + EFI_TCG2_BOOT_SERVICE_CAPABILITY caps; + + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + if ((efirc = bs->LocateProtocol(&tpm2_guid, + NULL, + (VOID **)&tcg)) != 0) + { + rc = -EEFI(efirc); + DBGC(efi_systab, "Failed to locate EFI_TCG2_PROTOCOL: %s\n", + strerror(rc)); + return FALSE; + } + + caps.Size = (uint8_t)sizeof(caps); + + if ((efirc = tcg->GetCapability(tcg, &caps)) != 0) + { + + DBGC(efi_systab, "Failed to query TPM2.0 capability\n"); + return FALSE; + } + + return caps.TPMPresentFlag; +} + +static BOOLEAN tpm1_present() +{ + EFI_TCG_PROTOCOL *tcg_protocol; + EFI_STATUS efirc; + int rc; + TCG_EFI_BOOT_SERVICE_CAPABILITY caps; + uint32_t tcg_feature_flags; + EFI_PHYSICAL_ADDRESS event_log_location; + EFI_PHYSICAL_ADDRESS event_log_last_entry; + + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + if ((efirc = bs->LocateProtocol(&efi_tcg_protocol_guid, + NULL, + (VOID **)&tcg_protocol)) != 0) + { + rc = -EEFI(efirc); + DBGC(efi_systab, "Failed to locate EFI_TCG_PROTOCOL: %s\n", strerror(rc)); + return FALSE; + } + + caps.Size = (uint8_t)sizeof(caps); + + if ((efirc = tcg_protocol->StatusCheck(tcg_protocol, &caps, &tcg_feature_flags, + &event_log_location, &event_log_last_entry)) != 0) + { + + DBGC(efi_systab, "Failed to query TPM status\n"); + return FALSE; + } + + if (caps.TPMDeactivatedFlag) + { + return FALSE; + } + + return caps.TPMPresentFlag; +} + +/** + * Fetch tpm setting + * + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int tpm_fetch(void *data, size_t len) +{ + uint8_t content; + + if (tpm2_present()) + { + content = 1; + } + else if (tpm1_present()) + { + content = 1; + } + else + { + content = 0; + } + + if (len > sizeof(content)) + len = sizeof(content); + memcpy(data, &content, len); + return sizeof(content); +} + +/** TPM setting */ +const struct setting tpm_setting __setting(SETTING_MISC, tpm) = { + .name = "tpm", + .description = "TPM presence information", + .type = &setting_type_uint8, + .scope = &builtin_scope, +}; + +/** TPM built-in setting */ +struct builtin_setting tpm_builtin_setting __builtin_setting = { + .setting = &tpm_setting, + .fetch = tpm_fetch, +};