diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index c671aed4b..d50d28f5d 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -88,6 +88,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/tpm.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h if COND_i386_pc diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 8dcae96d9..be78b5fc2 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -126,6 +126,7 @@ kernel = { common = kern/rescue_parser.c; common = kern/rescue_reader.c; common = kern/term.c; + common = kern/tpm.c; noemu = kern/compiler-rt.c; noemu = kern/mm.c; @@ -173,6 +174,7 @@ kernel = { efi = term/efi/console.c; efi = kern/acpi.c; efi = kern/efi/acpi.c; + efi = kern/efi/tpm.c; i386_coreboot = kern/i386/pc/acpi.c; i386_multiboot = kern/i386/pc/acpi.c; i386_coreboot = kern/acpi.c; @@ -217,6 +219,7 @@ kernel = { i386_pc = kern/i386/pc/init.c; i386_pc = kern/i386/pc/mmap.c; + i386_pc = kern/i386/pc/tpm.c; i386_pc = term/i386/pc/console.c; i386_qemu = bus/pci.c; diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S index 2bd0b2d28..4c63247e8 100644 --- a/grub-core/boot/i386/pc/boot.S +++ b/grub-core/boot/i386/pc/boot.S @@ -24,11 +24,14 @@ * defines for the code go here */ +#define TPM 1 + /* Print message string */ #define MSG(x) movw $x, %si; call LOCAL(message) #define ERR(x) movw $x, %si; jmp LOCAL(error_message) .macro floppy +#ifndef TPM part_start: LOCAL(probe_values): @@ -85,6 +88,7 @@ fd_probe_error_string: .asciz "Floppy" movb MACRO_DOLLAR(79), %ch jmp LOCAL(final_init) +#endif .endm .macro scratch @@ -255,6 +259,7 @@ real_start: /* set %si to the disk address packet */ movw $disk_address_packet, %si +#ifndef TPM /* check if LBA is supported */ movb $0x41, %ah movw $0x55aa, %bx @@ -274,6 +279,7 @@ real_start: andw $1, %cx jz LOCAL(chs_mode) +#endif LOCAL(lba_mode): xorw %ax, %ax @@ -317,6 +323,9 @@ LOCAL(lba_mode): jmp LOCAL(copy_buffer) LOCAL(chs_mode): +#ifdef TPM + jmp LOCAL(general_error) +#else /* * Determine the hard disk geometry from the BIOS! * We do this first, so that LS-120 IDE floppies work correctly. @@ -428,7 +437,7 @@ setup_sectors: jc LOCAL(read_error) movw %es, %bx - +#endif /* TPM */ LOCAL(copy_buffer): /* * We need to save %cx and %si because the startup code in @@ -451,6 +460,25 @@ LOCAL(copy_buffer): popw %ds popa +#ifdef TPM + pusha + + movw $0xBB00, %ax /* TCG_StatusCheck */ + int $0x1A + test %eax, %eax + jnz boot /* No TPM or TPM deactivated */ + + movw $0xBB07, %ax /* TCG_CompactHashLogExtendEvent */ + movw $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di + xorl %esi, %esi + movl $0x41504354, %ebx /* TCPA */ + movl $0x200, %ecx /* Measure 512 bytes */ + movl $0x8, %edx /* PCR 8 */ + int $0x1A + + popa +#endif +boot: /* boot kernel */ jmp *(LOCAL(kernel_address)) diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S index 1ee4cf5b2..3a324ea74 100644 --- a/grub-core/boot/i386/pc/diskboot.S +++ b/grub-core/boot/i386/pc/diskboot.S @@ -19,6 +19,8 @@ #include #include +#define TPM 1 + /* * defines for the code go here */ @@ -58,6 +60,21 @@ _start: /* this sets up for the first run through "bootloop" */ movw $LOCAL(firstlist), %di +#ifdef TPM + /* clear EAX to remove potential garbage */ + xorl %eax, %eax + /* 8(%di) = number of sectors to read */ + movw 8(%di), %ax + + /* Multiply number of sectors to read with 512 bytes. EAX is 32bit + * which is large enough to hold values of up to 4GB. I doubt there + * will ever be a core.img larger than that. ;-) */ + shll $9, %eax + + /* write result to bytes_to_measure var */ + movl %eax, bytes_to_measure +#endif + /* save the sector number of the second sector in %ebp */ movl (%di), %ebp @@ -295,6 +312,29 @@ LOCAL(copy_buffer): /* END OF MAIN LOOP */ LOCAL(bootit): +#ifdef TPM + pusha + movw $0xBB07, %ax /* TCG_CompactHashLogExtendEvent */ + + movw $0x0, %bx + movw %bx, %es + + /* We've already measured the first 512 bytes, now measure the rest */ + xorl %edi, %edi + movw $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200), %di + + movl $0x41504354, %ebx /* EBX = "TCPA" */ + + /* %ecx = The length, in bytes, of the buffer to measure */ + movl $bytes_to_measure, %esi + movl (%esi), %ecx + xorl %esi, %esi + movl $0x9, %edx /* PCR 9 */ + + int $0x1A + + popa +#endif /* print a newline */ MSG(notification_done) popw %dx /* this makes sure %dl is our "boot" drive */ @@ -329,6 +369,10 @@ geometry_error_string: .asciz "Geom" read_error_string: .asciz "Read" general_error_string: .asciz " Error" +#ifdef TPM +bytes_to_measure: .long 0 +#endif + /* * message: write the string pointed to by %si * diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index 7dcc852e5..794f9381d 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Platforms where modules are in a readonly area of memory. */ #if defined(GRUB_MACHINE_QEMU) @@ -723,6 +724,8 @@ grub_dl_load_file (const char *filename) opens of the same device. */ grub_file_close (file); + grub_tpm_measure(core, size, GRUB_TPM_PCR, filename); + mod = grub_dl_load_core (core, size); grub_free (core); if (! mod) diff --git a/grub-core/kern/efi/tpm.c b/grub-core/kern/efi/tpm.c new file mode 100644 index 000000000..c9fb3c133 --- /dev/null +++ b/grub-core/kern/efi/tpm.c @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_efi_guid_t tpm_guid = EFI_TPM_GUID; +static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; + +static grub_efi_boolean_t grub_tpm_present(grub_efi_tpm_protocol_t *tpm) +{ + grub_efi_status_t status; + TCG_EFI_BOOT_SERVICE_CAPABILITY caps; + grub_uint32_t flags; + grub_efi_physical_address_t eventlog, lastevent; + + caps.Size = (grub_uint8_t)sizeof(caps); + + status = efi_call_5(tpm->status_check, tpm, &caps, &flags, &eventlog, + &lastevent); + + if (status != GRUB_EFI_SUCCESS || caps.TPMDeactivatedFlag + || !caps.TPMPresentFlag) + return 0; + + return 1; +} + +static grub_efi_boolean_t grub_tpm2_present(grub_efi_tpm2_protocol_t *tpm) +{ + grub_efi_status_t status; + EFI_TCG2_BOOT_SERVICE_CAPABILITY caps; + + caps.Size = (grub_uint8_t)sizeof(caps); + + status = efi_call_2(tpm->get_capability, tpm, &caps); + + if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag) + return 0; + + return 1; +} + +static grub_efi_boolean_t grub_tpm_handle_find(grub_efi_handle_t *tpm_handle, + grub_efi_uint8_t *protocol_version) +{ + grub_efi_handle_t *handles; + grub_efi_uintn_t num_handles; + + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm_guid, NULL, + &num_handles); + if (handles && num_handles > 0) { + *tpm_handle = handles[0]; + *protocol_version = 1; + return 1; + } + + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL, + &num_handles); + if (handles && num_handles > 0) { + *tpm_handle = handles[0]; + *protocol_version = 2; + return 1; + } + + return 0; +} + +static grub_err_t +grub_tpm1_execute(grub_efi_handle_t tpm_handle, + PassThroughToTPM_InputParamBlock *inbuf, + PassThroughToTPM_OutputParamBlock *outbuf) +{ + grub_efi_status_t status; + grub_efi_tpm_protocol_t *tpm; + grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn); + grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut); + + tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!grub_tpm_present(tpm)) + return 0; + + /* UEFI TPM protocol takes the raw operand block, no param block header */ + status = efi_call_5 (tpm->pass_through_to_tpm, tpm, + inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn, + outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut); + + switch (status) { + case GRUB_EFI_SUCCESS: + return 0; + case GRUB_EFI_DEVICE_ERROR: + return grub_error (GRUB_ERR_IO, N_("Command failed")); + case GRUB_EFI_INVALID_PARAMETER: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); + } +} + +static grub_err_t +grub_tpm2_execute(grub_efi_handle_t tpm_handle, + PassThroughToTPM_InputParamBlock *inbuf, + PassThroughToTPM_OutputParamBlock *outbuf) +{ + grub_efi_status_t status; + grub_efi_tpm2_protocol_t *tpm; + grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn); + grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut); + + tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!grub_tpm2_present(tpm)) + return 0; + + /* UEFI TPM protocol takes the raw operand block, no param block header */ + status = efi_call_5 (tpm->submit_command, tpm, + inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn, + outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut); + + switch (status) { + case GRUB_EFI_SUCCESS: + return 0; + case GRUB_EFI_DEVICE_ERROR: + return grub_error (GRUB_ERR_IO, N_("Command failed")); + case GRUB_EFI_INVALID_PARAMETER: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); + } +} + +grub_err_t +grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf, + PassThroughToTPM_OutputParamBlock *outbuf) +{ + grub_efi_handle_t tpm_handle; + grub_uint8_t protocol_version; + + /* It's not a hard failure for there to be no TPM */ + if (!grub_tpm_handle_find(&tpm_handle, &protocol_version)) + return 0; + + if (protocol_version == 1) { + return grub_tpm1_execute(tpm_handle, inbuf, outbuf); + } else { + return grub_tpm2_execute(tpm_handle, inbuf, outbuf); + } +} + +typedef struct { + grub_uint32_t pcrindex; + grub_uint32_t eventtype; + grub_uint8_t digest[20]; + grub_uint32_t eventsize; + grub_uint8_t event[1]; +} Event; + + +static grub_err_t +grub_tpm1_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf, + grub_size_t size, grub_uint8_t pcr, + const char *description) +{ + Event *event; + grub_efi_status_t status; + grub_efi_tpm_protocol_t *tpm; + grub_efi_physical_address_t lastevent; + grub_uint32_t algorithm; + grub_uint32_t eventnum = 0; + + tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!grub_tpm_present(tpm)) + return 0; + + event = grub_zalloc(sizeof (Event) + grub_strlen(description) + 1); + if (!event) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + N_("cannot allocate TPM event buffer")); + + event->pcrindex = pcr; + event->eventtype = EV_IPL; + event->eventsize = grub_strlen(description) + 1; + grub_memcpy(event->event, description, event->eventsize); + + algorithm = TCG_ALG_SHA; + status = efi_call_7 (tpm->log_extend_event, tpm, buf, (grub_uint64_t) size, + algorithm, event, &eventnum, &lastevent); + + switch (status) { + case GRUB_EFI_SUCCESS: + return 0; + case GRUB_EFI_DEVICE_ERROR: + return grub_error (GRUB_ERR_IO, N_("Command failed")); + case GRUB_EFI_INVALID_PARAMETER: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); + } +} + +static grub_err_t +grub_tpm2_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf, + grub_size_t size, grub_uint8_t pcr, + const char *description) +{ + EFI_TCG2_EVENT *event; + grub_efi_status_t status; + grub_efi_tpm2_protocol_t *tpm; + + tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!grub_tpm2_present(tpm)) + return 0; + + event = grub_zalloc(sizeof (EFI_TCG2_EVENT) + grub_strlen(description) + 1); + if (!event) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + N_("cannot allocate TPM event buffer")); + + event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); + event->Header.HeaderVersion = 1; + event->Header.PCRIndex = pcr; + event->Header.EventType = EV_IPL; + event->Size = sizeof(*event) - sizeof(event->Event) + grub_strlen(description) + 1; + grub_memcpy(event->Event, description, grub_strlen(description) + 1); + + status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, buf, + (grub_uint64_t) size, event); + + switch (status) { + case GRUB_EFI_SUCCESS: + return 0; + case GRUB_EFI_DEVICE_ERROR: + return grub_error (GRUB_ERR_IO, N_("Command failed")); + case GRUB_EFI_INVALID_PARAMETER: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); + } +} + +grub_err_t +grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) +{ + grub_efi_handle_t tpm_handle; + grub_efi_uint8_t protocol_version; + + if (!grub_tpm_handle_find(&tpm_handle, &protocol_version)) + return 0; + + if (protocol_version == 1) { + return grub_tpm1_log_event(tpm_handle, buf, size, pcr, description); + } else { + return grub_tpm2_log_event(tpm_handle, buf, size, pcr, description); + } +} diff --git a/grub-core/kern/i386/pc/tpm.c b/grub-core/kern/i386/pc/tpm.c new file mode 100644 index 000000000..8c6c1e6ec --- /dev/null +++ b/grub-core/kern/i386/pc/tpm.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include + +#define TCPA_MAGIC 0x41504354 + +int tpm_present(void); + +int tpm_present(void) +{ + struct grub_bios_int_registers regs; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + regs.eax = 0xbb00; + regs.ebx = TCPA_MAGIC; + grub_bios_interrupt (0x1a, ®s); + + if (regs.eax == 0) + return 1; + + return 0; +} + +grub_err_t +grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf, + PassThroughToTPM_OutputParamBlock *outbuf) +{ + struct grub_bios_int_registers regs; + grub_addr_t inaddr, outaddr; + + if (!tpm_present()) + return 0; + + inaddr = (grub_addr_t) inbuf; + outaddr = (grub_addr_t) outbuf; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + regs.eax = 0xbb02; + regs.ebx = TCPA_MAGIC; + regs.ecx = 0; + regs.edx = 0; + regs.es = (inaddr & 0xffff0000) >> 4; + regs.edi = inaddr & 0xffff; + regs.ds = outaddr >> 4; + regs.esi = outaddr & 0xf; + + grub_bios_interrupt (0x1a, ®s); + + if (regs.eax) + return grub_error (GRUB_ERR_IO, N_("TPM error %x\n"), regs.eax); + + return 0; +} + +typedef struct { + grub_uint32_t pcrindex; + grub_uint32_t eventtype; + grub_uint8_t digest[20]; + grub_uint32_t eventdatasize; + grub_uint8_t event[0]; +} GRUB_PACKED Event; + +typedef struct { + grub_uint16_t ipblength; + grub_uint16_t reserved; + grub_uint32_t hashdataptr; + grub_uint32_t hashdatalen; + grub_uint32_t pcr; + grub_uint32_t reserved2; + grub_uint32_t logdataptr; + grub_uint32_t logdatalen; +} GRUB_PACKED EventIncoming; + +typedef struct { + grub_uint16_t opblength; + grub_uint16_t reserved; + grub_uint32_t eventnum; + grub_uint8_t hashvalue[20]; +} GRUB_PACKED EventOutgoing; + +grub_err_t +grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) +{ + struct grub_bios_int_registers regs; + EventIncoming incoming; + EventOutgoing outgoing; + Event *event; + grub_uint32_t datalength; + + if (!tpm_present()) + return 0; + + datalength = grub_strlen(description); + event = grub_zalloc(datalength + sizeof(Event)); + if (!event) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + N_("cannot allocate TPM event buffer")); + + event->pcrindex = pcr; + event->eventtype = 0x0d; + event->eventdatasize = grub_strlen(description); + grub_memcpy(event->event, description, datalength); + + incoming.ipblength = sizeof(incoming); + incoming.hashdataptr = (grub_uint32_t)buf; + incoming.hashdatalen = size; + incoming.pcr = pcr; + incoming.logdataptr = (grub_uint32_t)event; + incoming.logdatalen = datalength + sizeof(Event); + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + regs.eax = 0xbb01; + regs.ebx = TCPA_MAGIC; + regs.ecx = 0; + regs.edx = 0; + regs.es = (((grub_addr_t) &incoming) & 0xffff0000) >> 4; + regs.edi = ((grub_addr_t) &incoming) & 0xffff; + regs.ds = (((grub_addr_t) &outgoing) & 0xffff0000) >> 4; + regs.esi = ((grub_addr_t) &outgoing) & 0xffff; + + grub_bios_interrupt (0x1a, ®s); + + grub_free(event); + + if (regs.eax) + return grub_error (GRUB_ERR_IO, N_("TPM error %x\n"), regs.eax); + + return 0; +} diff --git a/grub-core/kern/tpm.c b/grub-core/kern/tpm.c new file mode 100644 index 000000000..1a991876c --- /dev/null +++ b/grub-core/kern/tpm.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include +#include + +grub_err_t +grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) +{ + return grub_tpm_log_event(buf, size, pcr, description); +} diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c index d5e10ee87..ac6e0b797 100644 --- a/grub-core/lib/cmdline.c +++ b/grub-core/lib/cmdline.c @@ -19,6 +19,7 @@ #include #include +#include static unsigned int check_arg (char *c, int *has_space) { @@ -67,7 +68,7 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf, { int i, space; unsigned int arg_size; - char *c; + char *c, *orig = buf; for (i = 0; i < argc; i++) { @@ -104,5 +105,8 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf, *buf = 0; + grub_tpm_measure ((void *)orig, grub_strlen (orig), GRUB_CMDLINE_PCR, + "Kernel Commandline"); + return i; } diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c index 48716cedf..32c20bc26 100644 --- a/grub-core/loader/i386/efi/linux.c +++ b/grub-core/loader/i386/efi/linux.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../verity-hash.h" @@ -168,6 +169,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), argv[i]); goto fail; } + grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR, "UEFI Linux initrd"); ptr += cursize; grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); ptr += ALIGN_UP_OVERHEAD (cursize, 4); @@ -193,7 +195,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; struct linux_kernel_header lh; grub_ssize_t len, start, filelen; - void *kernel; + void *kernel = NULL; grub_dl_ref (my_mod); @@ -223,6 +225,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } + grub_tpm_measure (kernel, filelen, GRUB_KERNEL_PCR, "UEFI Linux kernel"); + if (! grub_linuxefi_secure_validate (kernel, filelen)) { grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); @@ -230,10 +234,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } - grub_file_seek (file, 0); - - grub_free(kernel); - params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); if (! params) @@ -242,15 +242,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } - memset (params, 0, 16384); + grub_memset (params, 0, 16384); - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) - { - if (!grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - goto fail; - } + grub_memcpy (&lh, kernel, sizeof (lh)); if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) { @@ -311,27 +305,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } - if (grub_file_seek (file, start) == (grub_off_t) -1) - { - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - goto fail; - } + grub_memcpy (kernel_mem, (char *)kernel + start, len); + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); + loaded=1; - if (grub_file_read (file, kernel_mem, len) != len && !grub_errno) - { - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - } - - if (grub_errno == GRUB_ERR_NONE) - { - grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); - loaded = 1; - lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; - } - - memcpy(params, &lh, 2 * 512); + lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; + grub_memcpy (params, &lh, 2 * 512); params->type_of_loader = 0x21; @@ -340,6 +319,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (file) grub_file_close (file); + grub_free (kernel); + if (grub_errno != GRUB_ERR_NONE) { grub_dl_unref (my_mod); diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 3778341b8..99005ae15 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "verity-hash.h" GRUB_MOD_LICENSE ("GPLv3+"); @@ -681,12 +682,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; struct linux_kernel_header lh; grub_uint8_t setup_sects; - grub_size_t real_size, prot_size, prot_file_size; + grub_size_t real_size, prot_size, prot_file_size, kernel_offset; grub_ssize_t len; int i; grub_size_t align, min_align; int relocatable; grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR; + grub_uint8_t *kernel = NULL; grub_dl_ref (my_mod); @@ -700,7 +702,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! file) goto fail; - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) + len = grub_file_size (file); + kernel = grub_malloc (len); + if (!kernel) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); + goto fail; + } + + if (grub_file_read (file, kernel, len) != len) { if (!grub_errno) grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), @@ -708,6 +718,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } + grub_tpm_measure (kernel, len, GRUB_KERNEL_PCR, "Linux Kernel"); + + grub_memcpy (&lh, kernel, sizeof (lh)); + + kernel_offset = sizeof (lh); + if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) { grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); @@ -807,13 +823,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), linux_params.ps_mouse = linux_params.padding10 = 0; len = sizeof (linux_params) - sizeof (lh); - if (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len) - { - if (!grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - goto fail; - } + + grub_memcpy (&linux_params + sizeof (lh), kernel + kernel_offset, len); + kernel_offset += len; linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; @@ -872,7 +884,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* The other parameters are filled when booting. */ - grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); + kernel_offset = real_size + GRUB_DISK_SECTOR_SIZE; grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n", (unsigned) real_size, (unsigned) prot_size); @@ -1018,9 +1030,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_pass_verity_hash(&lh, linux_cmdline); len = prot_file_size; - if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); + grub_memcpy (prot_mode_mem, kernel + kernel_offset, len); + kernel_offset += len; if (grub_errno == GRUB_ERR_NONE) { @@ -1031,6 +1042,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), fail: + grub_free (kernel); + if (file) grub_file_close (file); diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index f60b70234..43a08e4b5 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef GRUB_MACHINE_EFI #include @@ -164,6 +165,8 @@ grub_multiboot_load (grub_file_t file, const char *filename) return grub_errno; } + grub_tpm_measure((unsigned char*)buffer, len, GRUB_KERNEL_PCR, filename); + header = find_header (buffer, len); if (header == 0) diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index a293b17aa..bd73addba 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -35,6 +35,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -123,13 +124,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; struct linux_kernel_header lh; grub_uint8_t setup_sects; - grub_size_t real_size; + grub_size_t real_size, kernel_offset = 0; grub_ssize_t len; int i; char *grub_linux_prot_chunk; int grub_linux_is_bzimage; grub_addr_t grub_linux_prot_target; grub_err_t err; + grub_uint8_t *kernel = NULL; grub_dl_ref (my_mod); @@ -143,7 +145,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! file) goto fail; - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) + len = grub_file_size (file); + kernel = grub_malloc (len); + if (!kernel) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); + goto fail; + } + + if (grub_file_read (file, kernel, len) != len) { if (!grub_errno) grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), @@ -151,6 +161,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } + grub_tpm_measure (kernel, len, GRUB_KERNEL_PCR, "BIOS Linux Kernel"); + + grub_memcpy (&lh, kernel, sizeof (lh)); + kernel_offset = sizeof (lh); + if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) { grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); @@ -314,13 +329,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh)); len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); - if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len) - { - if (!grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - goto fail; - } + grub_memcpy (grub_linux_real_chunk + sizeof (lh), kernel + kernel_offset, + len); + kernel_offset += len; if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE) || grub_le_to_cpu16 (lh.version) < 0x0200) @@ -355,10 +366,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } len = grub_linux16_prot_size; - if (grub_file_read (file, grub_linux_prot_chunk, grub_linux16_prot_size) - != (grub_ssize_t) grub_linux16_prot_size && !grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); + grub_memcpy (grub_linux_prot_chunk, kernel + kernel_offset, len); + kernel_offset += len; if (grub_errno == GRUB_ERR_NONE) { @@ -368,6 +377,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), fail: + grub_free (kernel); + if (file) grub_file_close (file); diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c index be6fa0f4d..3005c0d19 100644 --- a/grub-core/loader/linux.c +++ b/grub-core/loader/linux.c @@ -4,6 +4,7 @@ #include #include #include +#include struct newc_head { @@ -288,6 +289,7 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx, grub_initrd_close (initrd_ctx); return grub_errno; } + grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR, "Linux Initrd"); ptr += cursize; } if (newc) diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 73aa0aa12..fe9a79ae0 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -42,6 +42,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -384,6 +385,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), } grub_file_close (file); + grub_tpm_measure (module, size, GRUB_KERNEL_PCR, argv[0]); return GRUB_ERR_NONE; } diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index d7c19bc99..76c67c3b6 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -36,6 +36,7 @@ #include #include #include +#include #if defined (GRUB_MACHINE_EFI) #include @@ -126,6 +127,8 @@ grub_multiboot_load (grub_file_t file, const char *filename) COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0); + grub_tpm_measure ((unsigned char *)buffer, len, GRUB_KERNEL_PCR, filename); + header = find_header (buffer, len); if (header == 0) diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index bb70ebf17..95c8b11d1 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Max digits for a char is 3 (0xFF is 255), similarly for an int it is sizeof (int) * 3, and one extra for a possible -ve sign. */ @@ -933,8 +934,9 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) grub_err_t ret = 0; grub_script_function_t func = 0; char errnobuf[18]; - char *cmdname; - int argc; + char *cmdname, *cmdstring; + int argc, offset = 0, cmdlen = 0; + unsigned int i; char **args; int invert; struct grub_script_argv argv = { 0, 0, 0 }; @@ -943,6 +945,25 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0]) return grub_errno; + for (i = 0; i < argv.argc; i++) { + cmdlen += grub_strlen (argv.args[i]) + 1; + } + + cmdstring = grub_malloc (cmdlen); + if (!cmdstring) + { + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + N_("cannot allocate command buffer")); + } + + for (i = 0; i < argv.argc; i++) { + offset += grub_snprintf (cmdstring + offset, cmdlen - offset, "%s ", + argv.args[i]); + } + cmdstring[cmdlen-1]= '\0'; + grub_tpm_measure ((unsigned char *)cmdstring, cmdlen, GRUB_COMMAND_PCR, + cmdstring); + grub_free(cmdstring); invert = 0; argc = argv.argc - 1; args = argv.args + 1; diff --git a/include/grub/efi/tpm.h b/include/grub/efi/tpm.h new file mode 100644 index 000000000..e2aff4a3c --- /dev/null +++ b/include/grub/efi/tpm.h @@ -0,0 +1,153 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2015 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_EFI_TPM_HEADER +#define GRUB_EFI_TPM_HEADER 1 + +#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 }}; + +typedef struct { + grub_efi_uint8_t Major; + grub_efi_uint8_t Minor; + grub_efi_uint8_t RevMajor; + grub_efi_uint8_t RevMinor; +} TCG_VERSION; + +typedef struct _TCG_EFI_BOOT_SERVICE_CAPABILITY { + grub_efi_uint8_t Size; /// Size of this structure. + TCG_VERSION StructureVersion; + TCG_VERSION ProtocolSpecVersion; + grub_efi_uint8_t HashAlgorithmBitmap; /// Hash algorithms . + char TPMPresentFlag; /// 00h = TPM not present. + char TPMDeactivatedFlag; /// 01h = TPM currently deactivated. +} TCG_EFI_BOOT_SERVICE_CAPABILITY; + +typedef struct { + grub_efi_uint32_t PCRIndex; + grub_efi_uint32_t EventType; + grub_efi_uint8_t digest[20]; + grub_efi_uint32_t EventSize; + grub_efi_uint8_t Event[1]; +} TCG_PCR_EVENT; + +struct grub_efi_tpm_protocol +{ + grub_efi_status_t (*status_check) (struct grub_efi_tpm_protocol *this, + TCG_EFI_BOOT_SERVICE_CAPABILITY *ProtocolCapability, + grub_efi_uint32_t *TCGFeatureFlags, + grub_efi_physical_address_t *EventLogLocation, + grub_efi_physical_address_t *EventLogLastEntry); + grub_efi_status_t (*hash_all) (struct grub_efi_tpm_protocol *this, + grub_efi_uint8_t *HashData, + grub_efi_uint64_t HashLen, + grub_efi_uint32_t AlgorithmId, + grub_efi_uint64_t *HashedDataLen, + grub_efi_uint8_t **HashedDataResult); + grub_efi_status_t (*log_event) (struct grub_efi_tpm_protocol *this, + TCG_PCR_EVENT *TCGLogData, + grub_efi_uint32_t *EventNumber, + grub_efi_uint32_t Flags); + grub_efi_status_t (*pass_through_to_tpm) (struct grub_efi_tpm_protocol *this, + grub_efi_uint32_t TpmInputParameterBlockSize, + grub_efi_uint8_t *TpmInputParameterBlock, + grub_efi_uint32_t TpmOutputParameterBlockSize, + grub_efi_uint8_t *TpmOutputParameterBlock); + grub_efi_status_t (*log_extend_event) (struct grub_efi_tpm_protocol *this, + grub_efi_physical_address_t HashData, + grub_efi_uint64_t HashDataLen, + grub_efi_uint32_t AlgorithmId, + TCG_PCR_EVENT *TCGLogData, + grub_efi_uint32_t *EventNumber, + grub_efi_physical_address_t *EventLogLastEntry); +}; + +typedef struct grub_efi_tpm_protocol grub_efi_tpm_protocol_t; + +typedef grub_efi_uint32_t EFI_TCG2_EVENT_LOG_BITMAP; +typedef grub_efi_uint32_t EFI_TCG2_EVENT_LOG_FORMAT; +typedef grub_efi_uint32_t EFI_TCG2_EVENT_ALGORITHM_BITMAP; + +typedef struct tdEFI_TCG2_VERSION { + grub_efi_uint8_t Major; + grub_efi_uint8_t Minor; +} GRUB_PACKED EFI_TCG2_VERSION; + +typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY { + grub_efi_uint8_t Size; + EFI_TCG2_VERSION StructureVersion; + EFI_TCG2_VERSION ProtocolVersion; + EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap; + EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs; + grub_efi_boolean_t TPMPresentFlag; + grub_efi_uint16_t MaxCommandSize; + grub_efi_uint16_t MaxResponseSize; + grub_efi_uint32_t ManufacturerID; + grub_efi_uint32_t NumberOfPcrBanks; + EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks; +} EFI_TCG2_BOOT_SERVICE_CAPABILITY; + +typedef grub_efi_uint32_t TCG_PCRINDEX; +typedef grub_efi_uint32_t TCG_EVENTTYPE; + +typedef struct tdEFI_TCG2_EVENT_HEADER { + grub_efi_uint32_t HeaderSize; + grub_efi_uint16_t HeaderVersion; + TCG_PCRINDEX PCRIndex; + TCG_EVENTTYPE EventType; +} GRUB_PACKED EFI_TCG2_EVENT_HEADER; + +typedef struct tdEFI_TCG2_EVENT { + grub_efi_uint32_t Size; + EFI_TCG2_EVENT_HEADER Header; + grub_efi_uint8_t Event[1]; +} GRUB_PACKED EFI_TCG2_EVENT; + +struct grub_efi_tpm2_protocol +{ + grub_efi_status_t (*get_capability) (struct grub_efi_tpm2_protocol *this, + EFI_TCG2_BOOT_SERVICE_CAPABILITY *ProtocolCapability); + grub_efi_status_t (*get_event_log) (struct grub_efi_tpm2_protocol *this, + EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, + grub_efi_physical_address_t *EventLogLocation, + grub_efi_physical_address_t *EventLogLastEntry, + grub_efi_boolean_t *EventLogTruncated); + grub_efi_status_t (*hash_log_extend_event) (struct grub_efi_tpm2_protocol *this, + grub_efi_uint64_t Flags, + grub_efi_physical_address_t *DataToHash, + grub_efi_uint64_t DataToHashLen, + EFI_TCG2_EVENT *EfiTcgEvent); + grub_efi_status_t (*submit_command) (struct grub_efi_tpm2_protocol *this, + grub_efi_uint32_t InputParameterBlockSize, + grub_efi_uint8_t *InputParameterBlock, + grub_efi_uint32_t OutputParameterBlockSize, + grub_efi_uint8_t *OutputParameterBlock); + grub_efi_status_t (*get_active_pcr_blanks) (struct grub_efi_tpm2_protocol *this, + grub_efi_uint32_t *ActivePcrBanks); + grub_efi_status_t (*set_active_pcr_banks) (struct grub_efi_tpm2_protocol *this, + grub_efi_uint32_t ActivePcrBanks); + grub_efi_status_t (*get_result_of_set_active_pcr_banks) (struct grub_efi_tpm2_protocol *this, + grub_efi_uint32_t *OperationPresent, + grub_efi_uint32_t *Response); +}; + +typedef struct grub_efi_tpm2_protocol grub_efi_tpm2_protocol_t; + +#define TCG_ALG_SHA 0x00000004 + +#endif diff --git a/include/grub/tpm.h b/include/grub/tpm.h new file mode 100644 index 000000000..7fc9d77d2 --- /dev/null +++ b/include/grub/tpm.h @@ -0,0 +1,92 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2015 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_TPM_HEADER +#define GRUB_TPM_HEADER 1 + +#define SHA1_DIGEST_SIZE 20 + +#define TPM_BASE 0x0 +#define TPM_SUCCESS TPM_BASE +#define TPM_AUTHFAIL (TPM_BASE + 0x1) +#define TPM_BADINDEX (TPM_BASE + 0x2) + +#define GRUB_TPM_PCR 9 +#define GRUB_KERNEL_PCR 10 +#define GRUB_INITRD_PCR 11 +#define GRUB_CMDLINE_PCR 12 +#define GRUB_COMMAND_PCR 13 + +#define TPM_TAG_RQU_COMMAND 0x00C1 +#define TPM_ORD_Extend 0x14 + +#define EV_IPL 0x0d + +/* TCG_PassThroughToTPM Input Parameter Block */ +typedef struct { + grub_uint16_t IPBLength; + grub_uint16_t Reserved1; + grub_uint16_t OPBLength; + grub_uint16_t Reserved2; + grub_uint8_t TPMOperandIn[1]; +} GRUB_PACKED PassThroughToTPM_InputParamBlock; + +/* TCG_PassThroughToTPM Output Parameter Block */ +typedef struct { + grub_uint16_t OPBLength; + grub_uint16_t Reserved; + grub_uint8_t TPMOperandOut[1]; +} GRUB_PACKED PassThroughToTPM_OutputParamBlock; + +typedef struct { + grub_uint16_t tag; + grub_uint32_t paramSize; + grub_uint32_t ordinal; + grub_uint32_t pcrNum; + grub_uint8_t inDigest[SHA1_DIGEST_SIZE]; /* The 160 bit value representing the event to be recorded. */ +} GRUB_PACKED ExtendIncoming; + +/* TPM_Extend Outgoing Operand */ +typedef struct { + grub_uint16_t tag; + grub_uint32_t paramSize; + grub_uint32_t returnCode; + grub_uint8_t outDigest[SHA1_DIGEST_SIZE]; /* The PCR value after execution of the command. */ +} GRUB_PACKED ExtendOutgoing; + +grub_err_t EXPORT_FUNC(grub_tpm_measure) (unsigned char *buf, grub_size_t size, + grub_uint8_t pcr, + const char *description); +#if defined (GRUB_MACHINE_EFI) || defined (GRUB_MACHINE_PCBIOS) +grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf, + PassThroughToTPM_OutputParamBlock *outbuf); +grub_err_t grub_tpm_log_event(unsigned char *buf, grub_size_t size, + grub_uint8_t pcr, const char *description); +#else +static inline grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf, + PassThroughToTPM_OutputParamBlock *outbuf) { return 0; }; +static inline grub_err_t grub_tpm_log_event(unsigned char *buf, + grub_size_t size, + grub_uint8_t pcr, + const char *description) +{ + return 0; +}; +#endif + +#endif