diff --git a/shim.c b/shim.c index a479f33..fa4f2c5 100644 --- a/shim.c +++ b/shim.c @@ -51,6 +51,12 @@ static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TAB #include "cert.h" +typedef enum { + DATA_FOUND, + DATA_NOT_FOUND, + VAR_NOT_FOUND +} CHECK_STATUS; + static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINTN *size, void **buffer) { @@ -193,33 +199,81 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context, return EFI_SUCCESS; } -static EFI_STATUS check_blacklist (UINT8 *cert, UINT8 *hash) +static CHECK_STATUS check_db_cert(CHAR16 *dbname, WIN_CERTIFICATE_EFI_PKCS *data, UINT8 *hash) { EFI_STATUS efi_status; EFI_GUID global_var = EFI_GLOBAL_VARIABLE; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *Cert; - UINTN dbxsize = 0; + UINTN dbsize = 0; + UINTN CertCount, Index; + BOOLEAN IsFound; + void *db; + EFI_GUID CertType = EfiCertX509Guid; + + efi_status = get_variable(dbname, global_var, &dbsize, &db); + + if (efi_status != EFI_SUCCESS) + return VAR_NOT_FOUND; + + CertList = db; + + while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &CertType)) { + CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize; + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + for (Index = 0; Index < CertCount; Index++) { + IsFound = AuthenticodeVerify (data->CertData, + data->Hdr.dwLength - sizeof(data->Hdr), + Cert->SignatureData, + CertList->SignatureSize, + hash, SHA256_DIGEST_SIZE); + } + if (IsFound) { + break; + } + + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + + dbsize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + + FreePool(db); + + if (IsFound) + return DATA_FOUND; + + return DATA_NOT_FOUND; +} + +static CHECK_STATUS check_db_hash(CHAR16 *dbname, UINT8 *data) +{ + EFI_STATUS efi_status; + EFI_GUID global_var = EFI_GLOBAL_VARIABLE; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINTN dbsize = 0; UINTN CertCount, Index; BOOLEAN IsFound; void *db; unsigned int SignatureSize = SHA256_DIGEST_SIZE; - EFI_GUID CertType = EfiCertSha256Guid; + EFI_GUID CertType = EfiHashSha256Guid; - efi_status = get_variable(L"dbx", global_var, &dbxsize, &db); + efi_status = get_variable(dbname, global_var, &dbsize, &db); - /* If we can't read it then it can't be blacklisted */ if (efi_status != EFI_SUCCESS) - return EFI_SUCCESS; + return VAR_NOT_FOUND; CertList = db; - while ((dbxsize > 0) && (dbxsize >= CertList->SignatureListSize)) { + while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize; Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, &CertType))) { for (Index = 0; Index < CertCount; Index++) { - if (CompareMem (Cert->SignatureData, hash, SignatureSize) == 0) { + if (CompareMem (Cert->SignatureData, data, SignatureSize) == 0) { // // Find the signature in database. // @@ -234,18 +288,38 @@ static EFI_STATUS check_blacklist (UINT8 *cert, UINT8 *hash) } } - dbxsize -= CertList->SignatureListSize; + dbsize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } FreePool(db); if (IsFound) + return DATA_FOUND; + + return DATA_NOT_FOUND; +} + +static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert, UINT8 *hash) +{ + if (check_db_hash(L"dbx", hash) == DATA_FOUND) + return EFI_ACCESS_DENIED; + if (check_db_cert(L"dbx", cert, hash) == DATA_FOUND) return EFI_ACCESS_DENIED; return EFI_SUCCESS; } +static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert, UINT8 *hash) +{ + if (check_db_hash(L"db", hash) == DATA_FOUND) + return EFI_SUCCESS; + if (check_db_cert(L"db", cert, hash) == DATA_FOUND) + return EFI_SUCCESS; + + return EFI_ACCESS_DENIED; +} + /* * Check that the signature is valid and matches the binary */ @@ -429,13 +503,20 @@ static EFI_STATUS verify_buffer (char *data, int datasize, goto done; } - status = check_blacklist(vendor_cert, hash); + status = check_blacklist(cert, hash); if (status != EFI_SUCCESS) { Print(L"Binary is blacklisted\n"); goto done; } + status = check_whitelist(cert, hash); + + if (status == EFI_SUCCESS) { + Print(L"Binary is whitelisted\n"); + goto done; + } + if (!AuthenticodeVerify(cert->CertData, context->SecDir->Size - sizeof(cert->Hdr), vendor_cert, sizeof(vendor_cert), hash, diff --git a/signature.h b/signature.h index 154da5e..d2a8843 100644 --- a/signature.h +++ b/signature.h @@ -1,6 +1,7 @@ #define SHA256_DIGEST_SIZE 32 -EFI_GUID EfiCertSha256Guid = { 0xc1c41626, 0x504c, 0x4092, {0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 }}; +EFI_GUID EfiHashSha256Guid = { 0xc1c41626, 0x504c, 0x4092, {0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 }}; +EFI_GUID EfiCertX509Guid = { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 }}; typedef struct { ///