blob: bc5ea5ba223ce024c73235f72cfc08dbb8ac7e79 [file] [log] [blame]
/*
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
*
* see COPYING file
*
* Simple key manager for both MOK and SecureBoot variables
*/
#include <efi.h>
#include <efilib.h>
#include <simple_file.h>
#include <sha256.h>
#include <variables.h>
#include <console.h>
#include <efiauthenticated.h>
#include <guid.h>
#include <execute.h>
static CHAR16* keytoolbin = L"KeyTool.efi";
static int transition_to_setup = 0, reboot_to_uefi_menu = 0;
static EFI_HANDLE im;
#if 0
/* some UEFI machines have a buggy implementation
* see if we can tip the system into Setup Mode */
static EFI_STATUS
change_setup_mode(int user_mode)
{
static UINT8 *data = NULL;
static UINTN len = 0;
EFI_STATUS status;
if (user_mode) {
if (!data)
/* can only do this if we previously reset to setup */
return EFI_INVALID_PARAMETER;
status = SetSecureVariable(L"PK", data, len, GV_GUID, 0, 0);
if (status == EFI_SUCCESS) {
data = NULL;
len = 0;
}
return status;
} else {
status = get_variable(L"PK", &data, &len, GV_GUID);
if (status != EFI_SUCCESS)
return status;
/* try to update it to nothing */
return SetSecureVariable(L"PK", data, 0, GV_GUID, 0, 0);
}
}
#endif
static void
enroll_hash(void)
{
EFI_STATUS efi_status;
CHAR16 *file_name = NULL, *title[6], buf0[256], buf1[256], buf2[256],
*var;
EFI_GUID *owner;
UINT8 hash[SHA256_DIGEST_SIZE];
int i, setupmode = variable_is_setupmode();
simple_file_selector(&im, (CHAR16 *[]){
L"Select Binary",
L"",
L"The Selected Binary will have its hash Enrolled",
L"This means it will Subsequently Boot with no prompting",
L"Remember to make sure it is a genuine binary before Enroling its hash",
NULL
}, L"\\", L"", &file_name);
if (!file_name)
/* user pressed ESC */
return;
efi_status = sha256_get_pecoff_digest(im, file_name, hash);
if (efi_status != EFI_SUCCESS) {
console_error(L"Hash failed (is efi binary valid?)",
efi_status);
return;
}
StrCpy(buf0, L"Enroll this hash into ");
if (setupmode)
StrCat(buf0, L"UEFI signature database?");
else
StrCat(buf0, L"MOK database?");
title[0] = buf0;
title[1] = L"";
StrCpy(buf1, L"File: ");
StrCat(buf1, file_name);
title[2] = buf1;
StrCpy(buf2, L"Hash: ");
sha256_StrCat_hash(buf2, hash);
title[3] = buf2;
title[4] = NULL;
i = console_yes_no(title);
if (i == 0)
return;
/* We're in setup mode and the User asked us to add the signature
* of this binary to the authorized signatures database */
if (setupmode) {
var = L"db";
owner = &SIG_DB;
} else {
var = L"MokList";
owner = &MOK_OWNER;
}
efi_status = variable_enroll_hash(var, *owner, hash);
if (efi_status != EFI_SUCCESS && efi_status != EFI_ALREADY_STARTED) {
console_error(L"Failed to add signature to db", efi_status);
return;
}
}
void
transition_to_uefi_menu(void)
{
int option;
UINT64 indications = GetOSIndications();
if ((indications & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) == 0) {
console_errorbox(L"Platform Does not Support rebooting to firmware menu");
return;
}
option = console_yes_no( (CHAR16 *[]){
L"About to reboot to UEFI Setup Menu",
L"",
L"For more details about your system's setup menu",
L"Including how to reset the system to setup mode, see",
L"",
L"http://www.linuxfoundation.org/uefi",
NULL
});
/* user said no */
if (option == 0)
return;
SETOSIndicationsAndReboot(EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
return;
}
EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
UINT64 indications;
int option = 0;
im = image;
InitializeLib(image, systab);
indications = GetOSIndications();
if (indications & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
reboot_to_uefi_menu = 1;
#if 0
/*
* Microsoft objects to this code. What it does is test to see
* if the platform key is removable and offer a menu item to
* transition to setup mode
*/
if (!variable_is_setupmode()) {
if (change_setup_mode(0) == EFI_SUCCESS) {
transition_to_setup = 1;
change_setup_mode(1);
}
}
#endif
for (;;) {
CHAR16 line2[80], line3[80], **title, *options[6];
int c = 0, setup_mode = NOSEL, uefi_reboot = NOSEL,
reboot = NOSEL, exit_moktool = NOSEL, SetupMode,
setup_mode_arg = 0, keytool = NOSEL;
EFI_FILE *file;
if (simple_file_open(image, keytoolbin, &file, EFI_FILE_MODE_READ)
== EFI_SUCCESS) {
keytool = 1;
simple_file_close(file);
}
SetupMode = variable_is_setupmode();
StrCpy(line2, L"Platform is in ");
StrCat(line2, SetupMode ? L"Setup Mode" : L"User Mode");
StrCpy(line3, L"Secure Boot is ");
StrCat(line3, variable_is_secureboot() ? L"on" : L"off");
title = (CHAR16 *[]){L"Hash Tool main menu", L"", line2, line3, NULL };
options[c++] = L"Enroll Hash";
if (keytool != NOSEL) {
keytool = c;
options[c++] = L"Start UEFI Key Tool";
}
if (transition_to_setup) {
setup_mode = c;
if (SetupMode) {
setup_mode_arg = 1;
options[c++] = L"Enter User Mode";
} else {
setup_mode_arg = 0;
options[c++] = L"Enter Setup Mode";
}
}
if (reboot_to_uefi_menu) {
uefi_reboot = c;
options[c++] = L"Reboot to UEFI Menu";
}
reboot = c;
options[c++] = L"Reboot System";
exit_moktool = c;
options[c++] = L"Exit";
options[c++] = NULL;
option = console_select(title, options, option);
if (option == 0) {
enroll_hash();
} else if (option == keytool) {
EFI_STATUS status;
status = execute(image, keytoolbin);
if (status != EFI_SUCCESS)
console_error(L"Failed to execute KeyTool", status);
#if 0
} else if (option == setup_mode) {
change_setup_mode(setup_mode_arg);
#endif
} else if (option == uefi_reboot) {
transition_to_uefi_menu();
} else if (option == reboot) {
int selection;
selection = console_yes_no((CHAR16 *[]) {
L"Are you sure you want to reboot?",
NULL
});
if (selection == 1)
RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
} else if (option == exit_moktool) {
break;
}
}
return EFI_SUCCESS;
}