diff options
| -rw-r--r-- | MokManager.c | 153 | ||||
| -rw-r--r-- | MokVars.txt | 23 | ||||
| -rw-r--r-- | shim.c | 107 |
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. @@ -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 */ |
