summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shim.c41
-rw-r--r--tpm.c136
-rw-r--r--tpm.h16
3 files changed, 174 insertions, 19 deletions
diff --git a/shim.c b/shim.c
index 6e040c4f..91fd926b 100644
--- a/shim.c
+++ b/shim.c
@@ -428,7 +428,8 @@ static BOOLEAN verify_eku(UINT8 *Cert, UINTN CertSize)
static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
UINTN dbsize,
WIN_CERTIFICATE_EFI_PKCS *data,
- UINT8 *hash)
+ UINT8 *hash, CHAR16 *dbname,
+ EFI_GUID guid)
{
EFI_SIGNATURE_DATA *Cert;
UINTN CertSize;
@@ -446,8 +447,10 @@ static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
Cert->SignatureData,
CertSize,
hash, SHA256_DIGEST_SIZE);
- if (IsFound)
+ if (IsFound) {
+ tpm_measure_variable(dbname, guid, CertSize, Cert->SignatureData);
return DATA_FOUND;
+ }
}
} else if (verbose) {
console_notify(L"Not a DER encoding x.509 Certificate");
@@ -477,7 +480,7 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
CertList = (EFI_SIGNATURE_LIST *)db;
- rc = check_db_cert_in_ram(CertList, dbsize, data, hash);
+ rc = check_db_cert_in_ram(CertList, dbsize, data, hash, dbname, guid);
FreePool(db);
@@ -489,7 +492,8 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
*/
static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
UINTN dbsize, UINT8 *data,
- int SignatureSize, EFI_GUID CertType)
+ int SignatureSize, EFI_GUID CertType,
+ CHAR16 *dbname, EFI_GUID guid)
{
EFI_SIGNATURE_DATA *Cert;
UINTN CertCount, Index;
@@ -505,6 +509,7 @@ static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
// Find the signature in database.
//
IsFound = TRUE;
+ tpm_measure_variable(dbname, guid, SignatureSize, data);
break;
}
@@ -545,7 +550,8 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
CertList = (EFI_SIGNATURE_LIST *)db;
CHECK_STATUS rc = check_db_hash_in_ram(CertList, dbsize, data,
- SignatureSize, CertType);
+ SignatureSize, CertType,
+ dbname, guid);
FreePool(db);
return rc;
@@ -563,15 +569,18 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
EFI_SIGNATURE_LIST *dbx = (EFI_SIGNATURE_LIST *)vendor_dbx;
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
- SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) ==
+ SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID,
+ L"dbx", secure_var) ==
DATA_FOUND)
return EFI_SECURITY_VIOLATION;
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
- SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) ==
+ SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID,
+ L"dbx", secure_var) ==
DATA_FOUND)
return EFI_SECURITY_VIOLATION;
if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
- sha256hash) == DATA_FOUND)
+ sha256hash, L"dbx",
+ secure_var) == DATA_FOUND)
return EFI_SECURITY_VIOLATION;
if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
@@ -960,6 +969,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
EFI_STATUS status = EFI_SECURITY_VIOLATION;
WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
unsigned int size = datasize;
+ EFI_GUID shim_var = SHIM_LOCK_GUID;
if (context->SecDir->Size != 0) {
if (context->SecDir->Size >= size) {
@@ -1026,6 +1036,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
shim_cert, sizeof(shim_cert), sha256hash,
SHA256_DIGEST_SIZE)) {
update_verification_method(VERIFIED_BY_CERT);
+ tpm_measure_variable(L"Shim", shim_var, sizeof(shim_cert), shim_cert);
status = EFI_SUCCESS;
return status;
}
@@ -1039,6 +1050,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
vendor_cert, vendor_cert_size,
sha256hash, SHA256_DIGEST_SIZE)) {
update_verification_method(VERIFIED_BY_CERT);
+ tpm_measure_variable(L"Shim", shim_var, vendor_cert_size, vendor_cert);
status = EFI_SUCCESS;
return status;
}
@@ -1888,7 +1900,11 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
}
/*
- * Measure some of the MOK variables into the TPM
+ * Measure some of the MOK variables into the TPM. We measure the entirety
+ * of MokList into PCR 14, and also measure the raw MokSBState there. PCR 7
+ * will be extended with MokSBState in the Microsoft format, and we'll
+ * measure any matching hashes or certificates later on in order to behave
+ * consistently with the PCR 7 spec.
*/
EFI_STATUS measure_mok()
{
@@ -1915,9 +1931,14 @@ EFI_STATUS measure_mok()
if (efi_status != EFI_SUCCESS)
return efi_status;
+ efi_status = tpm_measure_variable(L"MokSBState", shim_lock_guid,
+ DataSize, Data);
+ if (efi_status != EFI_SUCCESS)
+ goto out;
+
efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
DataSize, 14, (CHAR8 *)"MokSBState");
-
+out:
FreePool(Data);
return efi_status;
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);
+}
diff --git a/tpm.h b/tpm.h
index cc1bbedb..3769a1d4 100644
--- a/tpm.h
+++ b/tpm.h
@@ -7,6 +7,8 @@
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
const CHAR8 *description);
+EFI_STATUS tpm_measure_variable(CHAR16 *dbname, EFI_GUID guid, UINTN size, void *data);
+
typedef struct {
uint8_t Major;
uint8_t Minor;
@@ -154,3 +156,17 @@ struct efi_tpm2_protocol
};
typedef struct efi_tpm2_protocol efi_tpm2_protocol_t;
+
+typedef UINT32 TCG_EVENTTYPE;
+
+#define EV_EFI_EVENT_BASE ((TCG_EVENTTYPE) 0x80000000)
+#define EV_EFI_VARIABLE_DRIVER_CONFIG (EV_EFI_EVENT_BASE + 1)
+#define EV_EFI_VARIABLE_BOOT (EV_EFI_EVENT_BASE + 2)
+#define EV_EFI_BOOT_SERVICES_APPLICATION (EV_EFI_EVENT_BASE + 3)
+#define EV_EFI_BOOT_SERVICES_DRIVER (EV_EFI_EVENT_BASE + 4)
+#define EV_EFI_RUNTIME_SERVICES_DRIVER (EV_EFI_EVENT_BASE + 5)
+#define EV_EFI_GPT_EVENT (EV_EFI_EVENT_BASE + 6)
+#define EV_EFI_ACTION (EV_EFI_EVENT_BASE + 7)
+#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)