diff options
Diffstat (limited to 'MokManager.c')
| -rw-r--r-- | MokManager.c | 1692 |
1 files changed, 1692 insertions, 0 deletions
diff --git a/MokManager.c b/MokManager.c new file mode 100644 index 00000000..5802d274 --- /dev/null +++ b/MokManager.c @@ -0,0 +1,1692 @@ +#include <efi.h> +#include <efilib.h> +#include <Library/BaseCryptLib.h> +#include <openssl/x509.h> +#include "shim.h" +#include "signature.h" +#include "PeImage.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 + +#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; +} __attribute__ ((packed)) MokListNode; + +typedef struct { + UINT32 MokSBState; + UINT32 PWLen; + CHAR16 Password[PASSWORD_MAX]; +} __attribute__ ((packed)) MokSBvar; + +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 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; + list[count].Mok = (void *)Cert->SignatureData; + + 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 != 48) { + 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 *MokNew, UINTN MokNewSize) +{ + UINT32 MokNum = 0; + MokListNode *keys = NULL; + INTN key_num = 0; + UINT8 initial = 1; + EFI_SIGNATURE_LIST *CertList = MokNew; + EFI_GUID CertType = EfiCertX509Guid; + EFI_GUID HashType = EfiHashSha256Guid; + UINTN dbsize = MokNewSize; + + if (MokNewSize < (sizeof(EFI_SIGNATURE_LIST) + + sizeof(EFI_SIGNATURE_DATA))) { + Print(L"No keys\n"); + Pause(); + return 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); + } + + keys = build_mok_list(MokNum, MokNew, MokNewSize); + + if (!keys) { + Print(L"Failed to construct key list in MokNew\n"); + return 0; + } + + do { + uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); + 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 new 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 store_keys (void *MokNew, UINTN MokNewSize, int authenticate) +{ + EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; + EFI_STATUS efi_status; + UINT8 hash[SHA256_DIGEST_SIZE]; + UINT8 auth[SHA256_DIGEST_SIZE]; + UINTN auth_size; + UINT32 attributes; + CHAR16 password[PASSWORD_MAX]; + UINT32 pw_length; + UINT8 fail_count = 0; + + 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; + } + + while (fail_count < 3) { + Print(L"Password(%d-%d characters): ", + PASSWORD_MIN, PASSWORD_MAX); + get_line(&pw_length, password, PASSWORD_MAX, 0); + + if (pw_length < 8) { + Print(L"At least %d characters for the password\n", + PASSWORD_MIN); + } + + efi_status = compute_pw_hash(MokNew, MokNewSize, password, + pw_length, hash); + + if (efi_status != EFI_SUCCESS) { + return efi_status; + } + + if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) { + Print(L"Password doesn't match\n"); + fail_count++; + } else { + break; + } + } + + if (fail_count >= 3) + 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) { + CHAR16 line[1]; + UINT32 length; + EFI_STATUS efi_status; + + do { + if (!list_keys(MokNew, MokNewSize)) { + 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; + } + 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_deletion_prompt (void *MokNew, void *data2, void *data3) { + CHAR16 line[1]; + UINT32 length; + EFI_STATUS efi_status; + + 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; + } + } + + return 0; +} + +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 fail_count = 0; + UINT8 hash[SHA256_DIGEST_SIZE]; + CHAR16 password[PASSWORD_MAX]; + 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; + } + + while (fail_count < 3) { + Print(L"Confirm MOK passphrase: "); + get_line(&length, password, PASSWORD_MAX, 0); + + if ((length < PASSWORD_MIN) || (length > PASSWORD_MAX)) { + Print(L"Invalid password length\n"); + fail_count++; + continue; + } + + efi_status = compute_pw_hash(NULL, 0, password, length, hash); + + if (efi_status != EFI_SUCCESS) { + Print(L"Unable to generate password hash\n"); + fail_count++; + continue; + } + + if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) != 0) { + Print(L"Password doesn't match\n"); + fail_count++; + continue; + } + + break; + } + + if (fail_count >= 3) { + 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; i<count; i++) { + if (items[i].text) + FreePool(items[i].text); + } + + FreePool(items); +} + +static void update_time (UINTN position, UINTN timeout) +{ + uefi_call_wrapper(ST->ConOut->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(); + } + 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; i<count; i++) { + EFI_HANDLE fs = filesystem_handles[i-1]; + EFI_FILE_IO_INTERFACE *fs_interface; + EFI_DEVICE_PATH *path; + EFI_FILE *root; + EFI_STATUS status; + CHAR16 *VolumeLabel = NULL; + EFI_FILE_SYSTEM_INFO *buffer = NULL; + UINTN buffersize = 0; + EFI_GUID file_info_guid = EFI_FILE_INFO_ID; + + status = uefi_call_wrapper(BS->HandleProtocol, 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; + CHAR16 password[PASSWORD_MAX]; + UINT8 fail_count = 0; + UINT8 hash[SHA256_DIGEST_SIZE]; + UINT8 pwhash[SHA256_DIGEST_SIZE]; + UINTN size = SHA256_DIGEST_SIZE; + UINT32 length; + 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); + + while (fail_count < 3) { + Print(L"Enter MOK password: "); + get_line(&length, password, PASSWORD_MAX, 0); + + if (length < PASSWORD_MIN || length > PASSWORD_MAX) { + Print(L"Invalid password length\n"); + fail_count++; + continue; + } + + efi_status = compute_pw_hash(NULL, 0, password, length, hash); + + if (efi_status != EFI_SUCCESS) { + Print(L"Unable to generate password hash\n"); + fail_count++; + continue; + } + + if (CompareMem(pwhash, hash, SHA256_DIGEST_SIZE) != 0) { + Print(L"Password doesn't match\n"); + fail_count++; + continue; + } + + return TRUE; + } + + Print(L"Password limit reached\n"); + return FALSE; +} + +static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew, + UINTN MokNewSize, void *MokSB, + UINTN MokSBSize, void *MokPW, UINTN MokPWSize) +{ + struct menu_item *menu_item; + UINT32 MokAuth = 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; + + if (MokNew || MokAuth) + 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"Delete MOK"); + menu_item[i].colour = EFI_WHITE; + menu_item[i].callback = mok_deletion_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 (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, MokSBSize = 0, MokPWSize = 0; + void *MokNew = NULL; + void *MokSB = NULL; + void *MokPW = NULL; + + MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize); + + MokSB = LibGetVariableAndSize(L"MokSB", &shim_lock_guid, &MokSBSize); + + MokPW = LibGetVariableAndSize(L"MokPW", &shim_lock_guid, &MokPWSize); + + enter_mok_menu(image_handle, MokNew, MokNewSize, 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 (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); + + return EFI_SUCCESS; +} + +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_rand(); + + efi_status = check_mok_request(image_handle); + + return efi_status; +} |
