From b13d18d4069032ccf6c885774e9eada6a1d80ddd Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 18 Feb 2014 17:29:19 +0800 Subject: [PATCH 1/3] Show the build-in certificate prompt This is an openSUSE-only patch. Pop up a window to ask if the user is willing to trust the built-in openSUSE certificate. If yes, set openSUSE_Verify, a BootService variable, to 1, and shim won't bother the user afterward. If no, continue the booting process without using the built-in certificate to verify the EFI images, and the window will show up again after reboot. The state will store in use_openSUSE_cert, a volatile RT variable. --- shim.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 19 deletions(-) Index: shim-0.7/shim.c =================================================================== --- shim-0.7.orig/shim.c +++ shim-0.7/shim.c @@ -90,6 +90,7 @@ UINT8 *vendor_dbx; */ verification_method_t verification_method; int loader_is_participating; +BOOLEAN use_builtin_cert; #define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }} @@ -817,7 +818,7 @@ static EFI_STATUS verify_buffer (char *d if (status == EFI_SUCCESS) return status; - if (cert) { + if (cert && use_builtin_cert) { /* * Check against the shim build key */ @@ -1523,11 +1524,14 @@ EFI_STATUS mirror_mok_list() if (efi_status != EFI_SUCCESS) DataSize = 0; - FullDataSize = DataSize - + sizeof (*CertList) - + sizeof (EFI_GUID) - + vendor_cert_size - ; + FullDataSize = DataSize; + if (use_builtin_cert) { + FullDataSize += sizeof (*CertList) + + sizeof (EFI_GUID) + + vendor_cert_size; + } else if (DataSize == 0) { + return EFI_SUCCESS; + } FullData = AllocatePool(FullDataSize); if (!FullData) { perror(L"Failed to allocate space for MokListRT\n"); @@ -1539,21 +1543,24 @@ EFI_STATUS mirror_mok_list() CopyMem(p, Data, DataSize); p += DataSize; } - CertList = (EFI_SIGNATURE_LIST *)p; - p += sizeof (*CertList); - CertData = (EFI_SIGNATURE_DATA *)p; - p += sizeof (EFI_GUID); - - CertList->SignatureType = EFI_CERT_X509_GUID; - CertList->SignatureListSize = vendor_cert_size - + sizeof (*CertList) - + sizeof (*CertData) - -1; - CertList->SignatureHeaderSize = 0; - CertList->SignatureSize = vendor_cert_size + sizeof (EFI_GUID); - CertData->SignatureOwner = SHIM_LOCK_GUID; - CopyMem(p, vendor_cert, vendor_cert_size); + if (use_builtin_cert) { + CertList = (EFI_SIGNATURE_LIST *)p; + p += sizeof (*CertList); + CertData = (EFI_SIGNATURE_DATA *)p; + p += sizeof (EFI_GUID); + + CertList->SignatureType = EFI_CERT_X509_GUID; + CertList->SignatureListSize = vendor_cert_size + + sizeof (*CertList) + + sizeof (*CertData) + -1; + CertList->SignatureHeaderSize = 0; + CertList->SignatureSize = vendor_cert_size + sizeof (EFI_GUID); + + CertData->SignatureOwner = SHIM_LOCK_GUID; + CopyMem(p, vendor_cert, vendor_cert_size); + } efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokListRT", &shim_lock_guid, @@ -1600,7 +1607,7 @@ EFI_STATUS check_mok_request(EFI_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"ClearVerify")) { efi_status = start_image(image_handle, MOK_MANAGER); if (efi_status != EFI_SUCCESS) { @@ -1840,6 +1847,75 @@ uninstall_shim_protocols(void) &shim_lock_guid, &shim_lock_interface); } +#define VENDOR_VERIFY L"openSUSE_Verify" + +/* Show the built-in certificate prompt if necessary */ +static int builtin_cert_prompt(void) +{ + EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; + EFI_STATUS status; + UINT32 attributes; + UINTN len = sizeof(UINT8); + UINT8 data; + + use_builtin_cert = FALSE; + + if (vendor_cert_size == 0) + return 0; + + status = uefi_call_wrapper(RT->GetVariable, 5, VENDOR_VERIFY, + &shim_lock_guid, &attributes, + &len, &data); + if (status != EFI_SUCCESS || + (attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + int choice; + + if (status != EFI_NOT_FOUND) + LibDeleteVariable(VENDOR_VERIFY, &shim_lock_guid); + + CHAR16 *str[] = {L"Trust openSUSE Certificate", + L"", + L"Do you agree to use the built-in openSUSE certificate", + L"to verify boot loaders and kernels?", + NULL}; + choice = console_yes_no(str); + if (choice != 1) { + data = 0; + goto done; + } + + data = 1; + status = uefi_call_wrapper(RT->SetVariable, 5, + VENDOR_VERIFY, + &shim_lock_guid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(UINT8), &data); + if (status != EFI_SUCCESS) { + console_error(L"Failed to set openSUSE_Verify", status); + return -1; + } + } + + use_builtin_cert = TRUE; + data = 1; + +done: + /* Setup a runtime variable to show the current state */ + status = uefi_call_wrapper(RT->SetVariable, 5, + L"use_openSUSE_cert", + &shim_lock_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT8), &data); + if (status != EFI_SUCCESS) { + console_error(L"Failed to set use_openSUSE_cert", status); + return -1; + } + + return 0; +} + EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab) { EFI_STATUS efi_status; @@ -1895,6 +1971,8 @@ EFI_STATUS efi_main (EFI_HANDLE image_ha */ hook_system_services(systab); loader_is_participating = 0; + if (builtin_cert_prompt() != 0) + return EFI_ABORTED; } } Index: shim-0.7/MokManager.c =================================================================== --- shim-0.7.orig/MokManager.c +++ shim-0.7/MokManager.c @@ -1701,6 +1701,36 @@ static INTN mok_pw_prompt (void *MokPW, return -1; } +static INTN mok_clear_verify_prompt(void *ClearVerify, UINTN ClearVerifySize) { + EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; + EFI_STATUS status; + + if (console_yes_no((CHAR16 *[]){L"Do you want to revoke openSUSE certificate?", NULL}) != 1) + return 0; + + if (ClearVerifySize == PASSWORD_CRYPT_SIZE) { + status = match_password((PASSWORD_CRYPT *)ClearVerify, NULL, 0, + NULL, NULL); + } + if (status != EFI_SUCCESS) + return -1; + + status = uefi_call_wrapper(RT->SetVariable, 5, + L"openSUSE_Verify", &shim_lock_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + 0, NULL); + if (status != EFI_SUCCESS) { + console_error(L"Failed to delete openSUSE_Verify", status); + return -1; + } + + 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 BOOLEAN verify_certificate(UINT8 *cert, UINTN size) { X509 *X509Cert; @@ -2053,6 +2083,7 @@ typedef enum { MOK_CHANGE_SB, MOK_SET_PW, MOK_CHANGE_DB, + MOK_CLEAR_VERIFY, MOK_KEY_ENROLL, MOK_HASH_ENROLL } mok_menu_item; @@ -2064,7 +2095,8 @@ static EFI_STATUS enter_mok_menu(EFI_HAN void *MokPW, UINTN MokPWSize, void *MokDB, UINTN MokDBSize, void *MokXNew, UINTN MokXNewSize, - void *MokXDel, UINTN MokXDelSize) + void *MokXDel, UINTN MokXDelSize, + void *ClearVerify, UINTN ClearVerifySize) { CHAR16 **menu_strings; mok_menu_item *menu_item; @@ -2138,6 +2170,9 @@ static EFI_STATUS enter_mok_menu(EFI_HAN if (MokDB) menucount++; + if (ClearVerify) + menucount++; + menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (menucount + 1)); if (!menu_strings) @@ -2207,6 +2242,12 @@ static EFI_STATUS enter_mok_menu(EFI_HAN i++; } + if (ClearVerify) { + menu_strings[i] = L"Revoke openSUSE certificate"; + menu_item[i] = MOK_CLEAR_VERIFY; + i++; + } + menu_strings[i] = L"Enroll key from disk"; menu_item[i] = MOK_KEY_ENROLL; i++; @@ -2257,6 +2298,9 @@ static EFI_STATUS enter_mok_menu(EFI_HAN case MOK_CHANGE_DB: mok_db_prompt(MokDB, MokDBSize); break; + case MOK_CLEAR_VERIFY: + mok_clear_verify_prompt(ClearVerify, ClearVerifySize); + break; case MOK_KEY_ENROLL: mok_key_enroll(); break; @@ -2282,6 +2326,7 @@ static EFI_STATUS check_mok_request(EFI_ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0; UINTN MokDBSize = 0, MokXNewSize = 0, MokXDelSize = 0; + UINTN ClearVerifySize = 0; void *MokNew = NULL; void *MokDel = NULL; void *MokSB = NULL; @@ -2289,6 +2334,7 @@ static EFI_STATUS check_mok_request(EFI_ void *MokDB = NULL; void *MokXNew = NULL; void *MokXDel = NULL; + void *ClearVerify = NULL; EFI_STATUS status; status = get_variable(L"MokNew", (UINT8 **)&MokNew, &MokNewSize, @@ -2361,9 +2407,20 @@ static EFI_STATUS check_mok_request(EFI_ console_error(L"Could not retrieve MokXDel", status); } + status = get_variable(L"ClearVerify", (UINT8 **)&ClearVerify, &ClearVerifySize, + shim_lock_guid); + if (status == EFI_SUCCESS) { + if (LibDeleteVariable(L"ClearVerify", &shim_lock_guid) != EFI_SUCCESS) { + console_notify(L"Failed to delete ClearVerify"); + } + } else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) { + console_error(L"Could not retrieve ClearVerify", status); + } + enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize, MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize, - MokXNew, MokXNewSize, MokXDel, MokXDelSize); + MokXNew, MokXNewSize, MokXDel, MokXDelSize, + ClearVerify, ClearVerifySize); if (MokNew) FreePool (MokNew); @@ -2386,6 +2443,9 @@ static EFI_STATUS check_mok_request(EFI_ if (MokXDel) FreePool (MokXDel); + if (ClearVerify) + FreePool (ClearVerify); + LibDeleteVariable(L"MokAuth", &shim_lock_guid); LibDeleteVariable(L"MokDelAuth", &shim_lock_guid); LibDeleteVariable(L"MokXAuth", &shim_lock_guid);