mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-07-27 08:57:14 +00:00
Measure state and second stage into TPM
Add support for measuring the MOK database and secure boot state into a TPM, and do the same for the second stage loader. This avoids a hole in TPM measurement between the firmware and the second stage loader.
This commit is contained in:
parent
dd66e12d73
commit
964f56b310
4
Makefile
4
Makefile
@ -67,9 +67,9 @@ endif
|
||||
LDFLAGS = --hash-style=sysv -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS) --build-id=sha1
|
||||
|
||||
TARGET = shim.efi MokManager.efi.signed fallback.efi.signed
|
||||
OBJS = shim.o netboot.o cert.o replacements.o version.o
|
||||
OBJS = shim.o netboot.o cert.o replacements.o tpm.o version.o
|
||||
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
|
||||
SOURCES = shim.c shim.h netboot.c include/PeImage.h include/wincert.h include/console.h replacements.c replacements.h version.c version.h
|
||||
SOURCES = shim.c shim.h netboot.c include/PeImage.h include/wincert.h include/console.h replacements.c replacements.h tpm.c tpm.h version.c version.h
|
||||
MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o
|
||||
MOK_SOURCES = MokManager.c shim.h include/console.h PasswordCrypt.c PasswordCrypt.h crypt_blowfish.c crypt_blowfish.h
|
||||
FALLBACK_OBJS = fallback.o
|
||||
|
54
shim.c
54
shim.c
@ -41,6 +41,7 @@
|
||||
#include "netboot.h"
|
||||
#include "shim_cert.h"
|
||||
#include "replacements.h"
|
||||
#include "tpm.h"
|
||||
#include "ucs2.h"
|
||||
|
||||
#include "guid.h"
|
||||
@ -1663,6 +1664,10 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
|
||||
}
|
||||
}
|
||||
|
||||
/* Measure the binary into the TPM */
|
||||
tpm_log_event((EFI_PHYSICAL_ADDRESS)data, datasize, 9,
|
||||
(CHAR8 *)"Second stage bootloader");
|
||||
|
||||
/*
|
||||
* We need to modify the loaded image protocol entry before running
|
||||
* the new binary, so back it up
|
||||
@ -1732,6 +1737,42 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Measure some of the MOK variables into the TPM
|
||||
*/
|
||||
EFI_STATUS measure_mok()
|
||||
{
|
||||
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
||||
EFI_STATUS efi_status;
|
||||
UINT8 *Data = NULL;
|
||||
UINTN DataSize = 0;
|
||||
|
||||
efi_status = get_variable(L"MokList", &Data, &DataSize, shim_lock_guid);
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
|
||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)Data, DataSize, 14,
|
||||
(CHAR8 *)"MokList");
|
||||
|
||||
FreePool(Data);
|
||||
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
|
||||
efi_status = get_variable(L"MokSBState", &Data, &DataSize,
|
||||
shim_lock_guid);
|
||||
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
|
||||
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)Data, DataSize, 14,
|
||||
(CHAR8 *)"MokSBState");
|
||||
|
||||
FreePool(Data);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the boot-services only MokList variable to the runtime-accessible
|
||||
* MokListRT variable. It's not marked NV, so the OS can't modify it.
|
||||
@ -2495,6 +2536,19 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
|
||||
*/
|
||||
debug_hook();
|
||||
|
||||
/*
|
||||
* Measure the MOK variables
|
||||
*/
|
||||
efi_status = measure_mok();
|
||||
if (efi_status != EFI_SUCCESS && efi_status != EFI_NOT_FOUND) {
|
||||
Print(L"Something has gone seriously wrong: %r\n", efi_status);
|
||||
Print(L"Shim was unable to measure state into the TPM\n");
|
||||
systab->BootServices->Stall(5000000);
|
||||
systab->RuntimeServices->ResetSystem(EfiResetShutdown,
|
||||
EFI_SECURITY_VIOLATION,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the user has configured the system to run in
|
||||
* insecure mode
|
||||
|
127
tpm.c
Normal file
127
tpm.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
EFI_TCG2_BOOT_SERVICE_CAPABILITY_1_0 *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 = (EFI_TCG2_BOOT_SERVICE_CAPABILITY_1_0 *)∩︀
|
||||
if (caps_1_0->TPMPresentFlag)
|
||||
return TRUE;
|
||||
} else {
|
||||
if (caps.TPMPresentFlag)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
145
tpm.h
Normal file
145
tpm.h
Normal file
@ -0,0 +1,145 @@
|
||||
#define EFI_TPM_GUID {0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd }};
|
||||
#define EFI_TPM2_GUID {0x607f766c, 0x7455, 0x42be, {0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }};
|
||||
|
||||
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
|
||||
const CHAR8 *description);
|
||||
|
||||
typedef struct {
|
||||
uint8_t Major;
|
||||
uint8_t Minor;
|
||||
uint8_t RevMajor;
|
||||
uint8_t RevMinor;
|
||||
} TCG_VERSION;
|
||||
|
||||
typedef struct _TCG_EFI_BOOT_SERVICE_CAPABILITY {
|
||||
uint8_t Size; /// Size of this structure.
|
||||
TCG_VERSION StructureVersion;
|
||||
TCG_VERSION ProtocolSpecVersion;
|
||||
uint8_t HashAlgorithmBitmap; /// Hash algorithms .
|
||||
char TPMPresentFlag; /// 00h = TPM not present.
|
||||
char TPMDeactivatedFlag; /// 01h = TPM currently deactivated.
|
||||
} TCG_EFI_BOOT_SERVICE_CAPABILITY;
|
||||
|
||||
typedef struct _TCG_PCR_EVENT {
|
||||
uint32_t PCRIndex;
|
||||
uint32_t EventType;
|
||||
uint8_t digest[20];
|
||||
uint32_t EventSize;
|
||||
uint8_t Event[1];
|
||||
} TCG_PCR_EVENT;
|
||||
|
||||
struct efi_tpm_protocol
|
||||
{
|
||||
EFI_STATUS (EFIAPI *status_check) (struct efi_tpm_protocol *this,
|
||||
TCG_EFI_BOOT_SERVICE_CAPABILITY *ProtocolCapability,
|
||||
uint32_t *TCGFeatureFlags,
|
||||
EFI_PHYSICAL_ADDRESS *EventLogLocation,
|
||||
EFI_PHYSICAL_ADDRESS *EventLogLastEntry);
|
||||
EFI_STATUS (EFIAPI *hash_all) (struct efi_tpm_protocol *this,
|
||||
uint8_t *HashData,
|
||||
uint64_t HashLen,
|
||||
uint32_t AlgorithmId,
|
||||
uint64_t *HashedDataLen,
|
||||
uint8_t **HashedDataResult);
|
||||
EFI_STATUS (EFIAPI *log_event) (struct efi_tpm_protocol *this,
|
||||
TCG_PCR_EVENT *TCGLogData,
|
||||
uint32_t *EventNumber,
|
||||
uint32_t Flags);
|
||||
EFI_STATUS (EFIAPI *pass_through_to_tpm) (struct efi_tpm_protocol *this,
|
||||
uint32_t TpmInputParameterBlockSize,
|
||||
uint8_t *TpmInputParameterBlock,
|
||||
uint32_t TpmOutputParameterBlockSize,
|
||||
uint8_t *TpmOutputParameterBlock);
|
||||
EFI_STATUS (EFIAPI *log_extend_event) (struct efi_tpm_protocol *this,
|
||||
EFI_PHYSICAL_ADDRESS HashData,
|
||||
uint64_t HashDataLen,
|
||||
uint32_t AlgorithmId,
|
||||
TCG_PCR_EVENT *TCGLogData,
|
||||
uint32_t *EventNumber,
|
||||
EFI_PHYSICAL_ADDRESS *EventLogLastEntry);
|
||||
};
|
||||
|
||||
typedef struct efi_tpm_protocol efi_tpm_protocol_t;
|
||||
|
||||
typedef uint32_t EFI_TCG2_EVENT_LOG_BITMAP;
|
||||
typedef uint32_t EFI_TCG2_EVENT_LOG_FORMAT;
|
||||
typedef uint32_t EFI_TCG2_EVENT_ALGORITHM_BITMAP;
|
||||
|
||||
typedef struct tdEFI_TCG2_VERSION {
|
||||
uint8_t Major;
|
||||
uint8_t Minor;
|
||||
} __attribute__ ((packed)) EFI_TCG2_VERSION;
|
||||
|
||||
typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY_1_0 {
|
||||
uint8_t Size;
|
||||
EFI_TCG2_VERSION StructureVersion;
|
||||
EFI_TCG2_VERSION ProtocolVersion;
|
||||
EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
|
||||
EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs;
|
||||
BOOLEAN TPMPresentFlag;
|
||||
uint16_t MaxCommandSize;
|
||||
uint16_t MaxResponseSize;
|
||||
uint32_t ManufacturerID;
|
||||
uint32_t NumberOfPcrBanks;
|
||||
EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks;
|
||||
} EFI_TCG2_BOOT_SERVICE_CAPABILITY_1_0;
|
||||
|
||||
typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY {
|
||||
uint8_t Size;
|
||||
EFI_TCG2_VERSION StructureVersion;
|
||||
EFI_TCG2_VERSION ProtocolVersion;
|
||||
EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
|
||||
EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs;
|
||||
BOOLEAN TPMPresentFlag;
|
||||
uint16_t MaxCommandSize;
|
||||
uint16_t MaxResponseSize;
|
||||
uint32_t ManufacturerID;
|
||||
uint32_t NumberOfPcrBanks;
|
||||
EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks;
|
||||
} __attribute__ ((packed)) EFI_TCG2_BOOT_SERVICE_CAPABILITY;
|
||||
|
||||
typedef uint32_t TCG_PCRINDEX;
|
||||
typedef uint32_t TCG_EVENTTYPE;
|
||||
|
||||
typedef struct tdEFI_TCG2_EVENT_HEADER {
|
||||
uint32_t HeaderSize;
|
||||
uint16_t HeaderVersion;
|
||||
TCG_PCRINDEX PCRIndex;
|
||||
TCG_EVENTTYPE EventType;
|
||||
} __attribute__ ((packed)) EFI_TCG2_EVENT_HEADER;
|
||||
|
||||
typedef struct tdEFI_TCG2_EVENT {
|
||||
uint32_t Size;
|
||||
EFI_TCG2_EVENT_HEADER Header;
|
||||
uint8_t Event[1];
|
||||
} __attribute__ ((packed)) EFI_TCG2_EVENT;
|
||||
|
||||
struct efi_tpm2_protocol
|
||||
{
|
||||
EFI_STATUS (EFIAPI *get_capability) (struct efi_tpm2_protocol *this,
|
||||
EFI_TCG2_BOOT_SERVICE_CAPABILITY *ProtocolCapability);
|
||||
EFI_STATUS (EFIAPI *get_event_log) (struct efi_tpm2_protocol *this,
|
||||
EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
|
||||
EFI_PHYSICAL_ADDRESS *EventLogLocation,
|
||||
EFI_PHYSICAL_ADDRESS *EventLogLastEntry,
|
||||
BOOLEAN *EventLogTruncated);
|
||||
EFI_STATUS (EFIAPI *hash_log_extend_event) (struct efi_tpm2_protocol *this,
|
||||
uint64_t Flags,
|
||||
EFI_PHYSICAL_ADDRESS DataToHash,
|
||||
uint64_t DataToHashLen,
|
||||
EFI_TCG2_EVENT *EfiTcgEvent);
|
||||
EFI_STATUS (EFIAPI *submit_command) (struct efi_tpm2_protocol *this,
|
||||
uint32_t InputParameterBlockSize,
|
||||
uint8_t *InputParameterBlock,
|
||||
uint32_t OutputParameterBlockSize,
|
||||
uint8_t *OutputParameterBlock);
|
||||
EFI_STATUS (EFIAPI *get_active_pcr_blanks) (struct efi_tpm2_protocol *this,
|
||||
uint32_t *ActivePcrBanks);
|
||||
EFI_STATUS (EFIAPI *set_active_pcr_banks) (struct efi_tpm2_protocol *this,
|
||||
uint32_t ActivePcrBanks);
|
||||
EFI_STATUS (EFIAPI *get_result_of_set_active_pcr_banks) (struct efi_tpm2_protocol *this,
|
||||
uint32_t *OperationPresent,
|
||||
uint32_t *Response);
|
||||
};
|
||||
|
||||
typedef struct efi_tpm2_protocol efi_tpm2_protocol_t;
|
Loading…
Reference in New Issue
Block a user