summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@google.com>2017-07-12 15:29:24 -0700
committerPeter Jones <pjones@redhat.com>2017-08-03 11:00:58 -0400
commit22f2737535ca09faf48762df89b61e81b8d4a2f8 (patch)
treeb5eb822e051e2b302b4485a206562ad4a875872a
parent8af7c4cacaf753f38f2564b26b962a7a2942d664 (diff)
downloadefi-boot-shim-22f2737535ca09faf48762df89b61e81b8d4a2f8.tar.gz
efi-boot-shim-22f2737535ca09faf48762df89b61e81b8d4a2f8.zip
Measure stage 2 according to spec
We're currently measuring the raw second stage loader into PCR 9, but we're closer to spec if we measure the semi-parsed PE into PCR 4. The hash that's logged is the same as the hash used for the Authenticode validation, so refactor shim.c a little to separate out the hash generation.
-rw-r--r--shim.c30
-rw-r--r--tpm.c55
-rw-r--r--tpm.h15
3 files changed, 83 insertions, 17 deletions
diff --git a/shim.c b/shim.c
index 91fd926b..ad72fbee 100644
--- a/shim.c
+++ b/shim.c
@@ -962,10 +962,9 @@ static EFI_STATUS verify_mok (void) {
* Check that the signature is valid and matches the binary
*/
static EFI_STATUS verify_buffer (char *data, int datasize,
- PE_COFF_LOADER_IMAGE_CONTEXT *context)
+ PE_COFF_LOADER_IMAGE_CONTEXT *context,
+ UINT8 *sha256hash, UINT8 *sha1hash)
{
- UINT8 sha256hash[SHA256_DIGEST_SIZE];
- UINT8 sha1hash[SHA1_DIGEST_SIZE];
EFI_STATUS status = EFI_SECURITY_VIOLATION;
WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
unsigned int size = datasize;
@@ -1206,6 +1205,8 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
unsigned int alignment, alloc_size;
EFI_PHYSICAL_ADDRESS alloc_address;
int found_entry_point = 0;
+ UINT8 sha1hash[SHA1_DIGEST_SIZE];
+ UINT8 sha256hash[SHA256_DIGEST_SIZE];
/*
* The binary header contains relevant context and section pointers
@@ -1219,8 +1220,17 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
/*
* We only need to verify the binary if we're in secure mode
*/
+ efi_status = generate_hash(data, datasize, &context, sha256hash,
+ sha1hash);
+ if (efi_status != EFI_SUCCESS)
+ return efi_status;
+
+ /* Measure the binary into the TPM */
+ tpm_log_pe((EFI_PHYSICAL_ADDRESS)(UINTN)data, datasize, sha1hash, 4);
+
if (secure_mode ()) {
- efi_status = verify_buffer(data, datasize, &context);
+ efi_status = verify_buffer(data, datasize, &context,
+ sha256hash, sha1hash);
if (EFI_ERROR(efi_status)) {
console_error(L"Verification failed", efi_status);
@@ -1711,6 +1721,8 @@ EFI_STATUS shim_verify (void *buffer, UINT32 size)
{
EFI_STATUS status = EFI_SUCCESS;
PE_COFF_LOADER_IMAGE_CONTEXT context;
+ UINT8 sha1hash[SHA1_DIGEST_SIZE];
+ UINT8 sha256hash[SHA256_DIGEST_SIZE];
loader_is_participating = 1;
in_protocol = 1;
@@ -1722,7 +1734,11 @@ EFI_STATUS shim_verify (void *buffer, UINT32 size)
if (status != EFI_SUCCESS)
goto done;
- status = verify_buffer(buffer, size, &context);
+ status = generate_hash(buffer, size, &context, sha256hash, sha1hash);
+ if (status != EFI_SUCCESS)
+ goto done;
+
+ status = verify_buffer(buffer, size, &context, sha256hash, sha1hash);
done:
in_protocol = 0;
return status;
@@ -1826,10 +1842,6 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
}
}
- /* Measure the binary into the TPM */
- tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)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
diff --git a/tpm.c b/tpm.c
index 6e3933cb..af6b126d 100644
--- a/tpm.c
+++ b/tpm.c
@@ -120,7 +120,7 @@ static EFI_STATUS trigger_tcg2_final_events_table(efi_tpm2_protocol_t *tpm2,
static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
UINT8 pcr, const CHAR8 *log, UINTN logsize,
- UINT32 type)
+ UINT32 type, CHAR8 *hash)
{
EFI_STATUS status;
efi_tpm_protocol_t *tpm;
@@ -161,8 +161,18 @@ static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
event->Header.EventType = type;
event->Size = sizeof(*event) - sizeof(event->Event) + logsize + 1;
CopyMem(event->Event, (VOID *)log, logsize);
- status = uefi_call_wrapper(tpm2->hash_log_extend_event, 5, tpm2,
- 0, buf, (UINT64) size, event);
+ if (hash) {
+ /* TPM 2 systems will generate the appropriate hash
+ themselves if we pass PE_COFF_IMAGE
+ */
+ status = uefi_call_wrapper(tpm2->hash_log_extend_event,
+ 5, tpm2, PE_COFF_IMAGE, buf,
+ (UINT64) size, event);
+ } else {
+ status = uefi_call_wrapper(tpm2->hash_log_extend_event,
+ 5, tpm2, 0, buf,
+ (UINT64) size, event);
+ }
FreePool(event);
return status;
} else {
@@ -189,9 +199,21 @@ static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
event->EventType = type;
event->EventSize = logsize;
CopyMem(event->Event, (VOID *)log, logsize);
- status = uefi_call_wrapper(tpm->log_extend_event, 7, tpm, buf,
- (UINT64)size, TPM_ALG_SHA, event,
- &eventnum, &lastevent);
+ if (hash) {
+ /* TPM 1.2 devices require us to pass the Authenticode
+ hash rather than allowing the firmware to attempt
+ to calculate it */
+ CopyMem(event->digest, hash, sizeof(event->digest));
+ status = uefi_call_wrapper(tpm->log_extend_event, 7,
+ tpm, 0, 0, TPM_ALG_SHA,
+ event, &eventnum,
+ &lastevent);
+ } else {
+ status = uefi_call_wrapper(tpm->log_extend_event, 7,
+ tpm, buf, (UINT64)size,
+ TPM_ALG_SHA, event,
+ &eventnum, &lastevent);
+ }
FreePool(event);
return status;
}
@@ -202,7 +224,24 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
const CHAR8 *description)
{
return tpm_log_event_raw(buf, size, pcr, description,
- strlen(description) + 1, 0xd);
+ strlen(description) + 1, 0xd, NULL);
+}
+
+EFI_STATUS tpm_log_pe(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 *sha1hash,
+ UINT8 pcr)
+{
+ EFI_IMAGE_LOAD_EVENT ImageLoad;
+
+ // All of this is informational and forces us to do more parsing before
+ // we can generate it, so let's just leave it out for now
+ ImageLoad.ImageLocationInMemory = 0;
+ ImageLoad.ImageLengthInMemory = 0;
+ ImageLoad.ImageLinkTimeAddress = 0;
+ ImageLoad.LengthOfDevicePath = 0;
+
+ return tpm_log_event_raw(buf, size, pcr, (CHAR8 *)&ImageLoad,
+ sizeof(ImageLoad),
+ EV_EFI_BOOT_SERVICES_APPLICATION, sha1hash);
}
typedef struct {
@@ -294,7 +333,7 @@ EFI_STATUS tpm_measure_variable(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarS
Status = tpm_log_event_raw((EFI_PHYSICAL_ADDRESS)VarLog, VarLogSize, 7,
(CHAR8 *)VarLog, VarLogSize,
- EV_EFI_VARIABLE_AUTHORITY);
+ EV_EFI_VARIABLE_AUTHORITY, NULL);
FreePool(VarLog);
diff --git a/tpm.h b/tpm.h
index 3769a1d4..e3c2b923 100644
--- a/tpm.h
+++ b/tpm.h
@@ -1,3 +1,5 @@
+#include <efilib.h>
+
#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 }};
@@ -7,6 +9,9 @@
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
const CHAR8 *description);
+EFI_STATUS tpm_log_pe(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 *sha1hash,
+ UINT8 pcr);
+
EFI_STATUS tpm_measure_variable(CHAR16 *dbname, EFI_GUID guid, UINTN size, void *data);
typedef struct {
@@ -33,6 +38,14 @@ typedef struct _TCG_PCR_EVENT {
uint8_t Event[1];
} TCG_PCR_EVENT;
+typedef struct _EFI_IMAGE_LOAD_EVENT {
+ EFI_PHYSICAL_ADDRESS ImageLocationInMemory;
+ UINTN ImageLengthInMemory;
+ UINTN ImageLinkTimeAddress;
+ UINTN LengthOfDevicePath;
+ EFI_DEVICE_PATH DevicePath[1];
+} EFI_IMAGE_LOAD_EVENT;
+
struct efi_tpm_protocol
{
EFI_STATUS (EFIAPI *status_check) (struct efi_tpm_protocol *this,
@@ -170,3 +183,5 @@ typedef UINT32 TCG_EVENTTYPE;
#define EV_EFI_PLATFORM_FIRMWARE_BLOB (EV_EFI_EVENT_BASE + 8)
#define EV_EFI_HANDOFF_TABLES (EV_EFI_EVENT_BASE + 9)
#define EV_EFI_VARIABLE_AUTHORITY (EV_EFI_EVENT_BASE + 0xE0)
+
+#define PE_COFF_IMAGE 0x0000000000000010