858f763466
Add support for performing basic TPM measurements. Right now this only supports extending PCRs statically and only on UEFI and BIOS systems, but will measure all modules as they're loaded.
132 lines
3 KiB
C
132 lines
3 KiB
C
#include <grub/err.h>
|
|
#include <grub/i18n.h>
|
|
#include <grub/mm.h>
|
|
#include <grub/tpm.h>
|
|
#include <grub/misc.h>
|
|
#include <grub/i386/pc/int.h>
|
|
|
|
#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;
|
|
}
|