summaryrefslogtreecommitdiff
path: root/tpm.c
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@google.com>2017-05-22 15:36:48 -0700
committerPeter Jones <pjones@redhat.com>2017-08-01 12:54:49 -0400
commit8af7c4cacaf753f38f2564b26b962a7a2942d664 (patch)
tree91852f5250854949db0532c744fc67d9b1435c86 /tpm.c
parenta8f3dc82be8e16d24ceab416c1b0af897c083f56 (diff)
downloadefi-boot-shim-8af7c4cacaf753f38f2564b26b962a7a2942d664.tar.gz
efi-boot-shim-8af7c4cacaf753f38f2564b26b962a7a2942d664.zip
Extend PCR 7
It's desirable to be able to use PCR 7 for all TPM policy on Secure Boot systems, but right now Shim doesn't record any information about its configuration or the signature used to launch the second stage loader. Add support for that.
Diffstat (limited to 'tpm.c')
-rw-r--r--tpm.c136
1 files changed, 127 insertions, 9 deletions
diff --git a/tpm.c b/tpm.c
index c37cc484..6e3933cb 100644
--- a/tpm.c
+++ b/tpm.c
@@ -14,6 +14,16 @@ extern UINT8 in_protocol;
})
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+ VOID *Data;
+ UINTN Size;
+} VARIABLE_RECORD;
+
+UINTN measuredcount = 0;
+VARIABLE_RECORD *measureddata = NULL;
+
EFI_GUID tpm_guid = EFI_TPM_GUID;
EFI_GUID tpm2_guid = EFI_TPM2_GUID;
@@ -108,8 +118,9 @@ static EFI_STATUS trigger_tcg2_final_events_table(efi_tpm2_protocol_t *tpm2,
&start, &end, &truncated);
}
-EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
- const CHAR8 *description)
+static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
+ UINT8 pcr, const CHAR8 *log, UINTN logsize,
+ UINT32 type)
{
EFI_STATUS status;
efi_tpm_protocol_t *tpm;
@@ -138,7 +149,7 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
return status;
}
- event = AllocatePool(sizeof(*event) + strlen(description) + 1);
+ event = AllocatePool(sizeof(*event) + logsize);
if (!event) {
perror(L"Unable to allocate event structure\n");
return EFI_OUT_OF_RESOURCES;
@@ -147,9 +158,9 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
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) + strlen(description) + 1;
- memcpy(event->Event, description, strlen(description) + 1);
+ 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);
FreePool(event);
@@ -167,7 +178,7 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
if (!tpm_present(tpm))
return EFI_SUCCESS;
- event = AllocatePool(sizeof(*event) + strlen(description) + 1);
+ event = AllocatePool(sizeof(*event) + logsize);
if (!event) {
perror(L"Unable to allocate event structure\n");
@@ -175,8 +186,9 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
}
event->PCRIndex = pcr;
- event->EventType = EV_IPL;
- event->EventSize = strlen(description) + 1;
+ 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);
@@ -186,3 +198,109 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
return EFI_SUCCESS;
}
+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);
+}
+
+typedef struct {
+ EFI_GUID VariableName;
+ UINT64 UnicodeNameLength;
+ UINT64 VariableDataLength;
+ CHAR16 UnicodeName[1];
+ INT8 VariableData[1];
+} EFI_VARIABLE_DATA_TREE;
+
+static BOOLEAN tpm_data_measured(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
+{
+ UINTN i;
+
+ for (i=0; i<measuredcount; i++) {
+ if ((StrCmp (VarName, measureddata[i].VariableName) == 0) &&
+ (CompareGuid (&VendorGuid, measureddata[i].VendorGuid)) &&
+ (VarSize == measureddata[i].Size) &&
+ (CompareMem (VarData, measureddata[i].Data, VarSize) == 0)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static EFI_STATUS tpm_record_data_measurement(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
+{
+ if (measureddata == NULL) {
+ measureddata = AllocatePool(sizeof(*measureddata));
+ } else {
+ measureddata = ReallocatePool(measureddata, measuredcount * sizeof(*measureddata),
+ (measuredcount + 1) * sizeof(*measureddata));
+ }
+
+ if (measureddata == NULL)
+ return EFI_OUT_OF_RESOURCES;
+
+ measureddata[measuredcount].VariableName = AllocatePool(StrSize(VarName));
+ measureddata[measuredcount].VendorGuid = AllocatePool(sizeof(EFI_GUID));
+ measureddata[measuredcount].Data = AllocatePool(VarSize);
+
+ if (measureddata[measuredcount].VariableName == NULL ||
+ measureddata[measuredcount].VendorGuid == NULL ||
+ measureddata[measuredcount].Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StrCpy(measureddata[measuredcount].VariableName, VarName);
+ CopyMem(measureddata[measuredcount].VendorGuid, &VendorGuid, sizeof(EFI_GUID));
+ CopyMem(measureddata[measuredcount].Data, VarData, VarSize);
+ measureddata[measuredcount].Size = VarSize;
+ measuredcount++;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS tpm_measure_variable(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
+{
+ EFI_STATUS Status;
+ UINTN VarNameLength;
+ EFI_VARIABLE_DATA_TREE *VarLog;
+ UINT32 VarLogSize;
+
+ /* Don't measure something that we've already measured */
+ if (tpm_data_measured(VarName, VendorGuid, VarSize, VarData))
+ return EFI_SUCCESS;
+
+ VarNameLength = StrLen (VarName);
+ VarLogSize = (UINT32)(sizeof (*VarLog) +
+ VarNameLength * sizeof (*VarName) +
+ VarSize -
+ sizeof (VarLog->UnicodeName) -
+ sizeof (VarLog->VariableData));
+
+ VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
+ if (VarLog == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (&VarLog->VariableName, &VendorGuid,
+ sizeof(VarLog->VariableName));
+ VarLog->UnicodeNameLength = VarNameLength;
+ VarLog->VariableDataLength = VarSize;
+ CopyMem (VarLog->UnicodeName, VarName,
+ VarNameLength * sizeof (*VarName));
+ CopyMem ((CHAR16 *)VarLog->UnicodeName + VarNameLength, VarData,
+ VarSize);
+
+ Status = tpm_log_event_raw((EFI_PHYSICAL_ADDRESS)VarLog, VarLogSize, 7,
+ (CHAR8 *)VarLog, VarLogSize,
+ EV_EFI_VARIABLE_AUTHORITY);
+
+ FreePool(VarLog);
+
+ if (Status != EFI_SUCCESS)
+ return Status;
+
+ return tpm_record_data_measurement(VarName, VendorGuid, VarSize,
+ VarData);
+}