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;
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");
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);
*/
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;
// Find the signature in database.
//
IsFound = TRUE;
+ tpm_measure_variable(dbname, guid, SignatureSize, data);
break;
}
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;
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,
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) {
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;
}
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;
}
}
/*
- * 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()
{
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;
})
+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;
&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;
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;
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);
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");
}
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);
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);
+}