Add black/white listing

This commit is contained in:
Matthew Garrett 2012-06-25 10:59:08 -04:00
parent 8877e13127
commit c16548d08b
2 changed files with 93 additions and 11 deletions

101
shim.c
View File

@ -51,6 +51,12 @@ static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TAB
#include "cert.h" #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, static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid,
UINTN *size, void **buffer) UINTN *size, void **buffer)
{ {
@ -193,33 +199,81 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
return EFI_SUCCESS; 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_STATUS efi_status;
EFI_GUID global_var = EFI_GLOBAL_VARIABLE; EFI_GUID global_var = EFI_GLOBAL_VARIABLE;
EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_LIST *CertList;
EFI_SIGNATURE_DATA *Cert; 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; UINTN CertCount, Index;
BOOLEAN IsFound; BOOLEAN IsFound;
void *db; void *db;
unsigned int SignatureSize = SHA256_DIGEST_SIZE; 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) if (efi_status != EFI_SUCCESS)
return EFI_SUCCESS; return VAR_NOT_FOUND;
CertList = db; CertList = db;
while ((dbxsize > 0) && (dbxsize >= CertList->SignatureListSize)) { while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize; CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); 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))) { if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, &CertType))) {
for (Index = 0; Index < CertCount; Index++) { 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. // 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); CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
} }
FreePool(db); FreePool(db);
if (IsFound) 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_ACCESS_DENIED;
return EFI_SUCCESS; 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 * 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; goto done;
} }
status = check_blacklist(vendor_cert, hash); status = check_blacklist(cert, hash);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
Print(L"Binary is blacklisted\n"); Print(L"Binary is blacklisted\n");
goto done; goto done;
} }
status = check_whitelist(cert, hash);
if (status == EFI_SUCCESS) {
Print(L"Binary is whitelisted\n");
goto done;
}
if (!AuthenticodeVerify(cert->CertData, if (!AuthenticodeVerify(cert->CertData,
context->SecDir->Size - sizeof(cert->Hdr), context->SecDir->Size - sizeof(cert->Hdr),
vendor_cert, sizeof(vendor_cert), hash, vendor_cert, sizeof(vendor_cert), hash,

View File

@ -1,6 +1,7 @@
#define SHA256_DIGEST_SIZE 32 #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 { typedef struct {
/// ///