#include #include #include #include #include "shim.h" #include "signature.h" #include "PeImage.h" #include "console_control.h" #define PASSWORD_MAX 16 #define PASSWORD_MIN 8 #define SB_PASSWORD_LEN 8 #ifndef SHIM_VENDOR #define SHIM_VENDOR L"Shim" #endif #define EFI_VARIABLE_APPEND_WRITE 0x00000040 EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }; #define CERT_STRING L"Select an X509 certificate to enroll:\n\n" #define HASH_STRING L"Select a file to trust:\n\n" struct menu_item { CHAR16 *text; INTN (* callback)(void *data, void *data2, void *data3); void *data; void *data2; void *data3; UINTN colour; }; typedef struct { UINT32 MokSize; UINT8 *Mok; EFI_GUID Type; } __attribute__ ((packed)) MokListNode; typedef struct { UINT32 MokSBState; UINT32 PWLen; CHAR16 Password[PASSWORD_MAX]; } __attribute__ ((packed)) MokSBvar; static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, UINTN *size, void **buffer) { EFI_STATUS efi_status; char allocate = !(*size); efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, attributes, size, buffer); if (efi_status != EFI_BUFFER_TOO_SMALL || !allocate) { return efi_status; } *buffer = AllocatePool(*size); if (!*buffer) { Print(L"Unable to allocate variable buffer\n"); return EFI_OUT_OF_RESOURCES; } efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, attributes, size, *buffer); return efi_status; } static EFI_INPUT_KEY get_keystroke (void) { EFI_INPUT_KEY key; UINTN EventIndex; uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &EventIndex); uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key); return key; } static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash) { EFI_STATUS status; unsigned int ctxsize; void *ctx = NULL; ctxsize = Sha1GetContextSize(); ctx = AllocatePool(ctxsize); if (!ctx) { Print(L"Unable to allocate memory for hash context\n"); return EFI_OUT_OF_RESOURCES; } if (!Sha1Init(ctx)) { Print(L"Unable to initialise hash\n"); status = EFI_OUT_OF_RESOURCES; goto done; } if (!(Sha1Update(ctx, Data, DataSize))) { Print(L"Unable to generate hash\n"); status = EFI_OUT_OF_RESOURCES; goto done; } if (!(Sha1Final(ctx, hash))) { Print(L"Unable to finalise hash\n"); status = EFI_OUT_OF_RESOURCES; goto done; } status = EFI_SUCCESS; done: return status; } static UINT32 count_keys(void *Data, UINTN DataSize) { EFI_SIGNATURE_LIST *CertList = Data; EFI_GUID CertType = EfiCertX509Guid; EFI_GUID HashType = EfiHashSha256Guid; UINTN dbsize = DataSize; UINT32 MokNum = 0; while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) && (CompareGuid (&CertList->SignatureType, &HashType) != 0)) { Print(L"Doesn't look like a key or hash\n"); dbsize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); continue; } if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) && (CertList->SignatureSize != 48)) { Print(L"Doesn't look like a valid hash\n"); dbsize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); continue; } MokNum++; dbsize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } return MokNum; } static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) { MokListNode *list; EFI_SIGNATURE_LIST *CertList = Data; EFI_SIGNATURE_DATA *Cert; EFI_GUID CertType = EfiCertX509Guid; EFI_GUID HashType = EfiHashSha256Guid; UINTN dbsize = DataSize; UINTN count = 0; list = AllocatePool(sizeof(MokListNode) * num); if (!list) { Print(L"Unable to allocate MOK list\n"); return NULL; } while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) && (CompareGuid (&CertList->SignatureType, &HashType) != 0)) { dbsize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList + CertList->SignatureListSize); continue; } if ((CompareGuid (&CertList->SignatureType, &HashType) == 0) && (CertList->SignatureSize != 48)) { dbsize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList + CertList->SignatureListSize); continue; } Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID); list[count].Mok = (void *)Cert->SignatureData; list[count].Type = CertList->SignatureType; count++; dbsize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } return list; } static void print_x509_name (X509_NAME *X509Name, CHAR16 *name) { char *str; str = X509_NAME_oneline(X509Name, NULL, 0); if (str) { Print(L" %s:\n %a\n", name, str); OPENSSL_free(str); } } static const char *mon[12]= { "Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec" }; static void print_x509_GENERALIZEDTIME_time (ASN1_TIME *time, CHAR16 *time_string) { char *v; int gmt = 0; int i; int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0; char *f = NULL; int f_len = 0; i=time->length; v=(char *)time->data; if (i < 12) goto error; if (v[i-1] == 'Z') gmt=1; for (i=0; i<12; i++) { if ((v[i] > '9') || (v[i] < '0')) goto error; } y = (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0'); M = (v[4]-'0')*10+(v[5]-'0'); if ((M > 12) || (M < 1)) goto error; d = (v[6]-'0')*10+(v[7]-'0'); h = (v[8]-'0')*10+(v[9]-'0'); m = (v[10]-'0')*10+(v[11]-'0'); if (time->length >= 14 && (v[12] >= '0') && (v[12] <= '9') && (v[13] >= '0') && (v[13] <= '9')) { s = (v[12]-'0')*10+(v[13]-'0'); /* Check for fractions of seconds. */ if (time->length >= 15 && v[14] == '.') { int l = time->length; f = &v[14]; /* The decimal point. */ f_len = 1; while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9') ++f_len; } } SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d%.*a %d%a", mon[M-1], d, h, m, s, f_len, f, y, (gmt)?" GMT":""); error: return; } static void print_x509_UTCTIME_time (ASN1_TIME *time, CHAR16 *time_string) { char *v; int gmt=0; int i; int y = 0,M = 0,d = 0,h = 0,m = 0,s = 0; i=time->length; v=(char *)time->data; if (i < 10) goto error; if (v[i-1] == 'Z') gmt=1; for (i=0; i<10; i++) if ((v[i] > '9') || (v[i] < '0')) goto error; y = (v[0]-'0')*10+(v[1]-'0'); if (y < 50) y+=100; M = (v[2]-'0')*10+(v[3]-'0'); if ((M > 12) || (M < 1)) goto error; d = (v[4]-'0')*10+(v[5]-'0'); h = (v[6]-'0')*10+(v[7]-'0'); m = (v[8]-'0')*10+(v[9]-'0'); if (time->length >=12 && (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) s = (v[10]-'0')*10+(v[11]-'0'); SPrint(time_string, 0, L"%a %2d %02d:%02d:%02d %d%a", mon[M-1], d, h, m, s, y+1900, (gmt)?" GMT":""); error: return; } static void print_x509_time (ASN1_TIME *time, CHAR16 *name) { CHAR16 time_string[30]; if (time->type == V_ASN1_UTCTIME) { print_x509_UTCTIME_time(time, time_string); } else if (time->type == V_ASN1_GENERALIZEDTIME) { print_x509_GENERALIZEDTIME_time(time, time_string); } else { time_string[0] = '\0'; } Print(L" %s:\n %s\n", name, time_string); } static void show_x509_info (X509 *X509Cert) { ASN1_INTEGER *serial; BIGNUM *bnser; unsigned char hexbuf[30]; X509_NAME *X509Name; ASN1_TIME *time; serial = X509_get_serialNumber(X509Cert); if (serial) { int i, n; bnser = ASN1_INTEGER_to_BN(serial, NULL); n = BN_bn2bin(bnser, hexbuf); Print(L" Serial Number:\n "); for (i = 0; i < n-1; i++) { Print(L"%02x:", hexbuf[i]); } Print(L"%02x\n", hexbuf[n-1]); } X509Name = X509_get_issuer_name(X509Cert); if (X509Name) { print_x509_name(X509Name, L"Issuer"); } X509Name = X509_get_subject_name(X509Cert); if (X509Name) { print_x509_name(X509Name, L"Subject"); } time = X509_get_notBefore(X509Cert); if (time) { print_x509_time(time, L"Validity from"); } time = X509_get_notAfter(X509Cert); if (time) { print_x509_time(time, L"Validity till"); } } static void show_mok_info (void *Mok, UINTN MokSize) { EFI_STATUS efi_status; UINT8 hash[SHA1_DIGEST_SIZE]; unsigned int i; X509 *X509Cert; if (!Mok || MokSize == 0) return; if (MokSize != SHA256_DIGEST_SIZE) { if (X509ConstructCertificate(Mok, MokSize, (UINT8 **) &X509Cert) && X509Cert != NULL) { show_x509_info(X509Cert); X509_free(X509Cert); } else { Print(L" Not a valid X509 certificate: %x\n\n", ((UINT32 *)Mok)[0]); return; } efi_status = get_sha1sum(Mok, MokSize, hash); if (efi_status != EFI_SUCCESS) { Print(L"Failed to compute MOK fingerprint\n"); return; } Print(L" Fingerprint (SHA1):\n "); for (i = 0; i < SHA1_DIGEST_SIZE; i++) { Print(L" %02x", hash[i]); if (i % 10 == 9) Print(L"\n "); } } else { Print(L"SHA256 hash:\n "); for (i = 0; i < SHA256_DIGEST_SIZE; i++) { Print(L" %02x", ((UINT8 *)Mok)[i]); if (i % 10 == 9) Print(L"\n "); } Print(L"\n"); } Print(L"\n"); } static INTN get_number () { EFI_INPUT_KEY input_key; CHAR16 input[10]; int count = 0; do { input_key = get_keystroke(); if ((input_key.UnicodeChar < '0' || input_key.UnicodeChar > '9' || count >= 10) && input_key.UnicodeChar != CHAR_BACKSPACE) { continue; } if (count == 0 && input_key.UnicodeChar == CHAR_BACKSPACE) continue; Print(L"%c", input_key.UnicodeChar); if (input_key.UnicodeChar == CHAR_BACKSPACE) { input[--count] = '\0'; continue; } input[count++] = input_key.UnicodeChar; } while (input_key.UnicodeChar != CHAR_CARRIAGE_RETURN); if (count == 0) return -1; input[count] = '\0'; return (INTN)Atoi(input); } static UINT8 list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title) { UINT32 MokNum = 0; MokListNode *keys = NULL; INTN key_num = 0; UINT8 initial = 1; if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA))) { Print(L"No keys\n"); Pause(); return 0; } MokNum = count_keys(KeyList, KeyListSize); keys = build_mok_list(MokNum, KeyList, KeyListSize); if (!keys) { Print(L"Failed to construct key list\n"); return 0; } do { uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); if (title) Print(L"%s\n", title); Print(L"Input the key number to show the details of the key or\n" L"type \'0\' to continue\n\n"); Print(L"%d key(s) in the key list\n\n", MokNum); if (key_num > MokNum) { Print(L"[Key %d]\n", key_num); Print(L"No such key\n\n"); } else if (initial != 1 && key_num > 0){ Print(L"[Key %d]\n", key_num); show_mok_info(keys[key_num-1].Mok, keys[key_num-1].MokSize); } Print(L"Key Number: "); key_num = get_number(); Print(L"\n\n"); if (key_num == -1) continue; initial = 0; } while (key_num != 0); FreePool(keys); return 1; } static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show) { EFI_INPUT_KEY key; int count = 0; do { key = get_keystroke(); if ((count >= line_max && key.UnicodeChar != CHAR_BACKSPACE) || key.UnicodeChar == CHAR_NULL || key.UnicodeChar == CHAR_TAB || key.UnicodeChar == CHAR_LINEFEED || key.UnicodeChar == CHAR_CARRIAGE_RETURN) { continue; } if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) { continue; } else if (key.UnicodeChar == CHAR_BACKSPACE) { if (show) { Print(L"\b"); } line[--count] = '\0'; continue; } if (show) { Print(L"%c", key.UnicodeChar); } line[count++] = key.UnicodeChar; } while (key.UnicodeChar != CHAR_CARRIAGE_RETURN); Print(L"\n"); *length = count; return 1; } static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *password, UINT32 pw_length, UINT8 *hash) { EFI_STATUS status; unsigned int ctxsize; void *ctx = NULL; ctxsize = Sha256GetContextSize(); ctx = AllocatePool(ctxsize); if (!ctx) { Print(L"Unable to allocate memory for hash context\n"); return EFI_OUT_OF_RESOURCES; } if (!Sha256Init(ctx)) { Print(L"Unable to initialise hash\n"); status = EFI_OUT_OF_RESOURCES; goto done; } if (MokNew && MokNewSize) { if (!(Sha256Update(ctx, MokNew, MokNewSize))) { Print(L"Unable to generate hash\n"); status = EFI_OUT_OF_RESOURCES; goto done; } } if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) { Print(L"Unable to generate hash\n"); status = EFI_OUT_OF_RESOURCES; goto done; } if (!(Sha256Final(ctx, hash))) { Print(L"Unable to finalise hash\n"); status = EFI_OUT_OF_RESOURCES; goto done; } status = EFI_SUCCESS; done: return status; } static EFI_STATUS match_password (void *Data, UINTN DataSize, UINT8 auth[SHA256_DIGEST_SIZE], CHAR16 *prompt) { EFI_STATUS efi_status; UINT8 hash[SHA256_DIGEST_SIZE]; CHAR16 password[PASSWORD_MAX]; UINT32 pw_length; UINT8 fail_count = 0; while (fail_count < 3) { if (prompt) { Print(L"%s", prompt); } else { Print(L"Password: "); } get_line(&pw_length, password, PASSWORD_MAX, 0); if (pw_length < PASSWORD_MIN || pw_length > PASSWORD_MAX) { Print(L"Invalid password length\n"); fail_count++; continue; } efi_status = compute_pw_hash(Data, DataSize, password, pw_length, hash); if (efi_status != EFI_SUCCESS) { Print(L"Unable to generate password hash\n"); fail_count++; continue; } if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) { Print(L"Password doesn't match\n"); fail_count++; continue; } break; } if (fail_count >= 3) return EFI_ACCESS_DENIED; return EFI_SUCCESS; } static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; UINT8 auth[SHA256_DIGEST_SIZE]; UINTN auth_size; UINT32 attributes; if (authenticate) { auth_size = SHA256_DIGEST_SIZE; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth", &shim_lock_guid, &attributes, &auth_size, auth); if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) { Print(L"Failed to get MokAuth %d\n", efi_status); return efi_status; } efi_status = match_password(MokNew, MokNewSize, auth, NULL); if (efi_status != EFI_SUCCESS) return EFI_ACCESS_DENIED; } if (!MokNewSize) { /* Delete MOK */ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList", &shim_lock_guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL); } else { /* Write new MOK */ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList", &shim_lock_guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_APPEND_WRITE, MokNewSize, MokNew); } if (efi_status != EFI_SUCCESS) { Print(L"Failed to set variable %d\n", efi_status); return efi_status; } return EFI_SUCCESS; } static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; CHAR16 line[1]; UINT32 length; EFI_STATUS efi_status; do { if (!list_keys(MokNew, MokNewSize, L"[Enroll MOK]")) { return 0; } Print(L"Enroll the key(s)? (y/n): "); get_line (&length, line, 1, 1); if (line[0] == 'Y' || line[0] == 'y') { efi_status = store_keys(MokNew, MokNewSize, auth); if (efi_status != EFI_SUCCESS) { Print(L"Failed to enroll keys\n"); return -1; } if (auth) { LibDeleteVariable(L"MokNew", &shim_lock_guid); LibDeleteVariable(L"MokAuth", &shim_lock_guid); Print(L"\nPress a key to reboot system\n"); Pause(); uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL); Print(L"Failed to reboot\n"); return -1; } return 0; } } while (line[0] != 'N' && line[0] != 'n'); return -1; } static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2, void *data3) { uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); return mok_enrollment_prompt(MokNew, (UINTN)data2, TRUE); } static INTN mok_reset_prompt (void *MokNew, void *data2, void *data3) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; CHAR16 line[1]; UINT32 length; EFI_STATUS efi_status; uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); Print(L"Erase all stored keys? (y/N): "); get_line (&length, line, 1, 1); if (line[0] == 'Y' || line[0] == 'y') { efi_status = store_keys(NULL, 0, TRUE); if (efi_status != EFI_SUCCESS) { Print(L"Failed to erase keys\n"); return -1; } LibDeleteVariable(L"MokNew", &shim_lock_guid); LibDeleteVariable(L"MokAuth", &shim_lock_guid); Print(L"\nPress a key to reboot system\n"); Pause(); uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL); Print(L"Failed to reboot\n"); return -1; } return 0; } static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *CertData; void *Data = NULL, *ptr; INTN DataSize = 0; int i; for (i = 0; i < key_num; i++) { if (list[i].Mok == NULL) continue; DataSize += sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID); DataSize += list[i].MokSize; } Data = AllocatePool(DataSize); if (Data == NULL && DataSize != 0) return EFI_OUT_OF_RESOURCES; ptr = Data; for (i = 0; i < key_num; i++) { if (list[i].Mok == NULL) continue; CertList = (EFI_SIGNATURE_LIST *)ptr; CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) + sizeof(EFI_SIGNATURE_LIST)); CertList->SignatureType = list[i].Type; CertList->SignatureListSize = list[i].MokSize + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1; CertList->SignatureHeaderSize = 0; CertList->SignatureSize = list[i].MokSize + sizeof(EFI_GUID); CertData->SignatureOwner = shim_lock_guid; CopyMem(CertData->SignatureData, list[i].Mok, list[i].MokSize); ptr = (uint8_t *)ptr + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) + list[i].MokSize; } efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList", &shim_lock_guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, DataSize, Data); if (Data) FreePool(Data); if (efi_status != EFI_SUCCESS) { Print(L"Failed to set variable %d\n", efi_status); return efi_status; } return EFI_SUCCESS; } static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; UINT8 auth[SHA256_DIGEST_SIZE]; UINTN auth_size = SHA256_DIGEST_SIZE; UINT32 attributes; void *MokListData = NULL; UINTN MokListDataSize = 0; MokListNode *mok, *del_key; INTN mok_num, del_num; int i, j; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth", &shim_lock_guid, &attributes, &auth_size, auth); if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) { Print(L"Failed to get MokDelAuth %d\n", efi_status); return efi_status; } efi_status = match_password(MokDel, MokDelSize, auth, NULL); if (efi_status != EFI_SUCCESS) return EFI_ACCESS_DENIED; efi_status = get_variable(L"MokList", shim_lock_guid, &attributes, &MokListDataSize, &MokListData); if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) { Print(L"MokList is compromised!\nErase all keys in MokList!\n"); if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) { Print(L"Failed to erase MokList\n"); } return EFI_ACCESS_DENIED; } /* Nothing to do */ if (!MokListData || MokListDataSize == 0) return EFI_SUCCESS; /* Construct lists */ mok_num = count_keys(MokListData, MokListDataSize); mok = build_mok_list(mok_num, MokListData, MokListDataSize); del_num = count_keys(MokDel, MokDelSize); del_key = build_mok_list(del_num, MokDel, MokDelSize); /* Search and destroy */ for (i = 0; i < del_num; i++) { UINT32 key_size = del_key[i].MokSize; void *key = del_key[i].Mok; for (j = 0; j < mok_num; j++) { if (mok[j].MokSize == key_size && CompareMem(key, mok[j].Mok, key_size) == 0) { /* Remove the key */ mok[j].Mok = NULL; mok[j].MokSize = 0; } } } efi_status = write_back_mok_list(mok, mok_num); if (MokListData) FreePool(MokListData); if (mok) FreePool(mok); if (del_key) FreePool(del_key); return efi_status; } static INTN mok_deletion_prompt (void *MokDel, void *data2, void *data3) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; UINTN MokDelSize = (UINTN)data2; CHAR16 line[1]; UINT32 length; EFI_STATUS efi_status; do { if (!list_keys(MokDel, MokDelSize, L"[Delete MOK]")) { return 0; } Print(L"Delete the key(s)? (y/n): "); get_line (&length, line, 1, 1); if (line[0] == 'Y' || line[0] == 'y') { efi_status = delete_keys(MokDel, MokDelSize); if (efi_status != EFI_SUCCESS) { Print(L"Failed to delete keys\n"); return -1; } LibDeleteVariable(L"MokDel", &shim_lock_guid); LibDeleteVariable(L"MokDelAuth", &shim_lock_guid); Print(L"\nPress a key to reboot system\n"); Pause(); uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL); Print(L"Failed to reboot\n"); return -1; } } while (line[0] != 'N' && line[0] != 'n'); return -1; } static INTN mok_sb_prompt (void *MokSB, void *data2, void *data3) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; UINTN MokSBSize = (UINTN)data2; MokSBvar *var = MokSB; CHAR16 pass1, pass2, pass3; UINT8 fail_count = 0; UINT32 length; CHAR16 line[1]; UINT8 sbval = 1; UINT8 pos1, pos2, pos3; if (MokSBSize != sizeof(MokSBvar)) { Print(L"Invalid MokSB variable contents\n"); return -1; } uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); 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); Print(L"Enter password character %d: ", pos1 + 1); get_line(&length, &pass1, 1, 0); Print(L"Enter password character %d: ", pos2 + 1); get_line(&length, &pass2, 1, 0); Print(L"Enter password character %d: ", pos3 + 1); get_line(&length, &pass3, 1, 0); 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) { Print(L"Password limit reached\n"); return -1; } if (var->MokSBState == 0) { Print(L"Disable Secure Boot? (y/n): "); } else { Print(L"Enable Secure Boot? (y/n): "); } do { get_line (&length, line, 1, 1); if (line[0] == 'Y' || line[0] == 'y') { if (var->MokSBState == 0) { efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokSBState", &shim_lock_guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 1, &sbval); if (efi_status != EFI_SUCCESS) { Print(L"Failed to set Secure Boot state\n"); return -1; } } else { LibDeleteVariable(L"MokSBState", &shim_lock_guid); } LibDeleteVariable(L"MokSB", &shim_lock_guid); Print(L"Press a key to reboot system\n"); Pause(); uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL); Print(L"Failed to reboot\n"); return -1; } } while (line[0] != 'N' && line[0] != 'n'); return -1; } static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; UINTN MokPWSize = (UINTN)data2; UINT8 hash[SHA256_DIGEST_SIZE]; UINT32 length; CHAR16 line[1]; if (MokPWSize != SHA256_DIGEST_SIZE) { Print(L"Invalid MokPW variable contents\n"); return -1; } uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); SetMem(hash, SHA256_DIGEST_SIZE, 0); if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0) { Print(L"Clear MOK password? (y/n): "); do { get_line (&length, line, 1, 1); if (line[0] == 'Y' || line[0] == 'y') { LibDeleteVariable(L"MokPWStore", &shim_lock_guid); LibDeleteVariable(L"MokPW", &shim_lock_guid); } } while (line[0] != 'N' && line[0] != 'n'); return 0; } efi_status = match_password(NULL, 0, MokPW, L"Confirm MOK passphrase: "); if (efi_status != EFI_SUCCESS) { Print(L"Password limit reached\n"); return -1; } Print(L"Set MOK password? (y/n): "); do { get_line (&length, line, 1, 1); if (line[0] == 'Y' || line[0] == 'y') { efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokPWStore", &shim_lock_guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, MokPWSize, MokPW); if (efi_status != EFI_SUCCESS) { Print(L"Failed to set MOK password\n"); return -1; } LibDeleteVariable(L"MokPW", &shim_lock_guid); Print(L"Press a key to reboot system\n"); Pause(); uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL); Print(L"Failed to reboot\n"); return -1; } } while (line[0] != 'N' && line[0] != 'n'); return 0; } static UINTN draw_menu (CHAR16 *header, UINTN lines, struct menu_item *items, UINTN count) { UINTN i; uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK); Print(L"%s UEFI key management\n\n", SHIM_VENDOR); if (header) Print(L"%s", header); for (i = 0; i < count; i++) { uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, items[i].colour | EFI_BACKGROUND_BLACK); Print(L" %s\n", items[i].text); } uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0); uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE); return 2 + lines; } static void free_menu (struct menu_item *items, UINTN count) { UINTN i; for (i=0; iConOut->SetCursorPosition, 3, ST->ConOut, 0, position); uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_BLACK | EFI_BACKGROUND_BLACK); Print(L" ", timeout); uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, position); uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK); if (timeout > 1) Print(L"Booting in %d seconds\n", timeout); else if (timeout) Print(L"Booting in %d second\n", timeout); } static void run_menu (CHAR16 *header, UINTN lines, struct menu_item *items, UINTN count, UINTN timeout) { UINTN index, pos = 0, wait = 0, offset; EFI_INPUT_KEY key; EFI_STATUS status; INTN ret; if (timeout) wait = 10000000; offset = draw_menu (header, lines, items, count); while (1) { update_time(count + offset + 1, timeout); uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, pos + offset); status = WaitForSingleEvent(ST->ConIn->WaitForKey, wait); if (status == EFI_TIMEOUT) { timeout--; if (!timeout) { free_menu(items, count); return; } continue; } wait = 0; timeout = 0; uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index); uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key); switch(key.ScanCode) { case SCAN_UP: if (pos == 0) continue; pos--; continue; break; case SCAN_DOWN: if (pos == (count - 1)) continue; pos++; continue; break; } switch(key.UnicodeChar) { case CHAR_LINEFEED: case CHAR_CARRIAGE_RETURN: if (items[pos].callback == NULL) { free_menu(items, count); return; } ret = items[pos].callback(items[pos].data, items[pos].data2, items[pos].data3); if (ret < 0) { Print(L"Press a key to continue\n"); Pause(); /* Clear the key in the queue */ uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key); } draw_menu (header, lines, items, count); pos = 0; break; } } } static UINTN verify_certificate(void *cert, UINTN size) { X509 *X509Cert; if (!cert || size == 0) return FALSE; if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) || X509Cert == NULL) { Print(L"Invalid X509 certificate\n"); Pause(); return FALSE; } X509_free(X509Cert); return TRUE; } static INTN file_callback (void *data, void *data2, void *data3) { EFI_FILE_INFO *buffer = NULL; UINTN buffersize = 0, mokbuffersize; EFI_STATUS status; EFI_FILE *file; CHAR16 *filename = data; EFI_FILE *parent = data2; BOOLEAN hash = !!data3; EFI_GUID file_info_guid = EFI_FILE_INFO_ID; EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *CertData; void *mokbuffer = NULL; status = uefi_call_wrapper(parent->Open, 5, parent, &file, filename, EFI_FILE_MODE_READ, 0); if (status != EFI_SUCCESS) return 1; status = uefi_call_wrapper(file->GetInfo, 4, file, &file_info_guid, &buffersize, buffer); if (status == EFI_BUFFER_TOO_SMALL) { buffer = AllocatePool(buffersize); status = uefi_call_wrapper(file->GetInfo, 4, file, &file_info_guid, &buffersize, buffer); } if (!buffer) return 0; buffersize = buffer->FileSize; if (hash) { void *binary; UINT8 sha256[SHA256_DIGEST_SIZE]; UINT8 sha1[SHA1_DIGEST_SIZE]; SHIM_LOCK *shim_lock; EFI_GUID shim_guid = SHIM_LOCK_GUID; PE_COFF_LOADER_IMAGE_CONTEXT context; status = LibLocateProtocol(&shim_guid, (VOID **)&shim_lock); if (status != EFI_SUCCESS) goto out; mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) + SHA256_DIGEST_SIZE; mokbuffer = AllocatePool(mokbuffersize); if (!mokbuffer) goto out; binary = AllocatePool(buffersize); status = uefi_call_wrapper(file->Read, 3, file, &buffersize, binary); if (status != EFI_SUCCESS) goto out; status = shim_lock->Context(binary, buffersize, &context); if (status != EFI_SUCCESS) goto out; status = shim_lock->Hash(binary, buffersize, &context, sha256, sha1); if (status != EFI_SUCCESS) goto out; CertList = mokbuffer; CertList->SignatureType = EfiHashSha256Guid; CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE; CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) + sizeof(EFI_SIGNATURE_LIST)); CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE); } else { mokbuffersize = buffersize + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID); mokbuffer = AllocatePool(mokbuffersize); if (!mokbuffer) goto out; CertList = mokbuffer; CertList->SignatureType = EfiCertX509Guid; CertList->SignatureSize = 16 + buffersize; status = uefi_call_wrapper(file->Read, 3, file, &buffersize, mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16); if (status != EFI_SUCCESS) goto out; CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) + sizeof(EFI_SIGNATURE_LIST)); } CertList->SignatureListSize = mokbuffersize; CertList->SignatureHeaderSize = 0; CertData->SignatureOwner = shim_lock_guid; if (!hash) { if (!verify_certificate(CertData->SignatureData, buffersize)) goto out; } mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE); out: if (buffer) FreePool(buffer); if (mokbuffer) FreePool(mokbuffer); return 0; } static INTN directory_callback (void *data, void *data2, void *data3) { EFI_FILE_INFO *buffer = NULL; UINTN buffersize = 0; EFI_STATUS status; UINTN dircount = 0, i = 0; struct menu_item *dircontent; EFI_FILE *dir; CHAR16 *filename = data; EFI_FILE *root = data2; BOOLEAN hash = !!data3; status = uefi_call_wrapper(root->Open, 5, root, &dir, filename, EFI_FILE_MODE_READ, 0); if (status != EFI_SUCCESS) return 1; while (1) { status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize, buffer); if (status == EFI_BUFFER_TOO_SMALL) { buffer = AllocatePool(buffersize); status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize, buffer); } if (status != EFI_SUCCESS) return 1; if (!buffersize) break; if ((StrCmp(buffer->FileName, L".") == 0) || (StrCmp(buffer->FileName, L"..") == 0)) continue; dircount++; FreePool(buffer); buffersize = 0; } dircount++; dircontent = AllocatePool(sizeof(struct menu_item) * dircount); dircontent[0].text = StrDuplicate(L".."); dircontent[0].callback = NULL; dircontent[0].colour = EFI_YELLOW; i++; uefi_call_wrapper(dir->SetPosition, 2, dir, 0); while (1) { status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize, buffer); if (status == EFI_BUFFER_TOO_SMALL) { buffer = AllocatePool(buffersize); status = uefi_call_wrapper(dir->Read, 3, dir, &buffersize, buffer); } if (status != EFI_SUCCESS) return 1; if (!buffersize) break; if ((StrCmp(buffer->FileName, L".") == 0) || (StrCmp(buffer->FileName, L"..") == 0)) continue; if (buffer->Attribute & EFI_FILE_DIRECTORY) { dircontent[i].text = StrDuplicate(buffer->FileName); dircontent[i].callback = directory_callback; dircontent[i].data = dircontent[i].text; dircontent[i].data2 = dir; dircontent[i].data3 = data3; dircontent[i].colour = EFI_YELLOW; } else { dircontent[i].text = StrDuplicate(buffer->FileName); dircontent[i].callback = file_callback; dircontent[i].data = dircontent[i].text; dircontent[i].data2 = dir; dircontent[i].data3 = data3; dircontent[i].colour = EFI_WHITE; } i++; FreePool(buffer); buffersize = 0; buffer = NULL; } if (hash) run_menu(HASH_STRING, 2, dircontent, dircount, 0); else run_menu(CERT_STRING, 2, dircontent, dircount, 0); return 0; } static INTN filesystem_callback (void *data, void *data2, void *data3) { EFI_FILE_INFO *buffer = NULL; UINTN buffersize = 0; EFI_STATUS status; UINTN dircount = 0, i = 0; struct menu_item *dircontent; EFI_FILE *root = data; BOOLEAN hash = !!data3; uefi_call_wrapper(root->SetPosition, 2, root, 0); while (1) { status = uefi_call_wrapper(root->Read, 3, root, &buffersize, buffer); if (status == EFI_BUFFER_TOO_SMALL) { buffer = AllocatePool(buffersize); status = uefi_call_wrapper(root->Read, 3, root, &buffersize, buffer); } if (status != EFI_SUCCESS) return 1; if (!buffersize) break; if ((StrCmp(buffer->FileName, L".") == 0) || (StrCmp(buffer->FileName, L"..") == 0)) continue; dircount++; FreePool(buffer); buffersize = 0; } dircount++; dircontent = AllocatePool(sizeof(struct menu_item) * dircount); dircontent[0].text = StrDuplicate(L"Return to filesystem list"); dircontent[0].callback = NULL; dircontent[0].colour = EFI_YELLOW; i++; uefi_call_wrapper(root->SetPosition, 2, root, 0); while (1) { status = uefi_call_wrapper(root->Read, 3, root, &buffersize, buffer); if (status == EFI_BUFFER_TOO_SMALL) { buffer = AllocatePool(buffersize); status = uefi_call_wrapper(root->Read, 3, root, &buffersize, buffer); } if (status != EFI_SUCCESS) return 1; if (!buffersize) break; if ((StrCmp(buffer->FileName, L".") == 0) || (StrCmp(buffer->FileName, L"..") == 0)) continue; if (buffer->Attribute & EFI_FILE_DIRECTORY) { dircontent[i].text = StrDuplicate(buffer->FileName); dircontent[i].callback = directory_callback; dircontent[i].data = dircontent[i].text; dircontent[i].data2 = root; dircontent[i].data3 = data3; dircontent[i].colour = EFI_YELLOW; } else { dircontent[i].text = StrDuplicate(buffer->FileName); dircontent[i].callback = file_callback; dircontent[i].data = dircontent[i].text; dircontent[i].data2 = root; dircontent[i].data3 = data3; dircontent[i].colour = EFI_WHITE; } i++; FreePool(buffer); buffer = NULL; buffersize = 0; } if (hash) run_menu(HASH_STRING, 2, dircontent, dircount, 0); else run_menu(CERT_STRING, 2, dircontent, dircount, 0); return 0; } static INTN find_fs (void *data, void *data2, void *data3) { EFI_GUID fs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL; UINTN count, i; UINTN OldSize, NewSize; EFI_HANDLE *filesystem_handles = NULL; struct menu_item *filesystems; BOOLEAN hash = !!data3; uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &fs_guid, NULL, &count, &filesystem_handles); if (!count || !filesystem_handles) { Print(L"No filesystems?\n"); return 1; } count++; filesystems = AllocatePool(sizeof(struct menu_item) * count); filesystems[0].text = StrDuplicate(L"Exit"); filesystems[0].callback = NULL; filesystems[0].colour = EFI_YELLOW; for (i=1; iHandleProtocol, 3, fs, &fs_guid, (void **)&fs_interface); if (status != EFI_SUCCESS || !fs_interface) continue; path = DevicePathFromHandle(fs); status = uefi_call_wrapper(fs_interface->OpenVolume, 2, fs_interface, &root); if (status != EFI_SUCCESS || !root) continue; status = uefi_call_wrapper(root->GetInfo, 4, root, &file_info_guid, &buffersize, buffer); if (status == EFI_BUFFER_TOO_SMALL) { buffer = AllocatePool(buffersize); status = uefi_call_wrapper(root->GetInfo, 4, root, &file_info_guid, &buffersize, buffer); } if (status == EFI_SUCCESS) VolumeLabel = buffer->VolumeLabel; if (path) filesystems[i].text = DevicePathToStr(path); else filesystems[i].text = StrDuplicate(L"Unknown device\n"); if (VolumeLabel) { OldSize = (StrLen(filesystems[i].text) + 1) * sizeof(CHAR16); NewSize = OldSize + StrLen(VolumeLabel) * sizeof(CHAR16); filesystems[i].text = ReallocatePool(filesystems[i].text, OldSize, NewSize); StrCat(filesystems[i].text, VolumeLabel); } if (buffersize) FreePool(buffer); filesystems[i].data = root; filesystems[i].data2 = NULL; filesystems[i].data3 = data3; filesystems[i].callback = filesystem_callback; filesystems[i].colour = EFI_YELLOW; } uefi_call_wrapper(BS->FreePool, 1, filesystem_handles); if (hash) run_menu(HASH_STRING, 2, filesystems, count, 0); else run_menu(CERT_STRING, 2, filesystems, count, 0); return 0; } static BOOLEAN verify_pw(void) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; UINT8 pwhash[SHA256_DIGEST_SIZE]; UINTN size = SHA256_DIGEST_SIZE; UINT32 attributes; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore", &shim_lock_guid, &attributes, &size, pwhash); /* * If anything can attack the password it could just set it to a * known value, so there's no safety advantage in failing to validate * purely because of a failure to read the variable */ if (efi_status != EFI_SUCCESS) return TRUE; if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) return TRUE; uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); efi_status = match_password(NULL, 0, pwhash, L"Enter MOK password: "); if (efi_status != EFI_SUCCESS) { Print(L"Password limit reached\n"); return FALSE; } return TRUE; } 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) { struct menu_item *menu_item; UINT32 MokAuth = 0; UINT32 MokDelAuth = 0; UINTN menucount = 3, i = 0; EFI_STATUS efi_status; EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; UINT8 auth[SHA256_DIGEST_SIZE]; UINTN auth_size = SHA256_DIGEST_SIZE; UINT32 attributes; if (verify_pw() == FALSE) return EFI_ACCESS_DENIED; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth", &shim_lock_guid, &attributes, &auth_size, auth); if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE)) MokAuth = 1; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth", &shim_lock_guid, &attributes, &auth_size, auth); if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE)) MokDelAuth = 1; if (MokNew || MokAuth) menucount++; if (MokDel || MokDelAuth) menucount++; if (MokSB) menucount++; if (MokPW) menucount++; menu_item = AllocateZeroPool(sizeof(struct menu_item) * menucount); if (!menu_item) return EFI_OUT_OF_RESOURCES; menu_item[i].text = StrDuplicate(L"Continue boot"); menu_item[i].colour = EFI_WHITE; menu_item[i].callback = NULL; i++; if (MokNew || MokAuth) { if (!MokNew) { menu_item[i].text = StrDuplicate(L"Reset MOK"); menu_item[i].colour = EFI_WHITE; menu_item[i].callback = mok_reset_prompt; } else { menu_item[i].text = StrDuplicate(L"Enroll MOK"); menu_item[i].colour = EFI_WHITE; menu_item[i].data = MokNew; menu_item[i].data2 = (void *)MokNewSize; menu_item[i].callback = mok_enrollment_prompt_callback; } i++; } if (MokDel || MokDelAuth) { menu_item[i].text = StrDuplicate(L"Delete MOK"); menu_item[i].colour = EFI_WHITE; menu_item[i].data = MokDel; menu_item[i].data2 = (void *)MokDelSize; menu_item[i].callback = mok_deletion_prompt; i++; } if (MokSB) { menu_item[i].text = StrDuplicate(L"Change Secure Boot state"); menu_item[i].colour = EFI_WHITE; menu_item[i].callback = mok_sb_prompt; menu_item[i].data = MokSB; menu_item[i].data2 = (void *)MokSBSize; i++; } if (MokPW) { menu_item[i].text = StrDuplicate(L"Set MOK password"); menu_item[i].colour = EFI_WHITE; menu_item[i].callback = mok_pw_prompt; menu_item[i].data = MokPW; menu_item[i].data2 = (void *)MokPWSize; i++; } menu_item[i].text = StrDuplicate(L"Enroll key from disk"); menu_item[i].colour = EFI_WHITE; menu_item[i].callback = find_fs; menu_item[i].data3 = (void *)FALSE; i++; menu_item[i].text = StrDuplicate(L"Enroll hash from disk"); menu_item[i].colour = EFI_WHITE; menu_item[i].callback = find_fs; menu_item[i].data3 = (void *)TRUE; i++; run_menu(NULL, 0, menu_item, menucount, 10); uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); return 0; } 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; void *MokNew = NULL; void *MokDel = NULL; void *MokSB = NULL; void *MokPW = NULL; MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize); MokDel = LibGetVariableAndSize(L"MokDel", &shim_lock_guid, &MokDelSize); MokSB = LibGetVariableAndSize(L"MokSB", &shim_lock_guid, &MokSBSize); MokPW = LibGetVariableAndSize(L"MokPW", &shim_lock_guid, &MokPWSize); enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize, MokSB, MokSBSize, MokPW, MokPWSize); if (MokNew) { if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) { Print(L"Failed to delete MokNew\n"); } FreePool (MokNew); } if (MokDel) { if (LibDeleteVariable(L"MokDel", &shim_lock_guid) != EFI_SUCCESS) { Print(L"Failed to delete MokDel\n"); } FreePool (MokDel); } if (MokSB) { if (LibDeleteVariable(L"MokSB", &shim_lock_guid) != EFI_SUCCESS) { Print(L"Failed to delete MokSB\n"); } FreePool (MokNew); } if (MokPW) { if (LibDeleteVariable(L"MokPW", &shim_lock_guid) != EFI_SUCCESS) { Print(L"Failed to delete MokPW\n"); } FreePool (MokNew); } LibDeleteVariable(L"MokAuth", &shim_lock_guid); LibDeleteVariable(L"MokDelAuth", &shim_lock_guid); return EFI_SUCCESS; } static VOID setup_console (int text) { EFI_STATUS status; EFI_GUID console_control_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; EFI_CONSOLE_CONTROL_PROTOCOL *concon; static EFI_CONSOLE_CONTROL_SCREEN_MODE mode = EfiConsoleControlScreenGraphics; EFI_CONSOLE_CONTROL_SCREEN_MODE new_mode; status = LibLocateProtocol(&console_control_guid, (VOID **)&concon); if (status != EFI_SUCCESS) return; if (text) { new_mode = EfiConsoleControlScreenText; status = uefi_call_wrapper(concon->GetMode, 4, concon, &mode, 0, 0); /* If that didn't work, assume it's graphics */ if (status != EFI_SUCCESS) mode = EfiConsoleControlScreenGraphics; } else { new_mode = mode; } uefi_call_wrapper(concon->SetMode, 2, concon, new_mode); } static EFI_STATUS setup_rand (void) { EFI_TIME time; EFI_STATUS efi_status; UINT64 seed; BOOLEAN status; efi_status = uefi_call_wrapper(RT->GetTime, 2, &time, NULL); if (efi_status != EFI_SUCCESS) return efi_status; seed = ((UINT64)time.Year << 48) | ((UINT64)time.Month << 40) | ((UINT64)time.Day << 32) | ((UINT64)time.Hour << 24) | ((UINT64)time.Minute << 16) | ((UINT64)time.Second << 8) | ((UINT64)time.Daylight); status = RandomSeed((UINT8 *)&seed, sizeof(seed)); if (!status) return EFI_ABORTED; return EFI_SUCCESS; } EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab) { EFI_STATUS efi_status; InitializeLib(image_handle, systab); setup_console(1); setup_rand(); efi_status = check_mok_request(image_handle); setup_console(0); return efi_status; }