summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2012-10-18 17:43:53 -0400
committerMatthew Garrett <mjg@redhat.com>2012-10-18 17:43:53 -0400
commit801d1b936be96f0d22fd5b91af973cafc1fcb68c (patch)
tree1beaeebe50cc02d06d2f3d1a675d8fc3b537f6a1
parentd08ea5363cec6f0159112aec1658d57fbaf1e471 (diff)
downloadefi-boot-shim-801d1b936be96f0d22fd5b91af973cafc1fcb68c.tar.gz
efi-boot-shim-801d1b936be96f0d22fd5b91af973cafc1fcb68c.zip
Add MOK password auth
Add support for setting an MOK password. The OS passes down a password hash. MokManager then presents an option for setting a password. Selecting it prompts the user for the same password again. If they match, the hash is enrolled into a boot services variable and MokManager will prompt for the password whenever it's started.
-rw-r--r--MokManager.c173
-rw-r--r--shim.c16
2 files changed, 180 insertions, 9 deletions
diff --git a/MokManager.c b/MokManager.c
index 88a08f72..18992f27 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -777,6 +777,86 @@ static INTN mok_sb_prompt (void *MokSB, void *data2, void *data3) {
return -1;
}
+
+static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS efi_status;
+ UINTN MokPWSize = (UINTN)data2;
+ UINT8 fail_count = 0;
+ UINT8 hash[SHA256_DIGEST_SIZE];
+ CHAR16 password[PASSWORD_MAX];
+ UINT32 length;
+ CHAR16 line[1];
+
+ if (MokPWSize != SHA256_DIGEST_SIZE) {
+ Print(L"Invalid MokPW variable contents\n");
+ return -1;
+ }
+
+ LibDeleteVariable(L"MokPW", &shim_lock_guid);
+
+ while (fail_count < 3) {
+ Print(L"Confirm MOK passphrase: ");
+ get_line(&length, password, PASSWORD_MAX, 0);
+
+ if ((length < PASSWORD_MIN) || (length > PASSWORD_MAX)) {
+ Print(L"Invalid password length\n");
+ fail_count++;
+ continue;
+ }
+
+ efi_status = compute_pw_hash(NULL, 0, password,
+ SB_PASSWORD_LEN, hash);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to generate password hash\n");
+ fail_count++;
+ continue;
+ }
+
+ if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) != 0) {
+ Print(L"Password doesn't match\n");
+ fail_count++;
+ continue;
+ }
+
+ break;
+ }
+
+ if (fail_count >= 3) {
+ Print(L"Password limit reached\n");
+ return -1;
+ }
+
+ Print(L"Set MOK password? (y/n): ");
+
+ do {
+ get_line (&length, line, 1, 1);
+
+ if (line[0] == 'Y' || line[0] == 'y') {
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5,
+ L"MokPWStore",
+ &shim_lock_guid,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ MokPWSize, MokPW);
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to set MOK password\n");
+ return -1;
+ }
+
+ Print(L"Press a key to reboot system\n");
+ Pause();
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
+ EFI_SUCCESS, 0, NULL);
+ Print(L"Failed to reboot\n");
+ return -1;
+ }
+ } while (line[0] != 'N' && line[0] != 'n');
+
+ return 0;
+}
+
static UINTN draw_menu (CHAR16 *header, UINTN lines, struct menu_item *items,
UINTN count) {
UINTN i;
@@ -1335,9 +1415,67 @@ static INTN find_fs (void *data, void *data2, void *data3) {
return 0;
}
+static BOOLEAN verify_pw(void)
+{
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS efi_status;
+ CHAR16 password[PASSWORD_MAX];
+ UINT8 fail_count = 0;
+ UINT8 hash[SHA256_DIGEST_SIZE];
+ UINT8 pwhash[SHA256_DIGEST_SIZE];
+ UINTN size = SHA256_DIGEST_SIZE;
+ UINT32 length;
+ UINT32 attributes;
+
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore",
+ &shim_lock_guid, &attributes, &size,
+ pwhash);
+
+ /*
+ * If anything can attack the password it could just set it to a
+ * known value, so there's no safety advantage in failing to validate
+ * purely because of a failure to read the variable
+ */
+ if (efi_status != EFI_SUCCESS)
+ return TRUE;
+
+ if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
+ return TRUE;
+
+ while (fail_count < 3) {
+ Print(L"Enter MOK password: ");
+ get_line(&length, password, PASSWORD_MAX, 0);
+
+ if (length < PASSWORD_MIN || length > PASSWORD_MAX) {
+ Print(L"Invalid password length\n");
+ fail_count++;
+ continue;
+ }
+
+ efi_status = compute_pw_hash(NULL, 0, password, length, hash);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to generate password hash\n");
+ fail_count++;
+ continue;
+ }
+
+ if (CompareMem(pwhash, hash, SHA256_DIGEST_SIZE) != 0) {
+ Print(L"Password doesn't match\n");
+ fail_count++;
+ continue;
+ }
+
+ return TRUE;
+ }
+
+ Print(L"Password limit reached\n");
+ return FALSE;
+}
+
static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
UINTN MokNewSize, void *MokSB,
- UINTN MokSBSize)
+ UINTN MokSBSize, void *MokPW, UINTN MokPWSize)
{
struct menu_item *menu_item;
UINT32 MokAuth = 0;
@@ -1348,6 +1486,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
UINTN auth_size = SHA256_DIGEST_SIZE;
UINT32 attributes;
+ if (verify_pw() == FALSE)
+ return EFI_ACCESS_DENIED;
+
efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
&shim_lock_guid,
&attributes, &auth_size, auth);
@@ -1361,6 +1502,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
if (MokSB)
menucount++;
+ if (MokPW)
+ menucount++;
+
menu_item = AllocateZeroPool(sizeof(struct menu_item) * menucount);
if (!menu_item)
@@ -1396,6 +1540,15 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
i++;
}
+ if (MokPW) {
+ menu_item[i].text = StrDuplicate(L"Set MOK password");
+ menu_item[i].colour = EFI_WHITE;
+ menu_item[i].callback = mok_pw_prompt;
+ menu_item[i].data = MokPW;
+ menu_item[i].data2 = (void *)MokPWSize;
+ i++;
+ }
+
menu_item[i].text = StrDuplicate(L"Enroll key from disk");
menu_item[i].colour = EFI_WHITE;
menu_item[i].callback = find_fs;
@@ -1420,15 +1573,19 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- UINTN MokNewSize = 0, MokSBSize = 0;
+ UINTN MokNewSize = 0, MokSBSize = 0, MokPWSize = 0;
void *MokNew = NULL;
void *MokSB = NULL;
+ void *MokPW = NULL;
MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize);
- MokSB = LibGetVariableAndSize(L"MokSB", &shim_lock_guid, &MokSBSize);
+ MokSB = LibGetVariableAndSize(L"MokSB", &shim_lock_guid, &MokSBSize);
+
+ MokPW = LibGetVariableAndSize(L"MokPW", &shim_lock_guid, &MokPWSize);
- enter_mok_menu(image_handle, MokNew, MokNewSize, MokSB, MokSBSize);
+ enter_mok_menu(image_handle, MokNew, MokNewSize, MokSB, MokSBSize,
+ MokPW, MokPWSize);
if (MokNew) {
if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
@@ -1443,6 +1600,14 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
}
FreePool (MokNew);
}
+
+ if (MokPW) {
+ if (LibDeleteVariable(L"MokPW", &shim_lock_guid) != EFI_SUCCESS) {
+ Print(L"Failed to delete MokPW\n");
+ }
+ FreePool (MokNew);
+ }
+
LibDeleteVariable(L"MokAuth", &shim_lock_guid);
return EFI_SUCCESS;
diff --git a/shim.c b/shim.c
index 39ad9bba..dbe5e849 100644
--- a/shim.c
+++ b/shim.c
@@ -1038,23 +1038,29 @@ done:
EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- EFI_STATUS moknew_status, moksb_status, efi_status;
+ EFI_STATUS moknew_status, moksb_status, mokpw_status, efi_status;
UINTN size = sizeof(UINT32);
- UINT32 MokNew;
+ UINT32 MokVar;
UINT32 attributes;
moknew_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokNew",
&shim_lock_guid, &attributes,
- &size, (void *)&MokNew);
+ &size, (void *)&MokVar);
moksb_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokSB",
&shim_lock_guid, &attributes,
- &size, (void *)&MokNew);
+ &size, (void *)&MokVar);
+
+ mokpw_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPW",
+ &shim_lock_guid, &attributes,
+ &size, (void *)&MokVar);
if (moknew_status == EFI_SUCCESS ||
moknew_status == EFI_BUFFER_TOO_SMALL ||
moksb_status == EFI_SUCCESS ||
- moksb_status == EFI_BUFFER_TOO_SMALL) {
+ moksb_status == EFI_BUFFER_TOO_SMALL ||
+ mokpw_status == EFI_SUCCESS ||
+ mokpw_status == EFI_BUFFER_TOO_SMALL) {
efi_status = start_image(image_handle, MOK_MANAGER);
if (efi_status != EFI_SUCCESS) {