Use the machine owner keys to verify images

This commit is contained in:
Gary Ching-Pang Lin 2012-09-11 16:39:12 +08:00
parent 333bd97743
commit 1342297309

100
shim.c
View File

@ -60,6 +60,11 @@ typedef enum {
VAR_NOT_FOUND VAR_NOT_FOUND
} CHECK_STATUS; } CHECK_STATUS;
typedef struct {
UINT32 MokSize;
UINT8 *Mok;
} MokListNode;
static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes,
UINTN *size, void **buffer) UINTN *size, void **buffer)
{ {
@ -97,6 +102,37 @@ static EFI_STATUS delete_variable (CHAR16 *name, EFI_GUID guid)
return efi_status; return efi_status;
} }
static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
MokListNode *list;
int i, remain = DataSize;
void *ptr;
list = AllocatePool(sizeof(MokListNode) * num);
if (!list) {
Print(L"Unable to allocate MOK list\n");
return NULL;
}
ptr = Data;
for (i = 0; i < num; i++) {
if (remain < 0) {
Print(L"MOK list was corrupted\n");
FreePool(list);
return NULL;
}
CopyMem(&list[i].MokSize, ptr, sizeof(UINT32));
ptr += sizeof(UINT32);
list[i].Mok = ptr;
ptr += list[i].MokSize;
remain -= sizeof(UINT32) + list[i].MokSize;
}
return list;
}
/* /*
* Perform basic bounds checking of the intra-image pointers * Perform basic bounds checking of the intra-image pointers
*/ */
@ -373,6 +409,7 @@ static BOOLEAN secure_mode (void)
static EFI_STATUS verify_buffer (char *data, int datasize, static EFI_STATUS verify_buffer (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context, int whitelist) PE_COFF_LOADER_IMAGE_CONTEXT *context, int whitelist)
{ {
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
unsigned int size = datasize; unsigned int size = datasize;
unsigned int ctxsize; unsigned int ctxsize;
void *ctx = NULL; void *ctx = NULL;
@ -386,6 +423,11 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
EFI_IMAGE_SECTION_HEADER *Section; EFI_IMAGE_SECTION_HEADER *Section;
EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL; EFI_IMAGE_SECTION_HEADER *SectionHeader = NULL;
EFI_IMAGE_SECTION_HEADER *SectionCache; EFI_IMAGE_SECTION_HEADER *SectionCache;
unsigned int i;
void *MokListData = NULL;
UINTN MokListDataSize = 0;
UINT32 MokNum, attributes;
MokListNode *list = NULL;
cert = ImageAddress (data, size, context->SecDir->VirtualAddress); cert = ImageAddress (data, size, context->SecDir->VirtualAddress);
@ -547,16 +589,60 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
} }
} }
if (!AuthenticodeVerify(cert->CertData, if (AuthenticodeVerify(cert->CertData,
context->SecDir->Size - sizeof(cert->Hdr), context->SecDir->Size - sizeof(cert->Hdr),
vendor_cert, vendor_cert_size, hash, vendor_cert, vendor_cert_size, hash,
SHA256_DIGEST_SIZE)) { SHA256_DIGEST_SIZE)) {
Print(L"Invalid signature\n");
status = EFI_ACCESS_DENIED;
} else {
status = EFI_SUCCESS; status = EFI_SUCCESS;
Print(L"Binary is verified by the vendor certificate\n");
goto done;
} }
status = get_variable(L"MokList", shim_lock_guid, &attributes,
&MokListDataSize, &MokListData);
if (status != EFI_SUCCESS) {
status = EFI_ACCESS_DENIED;
Print(L"Invalid signature\n");
goto done;
}
if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
Print(L"MokList is compromised!\nErase all keys in MokList!\n");
if (delete_variable(L"MokList", shim_lock_guid) != EFI_SUCCESS) {
Print(L"Failed to erase MokList\n");
}
status = EFI_ACCESS_DENIED;
goto done;
}
CopyMem(&MokNum, MokListData, sizeof(UINT32));
if (MokNum == 0)
goto done;
list = build_mok_list(MokNum,
(void *)MokListData + sizeof(UINT32),
MokListDataSize - sizeof(UINT32));
if (!list) {
Print(L"Failed to construct MOK list\n");
status = EFI_OUT_OF_RESOURCES;
goto done;
}
for (i = 0; i < MokNum; i++) {
if (AuthenticodeVerify(cert->CertData,
context->SecDir->Size - sizeof(cert->Hdr),
list[i].Mok, list[i].MokSize, hash,
SHA256_DIGEST_SIZE)) {
status = EFI_SUCCESS;
Print(L"Binary is verified by the machine owner key\n");
goto done;
}
}
Print(L"Invalid signature\n");
status = EFI_ACCESS_DENIED;
done: done:
if (SectionHeader) if (SectionHeader)
FreePool(SectionHeader); FreePool(SectionHeader);