| /* |
| * Copyright 2012 <James.Bottomley@HansenPartnership.com> |
| * |
| * see COPYING file |
| * |
| * Tool for manipulating system keys in setup mode |
| */ |
| #include <efi.h> |
| #include <efilib.h> |
| #include <console.h> |
| |
| #include <simple_file.h> |
| #include <variables.h> |
| #include <guid.h> |
| #include <x509.h> |
| #include <efiauthenticated.h> |
| |
| static EFI_HANDLE im; |
| static UINT8 SetupMode, SecureBoot, display_dbt; |
| |
| #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) |
| |
| enum { |
| KEY_PK = 0, |
| KEY_KEK, |
| KEY_DB, |
| KEY_DBX, |
| KEY_DBT, |
| KEY_MOK, |
| MAX_KEYS |
| }; |
| |
| static struct { |
| CHAR16 *name; |
| CHAR16 *text; |
| EFI_GUID *guid; |
| int authenticated:1; |
| int hash:1; |
| } keyinfo[] = { |
| [KEY_PK] = { |
| .name = L"PK", |
| .text = L"The Platform Key (PK)", |
| .guid = &GV_GUID, |
| .authenticated = 1, |
| .hash = 0, |
| }, |
| [KEY_KEK] = { |
| .name = L"KEK", |
| .text = L"The Key Exchange Key Database (KEK)", |
| .guid = &GV_GUID, |
| .authenticated = 1, |
| .hash = 0, |
| }, |
| [KEY_DB] = { |
| .name = L"db", |
| .text = L"The Allowed Signatures Database (db)", |
| .guid = &SIG_DB, |
| .authenticated = 1, |
| .hash = 1, |
| }, |
| [KEY_DBX] = { |
| .name = L"dbx", |
| .text = L"The Forbidden Signatures Database (dbx)", |
| .guid = &SIG_DB, |
| .authenticated = 1, |
| .hash = 1, |
| }, |
| [KEY_DBT] = { |
| .name = L"dbt", |
| .text = L"The Timestamp Signatures Database (dbt)", |
| .guid = &SIG_DB, |
| .authenticated = 1, |
| .hash = 0, |
| }, |
| [KEY_MOK] = { |
| .name = L"MokList", |
| .text = L"The Machine Owner Key List (MokList)", |
| .guid = &MOK_OWNER, |
| .authenticated = 0, |
| .hash = 1, |
| } |
| }; |
| static const int keyinfo_size = ARRAY_SIZE(keyinfo); |
| |
| struct { |
| EFI_GUID *guid; |
| CHAR16 *name; |
| } signatures[] = { |
| { .guid = &X509_GUID, |
| .name = L"X509", |
| }, |
| { .guid = &RSA2048_GUID, |
| .name = L"RSA2048", |
| }, |
| { .guid = &EFI_CERT_SHA256_GUID, |
| .name = L"SHA256 signature", |
| }, |
| { .guid = &EFI_CERT_X509_SHA256_GUID, |
| .name = L"X509 SHA256 signature", |
| }, |
| { .guid = &EFI_CERT_X509_SHA384_GUID, |
| .name = L"X509 SHA384 signature", |
| }, |
| { .guid = &EFI_CERT_X509_SHA384_GUID, |
| .name = L"X509 SHA256 signature", |
| }, |
| }; |
| static const int signatures_size = ARRAY_SIZE(signatures); |
| |
| static void |
| select_and_apply(CHAR16 **title, CHAR16 *ext, int key, UINTN options) |
| { |
| CHAR16 *file_name; |
| EFI_STATUS status; |
| EFI_FILE *file; |
| EFI_HANDLE h = NULL; |
| int use_setsecurevariable = 0; |
| |
| simple_file_selector(&h, title, L"\\", ext, &file_name); |
| if (file_name == NULL) |
| return; |
| |
| status = simple_file_open(h, file_name, &file, EFI_FILE_MODE_READ); |
| if (status != EFI_SUCCESS) |
| return; |
| |
| UINTN size; |
| void *esl; |
| simple_file_read_all(file, &size, &esl); |
| simple_file_close(file); |
| |
| /* PK is different: need to update with an authenticated bundle |
| * including a signature with the new PK */ |
| if (StrCmp(&file_name[StrLen(file_name) - 4], L".esl") == 0) { |
| if (keyinfo[key].authenticated) |
| use_setsecurevariable = 1; |
| else |
| use_setsecurevariable = 0; |
| } else if (StrCmp(&file_name[StrLen(file_name) - 5], L".auth") == 0) { |
| use_setsecurevariable = 0; |
| options |= EFI_VARIABLE_RUNTIME_ACCESS |
| | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; |
| ; |
| |
| if (!keyinfo[key].authenticated) { |
| console_errorbox(L"Can't set MOK variables with a .auth file"); |
| return; |
| } |
| } else { |
| if (keyinfo[key].authenticated) |
| use_setsecurevariable = 1; |
| else |
| use_setsecurevariable = 0; |
| void *newesl; |
| int newsize; |
| |
| status = variable_create_esl(esl, size, &X509_GUID, NULL, |
| &newesl, &newsize); |
| |
| if (status != EFI_SUCCESS) { |
| console_error(L"Failed to create proper ESL", status); |
| return; |
| } |
| FreePool(esl); |
| esl = newesl; |
| size = newsize; |
| } |
| if (use_setsecurevariable) { |
| status = SetSecureVariable(keyinfo[key].name, esl, size, |
| *keyinfo[key].guid, options, 0); |
| } else { |
| status = RT->SetVariable(keyinfo[key].name, keyinfo[key].guid, |
| EFI_VARIABLE_NON_VOLATILE |
| | EFI_VARIABLE_BOOTSERVICE_ACCESS |
| | options, |
| size, esl); |
| } |
| if (status != EFI_SUCCESS) { |
| console_error(L"Failed to update variable", status); |
| return; |
| } |
| } |
| |
| static int |
| StringSplit(CHAR16 *str, int maxlen, CHAR16 c, CHAR16 **out) |
| { |
| int len = StrLen(str); |
| int count = 0; |
| |
| if (len < maxlen) { |
| out[0] = str; |
| return 1; |
| } |
| while (len > 0) { |
| int i, found = 0; |
| |
| for (i = 0; i < maxlen; i++) { |
| if (str[i] == c) |
| found = i; |
| if (str[i] == '\0') { |
| found = i; |
| break; |
| } |
| } |
| out[count++] = str; |
| str[found] = '\0'; |
| str = str + found + 1; |
| len -= found + 1; |
| } |
| return count; |
| } |
| |
| static void |
| delete_key(int key, void *Data, int DataSize, EFI_SIGNATURE_LIST *CertList, |
| EFI_SIGNATURE_DATA *Cert) |
| { |
| EFI_STATUS status; |
| int certs = (CertList->SignatureListSize - sizeof(EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; |
| |
| if (certs == 1) { |
| /* delete entire sig list + data */ |
| DataSize -= CertList->SignatureListSize; |
| if (DataSize > 0) |
| CopyMem(CertList, (void *) CertList + CertList->SignatureListSize, DataSize - ((void *) CertList - Data)); |
| } else { |
| int remain = DataSize - ((void *)Cert - Data) - CertList->SignatureSize; |
| /* only delete single sig */ |
| DataSize -= CertList->SignatureSize; |
| CertList->SignatureListSize -= CertList->SignatureSize; |
| if (remain > 0) |
| CopyMem(Cert, (void *)Cert + CertList->SignatureSize, remain); |
| } |
| |
| if (keyinfo[key].authenticated) |
| status = SetSecureVariable(keyinfo[key].name, Data, |
| DataSize, |
| *keyinfo[key].guid, 0, 0); |
| else |
| status = RT->SetVariable(keyinfo[key].name, keyinfo[key].guid, |
| EFI_VARIABLE_NON_VOLATILE |
| | EFI_VARIABLE_BOOTSERVICE_ACCESS, |
| DataSize, Data); |
| |
| if (status != EFI_SUCCESS) |
| console_error(L"Failed to delete key", status); |
| } |
| |
| static void |
| show_key(int key, int offset, void *Data, int DataSize) |
| { |
| EFI_SIGNATURE_LIST *CertList; |
| EFI_SIGNATURE_DATA *Cert = NULL; |
| int cert_count = 0, i, Size, option = 0; |
| CHAR16 *title[20], *options[4]; |
| CHAR16 str[256], str1[256], str2[256]; |
| |
| title[0] = keyinfo[key].text; |
| |
| certlist_for_each_certentry(CertList, Data, Size, DataSize) { |
| certentry_for_each_cert(Cert, CertList) |
| if (cert_count++ == offset) |
| goto finished; |
| } |
| finished: |
| |
| SPrint(str, sizeof(str), L"Sig[%d] - owner: %g", offset, &Cert->SignatureOwner); |
| |
| int c = 0; |
| title[c++] = str; |
| title[c] = L"Unknown"; |
| |
| for (i = 0; i < signatures_size; i++) { |
| if (CompareGuid(signatures[i].guid, &CertList->SignatureType) == 0) { |
| SPrint(str1, sizeof(str1), L"Type: %s", signatures[i].name); |
| title[c] = str1; |
| break; |
| } |
| } |
| CHAR16 buf[1024], buf1[1024], *tmpbuf[10], *tmpbuf1[10]; |
| if (CompareGuid(&CertList->SignatureType, &EFI_CERT_SHA256_GUID) == 0) { |
| StrCpy(str2, L"Hash: "); |
| sha256_StrCat_hash(str2, Cert->SignatureData); |
| title[++c] = str2; |
| } else if (CompareGuid(&CertList->SignatureType, &X509_GUID) == 0) { |
| |
| x509_to_str(Cert->SignatureData, |
| CertList->SignatureSize, |
| X509_OBJ_SUBJECT, buf, sizeof(buf)); |
| |
| title[++c] = L""; |
| title[++c] = L"Subject:"; |
| |
| |
| int sp = StringSplit(buf, 70, ',', tmpbuf); |
| |
| for (i = 0; i < sp; i++) |
| title[++c] = tmpbuf[i]; |
| |
| x509_to_str(Cert->SignatureData, |
| CertList->SignatureSize, |
| X509_OBJ_ISSUER, buf1, sizeof(buf1)); |
| |
| sp = StringSplit(buf1, 70, ',', tmpbuf1); |
| |
| title[++c] = L"Issuer:"; |
| for (i = 0; i < sp; i++) |
| title[++c] = tmpbuf1[i]; |
| } else if (CompareGuid(&CertList->SignatureType, &EFI_CERT_X509_SHA256_GUID) == 0) { |
| EFI_CERT_X509_SHA256 *tmp = (void *)Cert->SignatureData; |
| StrCpy(str2, L"Hash: "); |
| sha256_StrCat_hash(str2, Cert->SignatureData); |
| title[++c] = str2; |
| EFI_TIME timestamp = tmp->TimeOfRevocation; |
| SPrint(buf, sizeof(buf), |
| L"Revocation Timestamp: %d-%d-%d %02d:%02d:%02d\n", |
| timestamp.Year, timestamp.Month, timestamp.Day, |
| timestamp.Hour, timestamp.Minute, timestamp.Second); |
| title[++c] = buf; |
| } |
| title[++c] = NULL; |
| |
| int o = 0; |
| int option_delete = NOSEL, option_delete_w_auth = NOSEL, |
| option_save = NOSEL; |
| |
| if (variable_is_setupmode() || key == KEY_MOK) { |
| option_delete = o; |
| options[o++] = L"Delete"; |
| } |
| option_save = o; |
| options[o++] = L"Save to File"; |
| if (key == KEY_PK) { |
| option_delete_w_auth = o; |
| options[o++] = L"Delete with .auth File"; |
| } |
| options[o++] = NULL; |
| option = console_select(title, options, option); |
| if (option == -1) |
| return; |
| if (option == option_delete) { |
| delete_key(key, Data, DataSize, CertList, Cert); |
| } else if (option == option_save) { |
| CHAR16 *filename; |
| EFI_FILE *file; |
| EFI_STATUS status; |
| EFI_HANDLE vol; |
| CHAR16 *volname; |
| |
| simple_volume_selector((CHAR16 *[]) { |
| L"Save Key", |
| L"", |
| L"Select a disk Volume to save the key file to", |
| L"The Key file will be saved in the top level directory", |
| L"", |
| L"Note: For USB volumes, some UEFI implementations aren't", |
| L"very good at hotplug, so you may have to boot with the USB", |
| L"Key already plugged in to see the volume", |
| NULL |
| }, &volname, &vol); |
| /* no selection or ESC pressed */ |
| if (!volname) |
| return; |
| FreePool(volname); |
| |
| filename = AllocatePool(1024); |
| |
| SPrint(filename, 0, L"%s-%d.esl", keyinfo[key].name, offset); |
| status = simple_file_open(vol, filename, &file, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE); |
| if (status == EFI_SUCCESS) { |
| status = simple_file_write_all(file, CertList->SignatureListSize, CertList); |
| simple_file_close(file); |
| } |
| |
| if (status != EFI_SUCCESS) { |
| CHAR16 str[80]; |
| |
| SPrint(str, sizeof(str), L"Failed to write %s", filename); |
| console_error(str, status); |
| } else { |
| CHAR16 str1[80], str2[80], str3[80]; |
| |
| SPrint(str1, sizeof(str1), L"Key %s[%d]", keyinfo[key].name, offset); |
| SPrint(str2, sizeof(str2), L"With GUID: %g", &Cert->SignatureOwner); |
| SPrint(str3, sizeof(str3), L"saved to %s", filename); |
| |
| console_alertbox((CHAR16 *[]) { |
| L"Successfully Saved", |
| L"", |
| str1, |
| str2, |
| str3, |
| NULL |
| }); |
| } |
| FreePool(filename); |
| } else if (option == option_delete_w_auth) { |
| title[0] = L"Select authority bundle to remove PK"; |
| title[1] = NULL; |
| select_and_apply(title, L".auth", key, 0); |
| } |
| } |
| |
| static void |
| add_new_key(int key, UINTN options) |
| { |
| CHAR16 *title[3]; |
| /* PK update must be signed: so require .auth file */ |
| CHAR16 *ext = (key != KEY_PK && variable_is_setupmode()) |
| ? L".esl|.auth|.cer" : L".auth"; |
| |
| title[0] = L"Select File containing additional key for"; |
| title[1] = keyinfo[key].text; |
| title[2] = NULL; |
| |
| select_and_apply(title, ext, key, options); |
| } |
| |
| static void |
| enroll_hash(int key) |
| { |
| EFI_STATUS efi_status; |
| CHAR16 *file_name = NULL, *title[6], buf0[256], buf1[256], buf2[256]; |
| UINT8 hash[SHA256_DIGEST_SIZE]; |
| int i; |
| EFI_HANDLE h = NULL; |
| |
| simple_file_selector(&h, (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 Enrolling its hash", |
| NULL |
| }, L"\\", NULL, &file_name); |
| |
| if (!file_name) |
| /* user pressed ESC */ |
| return; |
| |
| efi_status = sha256_get_pecoff_digest(h, file_name, hash); |
| if (efi_status != EFI_SUCCESS) { |
| console_error(L"Hash failed (is efi binary valid?)", |
| efi_status); |
| return; |
| } |
| |
| StrCpy(buf0, L"Enroll hash into "); |
| StrCat(buf0, keyinfo[key].text); |
| 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; |
| |
| efi_status = variable_enroll_hash(keyinfo[key].name, |
| *keyinfo[key].guid, hash); |
| if (efi_status != EFI_SUCCESS && efi_status != EFI_ALREADY_STARTED) { |
| console_error(L"Failed to add signature to db", efi_status); |
| return; |
| } |
| } |
| |
| static void |
| save_key_internal(int key, EFI_HANDLE vol, CHAR16 *error) |
| { |
| EFI_STATUS status; |
| EFI_FILE *file; |
| UINT8 *data; |
| UINTN len; |
| CHAR16 file_name[512]; |
| |
| StrCpy(error, keyinfo[key].name); |
| status = get_variable(keyinfo[key].name, &data, &len, |
| *keyinfo[key].guid); |
| if (status != EFI_SUCCESS) { |
| if (status == EFI_NOT_FOUND) |
| StrCat(error, L": Variable has no entries"); |
| else |
| SPrint(error, 1024, L"%s: Failed to get variable (Error: %d)", |
| error, status); |
| return; |
| } |
| StrCpy(file_name, L"\\"); |
| StrCat(file_name, keyinfo[key].name); |
| StrCat(file_name, L".esl"); |
| status = simple_file_open(vol, file_name, &file, |
| EFI_FILE_MODE_READ |
| | EFI_FILE_MODE_WRITE |
| | EFI_FILE_MODE_CREATE); |
| if (status != EFI_SUCCESS) { |
| SPrint(error, 1024, L"%s: Failed to open file %s (Error: %d)", |
| error, file_name, status); |
| return; |
| } |
| status = simple_file_write_all(file, len, data); |
| simple_file_close(file); |
| if (status != EFI_SUCCESS) { |
| SPrint(error, 1024, L"%s: Failed to write to %s (Error: %d)", |
| error, file_name, status); |
| return; |
| } |
| StrCat(error, L": Successfully written to "); |
| StrCat(error, file_name); |
| } |
| |
| static void |
| save_key(int key) |
| { |
| EFI_HANDLE vol; |
| CHAR16 *volname; |
| |
| simple_volume_selector((CHAR16 *[]) { |
| L"Save Key", |
| L"", |
| L"Select a disk Volume to save the key file to", |
| L"The key file will be saved in the top level directory", |
| L"", |
| L"Note: For USB volumes, some UEFI implementations aren't", |
| L"very good at hotplug, so you may have to boot with the USB", |
| L"USB device already plugged in to see the volume", |
| NULL |
| }, &volname, &vol); |
| /* no selection or ESC pressed */ |
| if (!volname) |
| return; |
| FreePool(volname); |
| |
| CHAR16 buf[1024], *title[2]; |
| |
| save_key_internal(key, vol, buf); |
| title[0] = buf; |
| title[1] = NULL; |
| |
| console_alertbox(title); |
| } |
| |
| static void |
| manipulate_key(int key) |
| { |
| CHAR16 *title[5]; |
| EFI_STATUS efi_status; |
| int setup_mode = variable_is_setupmode(), i; |
| |
| title[0] = L"Manipulating Contents of"; |
| title[1] = keyinfo[key].text; |
| title[2] = NULL; |
| |
| UINT8 *Data; |
| UINTN DataSize = 0, Size; |
| efi_status = RT->GetVariable(keyinfo[key].name, keyinfo[key].guid, NULL, &DataSize, NULL); |
| if (efi_status != EFI_BUFFER_TOO_SMALL && efi_status != EFI_NOT_FOUND) { |
| console_error(L"Failed to get DataSize", efi_status); |
| return; |
| } |
| |
| Data = AllocatePool(DataSize); |
| if (!Data) { |
| CHAR16 str[80]; |
| SPrint(str, sizeof(str), L"Failed to allocate %d", DataSize); |
| console_errorbox(str); |
| return; |
| } |
| |
| efi_status = RT->GetVariable(keyinfo[key].name, keyinfo[key].guid, NULL, &DataSize, Data); |
| if (efi_status == EFI_NOT_FOUND) { |
| int t = 2; |
| title[t++] = L"Variable is Empty"; |
| if (key == KEY_PK) |
| title[t++] = L"WARNING: Setting PK will take the platform out of Setup Mode"; |
| title[t++] = NULL; |
| } else if (efi_status != EFI_SUCCESS) { |
| console_error(L"Failed to get variable", efi_status); |
| return; |
| } |
| |
| EFI_SIGNATURE_LIST *CertList; |
| int cert_count = 0, add = NOSEL, replace = NOSEL, hash = NOSEL, |
| save = NOSEL; |
| certlist_for_each_certentry(CertList, Data, Size, DataSize) { |
| cert_count += (CertList->SignatureListSize - sizeof(EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; |
| } |
| |
| CHAR16 **guids = (CHAR16 **)AllocatePool((cert_count + 5)*sizeof(void *)); |
| cert_count = 0; |
| int g; |
| certlist_for_each_certentry(CertList, Data, Size, DataSize) { |
| EFI_SIGNATURE_DATA *Cert; |
| |
| certentry_for_each_cert(Cert, CertList) { |
| guids[cert_count] = AllocatePool(64*sizeof(CHAR16)); |
| SPrint(guids[cert_count++], 64*sizeof(CHAR16), L"%g", &Cert->SignatureOwner); |
| } |
| } |
| g = cert_count; |
| if (key != 0) { |
| add = g; |
| guids[g++] = L"Add New Key"; |
| } |
| replace = g; |
| guids[g++] = L"Replace Key(s)"; |
| |
| if (keyinfo[key].hash && (!keyinfo[key].authenticated || setup_mode)) { |
| hash = g; |
| guids[g++] = L"Enroll hash of binary"; |
| } |
| |
| if (cert_count != 0) { |
| save = g; |
| guids[g++] = L"Save key"; |
| } |
| |
| guids[g] = NULL; |
| int select = console_select(title, guids, 0); |
| for (i = 0; i < cert_count; i++) |
| FreePool(guids[i]); |
| FreePool(guids); |
| if (select == replace) |
| add_new_key(key, 0); |
| else if (select == add) |
| add_new_key(key, EFI_VARIABLE_APPEND_WRITE); |
| else if (select == hash) |
| enroll_hash(key); |
| else if (select == save) |
| save_key(key); |
| else if (select >= 0) |
| show_key(key, select, Data, DataSize); |
| FreePool(Data); |
| } |
| |
| static void |
| select_key(void) |
| { |
| int i, j; |
| int keymap[keyinfo_size + 1]; |
| CHAR16 *keys[keyinfo_size + 1]; |
| |
| for (i = 0, j = 0; i < keyinfo_size; i++) { |
| if (i == KEY_DBT && !display_dbt) |
| continue; |
| keys[j] = keyinfo[i].text; |
| keymap[j++] = i; |
| } |
| keys[j] = NULL; |
| |
| i = 0; |
| |
| for (;;) { |
| i = console_select( (CHAR16 *[]){ L"Select Key to Manipulate", NULL }, keys, i); |
| if (i == -1) |
| break; |
| manipulate_key(keymap[i]); |
| } |
| } |
| |
| static void |
| save_keys(void) |
| { |
| EFI_HANDLE vol; |
| CHAR16 *volname; |
| |
| simple_volume_selector((CHAR16 *[]) { |
| L"Save Keys", |
| L"", |
| L"Select a disk Volume to save all the key files to", |
| L"Key files will be saved in the top level directory", |
| L"", |
| L"Note: For USB volumes, some UEFI implementations aren't", |
| L"very good at hotplug, so you may have to boot with the USB", |
| L"USB device already plugged in to see the volume", |
| NULL |
| }, &volname, &vol); |
| /* no selection or ESC pressed */ |
| if (!volname) |
| return; |
| FreePool(volname); |
| |
| CHAR16 *title[10], buf[8000]; |
| int i, t_c = 0, b_c = 0; |
| |
| title[t_c++] = L"Results of Saving Keys"; |
| title[t_c++] = L""; |
| |
| for (i = 0; i < MAX_KEYS; i++) { |
| if (i == KEY_DBT && !display_dbt) |
| continue; |
| save_key_internal(i, vol, &buf[b_c]); |
| title[t_c++] = &buf[b_c]; |
| b_c += StrLen(&buf[b_c]) + 1; |
| } |
| title[t_c] = NULL; |
| console_alertbox(title); |
| } |
| |
| static void |
| execute_binary() |
| { |
| CHAR16 *bin_name; |
| EFI_HANDLE h = NULL; |
| EFI_HANDLE ih; |
| EFI_DEVICE_PATH *devpath; |
| EFI_STATUS status; |
| |
| simple_file_selector(&h, (CHAR16 *[]) { |
| L"Select Binary to Execute", |
| L"", |
| NULL |
| }, L"\\", |
| NULL, &bin_name); |
| if (!bin_name) { |
| /* user pressed ESC */ |
| return; |
| } |
| |
| /* the execute() call is designed to construct handles from |
| * local resources on the image. We have a handle and a full |
| * path name, so we follow proper process here */ |
| |
| devpath = FileDevicePath(h, bin_name); |
| |
| status = BS->LoadImage(FALSE, im, devpath, NULL, 0, &ih); |
| if (status != EFI_SUCCESS) { |
| console_error(L"Image failed to load", status); |
| return; |
| } |
| |
| status = BS->StartImage(ih, NULL, NULL); |
| BS->UnloadImage(ih); |
| |
| if (status != EFI_SUCCESS) |
| console_error(L"Execution returned error", status); |
| } |
| |
| EFI_STATUS |
| efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) |
| { |
| EFI_STATUS efi_status; |
| UINTN DataSize = sizeof(SetupMode); |
| int option = 0; |
| |
| im = image; |
| |
| InitializeLib(image, systab); |
| |
| if (GetOSIndications() & EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION) |
| display_dbt = 1; |
| |
| efi_status = RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); |
| |
| if (efi_status != EFI_SUCCESS) { |
| Print(L"No SetupMode variable ... is platform secure boot enabled?\n"); return EFI_SUCCESS; |
| } |
| |
| for (;;) { |
| |
| CHAR16 line2[80], line3[80], **title; |
| |
| SetupMode = variable_is_setupmode(); |
| SecureBoot = variable_is_secureboot(); |
| |
| line2[0] = line3[0] = L'\0'; |
| |
| StrCat(line2, L"Platform is in "); |
| StrCat(line2, SetupMode ? L"Setup Mode" : L"User Mode"); |
| StrCat(line3, L"Secure Boot is "); |
| StrCat(line3, SecureBoot ? L"on" : L"off"); |
| title = (CHAR16 *[]){L"KeyTool main menu", L"", line2, line3, NULL }; |
| |
| option = console_select(title, (CHAR16 *[]){ |
| L"Save Keys", |
| L"Edit Keys", |
| L"Execute Binary", |
| L"Exit", |
| NULL }, |
| option); |
| |
| switch (option) { |
| case 0: |
| save_keys(); |
| break; |
| case 1: |
| select_key(); |
| break; |
| case 2: |
| execute_binary(); |
| break; |
| case 3: |
| /* exit from programme */ |
| return EFI_SUCCESS; |
| default: |
| break; |
| } |
| } |
| |
| return EFI_SUCCESS; |
| } |