summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MokManager.c153
-rw-r--r--MokVars.txt23
-rw-r--r--shim.c107
3 files changed, 264 insertions, 19 deletions
diff --git a/MokManager.c b/MokManager.c
index de0eb59a..f5ed379c 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -50,6 +50,12 @@ typedef struct {
CHAR16 Password[SB_PASSWORD_LEN];
} __attribute__ ((packed)) MokSBvar;
+typedef struct {
+ UINT32 MokDBState;
+ UINT32 PWLen;
+ CHAR16 Password[SB_PASSWORD_LEN];
+} __attribute__ ((packed)) MokDBvar;
+
static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash)
{
EFI_STATUS status;
@@ -1116,6 +1122,118 @@ static INTN mok_sb_prompt (void *MokSB, UINTN MokSBSize) {
return -1;
}
+static INTN mok_db_prompt (void *MokDB, UINTN MokDBSize) {
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS efi_status;
+ SIMPLE_TEXT_OUTPUT_MODE SavedMode;
+ MokDBvar *var = MokDB;
+ CHAR16 *message[4];
+ CHAR16 pass1, pass2, pass3;
+ CHAR16 *str;
+ UINT8 fail_count = 0;
+ UINT8 dbval = 1;
+ UINT8 pos1, pos2, pos3;
+ int ret;
+
+ if (MokDBSize != sizeof(MokDBvar)) {
+ console_notify(L"Invalid MokDB variable contents");
+ return -1;
+ }
+
+ uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
+
+ message[0] = L"Change DB state";
+ message[1] = NULL;
+
+ console_save_and_set_mode(&SavedMode);
+ console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
+ console_restore_mode(&SavedMode);
+
+ while (fail_count < 3) {
+ RandomBytes (&pos1, sizeof(pos1));
+ pos1 = (pos1 % var->PWLen);
+
+ do {
+ RandomBytes (&pos2, sizeof(pos2));
+ pos2 = (pos2 % var->PWLen);
+ } while (pos2 == pos1);
+
+ do {
+ RandomBytes (&pos3, sizeof(pos3));
+ pos3 = (pos3 % var->PWLen) ;
+ } while (pos3 == pos2 || pos3 == pos1);
+
+ str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
+ if (!str) {
+ console_errorbox(L"Failed to allocate buffer");
+ return -1;
+ }
+ pass1 = get_password_charater(str);
+ FreePool(str);
+
+ str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
+ if (!str) {
+ console_errorbox(L"Failed to allocate buffer");
+ return -1;
+ }
+ pass2 = get_password_charater(str);
+ FreePool(str);
+
+ str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
+ if (!str) {
+ console_errorbox(L"Failed to allocate buffer");
+ return -1;
+ }
+ pass3 = get_password_charater(str);
+ FreePool(str);
+
+ if (pass1 != var->Password[pos1] ||
+ pass2 != var->Password[pos2] ||
+ pass3 != var->Password[pos3]) {
+ Print(L"Invalid character\n");
+ fail_count++;
+ } else {
+ break;
+ }
+ }
+
+ if (fail_count >= 3) {
+ console_notify(L"Password limit reached");
+ return -1;
+ }
+
+ if (var->MokDBState == 0)
+ ret = console_yes_no((CHAR16 *[]){L"Ignore DB certs/hashes", NULL});
+ else
+ ret = console_yes_no((CHAR16 *[]){L"Use DB certs/hashes", NULL});
+
+ if (ret == 0) {
+ LibDeleteVariable(L"MokDB", &shim_lock_guid);
+ return -1;
+ }
+
+ if (var->MokDBState == 0) {
+ efi_status = uefi_call_wrapper(RT->SetVariable,
+ 5, L"MokDBState",
+ &shim_lock_guid,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 1, &dbval);
+ if (efi_status != EFI_SUCCESS) {
+ console_notify(L"Failed to set DB state");
+ return -1;
+ }
+ } else {
+ LibDeleteVariable(L"MokDBState", &shim_lock_guid);
+ }
+
+ console_notify(L"The system must now be rebooted");
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
+ EFI_SUCCESS, 0, NULL);
+ console_notify(L"Failed to reboot");
+ return -1;
+}
+
static INTN mok_pw_prompt (void *MokPW, UINTN MokPWSize) {
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
@@ -1517,6 +1635,7 @@ typedef enum {
MOK_DELETE_MOK,
MOK_CHANGE_SB,
MOK_SET_PW,
+ MOK_CHANGE_DB,
MOK_KEY_ENROLL,
MOK_HASH_ENROLL
} mok_menu_item;
@@ -1525,7 +1644,8 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
void *MokNew, UINTN MokNewSize,
void *MokDel, UINTN MokDelSize,
void *MokSB, UINTN MokSBSize,
- void *MokPW, UINTN MokPWSize)
+ void *MokPW, UINTN MokPWSize,
+ void *MokDB, UINTN MokDBSize)
{
CHAR16 **menu_strings;
mok_menu_item *menu_item;
@@ -1572,6 +1692,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
if (MokPW)
menucount++;
+ if (MokDB)
+ menucount++;
+
menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (menucount + 1));
if (!menu_strings)
@@ -1618,6 +1741,12 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
i++;
}
+ if (MokDB) {
+ menu_strings[i] = L"Change DB state";
+ menu_item[i] = MOK_CHANGE_DB;
+ i++;
+ }
+
menu_strings[i] = L"Enroll key from disk";
menu_item[i] = MOK_KEY_ENROLL;
i++;
@@ -1656,6 +1785,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
case MOK_SET_PW:
mok_pw_prompt(MokPW, MokPWSize);
break;
+ case MOK_CHANGE_DB:
+ mok_db_prompt(MokDB, MokDBSize);
+ break;
case MOK_KEY_ENROLL:
mok_key_enroll();
break;
@@ -1679,11 +1811,13 @@ out:
static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
+ UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0,
+ MokDBSize = 0;
void *MokNew = NULL;
void *MokDel = NULL;
void *MokSB = NULL;
void *MokPW = NULL;
+ void *MokDB = NULL;
EFI_STATUS status;
status = get_variable(L"MokNew", (UINT8 **)&MokNew, &MokNewSize,
@@ -1726,8 +1860,18 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
console_error(L"Could not retrieve MokPW", status);
}
+ status = get_variable(L"MokDB", (UINT8 **)&MokDB, &MokDBSize,
+ shim_lock_guid);
+ if (status == EFI_SUCCESS) {
+ if (LibDeleteVariable(L"MokDB", &shim_lock_guid) != EFI_SUCCESS) {
+ console_notify(L"Failed to delete MokDB");
+ }
+ } else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
+ console_error(L"Could not retrieve MokDB", status);
+ }
+
enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
- MokSB, MokSBSize, MokPW, MokPWSize);
+ MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize);
if (MokNew)
FreePool (MokNew);
@@ -1741,6 +1885,9 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
if (MokPW)
FreePool (MokPW);
+ if (MokDB)
+ FreePool (MokDB);
+
LibDeleteVariable(L"MokAuth", &shim_lock_guid);
LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
diff --git a/MokVars.txt b/MokVars.txt
index 74f09083..cac5349f 100644
--- a/MokVars.txt
+++ b/MokVars.txt
@@ -25,6 +25,23 @@ three randomly chosen characters from the password. If successful,
they will then be prompted to change the signature validation
according to MokSBState. BS,RT,NV
+MokDB: Set by MokUtil when requesting a change in state of validation
+using db hashes and certs. A packed structure as follows:
+
+typedef struct {
+ UINT32 MokDBState;
+ UINT32 PWLen;
+ CHAR16 Password[PASSWORD_MAX];
+} __attribute__ ((packed)) MokDBvar;
+
+If MokDBState is 0, the user will be prompted to disable usage of db for
+validation. Otherwise, the user will be prompted to allow it. PWLen
+is the length of the password, in characters. Password is a UCS-2
+representation of the password. The user will be prompted to enter
+three randomly chosen characters from the password. If successful,
+they will then be prompted to change the signature validation
+according to MokDBState. BS,RT,NV
+
MokNew: Set by MokUtil when requesting the addition or removal of keys
from MokList. Is an EFI_SIGNATURE_LIST as described in the UEFI
specification. BS,RT,NV
@@ -46,6 +63,12 @@ MokListRT: A copy of MokList made available to the kernel at runtime. RT
MokSBState: An 8-bit unsigned integer. If 1, shim will switch to
insecure mode. BS,NV
+MokDBState: An 8-bit unsigned integer. If 1, shim will not use db for
+verification. BS,NV
+
+MokIgnoreDB: An 8-bit unsigned integer. This allows the OS to query whether
+or not to import DB certs for its own verification purposes.
+
MokPWStore: A SHA-256 representation of the password set by the user
via MokPW. The user will be prompted to enter this password in order
to interact with MokManager.
diff --git a/shim.c b/shim.c
index f311914d..690cb091 100644
--- a/shim.c
+++ b/shim.c
@@ -86,6 +86,7 @@ int loader_is_participating;
#define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
UINT8 insecure_mode;
+UINT8 ignore_db;
typedef enum {
DATA_FOUND,
@@ -393,28 +394,31 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
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,
- EFI_CERT_SHA256_GUID) == DATA_FOUND) {
- update_verification_method(VERIFIED_BY_HASH);
- return EFI_SUCCESS;
- }
- if (check_db_hash(L"db", secure_var, sha1hash, SHA1_DIGEST_SIZE,
- EFI_CERT_SHA1_GUID) == DATA_FOUND) {
- verification_method = VERIFIED_BY_HASH;
- update_verification_method(VERIFIED_BY_HASH);
- return EFI_SUCCESS;
+ if (!ignore_db) {
+ if (check_db_hash(L"db", secure_var, sha256hash, SHA256_DIGEST_SIZE,
+ EFI_CERT_SHA256_GUID) == DATA_FOUND) {
+ update_verification_method(VERIFIED_BY_HASH);
+ return EFI_SUCCESS;
+ }
+ if (check_db_hash(L"db", secure_var, sha1hash, SHA1_DIGEST_SIZE,
+ EFI_CERT_SHA1_GUID) == DATA_FOUND) {
+ verification_method = VERIFIED_BY_HASH;
+ update_verification_method(VERIFIED_BY_HASH);
+ return EFI_SUCCESS;
+ }
+ if (check_db_cert(L"db", secure_var, cert, sha256hash) == DATA_FOUND) {
+ verification_method = VERIFIED_BY_CERT;
+ update_verification_method(VERIFIED_BY_CERT);
+ return EFI_SUCCESS;
+ }
}
+
if (check_db_hash(L"MokList", shim_var, sha256hash, SHA256_DIGEST_SIZE,
EFI_CERT_SHA256_GUID) == DATA_FOUND) {
verification_method = VERIFIED_BY_HASH;
update_verification_method(VERIFIED_BY_HASH);
return EFI_SUCCESS;
}
- if (check_db_cert(L"db", secure_var, cert, sha256hash) == DATA_FOUND) {
- verification_method = VERIFIED_BY_CERT;
- update_verification_method(VERIFIED_BY_CERT);
- return EFI_SUCCESS;
- }
if (check_db_cert(L"MokList", shim_var, cert, sha256hash) == DATA_FOUND) {
verification_method = VERIFIED_BY_CERT;
update_verification_method(VERIFIED_BY_CERT);
@@ -1428,7 +1432,7 @@ EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
if (check_var(L"MokNew") || check_var(L"MokSB") ||
check_var(L"MokPW") || check_var(L"MokAuth") ||
- check_var(L"MokDel")) {
+ check_var(L"MokDel") || check_var(L"MokDB")) {
efi_status = start_image(image_handle, MOK_MANAGER);
if (efi_status != EFI_SUCCESS) {
@@ -1482,6 +1486,71 @@ static EFI_STATUS check_mok_sb (void)
}
/*
+ * Verify that MokDBState is valid, and if appropriate set ignore db mode
+ */
+
+static EFI_STATUS check_mok_db (void)
+{
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS status = EFI_SUCCESS;
+ UINT8 *MokDBState = NULL;
+ UINTN MokDBStateSize = 0;
+ UINT32 attributes;
+
+ status = get_variable_attr(L"MokDBState", &MokDBState, &MokDBStateSize,
+ shim_lock_guid, &attributes);
+
+ if (status != EFI_SUCCESS)
+ return EFI_ACCESS_DENIED;
+
+ ignore_db = 0;
+
+ /*
+ * Delete and ignore the variable if it's been set from or could be
+ * modified by the OS
+ */
+ if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
+ Print(L"MokDBState is compromised! Clearing it\n");
+ if (LibDeleteVariable(L"MokDBState", &shim_lock_guid) != EFI_SUCCESS) {
+ Print(L"Failed to erase MokDBState\n");
+ }
+ status = EFI_ACCESS_DENIED;
+ } else {
+ if (*(UINT8 *)MokDBState == 1) {
+ ignore_db = 1;
+ }
+ }
+
+ FreePool(MokDBState);
+
+ return status;
+}
+
+static EFI_STATUS mok_ignore_db()
+{
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS efi_status = EFI_SUCCESS;
+ UINT8 Data = 1;
+ UINTN DataSize = sizeof(UINT8);
+
+ check_mok_db();
+
+ if (ignore_db) {
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokIgnoreDB",
+ &shim_lock_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize, (void *)&Data);
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to set MokIgnoreDB %d\n", efi_status);
+ }
+ }
+
+ return efi_status;
+
+}
+
+/*
* Check the load options to specify the second stage loader
*/
EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
@@ -1653,6 +1722,12 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
efi_status = mirror_mok_list();
/*
+ * Create the runtime MokIgnoreDB variable so the kernel can make
+ * use of it
+ */
+ efi_status = mok_ignore_db();
+
+ /*
* Hand over control to the second stage bootloader
*/