Split out hashing

We want to be able to generate hashes, so split out the hash generation
function from the verification function
This commit is contained in:
Matthew Garrett 2012-10-11 12:24:36 -04:00
parent 7fa4dae051
commit f394b22e86

108
shim.c
View File

@ -406,46 +406,25 @@ static BOOLEAN secure_mode (void)
} }
/* /*
* Check that the signature is valid and matches the binary * Calculate the SHA1 and SHA256 hashes of a binary
*/ */
static EFI_STATUS verify_buffer (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context, int whitelist) static EFI_STATUS generate_hash (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context,
UINT8 *sha256hash, UINT8 *sha1hash)
{ {
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
unsigned int size = datasize;
unsigned int sha256ctxsize, sha1ctxsize; unsigned int sha256ctxsize, sha1ctxsize;
unsigned int size = datasize;
void *sha256ctx = NULL, *sha1ctx = NULL; void *sha256ctx = NULL, *sha1ctx = NULL;
UINT8 sha256hash[SHA256_DIGEST_SIZE];
UINT8 sha1hash[SHA1_DIGEST_SIZE];
EFI_STATUS status = EFI_ACCESS_DENIED;
char *hashbase; char *hashbase;
unsigned int hashsize; unsigned int hashsize;
WIN_CERTIFICATE_EFI_PKCS *cert;
unsigned int SumOfBytesHashed, SumOfSectionBytes; unsigned int SumOfBytesHashed, SumOfSectionBytes;
unsigned int index, pos; unsigned int index, pos;
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; EFI_STATUS status = EFI_SUCCESS;
void *MokListData = NULL;
UINTN MokListDataSize = 0;
UINT32 MokNum, attributes;
MokListNode *list = NULL;
cert = ImageAddress (data, size, context->SecDir->VirtualAddress);
if (!cert) {
Print(L"Certificate located outside the image\n");
return EFI_INVALID_PARAMETER;
}
if (cert->Hdr.wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
Print(L"Unsupported certificate type %x\n",
cert->Hdr.wCertificateType);
return EFI_UNSUPPORTED;
}
/* FIXME: Check which kind of hash */
sha256ctxsize = Sha256GetContextSize(); sha256ctxsize = Sha256GetContextSize();
sha256ctx = AllocatePool(sha256ctxsize); sha256ctx = AllocatePool(sha256ctxsize);
@ -585,11 +564,58 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
goto done; goto done;
} }
done:
if (SectionHeader)
FreePool(SectionHeader);
if (sha1ctx)
FreePool(sha1ctx);
if (sha256ctx)
FreePool(sha256ctx);
return status;
}
/*
* Check that the signature is valid and matches the binary
*/
static EFI_STATUS verify_buffer (char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context, int whitelist)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
UINT8 sha256hash[SHA256_DIGEST_SIZE];
UINT8 sha1hash[SHA1_DIGEST_SIZE];
EFI_STATUS status = EFI_ACCESS_DENIED;
WIN_CERTIFICATE_EFI_PKCS *cert;
void *MokListData = NULL;
UINTN MokListDataSize = 0;
UINT32 MokNum, attributes;
MokListNode *list = NULL;
unsigned int i;
unsigned int size = datasize;
cert = ImageAddress (data, size, context->SecDir->VirtualAddress);
if (!cert) {
Print(L"Certificate located outside the image\n");
return EFI_INVALID_PARAMETER;
}
if (cert->Hdr.wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
Print(L"Unsupported certificate type %x\n",
cert->Hdr.wCertificateType);
return EFI_UNSUPPORTED;
}
status = generate_hash(data, datasize, context, sha256hash, sha1hash);
if (status != EFI_SUCCESS)
return status;
status = check_blacklist(cert, sha256hash, sha1hash); status = check_blacklist(cert, sha256hash, sha1hash);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
Print(L"Binary is blacklisted\n"); Print(L"Binary is blacklisted\n");
goto done; return status;
} }
if (whitelist) { if (whitelist) {
@ -597,7 +623,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
if (status == EFI_SUCCESS) { if (status == EFI_SUCCESS) {
Print(L"Binary is whitelisted\n"); Print(L"Binary is whitelisted\n");
goto done; return status;
} }
} }
@ -607,7 +633,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
SHA256_DIGEST_SIZE)) { SHA256_DIGEST_SIZE)) {
status = EFI_SUCCESS; status = EFI_SUCCESS;
Print(L"Binary is verified by the vendor certificate\n"); Print(L"Binary is verified by the vendor certificate\n");
goto done; return status;
} }
status = get_variable(L"MokList", shim_lock_guid, &attributes, status = get_variable(L"MokList", shim_lock_guid, &attributes,
@ -616,7 +642,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
if (status != EFI_SUCCESS || MokListDataSize < sizeof(UINT32)) { if (status != EFI_SUCCESS || MokListDataSize < sizeof(UINT32)) {
status = EFI_ACCESS_DENIED; status = EFI_ACCESS_DENIED;
Print(L"Invalid signature\n"); Print(L"Invalid signature\n");
goto done; return status;
} }
if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) { if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
@ -625,13 +651,13 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
Print(L"Failed to erase MokList\n"); Print(L"Failed to erase MokList\n");
} }
status = EFI_ACCESS_DENIED; status = EFI_ACCESS_DENIED;
goto done; return status;
} }
CopyMem(&MokNum, MokListData, sizeof(UINT32)); CopyMem(&MokNum, MokListData, sizeof(UINT32));
if (MokNum == 0) { if (MokNum == 0) {
status = EFI_ACCESS_DENIED; status = EFI_ACCESS_DENIED;
goto done; return status;
} }
list = build_mok_list(MokNum, list = build_mok_list(MokNum,
@ -641,7 +667,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
if (!list) { if (!list) {
Print(L"Failed to construct MOK list\n"); Print(L"Failed to construct MOK list\n");
status = EFI_OUT_OF_RESOURCES; status = EFI_OUT_OF_RESOURCES;
goto done; return status;
} }
for (i = 0; i < MokNum; i++) { for (i = 0; i < MokNum; i++) {
@ -651,20 +677,12 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
SHA256_DIGEST_SIZE)) { SHA256_DIGEST_SIZE)) {
status = EFI_SUCCESS; status = EFI_SUCCESS;
Print(L"Binary is verified by the machine owner key\n"); Print(L"Binary is verified by the machine owner key\n");
goto done; return status;
} }
} }
Print(L"Invalid signature\n"); Print(L"Invalid signature\n");
status = EFI_ACCESS_DENIED; status = EFI_ACCESS_DENIED;
done:
if (SectionHeader)
FreePool(SectionHeader);
if (sha1ctx)
FreePool(sha1ctx);
if (sha256ctx)
FreePool(sha256ctx);
return status; return status;
} }