summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--shim.c54
-rw-r--r--tpm.c127
-rw-r--r--tpm.h145
4 files changed, 328 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 2c3d5544..9ceae064 100644
--- a/Makefile
+++ b/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
diff --git a/shim.c b/shim.c
index b72b4bdf..3232a171 100644
--- a/shim.c
+++ b/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
@@ -1733,6 +1738,42 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
}
/*
+ * 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.
*/
@@ -2496,6 +2537,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
*/
diff --git a/tpm.c b/tpm.c
new file mode 100644
index 00000000..71bcf9b9
--- /dev/null
+++ b/tpm.c
@@ -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 *)&caps;
+ 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;
+}
diff --git a/tpm.h b/tpm.h
new file mode 100644
index 00000000..2c21b262
--- /dev/null
+++ b/tpm.h
@@ -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;