diff options
| author | Matthew Garrett <mjg59@google.com> | 2017-07-12 15:29:24 -0700 |
|---|---|---|
| committer | Peter Jones <pjones@redhat.com> | 2017-08-03 11:00:58 -0400 |
| commit | 22f2737535ca09faf48762df89b61e81b8d4a2f8 (patch) | |
| tree | b5eb822e051e2b302b4485a206562ad4a875872a | |
| parent | 8af7c4cacaf753f38f2564b26b962a7a2942d664 (diff) | |
| download | efi-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.c | 30 | ||||
| -rw-r--r-- | tpm.c | 55 | ||||
| -rw-r--r-- | tpm.h | 15 |
3 files changed, 83 insertions, 17 deletions
@@ -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 @@ -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); @@ -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 |
