summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MokManager.c326
-rw-r--r--shim.c159
-rw-r--r--shim.h22
-rw-r--r--signature.h4
4 files changed, 320 insertions, 191 deletions
diff --git a/MokManager.c b/MokManager.c
index 4b3b0a5a..0d07c33f 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -3,6 +3,8 @@
#include <Library/BaseCryptLib.h>
#include <openssl/x509.h>
#include "shim.h"
+#include "signature.h"
+#include "PeImage.h"
#define PASSWORD_MAX 16
#define PASSWORD_MIN 8
@@ -11,11 +13,14 @@
#define SHIM_VENDOR L"Shim"
#endif
+#define EFI_VARIABLE_APPEND_WRITE 0x00000040
+
struct menu_item {
CHAR16 *text;
- INTN (* callback)(void *data, void *data2);
+ INTN (* callback)(void *data, void *data2, void *data3);
void *data;
void *data2;
+ void *data3;
UINTN colour;
};
@@ -75,12 +80,12 @@ done:
static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
MokListNode *list;
- INT64 remain = DataSize;
- int i;
- void *ptr;
-
- if (DataSize < sizeof(UINT32))
- return NULL;
+ EFI_SIGNATURE_LIST *CertList = Data;
+ EFI_SIGNATURE_DATA *Cert;
+ EFI_GUID CertType = EfiCertX509Guid;
+ EFI_GUID HashType = EfiHashSha256Guid;
+ UINTN dbsize = DataSize;
+ UINTN count = 0;
list = AllocatePool(sizeof(MokListNode) * num);
@@ -89,20 +94,33 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
return NULL;
}
- ptr = Data;
- for (i = 0; i < num; i++) {
- CopyMem(&list[i].MokSize, ptr, sizeof(UINT32));
- remain -= sizeof(UINT32) + list[i].MokSize;
+ while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
+ if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
+ (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
+ CertList->SignatureSize);
+ continue;
+ }
- if (remain < 0) {
- Print(L"the list was corrupted\n");
- FreePool(list);
- return NULL;
+ if ((CompareGuid (&CertList->SignatureType, &HashType) == 0) &&
+ (CertList->SignatureSize != 48)) {
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
+ CertList->SignatureSize);
+ continue;
}
- ptr += sizeof(UINT32);
- list[i].Mok = ptr;
- ptr += list[i].MokSize;
+ Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
+ sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+
+ list[count].MokSize = CertList->SignatureSize;
+ list[count].Mok = (void *)Cert->SignatureData;
+
+ count++;
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+ CertList->SignatureSize);
}
return list;
@@ -289,16 +307,25 @@ static void show_mok_info (void *Mok, UINTN MokSize)
if (!Mok || MokSize == 0)
return;
- if (X509ConstructCertificate(Mok, MokSize, (UINT8 **) &X509Cert) &&
- X509Cert != NULL) {
- show_x509_info(X509Cert);
- X509_free(X509Cert);
+ if (MokSize != 48) {
+ if (X509ConstructCertificate(Mok, MokSize, (UINT8 **) &X509Cert) &&
+ X509Cert != NULL) {
+ show_x509_info(X509Cert);
+ X509_free(X509Cert);
+ } else {
+ Print(L" Not a valid X509 certificate: %x\n\n",
+ ((UINT32 *)Mok)[0]);
+ return;
+ }
} else {
- Print(L" Not a valid X509 certificate: %x\n\n",
- ((UINT32 *)Mok)[0]);
- return;
+ Print(L"SHA256 hash:\n ");
+ for (i = 0; i < SHA256_DIGEST_SIZE; i++) {
+ Print(L" %02x", ((UINT8 *)Mok)[i]);
+ if (i % 10 == 9)
+ Print(L"\n ");
+ }
+ Print(L"\n");
}
-
efi_status = get_sha1sum(Mok, MokSize, hash);
if (efi_status != EFI_SUCCESS) {
@@ -354,20 +381,48 @@ static INTN get_number ()
static UINT8 list_keys (void *MokNew, UINTN MokNewSize)
{
- UINT32 MokNum;
+ UINT32 MokNum = 0;
MokListNode *keys = NULL;
INTN key_num = 0;
UINT8 initial = 1;
-
- CopyMem(&MokNum, MokNew, sizeof(UINT32));
- if (MokNum == 0) {
- Print(L"No key exists\n");
+ EFI_SIGNATURE_LIST *CertList = MokNew;
+ EFI_GUID CertType = EfiCertX509Guid;
+ EFI_GUID HashType = EfiHashSha256Guid;
+ UINTN dbsize = MokNewSize;
+
+ if (MokNewSize < (sizeof(EFI_SIGNATURE_LIST) +
+ sizeof(EFI_SIGNATURE_DATA))) {
+ Print(L"No keys\n");
+ Pause();
return 0;
}
- keys = build_mok_list(MokNum,
- (void *)MokNew + sizeof(UINT32),
- MokNewSize - sizeof(UINT32));
+ while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
+ if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
+ (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
+ Print(L"Doesn't look like a key or hash\n");
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+ CertList->SignatureSize);
+ continue;
+ }
+
+ if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
+ (CertList->SignatureSize != 48)) {
+ Print(L"Doesn't look like a valid hash\n");
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+ CertList->SignatureSize);
+ continue;
+ }
+
+ MokNum++;
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+ CertList->SignatureSize);
+ }
+
+ keys = build_mok_list(MokNum, MokNew, MokNewSize);
if (!keys) {
Print(L"Failed to construct key list in MokNew\n");
@@ -466,10 +521,12 @@ static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *passw
goto done;
}
- if (!(Sha256Update(ctx, MokNew, MokNewSize))) {
- Print(L"Unable to generate hash\n");
- status = EFI_OUT_OF_RESOURCES;
- goto done;
+ if (MokNew && MokNewSize) {
+ if (!(Sha256Update(ctx, MokNew, MokNewSize))) {
+ Print(L"Unable to generate hash\n");
+ status = EFI_OUT_OF_RESOURCES;
+ goto done;
+ }
}
if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) {
@@ -542,12 +599,24 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
return EFI_ACCESS_DENIED;
}
- /* Write new MOK */
- efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
- &shim_lock_guid,
- EFI_VARIABLE_NON_VOLATILE
- | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- MokNewSize, MokNew);
+ if (!MokNewSize) {
+ /* Delete MOK */
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
+ &shim_lock_guid,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_APPEND_WRITE,
+ 0, NULL);
+ } else {
+ /* Write new MOK */
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
+ &shim_lock_guid,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_APPEND_WRITE,
+ MokNewSize, MokNew);
+ }
+
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to set variable %d\n", efi_status);
return efi_status;
@@ -583,11 +652,12 @@ static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
return -1;
}
-static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2) {
+static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2,
+ void *data3) {
return mok_enrollment_prompt(MokNew, (UINTN)data2, TRUE);
}
-static INTN mok_deletion_prompt (void *MokNew, void *data2) {
+static INTN mok_deletion_prompt (void *MokNew, void *data2, void *data3) {
CHAR16 line[1];
UINT32 length;
EFI_STATUS efi_status;
@@ -597,7 +667,7 @@ static INTN mok_deletion_prompt (void *MokNew, void *data2) {
get_line (&length, line, 1, 1);
if (line[0] == 'Y' || line[0] == 'y') {
- efi_status = store_keys(MokNew, sizeof(UINT32), TRUE);
+ efi_status = store_keys(NULL, 0, TRUE);
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to erase keys\n");
@@ -713,7 +783,8 @@ static void run_menu (struct menu_item *items, UINTN count, UINTN timeout) {
return;
}
- items[pos].callback(items[pos].data, items[pos].data2);
+ items[pos].callback(items[pos].data, items[pos].data2,
+ items[pos].data3);
draw_menu (items, count);
pos = 0;
break;
@@ -721,20 +792,36 @@ static void run_menu (struct menu_item *items, UINTN count, UINTN timeout) {
}
}
-static INTN file_callback (void *data, void *data2) {
- EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+static UINTN verify_certificate(void *cert, UINTN size)
+{
+ X509 *X509Cert;
+ if (!cert || size == 0)
+ return FALSE;
+
+ if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) ||
+ X509Cert == NULL) {
+ Print(L"Invalid X509 certificate\n");
+ Pause();
+ return FALSE;
+ }
+
+ X509_free(X509Cert);
+ return TRUE;
+}
+
+static INTN file_callback (void *data, void *data2, void *data3) {
EFI_FILE_INFO *buffer = NULL;
- UINTN buffersize = 0, readsize;
+ UINTN buffersize = 0, mokbuffersize;
EFI_STATUS status;
EFI_FILE *file;
CHAR16 *filename = data;
EFI_FILE *parent = data2;
+ BOOLEAN hash = !!data3;
EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
- void *mokbuffer = NULL, *mok;
- UINTN MokSize = 0, MokNewSize;
- MokListNode *MokNew;
-
- mok = LibGetVariableAndSize(L"MokList", &shim_lock_guid, &MokSize);
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *CertData;
+ void *mokbuffer = NULL;
status = uefi_call_wrapper(parent->Open, 5, parent, &file, filename,
EFI_FILE_MODE_READ, 0);
@@ -755,36 +842,84 @@ static INTN file_callback (void *data, void *data2) {
if (!buffer)
return 0;
- readsize = buffer->FileSize;
+ buffersize = buffer->FileSize;
- if (mok) {
- MokNewSize = MokSize + readsize + sizeof(UINT32);
- mokbuffer = AllocateZeroPool(MokNewSize);
+ if (hash) {
+ void *binary;
+ UINT8 sha256[SHA256_DIGEST_SIZE];
+ UINT8 sha1[SHA1_DIGEST_SIZE];
+ SHIM_LOCK *shim_lock;
+ EFI_GUID shim_guid = SHIM_LOCK_GUID;
+ PE_COFF_LOADER_IMAGE_CONTEXT context;
+
+ status = LibLocateProtocol(&shim_guid, (VOID **)&shim_lock);
+
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) +
+ SHA256_DIGEST_SIZE;
+
+ mokbuffer = AllocatePool(mokbuffersize);
if (!mokbuffer)
goto out;
- CopyMem(mokbuffer, mok, MokSize);
- ((UINT32 *)mokbuffer)[0]++;
- MokNew = (MokListNode *)(((char *)mokbuffer) + MokSize);
+ binary = AllocatePool(buffersize);
+
+ status = uefi_call_wrapper(file->Read, 3, file, &buffersize,
+ binary);
+
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ status = shim_lock->Context(binary, buffersize, &context);
+
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ status = shim_lock->Hash(binary, buffersize, &context, sha256,
+ sha1);
+
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ CertList = mokbuffer;
+ CertList->SignatureType = EfiHashSha256Guid;
+ CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE;
+ CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
+ sizeof(EFI_SIGNATURE_LIST));
+ CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE);
} else {
- MokNewSize = readsize + (2 * sizeof(UINT32));
- mokbuffer = AllocateZeroPool(MokNewSize);
+ mokbuffersize = buffersize + sizeof(EFI_SIGNATURE_LIST) +
+ sizeof(EFI_GUID);
+ mokbuffer = AllocatePool(mokbuffersize);
if (!mokbuffer)
goto out;
- ((UINT32 *)mokbuffer)[0]=1;
- MokNew = (MokListNode *)(((UINT32 *)mokbuffer) + 1);
- }
- MokNew->MokSize = readsize;
+ CertList = mokbuffer;
+ CertList->SignatureType = EfiCertX509Guid;
+ CertList->SignatureSize = 16 + buffersize;
+ status = uefi_call_wrapper(file->Read, 3, file, &buffersize,
+ mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16);
+
+ if (status != EFI_SUCCESS)
+ goto out;
+ CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
+ sizeof(EFI_SIGNATURE_LIST));
+ }
- status = uefi_call_wrapper(file->Read, 3, file, &readsize, &MokNew->Mok);
+ CertList->SignatureListSize = mokbuffersize;
+ CertList->SignatureHeaderSize = 0;
+ CertData->SignatureOwner = shim_lock_guid;
- if (status != EFI_SUCCESS)
- goto out;
+ if (!hash) {
+ if (!verify_certificate(CertData->SignatureData, buffersize))
+ goto out;
+ }
- mok_enrollment_prompt(mokbuffer, MokNewSize, FALSE);
+ mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE);
out:
if (buffer)
FreePool(buffer);
@@ -795,7 +930,7 @@ out:
return 0;
}
-static INTN directory_callback (void *data, void *data2) {
+static INTN directory_callback (void *data, void *data2, void *data3) {
EFI_FILE_INFO *buffer = NULL;
UINTN buffersize = 0;
EFI_STATUS status;
@@ -873,12 +1008,14 @@ static INTN directory_callback (void *data, void *data2) {
dircontent[i].callback = directory_callback;
dircontent[i].data = dircontent[i].text;
dircontent[i].data2 = dir;
+ dircontent[i].data3 = data3;
dircontent[i].colour = EFI_YELLOW;
} else {
dircontent[i].text = StrDuplicate(buffer->FileName);
dircontent[i].callback = file_callback;
dircontent[i].data = dircontent[i].text;
dircontent[i].data2 = dir;
+ dircontent[i].data3 = data3;
dircontent[i].colour = EFI_WHITE;
}
@@ -893,7 +1030,7 @@ static INTN directory_callback (void *data, void *data2) {
return 0;
}
-static INTN filesystem_callback (void *data, void *data2) {
+static INTN filesystem_callback (void *data, void *data2, void *data3) {
EFI_FILE_INFO *buffer = NULL;
UINTN buffersize = 0;
EFI_STATUS status;
@@ -965,12 +1102,14 @@ static INTN filesystem_callback (void *data, void *data2) {
dircontent[i].callback = directory_callback;
dircontent[i].data = dircontent[i].text;
dircontent[i].data2 = root;
+ dircontent[i].data3 = data3;
dircontent[i].colour = EFI_YELLOW;
} else {
dircontent[i].text = StrDuplicate(buffer->FileName);
dircontent[i].callback = file_callback;
dircontent[i].data = dircontent[i].text;
dircontent[i].data2 = root;
+ dircontent[i].data3 = data3;
dircontent[i].colour = EFI_WHITE;
}
@@ -985,7 +1124,7 @@ static INTN filesystem_callback (void *data, void *data2) {
return 0;
}
-static INTN find_fs (void *data, void *data2) {
+static INTN find_fs (void *data, void *data2, void *data3) {
EFI_GUID fs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL;
UINTN count, i;
EFI_HANDLE **filesystem_handles;
@@ -1058,6 +1197,7 @@ static INTN find_fs (void *data, void *data2) {
filesystems[i].data = root;
filesystems[i].data2 = NULL;
+ filesystems[i].data3 = data3;
filesystems[i].callback = filesystem_callback;
filesystems[i].colour = EFI_YELLOW;
}
@@ -1073,13 +1213,25 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
UINTN MokNewSize)
{
struct menu_item *menu_item;
- UINT32 MokNum;
+ UINT32 MokAuth = 0;
UINTN menucount = 0;
+ EFI_STATUS efi_status;
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ UINT8 auth[SHA256_DIGEST_SIZE];
+ UINTN auth_size = SHA256_DIGEST_SIZE;
+ UINT32 attributes;
- if (MokNew)
- menu_item = AllocateZeroPool(sizeof(struct menu_item) * 3);
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
+ &shim_lock_guid,
+ &attributes, &auth_size, auth);
+
+ if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE))
+ MokAuth = 1;
+
+ if (MokNew || MokAuth)
+ menu_item = AllocateZeroPool(sizeof(struct menu_item) * 4);
else
- menu_item = AllocateZeroPool(sizeof(struct menu_item) * 2);
+ menu_item = AllocateZeroPool(sizeof(struct menu_item) * 3);
if (!menu_item)
return EFI_OUT_OF_RESOURCES;
@@ -1090,12 +1242,10 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
menucount++;
- if (MokNew) {
- CopyMem(&MokNum, MokNew, sizeof(UINT32));
- if (MokNum == 0) {
+ if (MokNew || MokAuth) {
+ if (!MokNew) {
menu_item[1].text = StrDuplicate(L"Delete MOK");
menu_item[1].colour = EFI_WHITE;
- menu_item[1].data = MokNew;
menu_item[1].callback = mok_deletion_prompt;
} else {
menu_item[1].text = StrDuplicate(L"Enroll MOK");
@@ -1110,6 +1260,14 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
menu_item[menucount].text = StrDuplicate(L"Enroll key from disk");
menu_item[menucount].colour = EFI_WHITE;
menu_item[menucount].callback = find_fs;
+ menu_item[menucount].data3 = (void *)FALSE;
+
+ menucount++;
+
+ menu_item[menucount].text = StrDuplicate(L"Enroll hash from disk");
+ menu_item[menucount].colour = EFI_WHITE;
+ menu_item[menucount].callback = find_fs;
+ menu_item[menucount].data3 = (void *)TRUE;
menucount++;
diff --git a/shim.c b/shim.c
index 3f5d7ea5..c1af0c8f 100644
--- a/shim.c
+++ b/shim.c
@@ -92,40 +92,6 @@ static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes,
return efi_status;
}
-static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
- MokListNode *list;
- int i, remain = DataSize;
- void *ptr;
-
- if (DataSize < sizeof(UINT32))
- return NULL;
-
- 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++) {
- CopyMem(&list[i].MokSize, ptr, sizeof(UINT32));
- remain -= sizeof(UINT32) + list[i].MokSize;
-
- if (remain < 0) {
- Print(L"MOK list was corrupted\n");
- FreePool(list);
- return NULL;
- }
-
- ptr += sizeof(UINT32);
- list[i].Mok = ptr;
- ptr += list[i].MokSize;
- }
-
- return list;
-}
-
/*
* Perform basic bounds checking of the intra-image pointers
*/
@@ -241,10 +207,10 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
return EFI_SUCCESS;
}
-static CHECK_STATUS check_db_cert(CHAR16 *dbname, WIN_CERTIFICATE_EFI_PKCS *data, UINT8 *hash)
+static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
+ WIN_CERTIFICATE_EFI_PKCS *data, UINT8 *hash)
{
EFI_STATUS efi_status;
- EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
EFI_SIGNATURE_LIST *CertList;
EFI_SIGNATURE_DATA *Cert;
UINTN dbsize = 0;
@@ -254,7 +220,7 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, WIN_CERTIFICATE_EFI_PKCS *data
void *db;
EFI_GUID CertType = EfiCertX509Guid;
- efi_status = get_variable(dbname, secure_var, &attributes, &dbsize, &db);
+ efi_status = get_variable(dbname, guid, &attributes, &dbsize, &db);
if (efi_status != EFI_SUCCESS)
return VAR_NOT_FOUND;
@@ -290,11 +256,10 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, WIN_CERTIFICATE_EFI_PKCS *data
return DATA_NOT_FOUND;
}
-static CHECK_STATUS check_db_hash(CHAR16 *dbname, UINT8 *data,
+static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
int SignatureSize, EFI_GUID CertType)
{
EFI_STATUS efi_status;
- EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
EFI_SIGNATURE_LIST *CertList;
EFI_SIGNATURE_DATA *Cert;
UINTN dbsize = 0;
@@ -303,7 +268,7 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, UINT8 *data,
BOOLEAN IsFound = FALSE;
void *db;
- efi_status = get_variable(dbname, secure_var, &attributes, &dbsize, &db);
+ efi_status = get_variable(dbname, guid, &attributes, &dbsize, &db);
if (efi_status != EFI_SUCCESS) {
return VAR_NOT_FOUND;
@@ -346,13 +311,15 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, UINT8 *data,
static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
UINT8 *sha256hash, UINT8 *sha1hash)
{
- if (check_db_hash(L"db", sha256hash, SHA256_DIGEST_SIZE,
+ EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
+
+ if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
EfiHashSha256Guid) == DATA_FOUND)
return EFI_ACCESS_DENIED;
- if (check_db_hash(L"db", sha1hash, SHA1_DIGEST_SIZE,
+ if (check_db_hash(L"dbx", secure_var, sha1hash, SHA1_DIGEST_SIZE,
EfiHashSha1Guid) == DATA_FOUND)
return EFI_ACCESS_DENIED;
- if (check_db_cert(L"dbx", cert, sha256hash) == DATA_FOUND)
+ if (check_db_cert(L"dbx", secure_var, cert, sha256hash) == DATA_FOUND)
return EFI_ACCESS_DENIED;
return EFI_SUCCESS;
@@ -361,13 +328,21 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
UINT8 *sha256hash, UINT8 *sha1hash)
{
- if (check_db_hash(L"db", sha256hash, SHA256_DIGEST_SIZE,
+ EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
+ EFI_GUID shim_var = SHIM_LOCK_GUID;
+
+ if (check_db_hash(L"db", secure_var, sha256hash, SHA256_DIGEST_SIZE,
EfiHashSha256Guid) == DATA_FOUND)
return EFI_SUCCESS;
- if (check_db_hash(L"db", sha1hash, SHA1_DIGEST_SIZE,
+ if (check_db_hash(L"db", secure_var, sha1hash, SHA1_DIGEST_SIZE,
EfiHashSha1Guid) == DATA_FOUND)
return EFI_SUCCESS;
- if (check_db_cert(L"db", cert, sha256hash) == DATA_FOUND)
+ if (check_db_hash(L"MokList", shim_var, sha256hash, SHA256_DIGEST_SIZE,
+ EfiHashSha256Guid) == DATA_FOUND)
+ return EFI_SUCCESS;
+ if (check_db_cert(L"db", secure_var, cert, sha256hash) == DATA_FOUND)
+ return EFI_SUCCESS;
+ if (check_db_cert(L"MokList", shim_var, cert, sha256hash) == DATA_FOUND)
return EFI_SUCCESS;
return EFI_ACCESS_DENIED;
@@ -575,22 +550,38 @@ done:
return status;
}
+static EFI_STATUS verify_mok (void) {
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS status = EFI_SUCCESS;
+ void *MokListData = NULL;
+ UINTN MokListDataSize = 0;
+ UINT32 attributes;
+
+ status = get_variable(L"MokList", shim_lock_guid, &attributes,
+ &MokListDataSize, &MokListData);
+
+ if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
+ Print(L"MokList is compromised!\nErase all keys in MokList!\n");
+ if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
+ Print(L"Failed to erase MokList\n");
+ }
+ status = EFI_ACCESS_DENIED;
+ return status;
+ }
+
+ return EFI_SUCCESS;
+}
+
/*
* 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)
+ PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
- 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);
@@ -611,6 +602,8 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
if (status != EFI_SUCCESS)
return status;
+ verify_mok();
+
status = check_blacklist(cert, sha256hash, sha1hash);
if (status != EFI_SUCCESS) {
@@ -618,13 +611,11 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
return status;
}
- if (whitelist) {
- status = check_whitelist(cert, sha256hash, sha1hash);
+ status = check_whitelist(cert, sha256hash, sha1hash);
- if (status == EFI_SUCCESS) {
- Print(L"Binary is whitelisted\n");
- return status;
- }
+ if (status == EFI_SUCCESS) {
+ Print(L"Binary is whitelisted\n");
+ return status;
}
if (AuthenticodeVerify(cert->CertData,
@@ -636,50 +627,6 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
return status;
}
- status = get_variable(L"MokList", shim_lock_guid, &attributes,
- &MokListDataSize, &MokListData);
-
- if (status != EFI_SUCCESS || MokListDataSize < sizeof(UINT32)) {
- status = EFI_ACCESS_DENIED;
- Print(L"Invalid signature\n");
- return status;
- }
-
- if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
- Print(L"MokList is compromised!\nErase all keys in MokList!\n");
- if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
- Print(L"Failed to erase MokList\n");
- }
- status = EFI_ACCESS_DENIED;
- return status;
- }
-
- CopyMem(&MokNum, MokListData, sizeof(UINT32));
- if (MokNum == 0) {
- status = EFI_ACCESS_DENIED;
- return status;
- }
-
- 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;
- return status;
- }
-
- for (i = 0; i < MokNum; i++) {
- if (AuthenticodeVerify(cert->CertData,
- context->SecDir->Size - sizeof(cert->Hdr),
- list[i].Mok, list[i].MokSize, sha256hash,
- SHA256_DIGEST_SIZE)) {
- status = EFI_SUCCESS;
- Print(L"Binary is verified by the machine owner key\n");
- return status;
- }
- }
Print(L"Invalid signature\n");
status = EFI_ACCESS_DENIED;
@@ -757,7 +704,7 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
}
if (secure_mode ()) {
- efi_status = verify_buffer(data, datasize, &context, 0);
+ efi_status = verify_buffer(data, datasize, &context);
if (efi_status != EFI_SUCCESS) {
Print(L"Verification failed\n");
@@ -984,7 +931,7 @@ EFI_STATUS shim_verify (void *buffer, UINT32 size)
if (status != EFI_SUCCESS)
return status;
- status = verify_buffer(buffer, size, &context, 1);
+ status = verify_buffer(buffer, size, &context);
return status;
}
@@ -1133,6 +1080,8 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
EFI_STATUS efi_status;
shim_lock_interface.Verify = shim_verify;
+ shim_lock_interface.Hash = generate_hash;
+ shim_lock_interface.Context = read_header;
systab = passed_systab;
diff --git a/shim.h b/shim.h
index b917ea24..08192591 100644
--- a/shim.h
+++ b/shim.h
@@ -1,3 +1,5 @@
+#include "PeImage.h"
+
#define SHIM_LOCK_GUID \
{ 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
@@ -10,6 +12,26 @@ EFI_STATUS
IN UINT32 size
);
+typedef
+EFI_STATUS
+(*EFI_SHIM_LOCK_HASH) (
+ IN char *data,
+ IN int datasize,
+ PE_COFF_LOADER_IMAGE_CONTEXT *context,
+ UINT8 *sha256hash,
+ UINT8 *sha1hash
+ );
+
+typedef
+EFI_STATUS
+(*EFI_SHIM_LOCK_CONTEXT) (
+ IN VOID *data,
+ IN unsigned int datasize,
+ PE_COFF_LOADER_IMAGE_CONTEXT *context
+ );
+
typedef struct _SHIM_LOCK {
EFI_SHIM_LOCK_VERIFY Verify;
+ EFI_SHIM_LOCK_HASH Hash;
+ EFI_SHIM_LOCK_CONTEXT Context;
} SHIM_LOCK;
diff --git a/signature.h b/signature.h
index 5737881d..722dbe64 100644
--- a/signature.h
+++ b/signature.h
@@ -13,7 +13,7 @@ typedef struct {
/// The format of the signature is defined by the SignatureType.
///
UINT8 SignatureData[1];
-} EFI_SIGNATURE_DATA;
+} __attribute__ ((packed)) EFI_SIGNATURE_DATA;
typedef struct {
///
@@ -40,4 +40,4 @@ typedef struct {
/// An array of signatures. Each signature is SignatureSize bytes in length.
/// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
///
-} EFI_SIGNATURE_LIST;
+} __attribute__ ((packed)) EFI_SIGNATURE_LIST;