grub/grub-core/kern/i386/pc/tpm.c
Matthew Garrett 858f763466 Core TPM support
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.
2016-01-05 14:35:05 -08:00

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, &regs);
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, &regs);
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, &regs);
grub_free(event);
if (regs.eax)
return grub_error (GRUB_ERR_IO, N_("TPM error %x\n"), regs.eax);
return 0;
}