diff options
| -rw-r--r-- | shim.c | 41 | ||||
| -rw-r--r-- | tpm.c | 136 | ||||
| -rw-r--r-- | tpm.h | 16 |
3 files changed, 174 insertions, 19 deletions
@@ -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; @@ -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); +} @@ -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) |
