From 4e513405b4f1641710115780d19dcec130c5208f Mon Sep 17 00:00:00 2001 From: Eric Snowberg Date: Tue, 5 Oct 2021 12:06:05 -0400 Subject: [PATCH] Introduce a new MOK variable called MokListTrustedRT Introduce a new MOK variable called MokListTrustedRT. It allows an end-user to decide if they want to trust MOKList keys within the soon to be booted Linux kernel. This variable does not change any functionality within shim itself. When Linux boots, if MokListTrustedRT is set and EFI_VARIABLE_NON_VOLATILE is not set, keys in MokListRT are loaded into the .machine keyring instead of the .platform keyring. Signed-off-by: Eric Snowberg --- MokManager.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++-- MokVars.txt | 6 ++ globals.c | 1 + mok.c | 17 +++++- shim.h | 1 + 5 files changed, 187 insertions(+), 5 deletions(-) diff --git a/MokManager.c b/MokManager.c index 08b15d6d1..c195cadc5 100644 --- a/MokManager.c +++ b/MokManager.c @@ -40,6 +40,12 @@ typedef struct { CHAR16 Password[SB_PASSWORD_LEN]; } __attribute__ ((packed)) MokDBvar; +typedef struct { + UINT32 MokTMLState; + UINT32 PWLen; + CHAR16 Password[SB_PASSWORD_LEN]; +} __attribute__ ((packed)) MokTMLvar; + typedef struct { INT32 Timeout; } __attribute__ ((packed)) MokTimeoutvar; @@ -1678,6 +1684,121 @@ static EFI_STATUS mok_db_prompt(void *MokDB, UINTN MokDBSize) return EFI_SUCCESS; } +static EFI_STATUS mok_tml_prompt(void *MokTML, UINTN MokTMLSize) +{ + EFI_STATUS efi_status; + SIMPLE_TEXT_OUTPUT_MODE SavedMode; + MokTMLvar *var = MokTML; + CHAR16 *message[4]; + CHAR16 pass1, pass2, pass3; + CHAR16 *str; + UINT8 fail_count = 0; + UINT8 dbval = 1; + UINT8 pos1, pos2, pos3; + int ret; + CHAR16 *untrust_tml[] = { L"Do not trust the MOK list", NULL }; + CHAR16 *trust_tml[] = { L"Trust the MOK list", NULL }; + + if (MokTMLSize != sizeof(MokTMLvar)) { + console_notify(L"Invalid MokTML variable contents"); + return EFI_INVALID_PARAMETER; + } + + clear_screen(); + + message[0] = L"Change Trusted MOK List Keyring 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 EFI_OUT_OF_RESOURCES; + } + 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 EFI_OUT_OF_RESOURCES; + } + 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 EFI_OUT_OF_RESOURCES; + } + pass3 = get_password_charater(str); + FreePool(str); + + if (pass1 != var->Password[pos1] || + pass2 != var->Password[pos2] || + pass3 != var->Password[pos3]) { + console_print(L"Invalid character\n"); + fail_count++; + } else { + break; + } + } + + if (fail_count >= 3) { + console_notify(L"Password limit reached"); + return EFI_ACCESS_DENIED; + } + + if (var->MokTMLState == 0) + ret = console_yes_no(trust_tml); + else + ret = console_yes_no(untrust_tml); + + if (ret == 0) { + LibDeleteVariable(L"MokListTrustedNew", &SHIM_LOCK_GUID); + return EFI_ABORTED; + } + + if (var->MokTMLState == 0) { + efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 1, &dbval); + if (EFI_ERROR(efi_status)) { + console_notify(L"Failed to set MokListTrusted state"); + return efi_status; + } + } else { + efi_status = RT->SetVariable(L"MokListTrusted", &SHIM_LOCK_GUID, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 0, NULL); + if (EFI_ERROR(efi_status)) { + console_notify(L"Failed to delete MokListTrusted state"); + return efi_status; + } + } + + return EFI_SUCCESS; +} + static EFI_STATUS mok_pw_prompt(void *MokPW, UINTN MokPWSize) { EFI_STATUS efi_status; @@ -2076,7 +2197,8 @@ typedef enum { MOK_SET_PW, MOK_CHANGE_DB, MOK_KEY_ENROLL, - MOK_HASH_ENROLL + MOK_HASH_ENROLL, + MOK_CHANGE_TML } mok_menu_item; static void free_menu(mok_menu_item * menu_item, CHAR16 ** menu_strings) @@ -2095,7 +2217,8 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED, void *MokPW, UINTN MokPWSize, void *MokDB, UINTN MokDBSize, void *MokXNew, UINTN MokXNewSize, - void *MokXDel, UINTN MokXDelSize) + void *MokXDel, UINTN MokXDelSize, + void *MokTML, UINTN MokTMLSize) { CHAR16 **menu_strings = NULL; mok_menu_item *menu_item = NULL; @@ -2171,6 +2294,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED, if (MokDB) menucount++; + if (MokTML) + menucount++; + menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (menucount + 1)); if (!menu_strings) @@ -2242,6 +2368,12 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED, i++; } + if (MokTML) { + menu_strings[i] = L"Change MOK List Trusted State"; + menu_item[i] = MOK_CHANGE_TML; + i++; + } + menu_strings[i] = L"Enroll key from disk"; menu_item[i] = MOK_KEY_ENROLL; i++; @@ -2352,6 +2484,17 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED, case MOK_HASH_ENROLL: efi_status = mok_hash_enroll(); break; + case MOK_CHANGE_TML: + if (!MokTML) { + console_print(L"MokManager: internal error: %s", + L"MokListTrusted was ! NULL bs is now NULL\n"); + ret = EFI_ABORTED; + goto out; + } + efi_status = mok_tml_prompt(MokTML, MokTMLSize); + if (!EFI_ERROR(efi_status)) + MokTML = NULL; + break; } if (!EFI_ERROR(efi_status)) @@ -2376,7 +2519,7 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle UNUSED, static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) { UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0; - UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0; + UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0, MokTMLSize = 0; void *MokNew = NULL; void *MokDel = NULL; void *MokSB = NULL; @@ -2384,6 +2527,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) void *MokDB = NULL; void *MokXNew = NULL; void *MokXDel = NULL; + void *MokTML = NULL; EFI_STATUS efi_status; efi_status = get_variable(L"MokNew", (UINT8 **) & MokNew, &MokNewSize, @@ -2436,6 +2580,18 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) console_error(L"Could not retrieve MokDB", efi_status); } + efi_status = get_variable(L"MokListTrustedNew", (UINT8 **) & MokTML, + &MokTMLSize, SHIM_LOCK_GUID); + if (!EFI_ERROR(efi_status)) { + efi_status = LibDeleteVariable(L"MokListTrustedNew", + &SHIM_LOCK_GUID); + if (EFI_ERROR(efi_status)) + console_notify(L"Failed to delete MokListTrustedNew"); + } else if (EFI_ERROR(efi_status) && efi_status != EFI_NOT_FOUND) { + console_error(L"Could not retrieve MokListTrustedNew", + efi_status); + } + efi_status = get_variable(L"MokXNew", (UINT8 **) & MokXNew, &MokXNewSize, SHIM_LOCK_GUID); if (!EFI_ERROR(efi_status)) { @@ -2458,7 +2614,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize, MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize, - MokXNew, MokXNewSize, MokXDel, MokXDelSize); + MokXNew, MokXNewSize, MokXDel, MokXDelSize, MokTML, MokTMLSize); if (MokNew) FreePool(MokNew); @@ -2481,6 +2637,9 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) if (MokXDel) FreePool(MokXDel); + if (MokTML) + FreePool(MokTML); + LibDeleteVariable(L"MokAuth", &SHIM_LOCK_GUID); LibDeleteVariable(L"MokDelAuth", &SHIM_LOCK_GUID); LibDeleteVariable(L"MokXAuth", &SHIM_LOCK_GUID); diff --git a/MokVars.txt b/MokVars.txt index 4b80a4134..cdfec2c8e 100644 --- a/MokVars.txt +++ b/MokVars.txt @@ -77,3 +77,9 @@ 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. + +MokListTrusted: An 8-bit unsigned integer. If 1, it signifies to Linux +to trust CA keys in the MokList. BS,NV + +MokListTrustedRT: A copy of MokListTrusted made available to the kernel +at runtime. RT diff --git a/globals.c b/globals.c index 476e2e9ca..4a1f432fd 100644 --- a/globals.c +++ b/globals.c @@ -25,6 +25,7 @@ int loader_is_participating; UINT8 user_insecure_mode; UINT8 ignore_db; +UINT8 trust_mok_list; UINT32 verbose = 0; diff --git a/mok.c b/mok.c index 7755eea9b..52dffc3ea 100644 --- a/mok.c +++ b/mok.c @@ -46,7 +46,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle) check_var(L"MokPW") || check_var(L"MokAuth") || check_var(L"MokDel") || check_var(L"MokDB") || check_var(L"MokXNew") || check_var(L"MokXDel") || - check_var(L"MokXAuth")) { + check_var(L"MokXAuth") || check_var(L"MokListTrustedNew")) { efi_status = start_image(image_handle, MOK_MANAGER); if (EFI_ERROR(efi_status)) { @@ -166,6 +166,20 @@ struct mok_state_variable mok_state_variable_data[] = { MOK_VARIABLE_MEASURE, .pcr = 7, }, + {.name = L"MokListTrusted", + .name8 = "MokListTrusted", + .rtname = L"MokListTrustedRT", + .rtname8 = "MokListTrustedRT", + .guid = &SHIM_LOCK_GUID, + .yes_attr = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + .no_attr = EFI_VARIABLE_RUNTIME_ACCESS, + .flags = MOK_MIRROR_DELETE_FIRST | + MOK_VARIABLE_MEASURE | + MOK_VARIABLE_LOG, + .pcr = 14, + .state = &trust_mok_list, + }, { NULL, } }; size_t n_mok_state_variables = sizeof(mok_state_variable_data) / sizeof(mok_state_variable_data[0]); @@ -897,6 +911,7 @@ EFI_STATUS import_mok_state(EFI_HANDLE image_handle) user_insecure_mode = 0; ignore_db = 0; + trust_mok_list = 0; UINT64 config_sz = 0; UINT8 *config_table = NULL; diff --git a/shim.h b/shim.h index 5e1ab36b5..69442da3f 100644 --- a/shim.h +++ b/shim.h @@ -255,6 +255,7 @@ extern UINT8 *build_cert; extern UINT8 user_insecure_mode; extern UINT8 ignore_db; +extern UINT8 trust_mok_list; extern UINT8 in_protocol; extern void *load_options; extern UINT32 load_options_size;