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.
This commit is contained in:
Matthew Garrett 2012-10-17 21:40:05 -04:00
parent 310ec753fa
commit 801c0faaf7
2 changed files with 180 additions and 9 deletions

View File

@ -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);
enter_mok_menu(image_handle, MokNew, MokNewSize, MokSB, MokSBSize);
MokPW = LibGetVariableAndSize(L"MokPW", &shim_lock_guid, &MokPWSize);
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;

16
shim.c
View File

@ -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) {