16ab868efc
- Update to 0.4 - Rebase patches + shim-suse-build.patch + shim-mokmanager-support-crypt-hash-method.patch + shim-bnc804631-fix-broken-bootpath.patch + shim-bnc798043-no-doulbe-separators.patch + shim-bnc807760-change-pxe-2nd-loader-name.patch + shim-bnc808106-correct-certcount.patch + shim-mokmanager-ui-revamp.patch - Add patches + shim-merge-lf-loader-code.patch: merge the Linux Foundation loader UI code + shim-fix-pointer-casting.patch: fix a casting issue and the size of an empty vendor cert + shim-fix-simple-file-selector.patch: fix the buffer allocation in the simple file selector - Remove upstreamed patches + shim-support-mok-delete.patch + shim-reboot-after-changes.patch + shim-clear-queued-key.patch + shim-local-key-sign-mokmanager.patch + shim-get-2nd-stage-loader.patch + shim-fix-loadoptions.patch - Remove unused patch: shim-mokmanager-new-pw-hash.patch and shim-keep-unsigned-mokmanager.patch - Install the vendor certificate to /etc/uefi/certs OBS-URL: https://build.opensuse.org/request/show/184039 OBS-URL: https://build.opensuse.org/package/show/devel:openSUSE:Factory/shim?expand=0&rev=28
5261 lines
148 KiB
Diff
5261 lines
148 KiB
Diff
From 43a23fadf063d0644d123a8024f9a864ed32135f Mon Sep 17 00:00:00 2001
|
|
From: Matthew Garrett <matthew.garrett@nebula.com>
|
|
Date: Sun, 19 May 2013 18:13:01 +0100
|
|
Subject: [PATCH] Port MokManager to Linux Foundation loader UI code
|
|
|
|
This is the first stage of porting the MokManager UI to the UI code used
|
|
by the Linux Foundation UEFI loader.
|
|
---
|
|
Makefile | 9 +-
|
|
MokManager.c | 1220 +++++++++++++++-----------------------------
|
|
include/PeImage.h | 787 ++++++++++++++++++++++++++++
|
|
include/configtable.h | 68 +++
|
|
include/console.h | 21 +
|
|
include/efiauthenticated.h | 222 ++++++++
|
|
include/errors.h | 9 +
|
|
include/execute.h | 5 +
|
|
include/guid.h | 18 +
|
|
include/security_policy.h | 6 +
|
|
include/shell.h | 2 +
|
|
include/simple_file.h | 21 +
|
|
include/variables.h | 59 +++
|
|
include/version.h | 8 +
|
|
include/wincert.h | 33 ++
|
|
lib/Makefile | 28 +
|
|
lib/configtable.c | 144 ++++++
|
|
lib/console.c | 402 +++++++++++++++
|
|
lib/execute.c | 127 +++++
|
|
lib/guid.c | 47 ++
|
|
lib/security_policy.c | 391 ++++++++++++++
|
|
lib/shell.c | 57 +++
|
|
lib/simple_file.c | 501 ++++++++++++++++++
|
|
lib/variables.c | 340 ++++++++++++
|
|
24 files changed, 3721 insertions(+), 804 deletions(-)
|
|
create mode 100644 include/PeImage.h
|
|
create mode 100644 include/configtable.h
|
|
create mode 100644 include/console.h
|
|
create mode 100644 include/efiauthenticated.h
|
|
create mode 100644 include/errors.h
|
|
create mode 100644 include/execute.h
|
|
create mode 100644 include/guid.h
|
|
create mode 100644 include/security_policy.h
|
|
create mode 100644 include/shell.h
|
|
create mode 100644 include/simple_file.h
|
|
create mode 100644 include/variables.h
|
|
create mode 100644 include/version.h
|
|
create mode 100644 include/wincert.h
|
|
create mode 100644 lib/Makefile
|
|
create mode 100644 lib/configtable.c
|
|
create mode 100644 lib/console.c
|
|
create mode 100644 lib/execute.c
|
|
create mode 100644 lib/guid.c
|
|
create mode 100644 lib/security_policy.c
|
|
create mode 100644 lib/shell.c
|
|
create mode 100644 lib/simple_file.c
|
|
create mode 100644 lib/variables.c
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 287fbcf..b37ceb3 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
|
|
|
|
-SUBDIRS = Cryptlib
|
|
+SUBDIRS = Cryptlib lib
|
|
|
|
LIB_PATH = /usr/lib64
|
|
|
|
@@ -74,8 +74,8 @@ fallback.so: $(FALLBACK_OBJS)
|
|
|
|
MokManager.o: $(SOURCES)
|
|
|
|
-MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a
|
|
- $(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
|
|
+MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
|
+ $(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS) lib/lib.a
|
|
|
|
Cryptlib/libcryptlib.a:
|
|
$(MAKE) -C Cryptlib
|
|
@@ -83,6 +83,9 @@ Cryptlib/libcryptlib.a:
|
|
Cryptlib/OpenSSL/libopenssl.a:
|
|
$(MAKE) -C Cryptlib/OpenSSL
|
|
|
|
+lib/lib.a:
|
|
+ $(MAKE) -C lib
|
|
+
|
|
%.efi: %.so
|
|
objcopy -j .text -j .sdata -j .data \
|
|
-j .dynamic -j .dynsym -j .rel \
|
|
diff --git a/MokManager.c b/MokManager.c
|
|
index 97588cb..60e799a 100644
|
|
--- a/MokManager.c
|
|
+++ b/MokManager.c
|
|
@@ -6,6 +6,9 @@
|
|
#include "signature.h"
|
|
#include "PeImage.h"
|
|
|
|
+#include "include/console.h"
|
|
+#include "include/simple_file.h"
|
|
+
|
|
#define PASSWORD_MAX 16
|
|
#define PASSWORD_MIN 8
|
|
#define SB_PASSWORD_LEN 8
|
|
@@ -16,18 +19,6 @@
|
|
|
|
#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;
|
|
@@ -56,7 +47,7 @@ static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes,
|
|
*buffer = AllocatePool(*size);
|
|
|
|
if (!*buffer) {
|
|
- Print(L"Unable to allocate variable buffer\n");
|
|
+ console_notify(L"Unable to allocate variable buffer");
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
@@ -88,24 +79,24 @@ static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash)
|
|
ctx = AllocatePool(ctxsize);
|
|
|
|
if (!ctx) {
|
|
- Print(L"Unable to allocate memory for hash context\n");
|
|
+ console_notify(L"Unable to allocate memory for hash context");
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (!Sha1Init(ctx)) {
|
|
- Print(L"Unable to initialise hash\n");
|
|
+ console_notify(L"Unable to initialise hash");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
if (!(Sha1Update(ctx, Data, DataSize))) {
|
|
- Print(L"Unable to generate hash\n");
|
|
+ console_notify(L"Unable to generate hash");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
if (!(Sha1Final(ctx, hash))) {
|
|
- Print(L"Unable to finalise hash\n");
|
|
+ console_notify(L"Unable to finalise hash");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto done;
|
|
}
|
|
@@ -126,7 +117,7 @@ static UINT32 count_keys(void *Data, UINTN DataSize)
|
|
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");
|
|
+ console_notify(L"Doesn't look like a key or hash");
|
|
dbsize -= CertList->SignatureListSize;
|
|
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
|
|
CertList->SignatureListSize);
|
|
@@ -135,7 +126,7 @@ static UINT32 count_keys(void *Data, UINTN DataSize)
|
|
|
|
if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
|
|
(CertList->SignatureSize != 48)) {
|
|
- Print(L"Doesn't look like a valid hash\n");
|
|
+ console_notify(L"Doesn't look like a valid hash");
|
|
dbsize -= CertList->SignatureListSize;
|
|
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
|
|
CertList->SignatureListSize);
|
|
@@ -163,7 +154,7 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
|
|
list = AllocatePool(sizeof(MokListNode) * num);
|
|
|
|
if (!list) {
|
|
- Print(L"Unable to allocate MOK list\n");
|
|
+ console_notify(L"Unable to allocate MOK list");
|
|
return NULL;
|
|
}
|
|
|
|
@@ -200,15 +191,17 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
|
|
return list;
|
|
}
|
|
|
|
-static void print_x509_name (X509_NAME *X509Name, CHAR16 *name)
|
|
+static CHAR16* get_x509_name (X509_NAME *X509Name, CHAR16 *name)
|
|
{
|
|
char *str;
|
|
+ CHAR16 *ret = NULL;
|
|
|
|
str = X509_NAME_oneline(X509Name, NULL, 0);
|
|
if (str) {
|
|
- Print(L" %s:\n %a\n", name, str);
|
|
+ ret = PoolPrint(L"%s: %a", name, str);
|
|
OPENSSL_free(str);
|
|
}
|
|
+ return ret;
|
|
}
|
|
|
|
static const char *mon[12]= {
|
|
@@ -315,7 +308,7 @@ error:
|
|
return;
|
|
}
|
|
|
|
-static void print_x509_time (ASN1_TIME *time, CHAR16 *name)
|
|
+static CHAR16* get_x509_time (ASN1_TIME *time, CHAR16 *name)
|
|
{
|
|
CHAR16 time_string[30];
|
|
|
|
@@ -327,48 +320,126 @@ static void print_x509_time (ASN1_TIME *time, CHAR16 *name)
|
|
time_string[0] = '\0';
|
|
}
|
|
|
|
- Print(L" %s:\n %s\n", name, time_string);
|
|
+ return PoolPrint(L"%s: %s", name, time_string);
|
|
}
|
|
|
|
-static void show_x509_info (X509 *X509Cert)
|
|
+static void show_x509_info (X509 *X509Cert, UINT8 *hash)
|
|
{
|
|
ASN1_INTEGER *serial;
|
|
BIGNUM *bnser;
|
|
unsigned char hexbuf[30];
|
|
X509_NAME *X509Name;
|
|
ASN1_TIME *time;
|
|
+ CHAR16 *issuer = NULL;
|
|
+ CHAR16 *subject = NULL;
|
|
+ CHAR16 *from = NULL;
|
|
+ CHAR16 *until = NULL;
|
|
+ POOL_PRINT hash_string1;
|
|
+ POOL_PRINT hash_string2;
|
|
+ POOL_PRINT serial_string;
|
|
+ int fields = 0;
|
|
+ CHAR16 **text;
|
|
+ int i = 0;
|
|
+
|
|
+ ZeroMem(&hash_string1, sizeof(hash_string1));
|
|
+ ZeroMem(&hash_string2, sizeof(hash_string2));
|
|
+ ZeroMem(&serial_string, sizeof(serial_string));
|
|
|
|
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]);
|
|
+ CatPrint(&serial_string, L"Serial Number:");
|
|
+ for (i = 0; i < n; i++) {
|
|
+ CatPrint(&serial_string, L"%02x:", hexbuf[i]);
|
|
}
|
|
- Print(L"%02x\n", hexbuf[n-1]);
|
|
}
|
|
|
|
+ if (serial_string.str)
|
|
+ fields++;
|
|
+
|
|
X509Name = X509_get_issuer_name(X509Cert);
|
|
if (X509Name) {
|
|
- print_x509_name(X509Name, L"Issuer");
|
|
+ issuer = get_x509_name(X509Name, L"Issuer");
|
|
+ if (issuer)
|
|
+ fields++;
|
|
}
|
|
|
|
X509Name = X509_get_subject_name(X509Cert);
|
|
if (X509Name) {
|
|
- print_x509_name(X509Name, L"Subject");
|
|
+ subject = get_x509_name(X509Name, L"Subject");
|
|
+ if (subject)
|
|
+ fields++;
|
|
}
|
|
|
|
time = X509_get_notBefore(X509Cert);
|
|
if (time) {
|
|
- print_x509_time(time, L"Validity from");
|
|
+ from = get_x509_time(time, L"Validity from");
|
|
+ if (time)
|
|
+ fields++;
|
|
}
|
|
|
|
time = X509_get_notAfter(X509Cert);
|
|
if (time) {
|
|
- print_x509_time(time, L"Validity till");
|
|
+ until = get_x509_time(time, L"Validity till");
|
|
+ if (until)
|
|
+ fields++;
|
|
+ }
|
|
+
|
|
+#if 0
|
|
+ CatPrint(&hash_string1, L"SHA1 Fingerprint: ");
|
|
+ for (i=0; i<10; i++)
|
|
+ CatPrint(&hash_string1, L"%02x ", hash[i]);
|
|
+ for (i=10; i<20; i++)
|
|
+ CatPrint(&hash_string2, L"%02x ", hash[i]);
|
|
+
|
|
+ if (hash_string1.str)
|
|
+ fields++;
|
|
+
|
|
+ if (hash_string2.str)
|
|
+ fields++;
|
|
+#endif
|
|
+ if (!fields)
|
|
+ return;
|
|
+
|
|
+ text = AllocateZeroPool(sizeof(CHAR16 *) * (fields + 1));
|
|
+ if (serial_string.str) {
|
|
+ text[i] = serial_string.str;
|
|
+ i++;
|
|
+ }
|
|
+ if (issuer) {
|
|
+ text[i] = issuer;
|
|
+ i++;
|
|
+ }
|
|
+ if (subject) {
|
|
+ text[i] = subject;
|
|
+ i++;
|
|
+ }
|
|
+ if (from) {
|
|
+ text[i] = from;
|
|
+ i++;
|
|
+ }
|
|
+ if (until) {
|
|
+ text[i] = until;
|
|
+ i++;
|
|
}
|
|
+ if (hash_string1.str) {
|
|
+ text[i] = hash_string1.str;
|
|
+ i++;
|
|
+ }
|
|
+ if (hash_string2.str) {
|
|
+ text[i] = hash_string2.str;
|
|
+ i++;
|
|
+ }
|
|
+ text[i] = NULL;
|
|
+
|
|
+ console_alertbox(text);
|
|
+
|
|
+ for (i=0; text[i] != NULL; i++)
|
|
+ FreePool(text[i]);
|
|
+
|
|
+ FreePool(text);
|
|
}
|
|
|
|
static void show_mok_info (void *Mok, UINTN MokSize)
|
|
@@ -382,28 +453,20 @@ static void show_mok_info (void *Mok, UINTN MokSize)
|
|
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");
|
|
+ console_notify(L"Failed to compute MOK fingerprint");
|
|
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 ");
|
|
+ if (X509ConstructCertificate(Mok, MokSize,
|
|
+ (UINT8 **) &X509Cert) && X509Cert != NULL) {
|
|
+ show_x509_info(X509Cert, hash);
|
|
+ X509_free(X509Cert);
|
|
+ } else {
|
|
+ console_notify(L"Not a valid X509 certificate");
|
|
+ return;
|
|
}
|
|
} else {
|
|
Print(L"SHA256 hash:\n ");
|
|
@@ -414,58 +477,19 @@ static void show_mok_info (void *Mok, UINTN MokSize)
|
|
}
|
|
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)
|
|
+static EFI_STATUS list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title)
|
|
{
|
|
UINT32 MokNum = 0;
|
|
MokListNode *keys = NULL;
|
|
INTN key_num = 0;
|
|
- UINT8 initial = 1;
|
|
+ CHAR16 **menu_strings;
|
|
+ int i;
|
|
|
|
if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) +
|
|
sizeof(EFI_SIGNATURE_DATA))) {
|
|
- Print(L"No keys\n");
|
|
- Pause();
|
|
+ console_notify(L"No MOK keys found");
|
|
return 0;
|
|
}
|
|
|
|
@@ -473,41 +497,38 @@ static UINT8 list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title)
|
|
keys = build_mok_list(MokNum, KeyList, KeyListSize);
|
|
|
|
if (!keys) {
|
|
- Print(L"Failed to construct key list\n");
|
|
+ console_notify(L"Failed to construct key list");
|
|
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);
|
|
- }
|
|
+ menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (MokNum + 2));
|
|
+
|
|
+ if (!menu_strings)
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
|
|
- Print(L"Key Number: ");
|
|
+ for (i=0; i<MokNum; i++) {
|
|
+ menu_strings[i] = PoolPrint(L"View key %d", i);
|
|
+ }
|
|
+ menu_strings[i] = StrDuplicate(L"Continue");
|
|
|
|
- key_num = get_number();
|
|
+ menu_strings[i+1] = NULL;
|
|
|
|
- Print(L"\n\n");
|
|
+ while (key_num < MokNum) {
|
|
+ key_num = console_select((CHAR16 *[]){ title, NULL },
|
|
+ menu_strings, 0);
|
|
|
|
- if (key_num == -1)
|
|
- continue;
|
|
+ if (key_num < MokNum)
|
|
+ show_mok_info(keys[key_num].Mok, keys[key_num].MokSize);
|
|
+ }
|
|
+
|
|
+ for (i=0; menu_strings[i] != NULL; i++)
|
|
+ FreePool(menu_strings[i]);
|
|
|
|
- initial = 0;
|
|
- } while (key_num != 0);
|
|
+ FreePool(menu_strings);
|
|
|
|
FreePool(keys);
|
|
|
|
- return 1;
|
|
+ return EFI_SUCCESS;
|
|
}
|
|
|
|
static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show)
|
|
@@ -561,32 +582,32 @@ static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *passw
|
|
ctx = AllocatePool(ctxsize);
|
|
|
|
if (!ctx) {
|
|
- Print(L"Unable to allocate memory for hash context\n");
|
|
+ console_notify(L"Unable to allocate memory for hash context");
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (!Sha256Init(ctx)) {
|
|
- Print(L"Unable to initialise hash\n");
|
|
+ console_notify(L"Unable to initialise hash");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
if (MokNew && MokNewSize) {
|
|
if (!(Sha256Update(ctx, MokNew, MokNewSize))) {
|
|
- Print(L"Unable to generate hash\n");
|
|
+ console_notify(L"Unable to generate hash");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) {
|
|
- Print(L"Unable to generate hash\n");
|
|
+ console_notify(L"Unable to generate hash");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
if (!(Sha256Final(ctx, hash))) {
|
|
- Print(L"Unable to finalise hash\n");
|
|
+ console_notify(L"Unable to finalise hash");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto done;
|
|
}
|
|
@@ -660,7 +681,7 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
|
|
|
|
|
|
if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
|
|
- Print(L"Failed to get MokAuth %d\n", efi_status);
|
|
+ console_error(L"Failed to get MokAuth", efi_status);
|
|
return efi_status;
|
|
}
|
|
|
|
@@ -687,7 +708,7 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
|
|
}
|
|
|
|
if (efi_status != EFI_SUCCESS) {
|
|
- Print(L"Failed to set variable %d\n", efi_status);
|
|
+ console_error(L"Failed to set variable", efi_status);
|
|
return efi_status;
|
|
}
|
|
|
|
@@ -696,84 +717,60 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
|
|
|
|
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 (list_keys(MokNew, MokNewSize, L"[Enroll MOK]") != EFI_SUCCESS)
|
|
+ return 0;
|
|
|
|
- if (line[0] == 'Y' || line[0] == 'y') {
|
|
- efi_status = store_keys(MokNew, MokNewSize, auth);
|
|
+ if (console_yes_no((CHAR16 *[]){L"Enroll the key(s)?", NULL}) == 0)
|
|
+ return 0;
|
|
|
|
- if (efi_status != EFI_SUCCESS) {
|
|
- Print(L"Failed to enroll keys\n");
|
|
- return -1;
|
|
- }
|
|
+ efi_status = store_keys(MokNew, MokNewSize, auth);
|
|
|
|
- if (auth) {
|
|
- LibDeleteVariable(L"MokNew", &shim_lock_guid);
|
|
- LibDeleteVariable(L"MokAuth", &shim_lock_guid);
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ console_notify(L"Failed to enroll keys\n");
|
|
+ return -1;
|
|
+ }
|
|
|
|
- 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;
|
|
- }
|
|
+ if (auth) {
|
|
+ LibDeleteVariable(L"MokNew", &shim_lock_guid);
|
|
+ LibDeleteVariable(L"MokAuth", &shim_lock_guid);
|
|
|
|
- return 0;
|
|
- }
|
|
- } while (line[0] != 'N' && line[0] != 'n');
|
|
- return -1;
|
|
-}
|
|
+ console_notify(L"The system must now be rebooted");
|
|
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
|
|
+ EFI_SUCCESS, 0, NULL);
|
|
+ console_notify(L"Failed to reboot");
|
|
+ return -1;
|
|
+ }
|
|
|
|
-static 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);
|
|
+ return 0;
|
|
}
|
|
|
|
-static INTN mok_reset_prompt (void *MokNew, void *data2, void *data3)
|
|
+static INTN mok_reset_prompt ()
|
|
{
|
|
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 (console_yes_no((CHAR16 *[]){L"Erase all stored keys?", NULL }) == 0)
|
|
+ return 0;
|
|
|
|
- if (efi_status != EFI_SUCCESS) {
|
|
- Print(L"Failed to erase keys\n");
|
|
- return -1;
|
|
- }
|
|
+ efi_status = store_keys(NULL, 0, TRUE);
|
|
|
|
- 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");
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ console_notify(L"Failed to erase keys\n");
|
|
return -1;
|
|
}
|
|
|
|
- return 0;
|
|
+ LibDeleteVariable(L"MokNew", &shim_lock_guid);
|
|
+ LibDeleteVariable(L"MokAuth", &shim_lock_guid);
|
|
+
|
|
+ console_notify(L"The system must now be rebooted");
|
|
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
|
|
+ EFI_SUCCESS, 0, NULL);
|
|
+ console_notify(L"Failed to reboot\n");
|
|
+ return -1;
|
|
}
|
|
|
|
static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num)
|
|
@@ -831,7 +828,7 @@ static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num)
|
|
FreePool(Data);
|
|
|
|
if (efi_status != EFI_SUCCESS) {
|
|
- Print(L"Failed to set variable %d\n", efi_status);
|
|
+ console_error(L"Failed to set variable", efi_status);
|
|
return efi_status;
|
|
}
|
|
|
|
@@ -856,7 +853,7 @@ static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
|
|
&attributes, &auth_size, auth);
|
|
|
|
if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
|
|
- Print(L"Failed to get MokDelAuth %d\n", efi_status);
|
|
+ console_error(L"Failed to get MokDelAuth", efi_status);
|
|
return efi_status;
|
|
}
|
|
|
|
@@ -868,9 +865,11 @@ static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
|
|
&MokListDataSize, &MokListData);
|
|
|
|
if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
|
|
- Print(L"MokList is compromised!\nErase all keys in MokList!\n");
|
|
+ console_alertbox((CHAR16 *[]){L"MokList is compromised!",
|
|
+ L"Erase all keys in MokList!",
|
|
+ NULL});
|
|
if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
|
|
- Print(L"Failed to erase MokList\n");
|
|
+ console_notify(L"Failed to erase MokList");
|
|
}
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
@@ -911,59 +910,48 @@ static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
|
|
return efi_status;
|
|
}
|
|
|
|
-static INTN mok_deletion_prompt (void *MokDel, void *data2, void *data3)
|
|
+static INTN mok_deletion_prompt (void *MokDel, UINTN MokDelSize)
|
|
{
|
|
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): ");
|
|
+ if (list_keys(MokDel, MokDelSize, L"[Delete MOK]") != EFI_SUCCESS) {
|
|
+ return 0;
|
|
+ }
|
|
|
|
- get_line (&length, line, 1, 1);
|
|
+ if (console_yes_no((CHAR16 *[]){L"Delete the key(s)?", NULL}) == 0)
|
|
+ return 0;
|
|
|
|
- if (line[0] == 'Y' || line[0] == 'y') {
|
|
- efi_status = delete_keys(MokDel, MokDelSize);
|
|
+ efi_status = delete_keys(MokDel, MokDelSize);
|
|
|
|
- if (efi_status != EFI_SUCCESS) {
|
|
- Print(L"Failed to delete keys\n");
|
|
- return -1;
|
|
- }
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ console_notify(L"Failed to delete keys");
|
|
+ return -1;
|
|
+ }
|
|
|
|
- LibDeleteVariable(L"MokDel", &shim_lock_guid);
|
|
- LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
|
|
+ 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');
|
|
+ console_notify(L"The system must now be rebooted");
|
|
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
|
|
+ EFI_SUCCESS, 0, NULL);
|
|
+ console_notify(L"Failed to reboot");
|
|
return -1;
|
|
}
|
|
|
|
-static INTN mok_sb_prompt (void *MokSB, void *data2, void *data3) {
|
|
+static INTN mok_sb_prompt (void *MokSB, UINTN MokSBSize) {
|
|
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;
|
|
+ int ret;
|
|
|
|
if (MokSBSize != sizeof(MokSBvar)) {
|
|
- Print(L"Invalid MokSB variable contents\n");
|
|
+ console_notify(L"Invalid MokSB variable contents");
|
|
return -1;
|
|
}
|
|
|
|
@@ -1003,61 +991,49 @@ static INTN mok_sb_prompt (void *MokSB, void *data2, void *data3) {
|
|
}
|
|
|
|
if (fail_count >= 3) {
|
|
- Print(L"Password limit reached\n");
|
|
+ console_notify(L"Password limit reached");
|
|
return -1;
|
|
}
|
|
|
|
- if (var->MokSBState == 0) {
|
|
- Print(L"Disable Secure Boot? (y/n): ");
|
|
- } else {
|
|
- Print(L"Enable Secure Boot? (y/n): ");
|
|
- }
|
|
+ if (var->MokSBState == 0)
|
|
+ ret = console_yes_no((CHAR16 *[]){L"Disable Secure Boot", NULL});
|
|
+ else
|
|
+ ret = console_yes_no((CHAR16 *[]){L"Enable Secure Boot", NULL});
|
|
|
|
- do {
|
|
- get_line (&length, line, 1, 1);
|
|
+ if (ret == 0) {
|
|
+ LibDeleteVariable(L"MokSB", &shim_lock_guid);
|
|
+ return -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,
|
|
+ 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");
|
|
+ 1, &sbval);
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ console_notify(L"Failed to set Secure Boot state");
|
|
return -1;
|
|
}
|
|
- } while (line[0] != 'N' && line[0] != 'n');
|
|
+ } else {
|
|
+ LibDeleteVariable(L"MokSBState", &shim_lock_guid);
|
|
+ }
|
|
|
|
+ console_notify(L"The system must now be rebooted");
|
|
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
|
|
+ EFI_SUCCESS, 0, NULL);
|
|
+ console_notify(L"Failed to reboot");
|
|
return -1;
|
|
}
|
|
|
|
-
|
|
-static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
|
|
+static INTN mok_pw_prompt (void *MokPW, UINTN MokPWSize) {
|
|
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");
|
|
+ console_notify(L"Invalid MokPW variable contents");
|
|
return -1;
|
|
}
|
|
|
|
@@ -1066,190 +1042,41 @@ static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
|
|
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');
|
|
+ if (console_yes_no((CHAR16 *[]){L"Clear MOK password?", NULL}) == 0)
|
|
+ return 0;
|
|
|
|
+ LibDeleteVariable(L"MokPWStore", &shim_lock_guid);
|
|
+ LibDeleteVariable(L"MokPW", &shim_lock_guid);
|
|
return 0;
|
|
}
|
|
|
|
efi_status = match_password(NULL, 0, MokPW, L"Confirm MOK passphrase: ");
|
|
if (efi_status != EFI_SUCCESS) {
|
|
- Print(L"Password limit reached\n");
|
|
+ console_notify(L"Password limit reached");
|
|
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;
|
|
+ if (console_yes_no((CHAR16 *[]){L"Set MOK password?", NULL}) == 0)
|
|
+ return 0;
|
|
|
|
- for (i=0; i<count; i++) {
|
|
- if (items[i].text)
|
|
- FreePool(items[i].text);
|
|
+ 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) {
|
|
+ console_notify(L"Failed to set MOK password");
|
|
+ return -1;
|
|
}
|
|
|
|
- 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;
|
|
- }
|
|
+ LibDeleteVariable(L"MokPW", &shim_lock_guid);
|
|
|
|
- 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;
|
|
- }
|
|
- }
|
|
+ console_notify(L"The system must now be rebooted");
|
|
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0,
|
|
+ NULL);
|
|
+ console_notify(L"Failed to reboot");
|
|
+ return -1;
|
|
}
|
|
|
|
static UINTN verify_certificate(void *cert, UINTN size)
|
|
@@ -1260,8 +1087,7 @@ static UINTN verify_certificate(void *cert, UINTN size)
|
|
|
|
if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) ||
|
|
X509Cert == NULL) {
|
|
- Print(L"Invalid X509 certificate\n");
|
|
- Pause();
|
|
+ console_notify(L"Invalid X509 certificate");
|
|
return FALSE;
|
|
}
|
|
|
|
@@ -1269,49 +1095,22 @@ static UINTN verify_certificate(void *cert, UINTN size)
|
|
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;
|
|
+static EFI_STATUS enroll_file (void *data, UINTN datasize, BOOLEAN hash)
|
|
+{
|
|
+ EFI_STATUS status = EFI_SUCCESS;
|
|
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
|
EFI_SIGNATURE_LIST *CertList;
|
|
EFI_SIGNATURE_DATA *CertData;
|
|
+ UINTN mokbuffersize;
|
|
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)
|
|
@@ -1325,20 +1124,12 @@ static INTN file_callback (void *data, void *data2, void *data3) {
|
|
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);
|
|
+ status = shim_lock->Context(data, datasize, &context);
|
|
|
|
if (status != EFI_SUCCESS)
|
|
goto out;
|
|
-
|
|
- status = shim_lock->Hash(binary, buffersize, &context, sha256,
|
|
+
|
|
+ status = shim_lock->Hash(data, datasize, &context, sha256,
|
|
sha1);
|
|
|
|
if (status != EFI_SUCCESS)
|
|
@@ -1351,7 +1142,7 @@ static INTN file_callback (void *data, void *data2, void *data3) {
|
|
sizeof(EFI_SIGNATURE_LIST));
|
|
CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE);
|
|
} else {
|
|
- mokbuffersize = buffersize + sizeof(EFI_SIGNATURE_LIST) +
|
|
+ mokbuffersize = datasize + sizeof(EFI_SIGNATURE_LIST) +
|
|
sizeof(EFI_GUID);
|
|
mokbuffer = AllocatePool(mokbuffersize);
|
|
|
|
@@ -1360,12 +1151,11 @@ static INTN file_callback (void *data, void *data2, void *data3) {
|
|
|
|
CertList = mokbuffer;
|
|
CertList->SignatureType = EfiCertX509Guid;
|
|
- CertList->SignatureSize = 16 + buffersize;
|
|
- status = uefi_call_wrapper(file->Read, 3, file, &buffersize,
|
|
- mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16);
|
|
+ CertList->SignatureSize = 16 + datasize;
|
|
+
|
|
+ memcpy(mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16, data,
|
|
+ datasize);
|
|
|
|
- if (status != EFI_SUCCESS)
|
|
- goto out;
|
|
CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
|
|
sizeof(EFI_SIGNATURE_LIST));
|
|
}
|
|
@@ -1375,316 +1165,100 @@ static INTN file_callback (void *data, void *data2, void *data3) {
|
|
CertData->SignatureOwner = shim_lock_guid;
|
|
|
|
if (!hash) {
|
|
- if (!verify_certificate(CertData->SignatureData, buffersize))
|
|
+ if (!verify_certificate(CertData->SignatureData, datasize))
|
|
goto out;
|
|
}
|
|
|
|
mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE);
|
|
out:
|
|
- if (buffer)
|
|
- FreePool(buffer);
|
|
-
|
|
if (mokbuffer)
|
|
FreePool(mokbuffer);
|
|
|
|
- return 0;
|
|
+ return status;
|
|
}
|
|
|
|
-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;
|
|
+static void mok_hash_enroll(void)
|
|
+{
|
|
+ EFI_STATUS efi_status;
|
|
+ CHAR16 *file_name = NULL;
|
|
+ EFI_HANDLE im = NULL;
|
|
+ EFI_FILE *file = NULL;
|
|
+ UINTN filesize;
|
|
+ void *data;
|
|
|
|
- if (!buffersize)
|
|
- break;
|
|
+ simple_file_selector(&im, (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 Enroling its hash",
|
|
+ NULL
|
|
+ }, L"\\", L"", &file_name);
|
|
|
|
- if ((StrCmp(buffer->FileName, L".") == 0) ||
|
|
- (StrCmp(buffer->FileName, L"..") == 0))
|
|
- continue;
|
|
+ if (!file_name)
|
|
+ return;
|
|
|
|
- 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;
|
|
- }
|
|
+ efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
|
|
|
|
- i++;
|
|
- FreePool(buffer);
|
|
- buffersize = 0;
|
|
- buffer = NULL;
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ console_error(L"Unable to open file", efi_status);
|
|
+ return;
|
|
}
|
|
|
|
- if (hash)
|
|
- run_menu(HASH_STRING, 2, dircontent, dircount, 0);
|
|
- else
|
|
- run_menu(CERT_STRING, 2, dircontent, dircount, 0);
|
|
+ simple_file_read_all(file, &filesize, &data);
|
|
+ simple_file_close(file);
|
|
|
|
- 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;
|
|
+ if (!filesize) {
|
|
+ console_error(L"Unable to read file", efi_status);
|
|
+ return;
|
|
}
|
|
|
|
- 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;
|
|
- }
|
|
+ efi_status = enroll_file(data, filesize, TRUE);
|
|
|
|
- if (hash)
|
|
- run_menu(HASH_STRING, 2, dircontent, dircount, 0);
|
|
- else
|
|
- run_menu(CERT_STRING, 2, dircontent, dircount, 0);
|
|
+ if (efi_status != EFI_SUCCESS)
|
|
+ console_error(L"Hash failed (did you select a valid EFI binary?)", efi_status);
|
|
|
|
- return 0;
|
|
+ FreePool(data);
|
|
}
|
|
|
|
-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);
|
|
+static void mok_key_enroll(void)
|
|
+{
|
|
+ EFI_STATUS efi_status;
|
|
+ CHAR16 *file_name = NULL;
|
|
+ EFI_HANDLE im = NULL;
|
|
+ EFI_FILE *file = NULL;
|
|
+ UINTN filesize;
|
|
+ void *data;
|
|
|
|
- if (status == EFI_BUFFER_TOO_SMALL) {
|
|
- buffer = AllocatePool(buffersize);
|
|
- status = uefi_call_wrapper(root->GetInfo, 4, root,
|
|
- &file_info_guid,
|
|
- &buffersize, buffer);
|
|
- }
|
|
+ simple_file_selector(&im, (CHAR16 *[]){
|
|
+ L"Select Key",
|
|
+ L"",
|
|
+ L"The selected key will be enrolled into the MOK database",
|
|
+ L"This means any binaries signed with it will be run without prompting",
|
|
+ L"Remember to make sure it is a genuine key before Enroling it",
|
|
+ NULL
|
|
+ }, L"\\", L"", &file_name);
|
|
|
|
- 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 (!file_name)
|
|
+ return;
|
|
|
|
- if (buffersize)
|
|
- FreePool(buffer);
|
|
+ efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
|
|
|
|
- filesystems[i].data = root;
|
|
- filesystems[i].data2 = NULL;
|
|
- filesystems[i].data3 = data3;
|
|
- filesystems[i].callback = filesystem_callback;
|
|
- filesystems[i].colour = EFI_YELLOW;
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ console_error(L"Unable to open file", efi_status);
|
|
+ return;
|
|
}
|
|
|
|
- uefi_call_wrapper(BS->FreePool, 1, filesystem_handles);
|
|
+ simple_file_read_all(file, &filesize, &data);
|
|
+ simple_file_close(file);
|
|
|
|
- if (hash)
|
|
- run_menu(HASH_STRING, 2, filesystems, count, 0);
|
|
- else
|
|
- run_menu(CERT_STRING, 2, filesystems, count, 0);
|
|
+ if (!filesize) {
|
|
+ console_error(L"Unable to read file", efi_status);
|
|
+ return;
|
|
+ }
|
|
|
|
- return 0;
|
|
+ enroll_file(data, filesize, FALSE);
|
|
+ FreePool(data);
|
|
}
|
|
|
|
static BOOLEAN verify_pw(void)
|
|
@@ -1714,20 +1288,33 @@ static BOOLEAN verify_pw(void)
|
|
|
|
efi_status = match_password(NULL, 0, pwhash, L"Enter MOK password: ");
|
|
if (efi_status != EFI_SUCCESS) {
|
|
- Print(L"Password limit reached\n");
|
|
+ console_notify(L"Password limit reached");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
+typedef enum {
|
|
+ MOK_CONTINUE_BOOT,
|
|
+ MOK_RESET_MOK,
|
|
+ MOK_ENROLL_MOK,
|
|
+ MOK_DELETE_MOK,
|
|
+ MOK_CHANGE_SB,
|
|
+ MOK_SET_PW,
|
|
+ MOK_KEY_ENROLL,
|
|
+ MOK_HASH_ENROLL
|
|
+} mok_menu_item;
|
|
+
|
|
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;
|
|
+ CHAR16 **menu_strings;
|
|
+ mok_menu_item *menu_item;
|
|
+ int choice = 0;
|
|
UINT32 MokAuth = 0;
|
|
UINT32 MokDelAuth = 0;
|
|
UINTN menucount = 3, i = 0;
|
|
@@ -1736,10 +1323,11 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
|
|
UINT8 auth[SHA256_DIGEST_SIZE];
|
|
UINTN auth_size = SHA256_DIGEST_SIZE;
|
|
UINT32 attributes;
|
|
+ EFI_STATUS ret = EFI_SUCCESS;
|
|
|
|
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);
|
|
@@ -1766,78 +1354,108 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
|
|
if (MokPW)
|
|
menucount++;
|
|
|
|
- menu_item = AllocateZeroPool(sizeof(struct menu_item) * menucount);
|
|
+ menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (menucount + 1));
|
|
|
|
- if (!menu_item)
|
|
+ if (!menu_strings)
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
- menu_item[i].text = StrDuplicate(L"Continue boot");
|
|
- menu_item[i].colour = EFI_WHITE;
|
|
- menu_item[i].callback = NULL;
|
|
+ menu_item = AllocateZeroPool(sizeof(mok_menu_item) * menucount);
|
|
+
|
|
+ if (!menu_item) {
|
|
+ FreePool(menu_strings);
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+ }
|
|
+
|
|
+ menu_strings[i] = StrDuplicate(L"Continue boot");
|
|
+ menu_item[i] = MOK_CONTINUE_BOOT;
|
|
|
|
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;
|
|
+ menu_strings[i] = StrDuplicate(L"Reset MOK");
|
|
+ menu_item[i] = MOK_RESET_MOK;
|
|
} 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;
|
|
+ menu_strings[i] = StrDuplicate(L"Enroll MOK");
|
|
+ menu_item[i] = MOK_ENROLL_MOK;
|
|
}
|
|
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;
|
|
+ if (MokDel || MokDelAuth) {
|
|
+ menu_strings[i] = StrDuplicate(L"Delete MOK");
|
|
+ menu_item[i] = MOK_DELETE_MOK;
|
|
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;
|
|
+ menu_strings[i] = StrDuplicate(L"Change Secure Boot state");
|
|
+ menu_item[i] = MOK_CHANGE_SB;
|
|
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;
|
|
+ menu_strings[i] = StrDuplicate(L"Set MOK password");
|
|
+ menu_item[i] = MOK_SET_PW;
|
|
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;
|
|
+ menu_strings[i] = StrDuplicate(L"Enroll key from disk");
|
|
+ menu_item[i] = MOK_KEY_ENROLL;
|
|
+ i++;
|
|
|
|
+ menu_strings[i] = StrDuplicate(L"Enroll hash from disk");
|
|
+ menu_item[i] = MOK_HASH_ENROLL;
|
|
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;
|
|
+ menu_strings[i] = NULL;
|
|
|
|
- i++;
|
|
+ while (choice >= 0) {
|
|
+ choice = console_select((CHAR16 *[]){ L"Perform MOK management", NULL },
|
|
+ menu_strings, 0);
|
|
|
|
- run_menu(NULL, 0, menu_item, menucount, 10);
|
|
+ if (choice < 0)
|
|
+ goto out;
|
|
|
|
- uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
|
+ switch (menu_item[choice]) {
|
|
+ case MOK_CONTINUE_BOOT:
|
|
+ goto out;
|
|
+ case MOK_RESET_MOK:
|
|
+ mok_reset_prompt();
|
|
+ break;
|
|
+ case MOK_ENROLL_MOK:
|
|
+ mok_enrollment_prompt(MokNew, MokNewSize, TRUE);
|
|
+ break;
|
|
+ case MOK_DELETE_MOK:
|
|
+ mok_deletion_prompt(MokDel, MokDelSize);
|
|
+ break;
|
|
+ case MOK_CHANGE_SB:
|
|
+ mok_sb_prompt(MokSB, MokSBSize);
|
|
+ break;
|
|
+ case MOK_SET_PW:
|
|
+ mok_pw_prompt(MokPW, MokPWSize);
|
|
+ break;
|
|
+ case MOK_KEY_ENROLL:
|
|
+ mok_key_enroll();
|
|
+ break;
|
|
+ case MOK_HASH_ENROLL:
|
|
+ mok_hash_enroll();
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
|
|
- return 0;
|
|
+out:
|
|
+ console_reset();
|
|
+
|
|
+ for (i=0; menu_strings[i] != NULL; i++)
|
|
+ FreePool(menu_strings[i]);
|
|
+
|
|
+ FreePool(menu_strings);
|
|
+
|
|
+ if (menu_item)
|
|
+ FreePool(menu_item);
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
|
|
@@ -1862,28 +1480,28 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
|
|
|
|
if (MokNew) {
|
|
if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
|
|
- Print(L"Failed to delete MokNew\n");
|
|
+ console_notify(L"Failed to delete MokNew");
|
|
}
|
|
FreePool (MokNew);
|
|
}
|
|
|
|
if (MokDel) {
|
|
if (LibDeleteVariable(L"MokDel", &shim_lock_guid) != EFI_SUCCESS) {
|
|
- Print(L"Failed to delete MokDel\n");
|
|
+ console_notify(L"Failed to delete MokDel");
|
|
}
|
|
FreePool (MokDel);
|
|
}
|
|
|
|
if (MokSB) {
|
|
if (LibDeleteVariable(L"MokSB", &shim_lock_guid) != EFI_SUCCESS) {
|
|
- Print(L"Failed to delete MokSB\n");
|
|
+ console_notify(L"Failed to delete MokSB");
|
|
}
|
|
FreePool (MokNew);
|
|
}
|
|
|
|
if (MokPW) {
|
|
if (LibDeleteVariable(L"MokPW", &shim_lock_guid) != EFI_SUCCESS) {
|
|
- Print(L"Failed to delete MokPW\n");
|
|
+ console_notify(L"Failed to delete MokPW");
|
|
}
|
|
FreePool (MokNew);
|
|
}
|
|
diff --git a/include/PeImage.h b/include/PeImage.h
|
|
new file mode 100644
|
|
index 0000000..ec13404
|
|
--- /dev/null
|
|
+++ b/include/PeImage.h
|
|
@@ -0,0 +1,787 @@
|
|
+/** @file
|
|
+ EFI image format for PE32, PE32+ and TE. Please note some data structures are
|
|
+ different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and
|
|
+ EFI_IMAGE_NT_HEADERS64 is for PE32+.
|
|
+
|
|
+ This file is coded to the Visual Studio, Microsoft Portable Executable and
|
|
+ Common Object File Format Specification, Revision 8.0 - May 16, 2006.
|
|
+ This file also includes some definitions in PI Specification, Revision 1.0.
|
|
+
|
|
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
|
|
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
|
+This program and the accompanying materials
|
|
+are licensed and made available under the terms and conditions of the BSD License
|
|
+which accompanies this distribution. The full text of the license may be found at
|
|
+http://opensource.org/licenses/bsd-license.php.
|
|
+
|
|
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
+
|
|
+**/
|
|
+
|
|
+#ifndef __PE_IMAGE_H__
|
|
+#define __PE_IMAGE_H__
|
|
+
|
|
+#include <wincert.h>
|
|
+
|
|
+#define SIGNATURE_16(A, B) ((A) | (B << 8))
|
|
+#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
|
|
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
|
|
+ (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32))
|
|
+
|
|
+#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
|
|
+#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment))))
|
|
+
|
|
+//
|
|
+// PE32+ Subsystem type for EFI images
|
|
+//
|
|
+#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10
|
|
+#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
|
|
+#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
|
|
+#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0
|
|
+
|
|
+
|
|
+//
|
|
+// PE32+ Machine type for EFI images
|
|
+//
|
|
+#define IMAGE_FILE_MACHINE_I386 0x014c
|
|
+#define IMAGE_FILE_MACHINE_IA64 0x0200
|
|
+#define IMAGE_FILE_MACHINE_EBC 0x0EBC
|
|
+#define IMAGE_FILE_MACHINE_X64 0x8664
|
|
+#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2
|
|
+
|
|
+//
|
|
+// EXE file formats
|
|
+//
|
|
+#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z')
|
|
+#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E')
|
|
+#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E')
|
|
+#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0')
|
|
+
|
|
+///
|
|
+/// PE images can start with an optional DOS header, so if an image is run
|
|
+/// under DOS it can print an error message.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT16 e_magic; ///< Magic number.
|
|
+ UINT16 e_cblp; ///< Bytes on last page of file.
|
|
+ UINT16 e_cp; ///< Pages in file.
|
|
+ UINT16 e_crlc; ///< Relocations.
|
|
+ UINT16 e_cparhdr; ///< Size of header in paragraphs.
|
|
+ UINT16 e_minalloc; ///< Minimum extra paragraphs needed.
|
|
+ UINT16 e_maxalloc; ///< Maximum extra paragraphs needed.
|
|
+ UINT16 e_ss; ///< Initial (relative) SS value.
|
|
+ UINT16 e_sp; ///< Initial SP value.
|
|
+ UINT16 e_csum; ///< Checksum.
|
|
+ UINT16 e_ip; ///< Initial IP value.
|
|
+ UINT16 e_cs; ///< Initial (relative) CS value.
|
|
+ UINT16 e_lfarlc; ///< File address of relocation table.
|
|
+ UINT16 e_ovno; ///< Overlay number.
|
|
+ UINT16 e_res[4]; ///< Reserved words.
|
|
+ UINT16 e_oemid; ///< OEM identifier (for e_oeminfo).
|
|
+ UINT16 e_oeminfo; ///< OEM information; e_oemid specific.
|
|
+ UINT16 e_res2[10]; ///< Reserved words.
|
|
+ UINT32 e_lfanew; ///< File address of new exe header.
|
|
+} EFI_IMAGE_DOS_HEADER;
|
|
+
|
|
+///
|
|
+/// COFF File Header (Object and Image).
|
|
+///
|
|
+typedef struct {
|
|
+ UINT16 Machine;
|
|
+ UINT16 NumberOfSections;
|
|
+ UINT32 TimeDateStamp;
|
|
+ UINT32 PointerToSymbolTable;
|
|
+ UINT32 NumberOfSymbols;
|
|
+ UINT16 SizeOfOptionalHeader;
|
|
+ UINT16 Characteristics;
|
|
+} EFI_IMAGE_FILE_HEADER;
|
|
+
|
|
+///
|
|
+/// Size of EFI_IMAGE_FILE_HEADER.
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_FILE_HEADER 20
|
|
+
|
|
+//
|
|
+// Characteristics
|
|
+//
|
|
+#define EFI_IMAGE_FILE_RELOCS_STRIPPED (1 << 0) ///< 0x0001 Relocation info stripped from file.
|
|
+#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE (1 << 1) ///< 0x0002 File is executable (i.e. no unresolved externel references).
|
|
+#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED (1 << 2) ///< 0x0004 Line nunbers stripped from file.
|
|
+#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED (1 << 3) ///< 0x0008 Local symbols stripped from file.
|
|
+#define EFI_IMAGE_FILE_BYTES_REVERSED_LO (1 << 7) ///< 0x0080 Bytes of machine word are reversed.
|
|
+#define EFI_IMAGE_FILE_32BIT_MACHINE (1 << 8) ///< 0x0100 32 bit word machine.
|
|
+#define EFI_IMAGE_FILE_DEBUG_STRIPPED (1 << 9) ///< 0x0200 Debugging info stripped from file in .DBG file.
|
|
+#define EFI_IMAGE_FILE_SYSTEM (1 << 12) ///< 0x1000 System File.
|
|
+#define EFI_IMAGE_FILE_DLL (1 << 13) ///< 0x2000 File is a DLL.
|
|
+#define EFI_IMAGE_FILE_BYTES_REVERSED_HI (1 << 15) ///< 0x8000 Bytes of machine word are reversed.
|
|
+
|
|
+///
|
|
+/// Header Data Directories.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 VirtualAddress;
|
|
+ UINT32 Size;
|
|
+} EFI_IMAGE_DATA_DIRECTORY;
|
|
+
|
|
+//
|
|
+// Directory Entries
|
|
+//
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9
|
|
+#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
|
|
+
|
|
+#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
|
|
+
|
|
+///
|
|
+/// @attention
|
|
+/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and
|
|
+/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
|
|
+/// after NT additional fields.
|
|
+///
|
|
+#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
|
|
+
|
|
+///
|
|
+/// Optional Header Standard Fields for PE32.
|
|
+///
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// Standard fields.
|
|
+ ///
|
|
+ UINT16 Magic;
|
|
+ UINT8 MajorLinkerVersion;
|
|
+ UINT8 MinorLinkerVersion;
|
|
+ UINT32 SizeOfCode;
|
|
+ UINT32 SizeOfInitializedData;
|
|
+ UINT32 SizeOfUninitializedData;
|
|
+ UINT32 AddressOfEntryPoint;
|
|
+ UINT32 BaseOfCode;
|
|
+ UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+.
|
|
+ ///
|
|
+ /// Optional Header Windows-Specific Fields.
|
|
+ ///
|
|
+ UINT32 ImageBase;
|
|
+ UINT32 SectionAlignment;
|
|
+ UINT32 FileAlignment;
|
|
+ UINT16 MajorOperatingSystemVersion;
|
|
+ UINT16 MinorOperatingSystemVersion;
|
|
+ UINT16 MajorImageVersion;
|
|
+ UINT16 MinorImageVersion;
|
|
+ UINT16 MajorSubsystemVersion;
|
|
+ UINT16 MinorSubsystemVersion;
|
|
+ UINT32 Win32VersionValue;
|
|
+ UINT32 SizeOfImage;
|
|
+ UINT32 SizeOfHeaders;
|
|
+ UINT32 CheckSum;
|
|
+ UINT16 Subsystem;
|
|
+ UINT16 DllCharacteristics;
|
|
+ UINT32 SizeOfStackReserve;
|
|
+ UINT32 SizeOfStackCommit;
|
|
+ UINT32 SizeOfHeapReserve;
|
|
+ UINT32 SizeOfHeapCommit;
|
|
+ UINT32 LoaderFlags;
|
|
+ UINT32 NumberOfRvaAndSizes;
|
|
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
|
|
+} EFI_IMAGE_OPTIONAL_HEADER32;
|
|
+
|
|
+///
|
|
+/// @attention
|
|
+/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and
|
|
+/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
|
|
+/// after NT additional fields.
|
|
+///
|
|
+#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
|
|
+
|
|
+///
|
|
+/// Optional Header Standard Fields for PE32+.
|
|
+///
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// Standard fields.
|
|
+ ///
|
|
+ UINT16 Magic;
|
|
+ UINT8 MajorLinkerVersion;
|
|
+ UINT8 MinorLinkerVersion;
|
|
+ UINT32 SizeOfCode;
|
|
+ UINT32 SizeOfInitializedData;
|
|
+ UINT32 SizeOfUninitializedData;
|
|
+ UINT32 AddressOfEntryPoint;
|
|
+ UINT32 BaseOfCode;
|
|
+ ///
|
|
+ /// Optional Header Windows-Specific Fields.
|
|
+ ///
|
|
+ UINT64 ImageBase;
|
|
+ UINT32 SectionAlignment;
|
|
+ UINT32 FileAlignment;
|
|
+ UINT16 MajorOperatingSystemVersion;
|
|
+ UINT16 MinorOperatingSystemVersion;
|
|
+ UINT16 MajorImageVersion;
|
|
+ UINT16 MinorImageVersion;
|
|
+ UINT16 MajorSubsystemVersion;
|
|
+ UINT16 MinorSubsystemVersion;
|
|
+ UINT32 Win32VersionValue;
|
|
+ UINT32 SizeOfImage;
|
|
+ UINT32 SizeOfHeaders;
|
|
+ UINT32 CheckSum;
|
|
+ UINT16 Subsystem;
|
|
+ UINT16 DllCharacteristics;
|
|
+ UINT64 SizeOfStackReserve;
|
|
+ UINT64 SizeOfStackCommit;
|
|
+ UINT64 SizeOfHeapReserve;
|
|
+ UINT64 SizeOfHeapCommit;
|
|
+ UINT32 LoaderFlags;
|
|
+ UINT32 NumberOfRvaAndSizes;
|
|
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
|
|
+} EFI_IMAGE_OPTIONAL_HEADER64;
|
|
+
|
|
+
|
|
+///
|
|
+/// @attention
|
|
+/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 Signature;
|
|
+ EFI_IMAGE_FILE_HEADER FileHeader;
|
|
+ EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader;
|
|
+} EFI_IMAGE_NT_HEADERS32;
|
|
+
|
|
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32)
|
|
+
|
|
+///
|
|
+/// @attention
|
|
+/// EFI_IMAGE_HEADERS64 is for use ONLY by tools.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 Signature;
|
|
+ EFI_IMAGE_FILE_HEADER FileHeader;
|
|
+ EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
|
+} EFI_IMAGE_NT_HEADERS64;
|
|
+
|
|
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64)
|
|
+
|
|
+//
|
|
+// Other Windows Subsystem Values
|
|
+//
|
|
+#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0
|
|
+#define EFI_IMAGE_SUBSYSTEM_NATIVE 1
|
|
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2
|
|
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3
|
|
+#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5
|
|
+#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7
|
|
+
|
|
+///
|
|
+/// Length of ShortName.
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
|
|
+
|
|
+///
|
|
+/// Section Table. This table immediately follows the optional header.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
|
|
+ union {
|
|
+ UINT32 PhysicalAddress;
|
|
+ UINT32 VirtualSize;
|
|
+ } Misc;
|
|
+ UINT32 VirtualAddress;
|
|
+ UINT32 SizeOfRawData;
|
|
+ UINT32 PointerToRawData;
|
|
+ UINT32 PointerToRelocations;
|
|
+ UINT32 PointerToLinenumbers;
|
|
+ UINT16 NumberOfRelocations;
|
|
+ UINT16 NumberOfLinenumbers;
|
|
+ UINT32 Characteristics;
|
|
+} EFI_IMAGE_SECTION_HEADER;
|
|
+
|
|
+///
|
|
+/// Size of EFI_IMAGE_SECTION_HEADER.
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40
|
|
+
|
|
+//
|
|
+// Section Flags Values
|
|
+//
|
|
+#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved.
|
|
+#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020
|
|
+#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040
|
|
+#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080
|
|
+
|
|
+#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved.
|
|
+#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information.
|
|
+#define EFI_IMAGE_SCN_LNK_REMOVE BIT11 ///< 0x00000800 ///< Section contents will not become part of image.
|
|
+#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000
|
|
+
|
|
+#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000
|
|
+#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000
|
|
+#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000
|
|
+#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000
|
|
+#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000
|
|
+#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000
|
|
+#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000
|
|
+
|
|
+#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000
|
|
+#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000
|
|
+#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000
|
|
+#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000
|
|
+#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000
|
|
+#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000
|
|
+#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000
|
|
+
|
|
+///
|
|
+/// Size of a Symbol Table Record.
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_SYMBOL 18
|
|
+
|
|
+//
|
|
+// Symbols have a section number of the section in which they are
|
|
+// defined. Otherwise, section numbers have the following meanings:
|
|
+//
|
|
+#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common.
|
|
+#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value.
|
|
+#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item.
|
|
+
|
|
+//
|
|
+// Symbol Type (fundamental) values.
|
|
+//
|
|
+#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type.
|
|
+#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type.
|
|
+#define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character.
|
|
+#define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer.
|
|
+#define EFI_IMAGE_SYM_TYPE_INT 4
|
|
+#define EFI_IMAGE_SYM_TYPE_LONG 5
|
|
+#define EFI_IMAGE_SYM_TYPE_FLOAT 6
|
|
+#define EFI_IMAGE_SYM_TYPE_DOUBLE 7
|
|
+#define EFI_IMAGE_SYM_TYPE_STRUCT 8
|
|
+#define EFI_IMAGE_SYM_TYPE_UNION 9
|
|
+#define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration.
|
|
+#define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration.
|
|
+#define EFI_IMAGE_SYM_TYPE_BYTE 12
|
|
+#define EFI_IMAGE_SYM_TYPE_WORD 13
|
|
+#define EFI_IMAGE_SYM_TYPE_UINT 14
|
|
+#define EFI_IMAGE_SYM_TYPE_DWORD 15
|
|
+
|
|
+//
|
|
+// Symbol Type (derived) values.
|
|
+//
|
|
+#define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type.
|
|
+#define EFI_IMAGE_SYM_DTYPE_POINTER 1
|
|
+#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2
|
|
+#define EFI_IMAGE_SYM_DTYPE_ARRAY 3
|
|
+
|
|
+//
|
|
+// Storage classes.
|
|
+//
|
|
+#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1)
|
|
+#define EFI_IMAGE_SYM_CLASS_NULL 0
|
|
+#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1
|
|
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2
|
|
+#define EFI_IMAGE_SYM_CLASS_STATIC 3
|
|
+#define EFI_IMAGE_SYM_CLASS_REGISTER 4
|
|
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5
|
|
+#define EFI_IMAGE_SYM_CLASS_LABEL 6
|
|
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
|
|
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
|
|
+#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9
|
|
+#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10
|
|
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
|
|
+#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12
|
|
+#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13
|
|
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
|
|
+#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15
|
|
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
|
|
+#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17
|
|
+#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18
|
|
+#define EFI_IMAGE_SYM_CLASS_BLOCK 100
|
|
+#define EFI_IMAGE_SYM_CLASS_FUNCTION 101
|
|
+#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102
|
|
+#define EFI_IMAGE_SYM_CLASS_FILE 103
|
|
+#define EFI_IMAGE_SYM_CLASS_SECTION 104
|
|
+#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
|
|
+
|
|
+//
|
|
+// type packing constants
|
|
+//
|
|
+#define EFI_IMAGE_N_BTMASK 017
|
|
+#define EFI_IMAGE_N_TMASK 060
|
|
+#define EFI_IMAGE_N_TMASK1 0300
|
|
+#define EFI_IMAGE_N_TMASK2 0360
|
|
+#define EFI_IMAGE_N_BTSHFT 4
|
|
+#define EFI_IMAGE_N_TSHIFT 2
|
|
+
|
|
+//
|
|
+// Communal selection types.
|
|
+//
|
|
+#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1
|
|
+#define EFI_IMAGE_COMDAT_SELECT_ANY 2
|
|
+#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3
|
|
+#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4
|
|
+#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
|
|
+
|
|
+//
|
|
+// the following values only be referred in PeCoff, not defined in PECOFF.
|
|
+//
|
|
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
|
|
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
|
|
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
|
|
+
|
|
+///
|
|
+/// Relocation format.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 VirtualAddress;
|
|
+ UINT32 SymbolTableIndex;
|
|
+ UINT16 Type;
|
|
+} EFI_IMAGE_RELOCATION;
|
|
+
|
|
+///
|
|
+/// Size of EFI_IMAGE_RELOCATION
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_RELOCATION 10
|
|
+
|
|
+//
|
|
+// I386 relocation types.
|
|
+//
|
|
+#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary.
|
|
+#define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address.
|
|
+#define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address.
|
|
+#define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address.
|
|
+#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included.
|
|
+#define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address.
|
|
+#define EFI_IMAGE_REL_I386_SECTION 0x000A
|
|
+#define EFI_IMAGE_REL_I386_SECREL 0x000B
|
|
+#define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address.
|
|
+
|
|
+//
|
|
+// x64 processor relocation types.
|
|
+//
|
|
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
|
|
+#define IMAGE_REL_AMD64_ADDR64 0x0001
|
|
+#define IMAGE_REL_AMD64_ADDR32 0x0002
|
|
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
|
|
+#define IMAGE_REL_AMD64_REL32 0x0004
|
|
+#define IMAGE_REL_AMD64_REL32_1 0x0005
|
|
+#define IMAGE_REL_AMD64_REL32_2 0x0006
|
|
+#define IMAGE_REL_AMD64_REL32_3 0x0007
|
|
+#define IMAGE_REL_AMD64_REL32_4 0x0008
|
|
+#define IMAGE_REL_AMD64_REL32_5 0x0009
|
|
+#define IMAGE_REL_AMD64_SECTION 0x000A
|
|
+#define IMAGE_REL_AMD64_SECREL 0x000B
|
|
+#define IMAGE_REL_AMD64_SECREL7 0x000C
|
|
+#define IMAGE_REL_AMD64_TOKEN 0x000D
|
|
+#define IMAGE_REL_AMD64_SREL32 0x000E
|
|
+#define IMAGE_REL_AMD64_PAIR 0x000F
|
|
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
|
|
+
|
|
+///
|
|
+/// Based relocation format.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 VirtualAddress;
|
|
+ UINT32 SizeOfBlock;
|
|
+} EFI_IMAGE_BASE_RELOCATION;
|
|
+
|
|
+///
|
|
+/// Size of EFI_IMAGE_BASE_RELOCATION.
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8
|
|
+
|
|
+//
|
|
+// Based relocation types.
|
|
+//
|
|
+#define EFI_IMAGE_REL_BASED_ABSOLUTE 0
|
|
+#define EFI_IMAGE_REL_BASED_HIGH 1
|
|
+#define EFI_IMAGE_REL_BASED_LOW 2
|
|
+#define EFI_IMAGE_REL_BASED_HIGHLOW 3
|
|
+#define EFI_IMAGE_REL_BASED_HIGHADJ 4
|
|
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5
|
|
+#define EFI_IMAGE_REL_BASED_ARM_MOV32A 5
|
|
+#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7
|
|
+#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
|
|
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9
|
|
+#define EFI_IMAGE_REL_BASED_DIR64 10
|
|
+
|
|
+///
|
|
+/// Line number format.
|
|
+///
|
|
+typedef struct {
|
|
+ union {
|
|
+ UINT32 SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0.
|
|
+ UINT32 VirtualAddress; ///< Virtual address of line number.
|
|
+ } Type;
|
|
+ UINT16 Linenumber; ///< Line number.
|
|
+} EFI_IMAGE_LINENUMBER;
|
|
+
|
|
+///
|
|
+/// Size of EFI_IMAGE_LINENUMBER.
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_LINENUMBER 6
|
|
+
|
|
+//
|
|
+// Archive format.
|
|
+//
|
|
+#define EFI_IMAGE_ARCHIVE_START_SIZE 8
|
|
+#define EFI_IMAGE_ARCHIVE_START "!<arch>\n"
|
|
+#define EFI_IMAGE_ARCHIVE_END "`\n"
|
|
+#define EFI_IMAGE_ARCHIVE_PAD "\n"
|
|
+#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ "
|
|
+#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
|
|
+
|
|
+///
|
|
+/// Archive Member Headers
|
|
+///
|
|
+typedef struct {
|
|
+ UINT8 Name[16]; ///< File member name - `/' terminated.
|
|
+ UINT8 Date[12]; ///< File member date - decimal.
|
|
+ UINT8 UserID[6]; ///< File member user id - decimal.
|
|
+ UINT8 GroupID[6]; ///< File member group id - decimal.
|
|
+ UINT8 Mode[8]; ///< File member mode - octal.
|
|
+ UINT8 Size[10]; ///< File member size - decimal.
|
|
+ UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A).
|
|
+} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
|
|
+
|
|
+///
|
|
+/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER.
|
|
+///
|
|
+#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
|
|
+
|
|
+
|
|
+//
|
|
+// DLL Support
|
|
+//
|
|
+
|
|
+///
|
|
+/// Export Directory Table.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 Characteristics;
|
|
+ UINT32 TimeDateStamp;
|
|
+ UINT16 MajorVersion;
|
|
+ UINT16 MinorVersion;
|
|
+ UINT32 Name;
|
|
+ UINT32 Base;
|
|
+ UINT32 NumberOfFunctions;
|
|
+ UINT32 NumberOfNames;
|
|
+ UINT32 AddressOfFunctions;
|
|
+ UINT32 AddressOfNames;
|
|
+ UINT32 AddressOfNameOrdinals;
|
|
+} EFI_IMAGE_EXPORT_DIRECTORY;
|
|
+
|
|
+///
|
|
+/// Hint/Name Table.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT16 Hint;
|
|
+ UINT8 Name[1];
|
|
+} EFI_IMAGE_IMPORT_BY_NAME;
|
|
+
|
|
+///
|
|
+/// Import Address Table RVA (Thunk Table).
|
|
+///
|
|
+typedef struct {
|
|
+ union {
|
|
+ UINT32 Function;
|
|
+ UINT32 Ordinal;
|
|
+ EFI_IMAGE_IMPORT_BY_NAME *AddressOfData;
|
|
+ } u1;
|
|
+} EFI_IMAGE_THUNK_DATA;
|
|
+
|
|
+#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32.
|
|
+#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
|
|
+#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
|
|
+
|
|
+///
|
|
+/// Import Directory Table
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 Characteristics;
|
|
+ UINT32 TimeDateStamp;
|
|
+ UINT32 ForwarderChain;
|
|
+ UINT32 Name;
|
|
+ EFI_IMAGE_THUNK_DATA *FirstThunk;
|
|
+} EFI_IMAGE_IMPORT_DESCRIPTOR;
|
|
+
|
|
+
|
|
+///
|
|
+/// Debug Directory Format.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 Characteristics;
|
|
+ UINT32 TimeDateStamp;
|
|
+ UINT16 MajorVersion;
|
|
+ UINT16 MinorVersion;
|
|
+ UINT32 Type;
|
|
+ UINT32 SizeOfData;
|
|
+ UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base.
|
|
+ UINT32 FileOffset; ///< The file pointer to the debug data.
|
|
+} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
|
|
+
|
|
+#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information.
|
|
+
|
|
+///
|
|
+/// Debug Data Structure defined in Microsoft C++.
|
|
+///
|
|
+#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0')
|
|
+typedef struct {
|
|
+ UINT32 Signature; ///< "NB10"
|
|
+ UINT32 Unknown;
|
|
+ UINT32 Unknown2;
|
|
+ UINT32 Unknown3;
|
|
+ //
|
|
+ // Filename of .PDB goes here
|
|
+ //
|
|
+} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
|
|
+
|
|
+///
|
|
+/// Debug Data Structure defined in Microsoft C++.
|
|
+///
|
|
+#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S')
|
|
+typedef struct {
|
|
+ UINT32 Signature; ///< "RSDS".
|
|
+ UINT32 Unknown;
|
|
+ UINT32 Unknown2;
|
|
+ UINT32 Unknown3;
|
|
+ UINT32 Unknown4;
|
|
+ UINT32 Unknown5;
|
|
+ //
|
|
+ // Filename of .PDB goes here
|
|
+ //
|
|
+} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
|
|
+
|
|
+
|
|
+///
|
|
+/// Debug Data Structure defined by Apple Mach-O to Coff utility.
|
|
+///
|
|
+#define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C')
|
|
+typedef struct {
|
|
+ UINT32 Signature; ///< "MTOC".
|
|
+ EFI_GUID MachOUuid;
|
|
+ //
|
|
+ // Filename of .DLL (Mach-O with debug info) goes here
|
|
+ //
|
|
+} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
|
|
+
|
|
+///
|
|
+/// Resource format.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 Characteristics;
|
|
+ UINT32 TimeDateStamp;
|
|
+ UINT16 MajorVersion;
|
|
+ UINT16 MinorVersion;
|
|
+ UINT16 NumberOfNamedEntries;
|
|
+ UINT16 NumberOfIdEntries;
|
|
+ //
|
|
+ // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here.
|
|
+ //
|
|
+} EFI_IMAGE_RESOURCE_DIRECTORY;
|
|
+
|
|
+///
|
|
+/// Resource directory entry format.
|
|
+///
|
|
+typedef struct {
|
|
+ union {
|
|
+ struct {
|
|
+ UINT32 NameOffset:31;
|
|
+ UINT32 NameIsString:1;
|
|
+ } s;
|
|
+ UINT32 Id;
|
|
+ } u1;
|
|
+ union {
|
|
+ UINT32 OffsetToData;
|
|
+ struct {
|
|
+ UINT32 OffsetToDirectory:31;
|
|
+ UINT32 DataIsDirectory:1;
|
|
+ } s;
|
|
+ } u2;
|
|
+} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY;
|
|
+
|
|
+///
|
|
+/// Resource directory entry for string.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT16 Length;
|
|
+ CHAR16 String[1];
|
|
+} EFI_IMAGE_RESOURCE_DIRECTORY_STRING;
|
|
+
|
|
+///
|
|
+/// Resource directory entry for data array.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT32 OffsetToData;
|
|
+ UINT32 Size;
|
|
+ UINT32 CodePage;
|
|
+ UINT32 Reserved;
|
|
+} EFI_IMAGE_RESOURCE_DATA_ENTRY;
|
|
+
|
|
+///
|
|
+/// Header format for TE images, defined in the PI Specification, 1.0.
|
|
+///
|
|
+typedef struct {
|
|
+ UINT16 Signature; ///< The signature for TE format = "VZ".
|
|
+ UINT16 Machine; ///< From the original file header.
|
|
+ UINT8 NumberOfSections; ///< From the original file header.
|
|
+ UINT8 Subsystem; ///< From original optional header.
|
|
+ UINT16 StrippedSize; ///< Number of bytes we removed from the header.
|
|
+ UINT32 AddressOfEntryPoint; ///< Offset to entry point -- from original optional header.
|
|
+ UINT32 BaseOfCode; ///< From original image -- required for ITP debug.
|
|
+ UINT64 ImageBase; ///< From original file header.
|
|
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory.
|
|
+} EFI_TE_IMAGE_HEADER;
|
|
+
|
|
+
|
|
+#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z')
|
|
+
|
|
+//
|
|
+// Data directory indexes in our TE image header
|
|
+//
|
|
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0
|
|
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1
|
|
+
|
|
+
|
|
+///
|
|
+/// Union of PE32, PE32+, and TE headers.
|
|
+///
|
|
+typedef union {
|
|
+ EFI_IMAGE_NT_HEADERS32 Pe32;
|
|
+ EFI_IMAGE_NT_HEADERS64 Pe32Plus;
|
|
+ EFI_TE_IMAGE_HEADER Te;
|
|
+} EFI_IMAGE_OPTIONAL_HEADER_UNION;
|
|
+
|
|
+typedef union {
|
|
+ EFI_IMAGE_NT_HEADERS32 *Pe32;
|
|
+ EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
|
|
+ EFI_TE_IMAGE_HEADER *Te;
|
|
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *Union;
|
|
+} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION;
|
|
+
|
|
+typedef struct {
|
|
+ WIN_CERTIFICATE Hdr;
|
|
+ UINT8 CertData[1];
|
|
+} WIN_CERTIFICATE_EFI_PKCS;
|
|
+
|
|
+#define SHA256_DIGEST_SIZE 32
|
|
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
|
+
|
|
+typedef struct {
|
|
+ UINT64 ImageAddress;
|
|
+ UINT64 ImageSize;
|
|
+ UINT64 EntryPoint;
|
|
+ UINTN SizeOfHeaders;
|
|
+ UINT16 ImageType;
|
|
+ UINT16 NumberOfSections;
|
|
+ EFI_IMAGE_SECTION_HEADER *FirstSection;
|
|
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;
|
|
+ EFI_IMAGE_DATA_DIRECTORY *SecDir;
|
|
+ UINT64 NumberOfRvaAndSizes;
|
|
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr;
|
|
+} PE_COFF_LOADER_IMAGE_CONTEXT;
|
|
+
|
|
+#endif
|
|
diff --git a/include/configtable.h b/include/configtable.h
|
|
new file mode 100644
|
|
index 0000000..fa2b505
|
|
--- /dev/null
|
|
+++ b/include/configtable.h
|
|
@@ -0,0 +1,68 @@
|
|
+/* definitions straight from TianoCore */
|
|
+
|
|
+typedef UINT32 EFI_IMAGE_EXECUTION_ACTION;
|
|
+
|
|
+#define EFI_IMAGE_EXECUTION_AUTHENTICATION 0x00000007
|
|
+#define EFI_IMAGE_EXECUTION_AUTH_UNTESTED 0x00000000
|
|
+#define EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED 0x00000001
|
|
+#define EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED 0x00000002
|
|
+#define EFI_IMAGE_EXECUTION_AUTH_SIG_NOT_FOUND 0x00000003
|
|
+#define EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND 0x00000004
|
|
+#define EFI_IMAGE_EXECUTION_POLICY_FAILED 0x00000005
|
|
+#define EFI_IMAGE_EXECUTION_INITIALIZED 0x00000008
|
|
+
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// Describes the action taken by the firmware regarding this image.
|
|
+ ///
|
|
+ EFI_IMAGE_EXECUTION_ACTION Action;
|
|
+ ///
|
|
+ /// Size of all of the entire structure.
|
|
+ ///
|
|
+ UINT32 InfoSize;
|
|
+ ///
|
|
+ /// If this image was a UEFI device driver (for option ROM, for example) this is the
|
|
+ /// null-terminated, user-friendly name for the device. If the image was for an application,
|
|
+ /// then this is the name of the application. If this cannot be determined, then a simple
|
|
+ /// NULL character should be put in this position.
|
|
+ /// CHAR16 Name[];
|
|
+ ///
|
|
+
|
|
+ ///
|
|
+ /// For device drivers, this is the device path of the device for which this device driver
|
|
+ /// was intended. In some cases, the driver itself may be stored as part of the system
|
|
+ /// firmware, but this field should record the device's path, not the firmware path. For
|
|
+ /// applications, this is the device path of the application. If this cannot be determined,
|
|
+ /// a simple end-of-path device node should be put in this position.
|
|
+ /// EFI_DEVICE_PATH_PROTOCOL DevicePath;
|
|
+ ///
|
|
+
|
|
+ ///
|
|
+ /// Zero or more image signatures. If the image contained no signatures,
|
|
+ /// then this field is empty.
|
|
+ ///
|
|
+ ///EFI_SIGNATURE_LIST Signature;
|
|
+ UINT8 Data[];
|
|
+} EFI_IMAGE_EXECUTION_INFO;
|
|
+
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// Number of EFI_IMAGE_EXECUTION_INFO structures.
|
|
+ ///
|
|
+ UINTN NumberOfImages;
|
|
+ ///
|
|
+ /// Number of image instances of EFI_IMAGE_EXECUTION_INFO structures.
|
|
+ ///
|
|
+ EFI_IMAGE_EXECUTION_INFO InformationInfo[];
|
|
+} EFI_IMAGE_EXECUTION_INFO_TABLE;
|
|
+
|
|
+
|
|
+void *
|
|
+configtable_get_table(EFI_GUID *guid);
|
|
+EFI_IMAGE_EXECUTION_INFO_TABLE *
|
|
+configtable_get_image_table(void);
|
|
+EFI_IMAGE_EXECUTION_INFO *
|
|
+configtable_find_image(const EFI_DEVICE_PATH *DevicePath);
|
|
+int
|
|
+configtable_image_is_forbidden(const EFI_DEVICE_PATH *DevicePath);
|
|
+
|
|
diff --git a/include/console.h b/include/console.h
|
|
new file mode 100644
|
|
index 0000000..7eb8a0b
|
|
--- /dev/null
|
|
+++ b/include/console.h
|
|
@@ -0,0 +1,21 @@
|
|
+EFI_INPUT_KEY
|
|
+console_get_keystroke(void);
|
|
+void
|
|
+console_print_box_at(CHAR16 *str_arr[], int highlight, int start_col, int start_row, int size_cols, int size_rows, int offset, int lines);
|
|
+void
|
|
+console_print_box(CHAR16 *str_arr[], int highlight);
|
|
+int
|
|
+console_yes_no(CHAR16 *str_arr[]);
|
|
+int
|
|
+console_select(CHAR16 *title[], CHAR16* selectors[], int start);
|
|
+void
|
|
+console_errorbox(CHAR16 *err);
|
|
+void
|
|
+console_error(CHAR16 *err, EFI_STATUS);
|
|
+void
|
|
+console_alertbox(CHAR16 **title);
|
|
+void
|
|
+console_notify(CHAR16 *string);
|
|
+void
|
|
+console_reset(void);
|
|
+#define NOSEL 0x7fffffff
|
|
diff --git a/include/efiauthenticated.h b/include/efiauthenticated.h
|
|
new file mode 100644
|
|
index 0000000..f7d6bcb
|
|
--- /dev/null
|
|
+++ b/include/efiauthenticated.h
|
|
@@ -0,0 +1,222 @@
|
|
+#ifndef _INC_EFIAUTHENTICATED_H
|
|
+#define _INC_EFIAUTHENTICATED_H
|
|
+#include <wincert.h>
|
|
+//***********************************************************************
|
|
+// Signature Database
|
|
+//***********************************************************************
|
|
+///
|
|
+/// The format of a signature database.
|
|
+///
|
|
+#pragma pack(1)
|
|
+
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// An identifier which identifies the agent which added the signature to the list.
|
|
+ ///
|
|
+ EFI_GUID SignatureOwner;
|
|
+ ///
|
|
+ /// The format of the signature is defined by the SignatureType.
|
|
+ ///
|
|
+ UINT8 SignatureData[1];
|
|
+} EFI_SIGNATURE_DATA;
|
|
+
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// Type of the signature. GUID signature types are defined in below.
|
|
+ ///
|
|
+ EFI_GUID SignatureType;
|
|
+ ///
|
|
+ /// Total size of the signature list, including this header.
|
|
+ ///
|
|
+ UINT32 SignatureListSize;
|
|
+ ///
|
|
+ /// Size of the signature header which precedes the array of signatures.
|
|
+ ///
|
|
+ UINT32 SignatureHeaderSize;
|
|
+ ///
|
|
+ /// Size of each signature.
|
|
+ ///
|
|
+ UINT32 SignatureSize;
|
|
+ ///
|
|
+ /// Header before the array of signatures. The format of this header is specified
|
|
+ /// by the SignatureType.
|
|
+ /// UINT8 SignatureHeader[SignatureHeaderSize];
|
|
+ ///
|
|
+ /// An array of signatures. Each signature is SignatureSize bytes in length.
|
|
+ /// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
|
|
+ ///
|
|
+} EFI_SIGNATURE_LIST;
|
|
+
|
|
+#pragma pack()
|
|
+
|
|
+//
|
|
+// _WIN_CERTIFICATE.wCertificateType
|
|
+//
|
|
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
|
+#define WIN_CERT_TYPE_EFI_PKCS115 0x0EF0
|
|
+#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
|
|
+
|
|
+#define EFI_CERT_X509_GUID \
|
|
+ (EFI_GUID){ \
|
|
+ 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} \
|
|
+ }
|
|
+
|
|
+#define EFI_CERT_RSA2048_GUID \
|
|
+ (EFI_GUID){ \
|
|
+ 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} \
|
|
+ }
|
|
+
|
|
+
|
|
+#define EFI_CERT_TYPE_PKCS7_GUID \
|
|
+ (EFI_GUID){ \
|
|
+ 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \
|
|
+ }
|
|
+
|
|
+///
|
|
+/// WIN_CERTIFICATE_UEFI_GUID.CertType
|
|
+///
|
|
+#define EFI_CERT_TYPE_RSA2048_SHA256_GUID \
|
|
+ {0xa7717414, 0xc616, 0x4977, {0x94, 0x20, 0x84, 0x47, 0x12, 0xa7, 0x35, 0xbf } }
|
|
+
|
|
+///
|
|
+/// WIN_CERTIFICATE_UEFI_GUID.CertData
|
|
+///
|
|
+typedef struct {
|
|
+ EFI_GUID HashType;
|
|
+ UINT8 PublicKey[256];
|
|
+ UINT8 Signature[256];
|
|
+} EFI_CERT_BLOCK_RSA_2048_SHA256;
|
|
+
|
|
+
|
|
+///
|
|
+/// Certificate which encapsulates a GUID-specific digital signature
|
|
+///
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// This is the standard WIN_CERTIFICATE header, where
|
|
+ /// wCertificateType is set to WIN_CERT_TYPE_UEFI_GUID.
|
|
+ ///
|
|
+ WIN_CERTIFICATE Hdr;
|
|
+ ///
|
|
+ /// This is the unique id which determines the
|
|
+ /// format of the CertData. .
|
|
+ ///
|
|
+ EFI_GUID CertType;
|
|
+ ///
|
|
+ /// The following is the certificate data. The format of
|
|
+ /// the data is determined by the CertType.
|
|
+ /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID,
|
|
+ /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure.
|
|
+ ///
|
|
+ UINT8 CertData[1];
|
|
+} WIN_CERTIFICATE_UEFI_GUID;
|
|
+
|
|
+
|
|
+///
|
|
+/// Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital signature.
|
|
+///
|
|
+/// The WIN_CERTIFICATE_UEFI_PKCS1_15 structure is derived from
|
|
+/// WIN_CERTIFICATE and encapsulate the information needed to
|
|
+/// implement the RSASSA-PKCS1-v1_5 digital signature algorithm as
|
|
+/// specified in RFC2437.
|
|
+///
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// This is the standard WIN_CERTIFICATE header, where
|
|
+ /// wCertificateType is set to WIN_CERT_TYPE_UEFI_PKCS1_15.
|
|
+ ///
|
|
+ WIN_CERTIFICATE Hdr;
|
|
+ ///
|
|
+ /// This is the hashing algorithm which was performed on the
|
|
+ /// UEFI executable when creating the digital signature.
|
|
+ ///
|
|
+ EFI_GUID HashAlgorithm;
|
|
+ ///
|
|
+ /// The following is the actual digital signature. The
|
|
+ /// size of the signature is the same size as the key
|
|
+ /// (1024-bit key is 128 bytes) and can be determined by
|
|
+ /// subtracting the length of the other parts of this header
|
|
+ /// from the total length of the certificate as found in
|
|
+ /// Hdr.dwLength.
|
|
+ ///
|
|
+ /// UINT8 Signature[];
|
|
+ ///
|
|
+} WIN_CERTIFICATE_EFI_PKCS1_15;
|
|
+
|
|
+#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
|
|
+
|
|
+///
|
|
+/// Attributes of Authenticated Variable
|
|
+///
|
|
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
|
|
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
|
|
+#define EFI_VARIABLE_APPEND_WRITE 0x00000040
|
|
+
|
|
+///
|
|
+/// AuthInfo is a WIN_CERTIFICATE using the wCertificateType
|
|
+/// WIN_CERTIFICATE_UEFI_GUID and the CertType
|
|
+/// EFI_CERT_TYPE_RSA2048_SHA256_GUID. If the attribute specifies
|
|
+/// authenticated access, then the Data buffer should begin with an
|
|
+/// authentication descriptor prior to the data payload and DataSize
|
|
+/// should reflect the the data.and descriptor size. The caller
|
|
+/// shall digest the Monotonic Count value and the associated data
|
|
+/// for the variable update using the SHA-256 1-way hash algorithm.
|
|
+/// The ensuing the 32-byte digest will be signed using the private
|
|
+/// key associated w/ the public/private 2048-bit RSA key-pair. The
|
|
+/// WIN_CERTIFICATE shall be used to describe the signature of the
|
|
+/// Variable data *Data. In addition, the signature will also
|
|
+/// include the MonotonicCount value to guard against replay attacks.
|
|
+///
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// Included in the signature of
|
|
+ /// AuthInfo.Used to ensure freshness/no
|
|
+ /// replay. Incremented during each
|
|
+ /// "Write" access.
|
|
+ ///
|
|
+ UINT64 MonotonicCount;
|
|
+ ///
|
|
+ /// Provides the authorization for the variable
|
|
+ /// access. It is a signature across the
|
|
+ /// variable data and the Monotonic Count
|
|
+ /// value. Caller uses Private key that is
|
|
+ /// associated with a public key that has been
|
|
+ /// provisioned via the key exchange.
|
|
+ ///
|
|
+ WIN_CERTIFICATE_UEFI_GUID AuthInfo;
|
|
+} EFI_VARIABLE_AUTHENTICATION;
|
|
+
|
|
+///
|
|
+/// When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
|
|
+/// set, then the Data buffer shall begin with an instance of a complete (and serialized)
|
|
+/// EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
|
|
+/// variable value and DataSize shall reflect the combined size of the descriptor and the new
|
|
+/// variable value. The authentication descriptor is not part of the variable data and is not
|
|
+/// returned by subsequent calls to GetVariable().
|
|
+///
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// For the TimeStamp value, components Pad1, Nanosecond, TimeZone, Daylight and
|
|
+ /// Pad2 shall be set to 0. This means that the time shall always be expressed in GMT.
|
|
+ ///
|
|
+ EFI_TIME TimeStamp;
|
|
+ ///
|
|
+ /// Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted.
|
|
+ ///
|
|
+ WIN_CERTIFICATE_UEFI_GUID AuthInfo;
|
|
+ } EFI_VARIABLE_AUTHENTICATION_2;
|
|
+
|
|
+///
|
|
+/// Size of AuthInfo prior to the data payload.
|
|
+///
|
|
+#define AUTHINFO_SIZE ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
|
|
+ (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
|
|
+ sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256))
|
|
+
|
|
+#define AUTHINFO2_SIZE(VarAuth2) ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) + \
|
|
+ (UINTN) ((EFI_VARIABLE_AUTHENTICATION_2 *) (VarAuth2))->AuthInfo.Hdr.dwLength)
|
|
+
|
|
+#define OFFSET_OF_AUTHINFO2_CERT_DATA ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) + \
|
|
+ (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
|
|
+
|
|
+#endif
|
|
diff --git a/include/errors.h b/include/errors.h
|
|
new file mode 100644
|
|
index 0000000..0da4bb5
|
|
--- /dev/null
|
|
+++ b/include/errors.h
|
|
@@ -0,0 +1,9 @@
|
|
+#include <efierr.h>
|
|
+
|
|
+#ifndef EFI_INCOMPATIBLE_VERSION
|
|
+#define EFI_INCOMPATIBLE_VERSION EFIERR(25)
|
|
+#endif
|
|
+#ifndef EFI_SECURITY_VIOLATION
|
|
+#define EFI_SECURITY_VIOLATION EFIERR(26)
|
|
+#endif
|
|
+
|
|
diff --git a/include/execute.h b/include/execute.h
|
|
new file mode 100644
|
|
index 0000000..9aecbff
|
|
--- /dev/null
|
|
+++ b/include/execute.h
|
|
@@ -0,0 +1,5 @@
|
|
+EFI_STATUS
|
|
+generate_path(CHAR16* name, EFI_LOADED_IMAGE *li,
|
|
+ EFI_DEVICE_PATH **path, CHAR16 **PathName);
|
|
+EFI_STATUS
|
|
+execute(EFI_HANDLE image, CHAR16 *name);
|
|
diff --git a/include/guid.h b/include/guid.h
|
|
new file mode 100644
|
|
index 0000000..10f865a
|
|
--- /dev/null
|
|
+++ b/include/guid.h
|
|
@@ -0,0 +1,18 @@
|
|
+#include <efi.h>
|
|
+
|
|
+#ifndef BUILD_EFI
|
|
+const char *guid_to_str(EFI_GUID *guid);
|
|
+void str_to_guid(const char *str, EFI_GUID *guid);
|
|
+#endif
|
|
+
|
|
+extern EFI_GUID GV_GUID;
|
|
+extern EFI_GUID SIG_DB;
|
|
+extern EFI_GUID X509_GUID;
|
|
+extern EFI_GUID RSA2048_GUID;
|
|
+extern EFI_GUID PKCS7_GUID;
|
|
+extern EFI_GUID IMAGE_PROTOCOL;
|
|
+extern EFI_GUID SIMPLE_FS_PROTOCOL;
|
|
+extern EFI_GUID EFI_CERT_SHA256_GUID;
|
|
+extern EFI_GUID MOK_OWNER;
|
|
+extern EFI_GUID SECURITY_PROTOCOL_GUID;
|
|
+extern EFI_GUID SECURITY2_PROTOCOL_GUID;
|
|
diff --git a/include/security_policy.h b/include/security_policy.h
|
|
new file mode 100644
|
|
index 0000000..a1c1002
|
|
--- /dev/null
|
|
+++ b/include/security_policy.h
|
|
@@ -0,0 +1,6 @@
|
|
+EFI_STATUS
|
|
+security_policy_install(void);
|
|
+EFI_STATUS
|
|
+security_policy_uninstall(void);
|
|
+void
|
|
+security_protocol_set_hashes(unsigned char *esl, int len);
|
|
diff --git a/include/shell.h b/include/shell.h
|
|
new file mode 100644
|
|
index 0000000..9cb5d47
|
|
--- /dev/null
|
|
+++ b/include/shell.h
|
|
@@ -0,0 +1,2 @@
|
|
+EFI_STATUS
|
|
+argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV);
|
|
diff --git a/include/simple_file.h b/include/simple_file.h
|
|
new file mode 100644
|
|
index 0000000..fe4fd97
|
|
--- /dev/null
|
|
+++ b/include/simple_file.h
|
|
@@ -0,0 +1,21 @@
|
|
+EFI_STATUS
|
|
+simple_file_open (EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode);
|
|
+EFI_STATUS
|
|
+simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode);
|
|
+EFI_STATUS
|
|
+simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer);
|
|
+EFI_STATUS
|
|
+simple_file_write_all(EFI_FILE *file, UINTN size, void *buffer);
|
|
+void
|
|
+simple_file_close(EFI_FILE *file);
|
|
+EFI_STATUS
|
|
+simple_dir_read_all(EFI_HANDLE image, CHAR16 *name, EFI_FILE_INFO **Entries,
|
|
+ int *count);
|
|
+EFI_STATUS
|
|
+simple_dir_filter(EFI_HANDLE image, CHAR16 *name, CHAR16 *filter,
|
|
+ CHAR16 ***result, int *count, EFI_FILE_INFO **entries);
|
|
+void
|
|
+simple_file_selector(EFI_HANDLE *im, CHAR16 **title, CHAR16 *name,
|
|
+ CHAR16 *filter, CHAR16 **result);
|
|
+EFI_STATUS
|
|
+simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h);
|
|
diff --git a/include/variables.h b/include/variables.h
|
|
new file mode 100644
|
|
index 0000000..c171bd5
|
|
--- /dev/null
|
|
+++ b/include/variables.h
|
|
@@ -0,0 +1,59 @@
|
|
+#include <efiauthenticated.h>
|
|
+
|
|
+#include <sha256.h> /* for SHA256_DIGEST_SIZE */
|
|
+
|
|
+#define certlist_for_each_certentry(cl, cl_init, s, s_init) \
|
|
+ for (cl = (EFI_SIGNATURE_LIST *)(cl_init), s = (s_init); \
|
|
+ s > 0 && s >= cl->SignatureListSize; \
|
|
+ s -= cl->SignatureListSize, \
|
|
+ cl = (EFI_SIGNATURE_LIST *) ((UINT8 *)cl + cl->SignatureListSize))
|
|
+
|
|
+/*
|
|
+ * Warning: this assumes (cl)->SignatureHeaderSize is zero. It is for all
|
|
+ * the signatures we process (X509, RSA2048, SHA256)
|
|
+ */
|
|
+#define certentry_for_each_cert(c, cl) \
|
|
+ for (c = (EFI_SIGNATURE_DATA *)((UINT8 *) (cl) + sizeof(EFI_SIGNATURE_LIST) + (cl)->SignatureHeaderSize); \
|
|
+ (UINT8 *)c < ((UINT8 *)(cl)) + (cl)->SignatureListSize; \
|
|
+ c = (EFI_SIGNATURE_DATA *)((UINT8 *)c + (cl)->SignatureSize))
|
|
+
|
|
+EFI_STATUS
|
|
+CreatePkX509SignatureList (
|
|
+ IN UINT8 *X509Data,
|
|
+ IN UINTN X509DataSize,
|
|
+ IN EFI_GUID owner,
|
|
+ OUT EFI_SIGNATURE_LIST **PkCert
|
|
+ );
|
|
+EFI_STATUS
|
|
+CreateTimeBasedPayload (
|
|
+ IN OUT UINTN *DataSize,
|
|
+ IN OUT UINT8 **Data
|
|
+ );
|
|
+EFI_STATUS
|
|
+SetSecureVariable(CHAR16 *var, UINT8 *Data, UINTN len, EFI_GUID owner, UINT32 options, int createtimebased);
|
|
+EFI_STATUS
|
|
+get_variable(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner);
|
|
+EFI_STATUS
|
|
+get_variable_attr(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner,
|
|
+ UINT32 *attributes);
|
|
+EFI_STATUS
|
|
+find_in_esl(UINT8 *Data, UINTN DataSize, UINT8 *key, UINTN keylen);
|
|
+EFI_STATUS
|
|
+find_in_variable_esl(CHAR16* var, EFI_GUID owner, UINT8 *key, UINTN keylen);
|
|
+
|
|
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
|
|
+
|
|
+UINT64
|
|
+GetOSIndications(void);
|
|
+EFI_STATUS
|
|
+SETOSIndicationsAndReboot(UINT64 indications);
|
|
+int
|
|
+variable_is_secureboot(void);
|
|
+int
|
|
+variable_is_setupmode(void);
|
|
+EFI_STATUS
|
|
+variable_enroll_hash(CHAR16 *var, EFI_GUID owner,
|
|
+ UINT8 hash[SHA256_DIGEST_SIZE]);
|
|
+EFI_STATUS
|
|
+variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner,
|
|
+ void **out, int *outlen);
|
|
diff --git a/include/version.h b/include/version.h
|
|
new file mode 100644
|
|
index 0000000..09fd44a
|
|
--- /dev/null
|
|
+++ b/include/version.h
|
|
@@ -0,0 +1,8 @@
|
|
+#define VERSION "1.3.4"
|
|
+
|
|
+static void
|
|
+version(const char *progname)
|
|
+{
|
|
+ printf("%s " VERSION "\n", progname);
|
|
+}
|
|
+
|
|
diff --git a/include/wincert.h b/include/wincert.h
|
|
new file mode 100644
|
|
index 0000000..68d1974
|
|
--- /dev/null
|
|
+++ b/include/wincert.h
|
|
@@ -0,0 +1,33 @@
|
|
+#ifndef _INC_WINCERT_H
|
|
+#define _INC_WINCERT_H
|
|
+
|
|
+///
|
|
+/// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
|
|
+///
|
|
+typedef struct {
|
|
+ ///
|
|
+ /// The length of the entire certificate,
|
|
+ /// including the length of the header, in bytes.
|
|
+ ///
|
|
+ UINT32 dwLength;
|
|
+ ///
|
|
+ /// The revision level of the WIN_CERTIFICATE
|
|
+ /// structure. The current revision level is 0x0200.
|
|
+ ///
|
|
+ UINT16 wRevision;
|
|
+ ///
|
|
+ /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI
|
|
+ /// certificate types. The UEFI specification reserves the range of
|
|
+ /// certificate type values from 0x0EF0 to 0x0EFF.
|
|
+ ///
|
|
+ UINT16 wCertificateType;
|
|
+ ///
|
|
+ /// The following is the actual certificate. The format of
|
|
+ /// the certificate depends on wCertificateType.
|
|
+ ///
|
|
+ /// UINT8 bCertificate[ANYSIZE_ARRAY];
|
|
+ ///
|
|
+} WIN_CERTIFICATE;
|
|
+
|
|
+
|
|
+#endif
|
|
diff --git a/lib/Makefile b/lib/Makefile
|
|
new file mode 100644
|
|
index 0000000..be5f354
|
|
--- /dev/null
|
|
+++ b/lib/Makefile
|
|
@@ -0,0 +1,28 @@
|
|
+TARGET = lib.a
|
|
+
|
|
+LIBFILES = simple_file.o guid.o console.o execute.o configtable.o shell.o
|
|
+
|
|
+ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
|
|
+
|
|
+EFI_INCLUDE = /usr/include/efi
|
|
+EFI_INCLUDES = -I$(EFI_INCLUDE) -I$(EFI_INCLUDE)/$(ARCH) -I$(EFI_INCLUDE)/protocol -I../include
|
|
+EFI_PATH = /usr/lib64/gnuefi
|
|
+
|
|
+EFI_CRT_OBJS = $(EFI_PATH)/crt0-efi-$(ARCH).o
|
|
+EFI_LDS = $(EFI_PATH)/elf_$(ARCH)_efi.lds
|
|
+
|
|
+CFLAGS = -ggdb -O0 -fno-stack-protector -fno-strict-aliasing -fpic \
|
|
+ -fshort-wchar -Wall -mno-red-zone -DBUILD_EFI $(EFI_INCLUDES)
|
|
+ifeq ($(ARCH),x86_64)
|
|
+ CFLAGS += -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI
|
|
+endif
|
|
+
|
|
+lib.a: $(LIBFILES)
|
|
+ ar rcs lib.a $(LIBFILES)
|
|
+
|
|
+all: $(TARGET)
|
|
+
|
|
+clean:
|
|
+ rm -f lib.a
|
|
+ rm -f $(LIBFILES)
|
|
+
|
|
diff --git a/lib/configtable.c b/lib/configtable.c
|
|
new file mode 100644
|
|
index 0000000..735ce8f
|
|
--- /dev/null
|
|
+++ b/lib/configtable.c
|
|
@@ -0,0 +1,144 @@
|
|
+/*
|
|
+ * Copyright 2013 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ *
|
|
+ * read some platform configuration tables
|
|
+ */
|
|
+#include <efi.h>
|
|
+#include <efilib.h>
|
|
+
|
|
+#include <guid.h>
|
|
+#include <configtable.h>
|
|
+
|
|
+void *
|
|
+configtable_get_table(EFI_GUID *guid)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
|
|
+ EFI_CONFIGURATION_TABLE *CT = &ST->ConfigurationTable[i];
|
|
+
|
|
+ if (CompareGuid(guid, &CT->VendorGuid) == 0) {
|
|
+ return CT->VendorTable;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+EFI_IMAGE_EXECUTION_INFO_TABLE *
|
|
+configtable_get_image_table(void)
|
|
+{
|
|
+ return configtable_get_table(&SIG_DB);
|
|
+}
|
|
+
|
|
+EFI_IMAGE_EXECUTION_INFO *
|
|
+configtable_find_image(const EFI_DEVICE_PATH *DevicePath)
|
|
+{
|
|
+ EFI_IMAGE_EXECUTION_INFO_TABLE *t = configtable_get_image_table();
|
|
+
|
|
+ if (!t)
|
|
+ return NULL;
|
|
+
|
|
+ int entries = t->NumberOfImages;
|
|
+ EFI_IMAGE_EXECUTION_INFO *e = t->InformationInfo;
|
|
+
|
|
+ int i;
|
|
+ for (i = 0; i < entries; i++) {
|
|
+#ifdef DEBUG_CONFIG
|
|
+ Print(L"InfoSize = %d Action = %d\n", e->InfoSize, e->Action);
|
|
+
|
|
+ /* print what we have for debugging */
|
|
+ UINT8 *d = (UINT8 *)e; // + sizeof(UINT32)*2;
|
|
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
|
+ d += 16;
|
|
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
|
+ d += 16;
|
|
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
|
+ d += 16;
|
|
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
|
+ d += 16;
|
|
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
|
+ d += 16;
|
|
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
|
+#endif
|
|
+ CHAR16 *name = (CHAR16 *)(e->Data);
|
|
+ int skip = 0;
|
|
+
|
|
+ /* There's a bug in a lot of EFI platforms and they forget to
|
|
+ * put the name here. The only real way of detecting it is to
|
|
+ * look for either a UC16 NULL or ASCII as UC16 */
|
|
+ if (name[0] == '\0' || (e->Data[1] == 0 && e->Data[3] == 0)) {
|
|
+ skip = StrSize(name);
|
|
+#ifdef DEBUG_CONFIG
|
|
+ Print(L"FOUND NAME %s (%d)\n", name, skip);
|
|
+#endif
|
|
+ }
|
|
+ EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)(e->Data + skip), *dpn = dp;
|
|
+ if (dp->Type == 0 || dp->Type > 6 || dp->SubType == 0
|
|
+ || (((dp->Length[1] << 8) + dp->Length[0]) > e->InfoSize)) {
|
|
+ /* Parse error, table corrupt, bail */
|
|
+ Print(L"Image Execution Information table corrupt\n");
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ UINTN Size;
|
|
+ DevicePathInstance(&dpn, &Size);
|
|
+#ifdef DEBUG_CONFIG
|
|
+ Print(L"Path: %s\n", DevicePathToStr(dp));
|
|
+ Print(L"Device Path Size %d\n", Size);
|
|
+#endif
|
|
+ if (Size > e->InfoSize) {
|
|
+ /* parse error; the platform obviously has a
|
|
+ * corrupted image table; bail */
|
|
+ Print(L"Image Execution Information table corrupt\n");
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (CompareMem(dp, DevicePath, Size) == 0) {
|
|
+#ifdef DEBUG_CONFIG
|
|
+ Print(L"***FOUND\n");
|
|
+ console_get_keystroke();
|
|
+#endif
|
|
+ return e;
|
|
+ }
|
|
+ e = (EFI_IMAGE_EXECUTION_INFO *)((UINT8 *)e + e->InfoSize);
|
|
+ }
|
|
+
|
|
+#ifdef DEBUG_CONFIG
|
|
+ Print(L"***NOT FOUND\n");
|
|
+ console_get_keystroke();
|
|
+#endif
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+int
|
|
+configtable_image_is_forbidden(const EFI_DEVICE_PATH *DevicePath)
|
|
+{
|
|
+ EFI_IMAGE_EXECUTION_INFO *e = configtable_find_image(DevicePath);
|
|
+
|
|
+ /* Image may not be in DB if it gets executed successfully If it is,
|
|
+ * and EFI_IMAGE_EXECUTION_INITIALIZED is not set, then the image
|
|
+ * isn't authenticated. If there's no signature, usually
|
|
+ * EFI_IMAGE_EXECUTION_AUTH_UNTESTED is set, if the hash is in dbx,
|
|
+ * EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND is returned, and if the key is
|
|
+ * in dbx, EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED is returned*/
|
|
+
|
|
+ if (e && (e->Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND
|
|
+ || e->Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED)) {
|
|
+ /* this means the images signing key is in dbx */
|
|
+#ifdef DEBUG_CONFIG
|
|
+ Print(L"SIGNATURE IS IN DBX, FORBIDDING EXECUTION\n");
|
|
+#endif
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/lib/console.c b/lib/console.c
|
|
new file mode 100644
|
|
index 0000000..af01f03
|
|
--- /dev/null
|
|
+++ b/lib/console.c
|
|
@@ -0,0 +1,402 @@
|
|
+/*
|
|
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ */
|
|
+#include <efi/efi.h>
|
|
+#include <efi/efilib.h>
|
|
+
|
|
+#include <console.h>
|
|
+#include <errors.h>
|
|
+
|
|
+static int min(int a, int b)
|
|
+{
|
|
+ if (a < b)
|
|
+ return a;
|
|
+ return b;
|
|
+}
|
|
+
|
|
+static int
|
|
+count_lines(CHAR16 *str_arr[])
|
|
+{
|
|
+ int i = 0;
|
|
+
|
|
+ while (str_arr[i])
|
|
+ i++;
|
|
+ return i;
|
|
+}
|
|
+
|
|
+static void
|
|
+SetMem16(CHAR16 *dst, UINT32 n, CHAR16 c)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < n/2; i++) {
|
|
+ dst[i] = c;
|
|
+ }
|
|
+}
|
|
+
|
|
+EFI_INPUT_KEY
|
|
+console_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;
|
|
+}
|
|
+
|
|
+void
|
|
+console_print_box_at(CHAR16 *str_arr[], int highlight, int start_col, int start_row, int size_cols, int size_rows, int offset, int lines)
|
|
+{
|
|
+ int i;
|
|
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
|
+ UINTN rows, cols;
|
|
+ CHAR16 *Line;
|
|
+
|
|
+ if (lines == 0)
|
|
+ return;
|
|
+
|
|
+ uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
|
|
+
|
|
+ /* last row on screen is unusable without scrolling, so ignore it */
|
|
+ rows--;
|
|
+
|
|
+ if (size_rows < 0)
|
|
+ size_rows = rows + size_rows + 1;
|
|
+ if (size_cols < 0)
|
|
+ size_cols = cols + size_cols + 1;
|
|
+
|
|
+ if (start_col < 0)
|
|
+ start_col = (cols + start_col + 2)/2;
|
|
+ if (start_row < 0)
|
|
+ start_row = (rows + start_row + 2)/2;
|
|
+ if (start_col < 0)
|
|
+ start_col = 0;
|
|
+ if (start_row < 0)
|
|
+ start_row = 0;
|
|
+
|
|
+ if (start_col > cols || start_row > rows) {
|
|
+ Print(L"Starting Position (%d,%d) is off screen\n",
|
|
+ start_col, start_row);
|
|
+ return;
|
|
+ }
|
|
+ if (size_cols + start_col > cols)
|
|
+ size_cols = cols - start_col;
|
|
+ if (size_rows + start_row > rows)
|
|
+ size_rows = rows - start_row;
|
|
+
|
|
+ if (lines > size_rows - 2)
|
|
+ lines = size_rows - 2;
|
|
+
|
|
+ Line = AllocatePool((size_cols+1)*sizeof(CHAR16));
|
|
+ if (!Line) {
|
|
+ Print(L"Failed Allocation\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
|
|
+
|
|
+ Line[0] = BOXDRAW_DOWN_RIGHT;
|
|
+ Line[size_cols - 1] = BOXDRAW_DOWN_LEFT;
|
|
+ Line[size_cols] = L'\0';
|
|
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, start_row);
|
|
+ uefi_call_wrapper(co->OutputString, 2, co, Line);
|
|
+
|
|
+ int start;
|
|
+ if (offset == 0)
|
|
+ /* middle */
|
|
+ start = (size_rows - lines)/2 + start_row + offset;
|
|
+ else if (offset < 0)
|
|
+ /* from bottom */
|
|
+ start = start_row + size_rows - lines + offset - 1;
|
|
+ else
|
|
+ /* from top */
|
|
+ start = start_row + offset;
|
|
+
|
|
+
|
|
+ for (i = start_row + 1; i < size_rows + start_row - 1; i++) {
|
|
+ int line = i - start;
|
|
+
|
|
+ SetMem16 (Line, size_cols*2, L' ');
|
|
+ Line[0] = BOXDRAW_VERTICAL;
|
|
+ Line[size_cols - 1] = BOXDRAW_VERTICAL;
|
|
+ Line[size_cols] = L'\0';
|
|
+ if (line >= 0 && line < lines) {
|
|
+ CHAR16 *s = str_arr[line];
|
|
+ int len = StrLen(s);
|
|
+ int col = (size_cols - 2 - len)/2;
|
|
+
|
|
+ if (col < 0)
|
|
+ col = 0;
|
|
+
|
|
+ CopyMem(Line + col + 1, s, min(len, size_cols - 2)*2);
|
|
+ }
|
|
+ if (line >= 0 && line == highlight)
|
|
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
|
|
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
|
|
+ uefi_call_wrapper(co->OutputString, 2, co, Line);
|
|
+ if (line >= 0 && line == highlight)
|
|
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
|
|
+
|
|
+ }
|
|
+ SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
|
|
+ Line[0] = BOXDRAW_UP_RIGHT;
|
|
+ Line[size_cols - 1] = BOXDRAW_UP_LEFT;
|
|
+ Line[size_cols] = L'\0';
|
|
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
|
|
+ uefi_call_wrapper(co->OutputString, 2, co, Line);
|
|
+
|
|
+ FreePool (Line);
|
|
+
|
|
+}
|
|
+
|
|
+void
|
|
+console_print_box(CHAR16 *str_arr[], int highlight)
|
|
+{
|
|
+ SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
|
|
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
|
+ CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
|
|
+ uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
|
|
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
|
|
+
|
|
+ console_print_box_at(str_arr, highlight, 0, 0, -1, -1, 0,
|
|
+ count_lines(str_arr));
|
|
+
|
|
+ console_get_keystroke();
|
|
+
|
|
+ uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
|
+
|
|
+ uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
|
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
|
|
+ uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
|
|
+}
|
|
+
|
|
+int
|
|
+console_select(CHAR16 *title[], CHAR16* selectors[], int start)
|
|
+{
|
|
+ SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
|
|
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
|
+ EFI_INPUT_KEY k;
|
|
+ int selector;
|
|
+ int selector_lines = count_lines(selectors);
|
|
+ int selector_max_cols = 0;
|
|
+ int i, offs_col, offs_row, size_cols, size_rows, lines;
|
|
+ int selector_offset;
|
|
+ UINTN cols, rows;
|
|
+
|
|
+ uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
|
|
+
|
|
+ for (i = 0; i < selector_lines; i++) {
|
|
+ int len = StrLen(selectors[i]);
|
|
+
|
|
+ if (len > selector_max_cols)
|
|
+ selector_max_cols = len;
|
|
+ }
|
|
+
|
|
+ if (start < 0)
|
|
+ start = 0;
|
|
+ if (start >= selector_lines)
|
|
+ start = selector_lines - 1;
|
|
+
|
|
+ offs_col = - selector_max_cols - 4;
|
|
+ size_cols = selector_max_cols + 4;
|
|
+
|
|
+ if (selector_lines > rows - 10) {
|
|
+ int title_lines = count_lines(title);
|
|
+ offs_row = title_lines + 1;
|
|
+ size_rows = rows - 3 - title_lines;
|
|
+ lines = size_rows - 2;
|
|
+ } else {
|
|
+ offs_row = - selector_lines - 4;
|
|
+ size_rows = selector_lines + 2;
|
|
+ lines = selector_lines;
|
|
+ }
|
|
+
|
|
+ if (start > lines) {
|
|
+ selector = lines;
|
|
+ selector_offset = start - lines;
|
|
+ } else {
|
|
+ selector = start;
|
|
+ selector_offset = 0;
|
|
+ }
|
|
+
|
|
+ CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
|
|
+ uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
|
|
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
|
|
+
|
|
+ console_print_box_at(title, -1, 0, 0, -1, -1, 1, count_lines(title));
|
|
+
|
|
+ console_print_box_at(selectors, selector, offs_col, offs_row,
|
|
+ size_cols, size_rows, 0, lines);
|
|
+
|
|
+ do {
|
|
+ k = console_get_keystroke();
|
|
+
|
|
+ if (k.ScanCode == SCAN_ESC) {
|
|
+ selector = -1;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (k.ScanCode == SCAN_UP) {
|
|
+ if (selector > 0)
|
|
+ selector--;
|
|
+ else if (selector_offset > 0)
|
|
+ selector_offset--;
|
|
+ } else if (k.ScanCode == SCAN_DOWN) {
|
|
+ if (selector < lines - 1)
|
|
+ selector++;
|
|
+ else if (selector_offset < (selector_lines - lines))
|
|
+ selector_offset++;
|
|
+ }
|
|
+
|
|
+ console_print_box_at(&selectors[selector_offset], selector,
|
|
+ offs_col, offs_row,
|
|
+ size_cols, size_rows, 0, lines);
|
|
+ } while (!(k.ScanCode == SCAN_NULL
|
|
+ && k.UnicodeChar == CHAR_CARRIAGE_RETURN));
|
|
+
|
|
+ uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
|
+
|
|
+ uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
|
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
|
|
+ uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
|
|
+
|
|
+ if (selector < 0)
|
|
+ /* ESC pressed */
|
|
+ return selector;
|
|
+ return selector + selector_offset;
|
|
+}
|
|
+
|
|
+
|
|
+int
|
|
+console_yes_no(CHAR16 *str_arr[])
|
|
+{
|
|
+ return console_select(str_arr, (CHAR16 *[]){ L"No", L"Yes", NULL }, 0);
|
|
+}
|
|
+
|
|
+void
|
|
+console_alertbox(CHAR16 **title)
|
|
+{
|
|
+ console_select(title, (CHAR16 *[]){ L"OK", 0 }, 0);
|
|
+}
|
|
+
|
|
+void
|
|
+console_errorbox(CHAR16 *err)
|
|
+{
|
|
+ CHAR16 **err_arr = (CHAR16 *[]){
|
|
+ L"ERROR",
|
|
+ L"",
|
|
+ 0,
|
|
+ 0,
|
|
+ };
|
|
+
|
|
+ err_arr[2] = err;
|
|
+
|
|
+ console_alertbox(err_arr);
|
|
+}
|
|
+
|
|
+void
|
|
+console_notify(CHAR16 *string)
|
|
+{
|
|
+ CHAR16 **str_arr = (CHAR16 *[]){
|
|
+ 0,
|
|
+ 0,
|
|
+ };
|
|
+
|
|
+ str_arr[0] = string;
|
|
+
|
|
+ console_alertbox(str_arr);
|
|
+}
|
|
+
|
|
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
|
|
+
|
|
+/* Copy of gnu-efi-3.0 with the added secure boot strings */
|
|
+static struct {
|
|
+ EFI_STATUS Code;
|
|
+ WCHAR *Desc;
|
|
+} error_table[] = {
|
|
+ { EFI_SUCCESS, L"Success"},
|
|
+ { EFI_LOAD_ERROR, L"Load Error"},
|
|
+ { EFI_INVALID_PARAMETER, L"Invalid Parameter"},
|
|
+ { EFI_UNSUPPORTED, L"Unsupported"},
|
|
+ { EFI_BAD_BUFFER_SIZE, L"Bad Buffer Size"},
|
|
+ { EFI_BUFFER_TOO_SMALL, L"Buffer Too Small"},
|
|
+ { EFI_NOT_READY, L"Not Ready"},
|
|
+ { EFI_DEVICE_ERROR, L"Device Error"},
|
|
+ { EFI_WRITE_PROTECTED, L"Write Protected"},
|
|
+ { EFI_OUT_OF_RESOURCES, L"Out of Resources"},
|
|
+ { EFI_VOLUME_CORRUPTED, L"Volume Corrupt"},
|
|
+ { EFI_VOLUME_FULL, L"Volume Full"},
|
|
+ { EFI_NO_MEDIA, L"No Media"},
|
|
+ { EFI_MEDIA_CHANGED, L"Media changed"},
|
|
+ { EFI_NOT_FOUND, L"Not Found"},
|
|
+ { EFI_ACCESS_DENIED, L"Access Denied"},
|
|
+ { EFI_NO_RESPONSE, L"No Response"},
|
|
+ { EFI_NO_MAPPING, L"No mapping"},
|
|
+ { EFI_TIMEOUT, L"Time out"},
|
|
+ { EFI_NOT_STARTED, L"Not started"},
|
|
+ { EFI_ALREADY_STARTED, L"Already started"},
|
|
+ { EFI_ABORTED, L"Aborted"},
|
|
+ { EFI_ICMP_ERROR, L"ICMP Error"},
|
|
+ { EFI_TFTP_ERROR, L"TFTP Error"},
|
|
+ { EFI_PROTOCOL_ERROR, L"Protocol Error"},
|
|
+ { EFI_INCOMPATIBLE_VERSION, L"Incompatible Version"},
|
|
+ { EFI_SECURITY_VIOLATION, L"Security Violation"},
|
|
+
|
|
+ // warnings
|
|
+ { EFI_WARN_UNKOWN_GLYPH, L"Warning Unknown Glyph"},
|
|
+ { EFI_WARN_DELETE_FAILURE, L"Warning Delete Failure"},
|
|
+ { EFI_WARN_WRITE_FAILURE, L"Warning Write Failure"},
|
|
+ { EFI_WARN_BUFFER_TOO_SMALL, L"Warning Buffer Too Small"},
|
|
+ { 0, NULL}
|
|
+} ;
|
|
+
|
|
+
|
|
+static CHAR16 *
|
|
+err_string (
|
|
+ IN EFI_STATUS Status
|
|
+ )
|
|
+{
|
|
+ UINTN Index;
|
|
+
|
|
+ for (Index = 0; error_table[Index].Desc; Index +=1) {
|
|
+ if (error_table[Index].Code == Status) {
|
|
+ return error_table[Index].Desc;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return L"";
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+console_error(CHAR16 *err, EFI_STATUS status)
|
|
+{
|
|
+ CHAR16 **err_arr = (CHAR16 *[]){
|
|
+ L"ERROR",
|
|
+ L"",
|
|
+ 0,
|
|
+ 0,
|
|
+ };
|
|
+ CHAR16 str[512];
|
|
+
|
|
+ SPrint(str, sizeof(str), L"%s: (%d) %s", err, status, err_string(status));
|
|
+
|
|
+ err_arr[2] = str;
|
|
+
|
|
+ console_alertbox(err_arr);
|
|
+}
|
|
+
|
|
+void
|
|
+console_reset(void)
|
|
+{
|
|
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
|
+
|
|
+ uefi_call_wrapper(co->Reset, 2, co, TRUE);
|
|
+ /* set mode 0 - required to be 80x25 */
|
|
+ uefi_call_wrapper(co->SetMode, 2, co, 0);
|
|
+ uefi_call_wrapper(co->ClearScreen, 1, co);
|
|
+}
|
|
diff --git a/lib/execute.c b/lib/execute.c
|
|
new file mode 100644
|
|
index 0000000..8d726eb
|
|
--- /dev/null
|
|
+++ b/lib/execute.c
|
|
@@ -0,0 +1,127 @@
|
|
+/*
|
|
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ *
|
|
+ * --
|
|
+ *
|
|
+ * generate_path is a cut and paste from
|
|
+ *
|
|
+ * git://github.com/mjg59/shim.git
|
|
+ *
|
|
+ * Code Copyright 2012 Red Hat, Inc <mjg@redhat.com>
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ *
|
|
+ * Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ *
|
|
+ * Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the
|
|
+ * distribution.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <efi.h>
|
|
+#include <efilib.h>
|
|
+
|
|
+#include <guid.h>
|
|
+#include <execute.h>
|
|
+
|
|
+EFI_STATUS
|
|
+generate_path(CHAR16* name, EFI_LOADED_IMAGE *li, EFI_DEVICE_PATH **path, CHAR16 **PathName)
|
|
+{
|
|
+ unsigned int pathlen;
|
|
+ EFI_STATUS efi_status = EFI_SUCCESS;
|
|
+ CHAR16 *devpathstr = DevicePathToStr(li->FilePath),
|
|
+ *found = NULL;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < StrLen(devpathstr); i++) {
|
|
+ if (devpathstr[i] == '/')
|
|
+ devpathstr[i] = '\\';
|
|
+ if (devpathstr[i] == '\\')
|
|
+ found = &devpathstr[i];
|
|
+ }
|
|
+ if (!found) {
|
|
+ pathlen = 0;
|
|
+ } else {
|
|
+ while (*(found - 1) == '\\')
|
|
+ --found;
|
|
+ *found = '\0';
|
|
+ pathlen = StrLen(devpathstr);
|
|
+ }
|
|
+
|
|
+ if (name[0] != '\\')
|
|
+ pathlen++;
|
|
+
|
|
+ *PathName = AllocatePool((pathlen + 1 + StrLen(name))*sizeof(CHAR16));
|
|
+
|
|
+ if (!*PathName) {
|
|
+ Print(L"Failed to allocate path buffer\n");
|
|
+ efi_status = EFI_OUT_OF_RESOURCES;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ StrCpy(*PathName, devpathstr);
|
|
+
|
|
+ if (name[0] != '\\')
|
|
+ StrCat(*PathName, L"\\");
|
|
+ StrCat(*PathName, name);
|
|
+
|
|
+ *path = FileDevicePath(li->DeviceHandle, *PathName);
|
|
+
|
|
+error:
|
|
+ FreePool(devpathstr);
|
|
+
|
|
+ return efi_status;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+execute(EFI_HANDLE image, CHAR16 *name)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+ EFI_HANDLE h;
|
|
+ EFI_LOADED_IMAGE *li;
|
|
+ EFI_DEVICE_PATH *devpath;
|
|
+ CHAR16 *PathName;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
|
|
+ &IMAGE_PROTOCOL, &li);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ return status;
|
|
+
|
|
+
|
|
+ status = generate_path(name, li, &devpath, &PathName);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ return status;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image,
|
|
+ devpath, NULL, 0, &h);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ goto out;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->StartImage, 3, h, NULL, NULL);
|
|
+ uefi_call_wrapper(BS->UnloadImage, 1, h);
|
|
+
|
|
+ out:
|
|
+ FreePool(PathName);
|
|
+ FreePool(devpath);
|
|
+ return status;
|
|
+}
|
|
diff --git a/lib/guid.c b/lib/guid.c
|
|
new file mode 100644
|
|
index 0000000..25db91a
|
|
--- /dev/null
|
|
+++ b/lib/guid.c
|
|
@@ -0,0 +1,47 @@
|
|
+/*
|
|
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ */
|
|
+
|
|
+#include <guid.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#ifndef BUILD_EFI
|
|
+/* EFI has %g for this, so it's only needed in platform c */
|
|
+const char *guid_to_str(EFI_GUID *guid)
|
|
+{
|
|
+ static char str[256];
|
|
+
|
|
+ sprintf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
|
|
+ guid->Data1, guid->Data2, guid->Data3,
|
|
+ guid->Data4[0], guid->Data4[1], guid->Data4[2],
|
|
+ guid->Data4[3], guid->Data4[4], guid->Data4[5],
|
|
+ guid->Data4[6], guid->Data4[7]);
|
|
+
|
|
+ return str;
|
|
+}
|
|
+
|
|
+void str_to_guid(const char *str, EFI_GUID *guid)
|
|
+{
|
|
+ sscanf(str, "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
|
|
+ &guid->Data1, &guid->Data2, &guid->Data3,
|
|
+ guid->Data4, guid->Data4 + 1, guid->Data4 + 2,
|
|
+ guid->Data4 + 3, guid->Data4 + 4, guid->Data4 + 5,
|
|
+ guid->Data4 + 6, guid->Data4 + 7);
|
|
+}
|
|
+#endif
|
|
+
|
|
+/* all the necessary guids */
|
|
+EFI_GUID GV_GUID = EFI_GLOBAL_VARIABLE;
|
|
+EFI_GUID SIG_DB = { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f }};
|
|
+
|
|
+EFI_GUID X509_GUID = { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} };
|
|
+EFI_GUID RSA2048_GUID = { 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} };
|
|
+EFI_GUID PKCS7_GUID = { 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} };
|
|
+EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
|
|
+EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
|
|
+EFI_GUID EFI_CERT_SHA256_GUID = { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } };
|
|
+EFI_GUID MOK_OWNER = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
|
|
+EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } };
|
|
+EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } };
|
|
diff --git a/lib/security_policy.c b/lib/security_policy.c
|
|
new file mode 100644
|
|
index 0000000..e7becbf
|
|
--- /dev/null
|
|
+++ b/lib/security_policy.c
|
|
@@ -0,0 +1,391 @@
|
|
+/*
|
|
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ *
|
|
+ * Install and remove a platform security2 override policy
|
|
+ */
|
|
+
|
|
+#include <efi.h>
|
|
+#include <efilib.h>
|
|
+
|
|
+#include <guid.h>
|
|
+#include <sha256.h>
|
|
+#include <variables.h>
|
|
+#include <simple_file.h>
|
|
+#include <errors.h>
|
|
+
|
|
+#include <security_policy.h>
|
|
+
|
|
+/*
|
|
+ * See the UEFI Platform Initialization manual (Vol2: DXE) for this
|
|
+ */
|
|
+struct _EFI_SECURITY2_PROTOCOL;
|
|
+struct _EFI_SECURITY_PROTOCOL;
|
|
+typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL;
|
|
+typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL;
|
|
+typedef EFI_DEVICE_PATH EFI_DEVICE_PATH_PROTOCOL;
|
|
+
|
|
+typedef EFI_STATUS (EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) (
|
|
+ const EFI_SECURITY_PROTOCOL *This,
|
|
+ UINT32 AuthenticationStatus,
|
|
+ const EFI_DEVICE_PATH_PROTOCOL *File
|
|
+ );
|
|
+typedef EFI_STATUS (EFIAPI *EFI_SECURITY2_FILE_AUTHENTICATION) (
|
|
+ const EFI_SECURITY2_PROTOCOL *This,
|
|
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
+ VOID *FileBuffer,
|
|
+ UINTN FileSize,
|
|
+ BOOLEAN BootPolicy
|
|
+ );
|
|
+
|
|
+struct _EFI_SECURITY2_PROTOCOL {
|
|
+ EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication;
|
|
+};
|
|
+
|
|
+struct _EFI_SECURITY_PROTOCOL {
|
|
+ EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState;
|
|
+};
|
|
+
|
|
+
|
|
+static UINT8 *security_policy_esl = NULL;
|
|
+static UINTN security_policy_esl_len;
|
|
+
|
|
+static EFI_STATUS
|
|
+security_policy_check_mok(void *data, UINTN len)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+ UINT8 hash[SHA256_DIGEST_SIZE];
|
|
+ UINT32 attr;
|
|
+ UINT8 *VarData;
|
|
+ UINTN VarLen;
|
|
+
|
|
+ /* first check is MokSBState. If we're in insecure mode, boot
|
|
+ * anyway regardless of dbx contents */
|
|
+ status = get_variable_attr(L"MokSBState", &VarData, &VarLen,
|
|
+ MOK_OWNER, &attr);
|
|
+ if (status == EFI_SUCCESS) {
|
|
+ UINT8 MokSBState = VarData[0];
|
|
+
|
|
+ FreePool(VarData);
|
|
+ if ((attr & EFI_VARIABLE_RUNTIME_ACCESS) == 0
|
|
+ && MokSBState)
|
|
+ return EFI_SUCCESS;
|
|
+ }
|
|
+
|
|
+ status = sha256_get_pecoff_digest_mem(data, len, hash);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ return status;
|
|
+
|
|
+ if (find_in_variable_esl(L"dbx", SIG_DB, hash, SHA256_DIGEST_SIZE)
|
|
+ == EFI_SUCCESS)
|
|
+ /* MOK list cannot override dbx */
|
|
+ return EFI_SECURITY_VIOLATION;
|
|
+
|
|
+ status = get_variable_attr(L"MokList", &VarData, &VarLen, MOK_OWNER,
|
|
+ &attr);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ goto check_tmplist;
|
|
+
|
|
+ FreePool(VarData);
|
|
+
|
|
+ if (attr & EFI_VARIABLE_RUNTIME_ACCESS)
|
|
+ goto check_tmplist;
|
|
+
|
|
+ if (find_in_variable_esl(L"MokList", MOK_OWNER, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS)
|
|
+ return EFI_SUCCESS;
|
|
+
|
|
+ check_tmplist:
|
|
+ if (security_policy_esl
|
|
+ && find_in_esl(security_policy_esl, security_policy_esl_len, hash,
|
|
+ SHA256_DIGEST_SIZE) == EFI_SUCCESS)
|
|
+ return EFI_SUCCESS;
|
|
+
|
|
+ return EFI_SECURITY_VIOLATION;
|
|
+}
|
|
+
|
|
+static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
|
|
+static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
|
|
+
|
|
+static EFI_STATUS thunk_security_policy_authentication(
|
|
+ const EFI_SECURITY_PROTOCOL *This,
|
|
+ UINT32 AuthenticationStatus,
|
|
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
+ )
|
|
+__attribute__((unused));
|
|
+
|
|
+static EFI_STATUS thunk_security2_policy_authentication(
|
|
+ const EFI_SECURITY2_PROTOCOL *This,
|
|
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
+ VOID *FileBuffer,
|
|
+ UINTN FileSize,
|
|
+ BOOLEAN BootPolicy
|
|
+ )
|
|
+__attribute__((unused));
|
|
+
|
|
+static __attribute__((used)) EFI_STATUS
|
|
+security2_policy_authentication (
|
|
+ const EFI_SECURITY2_PROTOCOL *This,
|
|
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
+ VOID *FileBuffer,
|
|
+ UINTN FileSize,
|
|
+ BOOLEAN BootPolicy
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS status, auth;
|
|
+
|
|
+ /* Chain original security policy */
|
|
+
|
|
+ status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer,
|
|
+ FileSize, BootPolicy);
|
|
+
|
|
+ /* if OK, don't bother with MOK check */
|
|
+ if (status == EFI_SUCCESS)
|
|
+ return status;
|
|
+
|
|
+ auth = security_policy_check_mok(FileBuffer, FileSize);
|
|
+
|
|
+ if (auth == EFI_SECURITY_VIOLATION || auth == EFI_ACCESS_DENIED)
|
|
+ /* return previous status, which is the correct one
|
|
+ * for the platform: may be either EFI_ACCESS_DENIED
|
|
+ * or EFI_SECURITY_VIOLATION */
|
|
+ return status;
|
|
+
|
|
+ return auth;
|
|
+}
|
|
+
|
|
+static __attribute__((used)) EFI_STATUS
|
|
+security_policy_authentication (
|
|
+ const EFI_SECURITY_PROTOCOL *This,
|
|
+ UINT32 AuthenticationStatus,
|
|
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS status, fail_status;
|
|
+ EFI_DEVICE_PATH *DevPath
|
|
+ = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst),
|
|
+ *OrigDevPath = DevPath;
|
|
+ EFI_HANDLE h;
|
|
+ EFI_FILE *f;
|
|
+ VOID *FileBuffer;
|
|
+ UINTN FileSize;
|
|
+ CHAR16* DevPathStr;
|
|
+
|
|
+ /* Chain original security policy */
|
|
+ status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus,
|
|
+ DevicePathConst);
|
|
+
|
|
+ /* if OK avoid checking MOK: It's a bit expensive to
|
|
+ * read the whole file in again (esfas already did this) */
|
|
+ if (status == EFI_SUCCESS)
|
|
+ goto out;
|
|
+
|
|
+ /* capture failure status: may be either EFI_ACCESS_DENIED or
|
|
+ * EFI_SECURITY_VIOLATION */
|
|
+ fail_status = status;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->LocateDevicePath, 3,
|
|
+ &SIMPLE_FS_PROTOCOL, &DevPath, &h);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ goto out;
|
|
+
|
|
+ DevPathStr = DevicePathToStr(DevPath);
|
|
+
|
|
+ status = simple_file_open_by_handle(h, DevPathStr, &f,
|
|
+ EFI_FILE_MODE_READ);
|
|
+ FreePool(DevPathStr);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ goto out;
|
|
+
|
|
+ status = simple_file_read_all(f, &FileSize, &FileBuffer);
|
|
+ simple_file_close(f);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ goto out;
|
|
+
|
|
+ status = security_policy_check_mok(FileBuffer, FileSize);
|
|
+ FreePool(FileBuffer);
|
|
+
|
|
+ if (status == EFI_ACCESS_DENIED || status == EFI_SECURITY_VIOLATION)
|
|
+ /* return what the platform originally said */
|
|
+ status = fail_status;
|
|
+ out:
|
|
+ FreePool(OrigDevPath);
|
|
+ return status;
|
|
+}
|
|
+
|
|
+
|
|
+/* Nasty: ELF and EFI have different calling conventions. Here is the map for
|
|
+ * calling ELF -> EFI
|
|
+ *
|
|
+ * 1) rdi -> rcx (32 saved)
|
|
+ * 2) rsi -> rdx (32 saved)
|
|
+ * 3) rdx -> r8 ( 32 saved)
|
|
+ * 4) rcx -> r9 (32 saved)
|
|
+ * 5) r8 -> 32(%rsp) (48 saved)
|
|
+ * 6) r9 -> 40(%rsp) (48 saved)
|
|
+ * 7) pad+0(%rsp) -> 48(%rsp) (64 saved)
|
|
+ * 8) pad+8(%rsp) -> 56(%rsp) (64 saved)
|
|
+ * 9) pad+16(%rsp) -> 64(%rsp) (80 saved)
|
|
+ * 10) pad+24(%rsp) -> 72(%rsp) (80 saved)
|
|
+ * 11) pad+32(%rsp) -> 80(%rsp) (96 saved)
|
|
+
|
|
+ *
|
|
+ * So for a five argument callback, the map is ignore the first two arguments
|
|
+ * and then map (EFI -> ELF) assuming pad = 0.
|
|
+ *
|
|
+ * ARG4 -> ARG1
|
|
+ * ARG3 -> ARG2
|
|
+ * ARG5 -> ARG3
|
|
+ * ARG6 -> ARG4
|
|
+ * ARG11 -> ARG5
|
|
+ *
|
|
+ * Calling conventions also differ over volatile and preserved registers in
|
|
+ * MS: RBX, RBP, RDI, RSI, R12, R13, R14, and R15 are considered nonvolatile .
|
|
+ * In ELF: Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling
|
|
+ * function and the called function is required to preserve their values.
|
|
+ *
|
|
+ * This means when accepting a function callback from MS -> ELF, we have to do
|
|
+ * separate preservation on %rdi, %rsi before swizzling the arguments and
|
|
+ * handing off to the ELF function.
|
|
+ */
|
|
+
|
|
+asm (
|
|
+".type security2_policy_authentication,@function\n"
|
|
+"thunk_security2_policy_authentication:\n\t"
|
|
+ "mov 0x28(%rsp), %r10 # ARG5\n\t"
|
|
+ "push %rdi\n\t"
|
|
+ "push %rsi\n\t"
|
|
+ "mov %r10, %rdi\n\t"
|
|
+ "subq $8, %rsp # space for storing stack pad\n\t"
|
|
+ "mov $0x08, %rax\n\t"
|
|
+ "mov $0x10, %r10\n\t"
|
|
+ "and %rsp, %rax\n\t"
|
|
+ "cmovnz %rax, %r11\n\t"
|
|
+ "cmovz %r10, %r11\n\t"
|
|
+ "subq %r11, %rsp\n\t"
|
|
+ "addq $8, %r11\n\t"
|
|
+ "mov %r11, (%rsp)\n\t"
|
|
+"# five argument swizzle\n\t"
|
|
+ "mov %rdi, %r10\n\t"
|
|
+ "mov %rcx, %rdi\n\t"
|
|
+ "mov %rdx, %rsi\n\t"
|
|
+ "mov %r8, %rdx\n\t"
|
|
+ "mov %r9, %rcx\n\t"
|
|
+ "mov %r10, %r8\n\t"
|
|
+ "callq security2_policy_authentication@PLT\n\t"
|
|
+ "mov (%rsp), %r11\n\t"
|
|
+ "addq %r11, %rsp\n\t"
|
|
+ "pop %rsi\n\t"
|
|
+ "pop %rdi\n\t"
|
|
+ "ret\n"
|
|
+);
|
|
+
|
|
+asm (
|
|
+".type security_policy_authentication,@function\n"
|
|
+"thunk_security_policy_authentication:\n\t"
|
|
+ "push %rdi\n\t"
|
|
+ "push %rsi\n\t"
|
|
+ "subq $8, %rsp # space for storing stack pad\n\t"
|
|
+ "mov $0x08, %rax\n\t"
|
|
+ "mov $0x10, %r10\n\t"
|
|
+ "and %rsp, %rax\n\t"
|
|
+ "cmovnz %rax, %r11\n\t"
|
|
+ "cmovz %r10, %r11\n\t"
|
|
+ "subq %r11, %rsp\n\t"
|
|
+ "addq $8, %r11\n\t"
|
|
+ "mov %r11, (%rsp)\n\t"
|
|
+"# three argument swizzle\n\t"
|
|
+ "mov %rcx, %rdi\n\t"
|
|
+ "mov %rdx, %rsi\n\t"
|
|
+ "mov %r8, %rdx\n\t"
|
|
+ "callq security_policy_authentication@PLT\n\t"
|
|
+ "mov (%rsp), %r11\n\t"
|
|
+ "addq %r11, %rsp\n\t"
|
|
+ "pop %rsi\n\t"
|
|
+ "pop %rdi\n\t"
|
|
+ "ret\n"
|
|
+);
|
|
+
|
|
+EFI_STATUS
|
|
+security_policy_install(void)
|
|
+{
|
|
+ EFI_SECURITY_PROTOCOL *security_protocol;
|
|
+ EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
|
|
+ EFI_STATUS status;
|
|
+
|
|
+ if (esfas)
|
|
+ /* Already Installed */
|
|
+ return EFI_ALREADY_STARTED;
|
|
+
|
|
+ /* Don't bother with status here. The call is allowed
|
|
+ * to fail, since SECURITY2 was introduced in PI 1.2.1
|
|
+ * If it fails, use security2_protocol == NULL as indicator */
|
|
+ uefi_call_wrapper(BS->LocateProtocol, 3,
|
|
+ &SECURITY2_PROTOCOL_GUID, NULL,
|
|
+ &security2_protocol);
|
|
+
|
|
+ status = uefi_call_wrapper(BS->LocateProtocol, 3,
|
|
+ &SECURITY_PROTOCOL_GUID, NULL,
|
|
+ &security_protocol);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ /* This one is mandatory, so there's a serious problem */
|
|
+ return status;
|
|
+
|
|
+ if (security2_protocol) {
|
|
+ es2fa = security2_protocol->FileAuthentication;
|
|
+ security2_protocol->FileAuthentication =
|
|
+ thunk_security2_policy_authentication;
|
|
+ }
|
|
+
|
|
+ esfas = security_protocol->FileAuthenticationState;
|
|
+ security_protocol->FileAuthenticationState =
|
|
+ thunk_security_policy_authentication;
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+security_policy_uninstall(void)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+
|
|
+ if (esfas) {
|
|
+ EFI_SECURITY_PROTOCOL *security_protocol;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->LocateProtocol, 3,
|
|
+ &SECURITY_PROTOCOL_GUID, NULL,
|
|
+ &security_protocol);
|
|
+
|
|
+ if (status != EFI_SUCCESS)
|
|
+ return status;
|
|
+
|
|
+ security_protocol->FileAuthenticationState = esfas;
|
|
+ esfas = NULL;
|
|
+ } else {
|
|
+ /* nothing installed */
|
|
+ return EFI_NOT_STARTED;
|
|
+ }
|
|
+
|
|
+ if (es2fa) {
|
|
+ EFI_SECURITY2_PROTOCOL *security2_protocol;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->LocateProtocol, 3,
|
|
+ &SECURITY2_PROTOCOL_GUID, NULL,
|
|
+ &security2_protocol);
|
|
+
|
|
+ if (status != EFI_SUCCESS)
|
|
+ return status;
|
|
+
|
|
+ security2_protocol->FileAuthentication = es2fa;
|
|
+ es2fa = NULL;
|
|
+ }
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+void
|
|
+security_protocol_set_hashes(unsigned char *esl, int len)
|
|
+{
|
|
+ security_policy_esl = esl;
|
|
+ security_policy_esl_len = len;
|
|
+}
|
|
diff --git a/lib/shell.c b/lib/shell.c
|
|
new file mode 100644
|
|
index 0000000..51de4e0
|
|
--- /dev/null
|
|
+++ b/lib/shell.c
|
|
@@ -0,0 +1,57 @@
|
|
+/*
|
|
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ *
|
|
+ * misc shell helper functions
|
|
+ */
|
|
+#include <efi.h>
|
|
+#include <efilib.h>
|
|
+
|
|
+#include <shell.h>
|
|
+
|
|
+EFI_STATUS
|
|
+argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV)
|
|
+{
|
|
+ int i, count = 1;
|
|
+ EFI_STATUS status;
|
|
+ EFI_LOADED_IMAGE *info;
|
|
+ CHAR16 *start;
|
|
+
|
|
+ *argc = 0;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (VOID **) &info);
|
|
+ if (EFI_ERROR(status)) {
|
|
+ Print(L"Failed to get arguments\n");
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < info->LoadOptionsSize; i += 2) {
|
|
+ CHAR16 *c = (CHAR16 *)(info->LoadOptions + i);
|
|
+ if (*c == L' ' && *(c+1) != '\0') {
|
|
+ (*argc)++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ (*argc)++; /* we counted spaces, so add one for initial */
|
|
+
|
|
+ *ARGV = AllocatePool(*argc * sizeof(*ARGV));
|
|
+ if (!*ARGV) {
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+ }
|
|
+ (*ARGV)[0] = (CHAR16 *)info->LoadOptions;
|
|
+ for (i = 0; i < info->LoadOptionsSize; i += 2) {
|
|
+ CHAR16 *c = (CHAR16 *)(info->LoadOptions + i);
|
|
+ if (*c == L' ') {
|
|
+ *c = L'\0';
|
|
+ if (*(c + 1) == '\0')
|
|
+ /* strip trailing space */
|
|
+ break;
|
|
+ start = c + 1;
|
|
+ (*ARGV)[count++] = start;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
diff --git a/lib/simple_file.c b/lib/simple_file.c
|
|
new file mode 100644
|
|
index 0000000..0e5ecd2
|
|
--- /dev/null
|
|
+++ b/lib/simple_file.c
|
|
@@ -0,0 +1,501 @@
|
|
+/*
|
|
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ */
|
|
+
|
|
+#include <efi.h>
|
|
+#include <efilib.h>
|
|
+
|
|
+#include <console.h>
|
|
+#include <simple_file.h>
|
|
+#include <efiauthenticated.h>
|
|
+#include <execute.h> /* for generate_path() */
|
|
+
|
|
+static EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
|
|
+static EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
|
|
+static EFI_GUID FILE_INFO = EFI_FILE_INFO_ID;
|
|
+static EFI_GUID FS_INFO = EFI_FILE_SYSTEM_INFO_ID;
|
|
+
|
|
+EFI_STATUS
|
|
+simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode)
|
|
+{
|
|
+ EFI_STATUS efi_status;
|
|
+ EFI_FILE_IO_INTERFACE *drive;
|
|
+ EFI_FILE *root;
|
|
+
|
|
+ efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
|
|
+ &SIMPLE_FS_PROTOCOL, &drive);
|
|
+
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ Print(L"Unable to find simple file protocol (%d)\n", efi_status);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
|
|
+
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ Print(L"Failed to open drive volume (%d)\n", efi_status);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ efi_status = uefi_call_wrapper(root->Open, 5, root, file, name,
|
|
+ mode, 0);
|
|
+
|
|
+ error:
|
|
+ return efi_status;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode)
|
|
+{
|
|
+ EFI_STATUS efi_status;
|
|
+ EFI_HANDLE device;
|
|
+ EFI_LOADED_IMAGE *li;
|
|
+ EFI_DEVICE_PATH *loadpath = NULL;
|
|
+ CHAR16 *PathName = NULL;
|
|
+
|
|
+ efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
|
|
+ &IMAGE_PROTOCOL, &li);
|
|
+
|
|
+ if (efi_status != EFI_SUCCESS)
|
|
+ return simple_file_open_by_handle(image, name, file, mode);
|
|
+
|
|
+ efi_status = generate_path(name, li, &loadpath, &PathName);
|
|
+
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ Print(L"Unable to generate load path for %s\n", name);
|
|
+ return efi_status;
|
|
+ }
|
|
+
|
|
+ device = li->DeviceHandle;
|
|
+
|
|
+ efi_status = simple_file_open_by_handle(device, PathName, file, mode);
|
|
+
|
|
+ FreePool(PathName);
|
|
+ FreePool(loadpath);
|
|
+
|
|
+ return efi_status;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+simple_dir_read_all_by_handle(EFI_HANDLE image, EFI_FILE *file, CHAR16* name, EFI_FILE_INFO **entries,
|
|
+ int *count)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+ char buf[4096];
|
|
+ UINTN size = sizeof(buf);
|
|
+ EFI_FILE_INFO *fi = (void *)buf;
|
|
+
|
|
+ status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO,
|
|
+ &size, fi);
|
|
+ if (status != EFI_SUCCESS) {
|
|
+ Print(L"Failed to get file info\n");
|
|
+ goto out;
|
|
+ }
|
|
+ if ((fi->Attribute & EFI_FILE_DIRECTORY) == 0) {
|
|
+ Print(L"Not a directory %s\n", name);
|
|
+ status = EFI_INVALID_PARAMETER;
|
|
+ goto out;
|
|
+ }
|
|
+ size = 0;
|
|
+ *count = 0;
|
|
+ for (;;) {
|
|
+ UINTN len = sizeof(buf);
|
|
+ status = uefi_call_wrapper(file->Read, 3, file, &len, buf);
|
|
+ if (status != EFI_SUCCESS || len == 0)
|
|
+ break;
|
|
+ (*count)++;
|
|
+ size += len;
|
|
+ }
|
|
+ uefi_call_wrapper(file->SetPosition, 2, file, 0);
|
|
+
|
|
+ char *ptr = AllocatePool(size);
|
|
+ *entries = (EFI_FILE_INFO *)ptr;
|
|
+ if (!*entries)
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+ int i;
|
|
+ for (i = 0; i < *count; i++) {
|
|
+ int len = size;
|
|
+ uefi_call_wrapper(file->Read, 3, file, &len, ptr);
|
|
+ ptr += len;
|
|
+ size -= len;
|
|
+ }
|
|
+ status = EFI_SUCCESS;
|
|
+ out:
|
|
+ simple_file_close(file);
|
|
+ if (status != EFI_SUCCESS && *entries) {
|
|
+ FreePool(*entries);
|
|
+ *entries = NULL;
|
|
+ }
|
|
+ return status;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+simple_dir_read_all(EFI_HANDLE image, CHAR16 *name, EFI_FILE_INFO **entries,
|
|
+ int *count)
|
|
+{
|
|
+ EFI_FILE *file;
|
|
+ EFI_STATUS status;
|
|
+
|
|
+ status = simple_file_open(image, name, &file, EFI_FILE_MODE_READ);
|
|
+ if (status != EFI_SUCCESS) {
|
|
+ Print(L"failed to open file %s: %d\n", name, status);
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ return simple_dir_read_all_by_handle(image, file, name, entries, count);
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer)
|
|
+{
|
|
+ EFI_STATUS efi_status;
|
|
+ EFI_FILE_INFO *fi;
|
|
+ char buf[1024];
|
|
+
|
|
+ *size = sizeof(buf);
|
|
+ fi = (void *)buf;
|
|
+
|
|
+
|
|
+ efi_status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO,
|
|
+ size, fi);
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ Print(L"Failed to get file info\n");
|
|
+ return efi_status;
|
|
+ }
|
|
+
|
|
+ *size = fi->FileSize;
|
|
+
|
|
+ *buffer = AllocatePool(*size);
|
|
+ if (!*buffer) {
|
|
+ Print(L"Failed to allocate buffer of size %d\n", *size);
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+ }
|
|
+ efi_status = uefi_call_wrapper(file->Read, 3, file, size, *buffer);
|
|
+
|
|
+ return efi_status;
|
|
+}
|
|
+
|
|
+
|
|
+EFI_STATUS
|
|
+simple_file_write_all(EFI_FILE *file, UINTN size, void *buffer)
|
|
+{
|
|
+ EFI_STATUS efi_status;
|
|
+
|
|
+ efi_status = uefi_call_wrapper(file->Write, 3, file, &size, buffer);
|
|
+
|
|
+ return efi_status;
|
|
+}
|
|
+
|
|
+void
|
|
+simple_file_close(EFI_FILE *file)
|
|
+{
|
|
+ uefi_call_wrapper(file->Close, 1, file);
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h)
|
|
+{
|
|
+ UINTN count, i;
|
|
+ EFI_HANDLE *vol_handles = NULL;
|
|
+ EFI_STATUS status;
|
|
+ CHAR16 **entries;
|
|
+ int val;
|
|
+
|
|
+ uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol,
|
|
+ &SIMPLE_FS_PROTOCOL, NULL, &count, &vol_handles);
|
|
+
|
|
+ if (!count || !vol_handles)
|
|
+ return EFI_NOT_FOUND;
|
|
+
|
|
+ entries = AllocatePool(sizeof(CHAR16 *) * (count+1));
|
|
+ if (!entries)
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+
|
|
+ for (i = 0; i < count; i++) {
|
|
+ char buf[4096];
|
|
+ UINTN size = sizeof(buf);
|
|
+ EFI_FILE_SYSTEM_INFO *fi = (void *)buf;
|
|
+ EFI_FILE *root;
|
|
+ CHAR16 *name;
|
|
+ EFI_FILE_IO_INTERFACE *drive;
|
|
+
|
|
+ status = uefi_call_wrapper(BS->HandleProtocol, 3,
|
|
+ vol_handles[i],
|
|
+ &SIMPLE_FS_PROTOCOL, &drive);
|
|
+ if (status != EFI_SUCCESS || !drive)
|
|
+ continue;
|
|
+
|
|
+ status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ continue;
|
|
+
|
|
+ status = uefi_call_wrapper(root->GetInfo, 4, root, &FS_INFO,
|
|
+ &size, fi);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ continue;
|
|
+
|
|
+ name = fi->VolumeLabel;
|
|
+
|
|
+ if (!name || StrLen(name) == 0 || StrCmp(name, L" ") == 0)
|
|
+ name = DevicePathToStr(DevicePathFromHandle(vol_handles[i]));
|
|
+
|
|
+ entries[i] = AllocatePool((StrLen(name) + 2) * sizeof(CHAR16));
|
|
+ if (!entries[i])
|
|
+ break;
|
|
+ StrCpy(entries[i], name);
|
|
+ }
|
|
+ entries[i] = NULL;
|
|
+
|
|
+ val = console_select(title, entries, 0);
|
|
+
|
|
+ if (val >= 0) {
|
|
+ *selected = AllocatePool((StrLen(entries[val]) + 1) * sizeof(CHAR16));
|
|
+ if (*selected) {
|
|
+ StrCpy(*selected , entries[val]);
|
|
+ }
|
|
+ *h = vol_handles[val];
|
|
+ } else {
|
|
+ *selected = NULL;
|
|
+ *h = 0;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < count; i++) {
|
|
+ if (entries[i])
|
|
+ FreePool(entries[i]);
|
|
+ }
|
|
+ FreePool(entries);
|
|
+ FreePool(vol_handles);
|
|
+
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+simple_dir_filter(EFI_HANDLE image, CHAR16 *name, CHAR16 *filter,
|
|
+ CHAR16 ***result, int *count, EFI_FILE_INFO **entries)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+ int tot, offs = StrLen(filter), i, c, filtercount = 1;
|
|
+ EFI_FILE_INFO *next;
|
|
+ void *ptr;
|
|
+ CHAR16 *newfilter = AllocatePool((StrLen(filter) + 1) * sizeof(CHAR16)),
|
|
+ **filterarr;
|
|
+
|
|
+ if (!newfilter)
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+
|
|
+ /* just in case efi ever stops writeable strings */
|
|
+ StrCpy(newfilter, filter);
|
|
+
|
|
+ for (i = 0; i < offs; i++) {
|
|
+ if (filter[i] == '|')
|
|
+ filtercount++;
|
|
+ }
|
|
+ filterarr = AllocatePool(filtercount * sizeof(void *));
|
|
+ if (!filterarr)
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+ c = 0;
|
|
+ filterarr[c++] = newfilter;
|
|
+ for (i = 0; i < offs; i++) {
|
|
+ if (filter[i] == '|') {
|
|
+ newfilter[i] = '\0';
|
|
+ filterarr[c++] = &newfilter[i+1];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *count = 0;
|
|
+
|
|
+ status = simple_dir_read_all(image, name, entries, &tot);
|
|
+
|
|
+ if (status != EFI_SUCCESS)
|
|
+ goto out;
|
|
+ ptr = next = *entries;
|
|
+
|
|
+ for (i = 0; i < tot; i++) {
|
|
+ int len = StrLen(next->FileName);
|
|
+
|
|
+ for (c = 0; c < filtercount; c++) {
|
|
+ offs = StrLen(filterarr[c]);
|
|
+
|
|
+ if (StrCmp(&next->FileName[len - offs], filterarr[c]) == 0
|
|
+ || (next->Attribute & EFI_FILE_DIRECTORY)) {
|
|
+ (*count)++;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ ptr += OFFSET_OF(EFI_FILE_INFO, FileName) + (len + 1)*sizeof(CHAR16);
|
|
+ next = ptr;
|
|
+ }
|
|
+ if (*count)
|
|
+ *result = AllocatePool(((*count) + 1) * sizeof(void *));
|
|
+ else
|
|
+ *result = AllocatePool(2 * sizeof(void *));
|
|
+
|
|
+ *count = 0;
|
|
+ ptr = next = *entries;
|
|
+
|
|
+ for (i = 0; i < tot; i++) {
|
|
+ int len = StrLen(next->FileName);
|
|
+
|
|
+ if (StrCmp(next->FileName, L".") == 0)
|
|
+ /* ignore . directory */
|
|
+ goto next;
|
|
+
|
|
+ if (next->Attribute & EFI_FILE_DIRECTORY) {
|
|
+ (*result)[(*count)] = next->FileName;
|
|
+ (*result)[(*count)][len] = '/';
|
|
+ (*result)[(*count)++][len + 1] = '\0';
|
|
+ goto next;
|
|
+ }
|
|
+
|
|
+ for (c = 0; c < filtercount; c++) {
|
|
+ offs = StrLen(filterarr[c]);
|
|
+
|
|
+ if (StrCmp(&next->FileName[len - offs], filterarr[c]) == 0) {
|
|
+ (*result)[(*count)++] = next->FileName;
|
|
+ } else {
|
|
+ continue;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ next:
|
|
+ if (StrCmp(next->FileName, L"../") == 0) {
|
|
+ /* place .. directory first */
|
|
+ CHAR16 *tmp = (*result)[(*count) - 1];
|
|
+
|
|
+ (*result)[(*count) - 1] = (*result)[0];
|
|
+ (*result)[0] = tmp;
|
|
+ }
|
|
+
|
|
+ ptr += OFFSET_OF(EFI_FILE_INFO, FileName) + (len + 1)*sizeof(CHAR16);
|
|
+ next = ptr;
|
|
+ }
|
|
+ if (*count == 0) {
|
|
+ /* no entries at all ... can happen because top level dir has no . or .. */
|
|
+ (*result)[(*count)++] = L"./";
|
|
+ }
|
|
+ (*result)[*count] = NULL;
|
|
+ status = EFI_SUCCESS;
|
|
+
|
|
+ out:
|
|
+ if (status != EFI_SUCCESS) {
|
|
+ if (*entries)
|
|
+ FreePool(*entries);
|
|
+ *entries = NULL;
|
|
+ if (*result)
|
|
+ FreePool(*result);
|
|
+ *result = NULL;
|
|
+ }
|
|
+ return status;
|
|
+}
|
|
+
|
|
+void
|
|
+simple_file_selector(EFI_HANDLE *im, CHAR16 **title, CHAR16 *name,
|
|
+ CHAR16 *filter, CHAR16 **result)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+ CHAR16 **entries;
|
|
+ EFI_FILE_INFO *dmp;
|
|
+ int count, select, len;
|
|
+ CHAR16 *newname, *selected;
|
|
+
|
|
+ *result = NULL;
|
|
+ if (!name)
|
|
+ name = L"\\";
|
|
+ if (!filter)
|
|
+ filter = L"";
|
|
+ if (!*im) {
|
|
+ EFI_HANDLE h;
|
|
+ CHAR16 *volname;
|
|
+
|
|
+ simple_volume_selector(title, &volname, &h);
|
|
+ if (!volname)
|
|
+ return;
|
|
+ FreePool(volname);
|
|
+ *im = h;
|
|
+ }
|
|
+
|
|
+ newname = AllocatePool((StrLen(name) + 1)*sizeof(CHAR16));
|
|
+ if (!newname)
|
|
+ return;
|
|
+
|
|
+ StrCpy(newname, name);
|
|
+ name = newname;
|
|
+
|
|
+ redo:
|
|
+ status = simple_dir_filter(*im, name, filter, &entries, &count, &dmp);
|
|
+
|
|
+ if (status != EFI_SUCCESS)
|
|
+ goto out_free_name;
|
|
+
|
|
+ select = console_select(title, entries, 0);
|
|
+ if (select < 0)
|
|
+ /* ESC key */
|
|
+ goto out_free;
|
|
+ selected = entries[select];
|
|
+ FreePool(entries);
|
|
+ entries = NULL;
|
|
+ /* note that memory used by selected is valid until dmp is freed */
|
|
+ len = StrLen(selected);
|
|
+ if (selected[len - 1] == '/') {
|
|
+ CHAR16 *newname;
|
|
+
|
|
+ /* stay where we are */
|
|
+ if (StrCmp(selected, L"./") == 0) {
|
|
+ FreePool(dmp);
|
|
+ goto redo;
|
|
+ } else if (StrCmp(selected, L"../") == 0) {
|
|
+ int i;
|
|
+
|
|
+ i = StrLen(name) - 1;
|
|
+
|
|
+
|
|
+ for (i = StrLen(name); i > 0; --i) {
|
|
+ if (name[i] == '\\')
|
|
+ break;
|
|
+ }
|
|
+ if (i == 0)
|
|
+ i = 1;
|
|
+
|
|
+ if (StrCmp(name, L"\\") != 0
|
|
+ && StrCmp(&name[i], L"..") != 0) {
|
|
+ name[i] = '\0';
|
|
+ FreePool(dmp);
|
|
+ goto redo;
|
|
+ }
|
|
+ }
|
|
+ newname = AllocatePool((StrLen(name) + len + 2)*sizeof(CHAR16));
|
|
+ if (!newname)
|
|
+ goto out_free;
|
|
+ StrCpy(newname, name);
|
|
+
|
|
+ if (name[StrLen(name) - 1] != '\\')
|
|
+ StrCat(newname, L"\\");
|
|
+ StrCat(newname, selected);
|
|
+ /* remove trailing / */
|
|
+ newname[StrLen(newname) - 1] = '\0';
|
|
+
|
|
+ FreePool(dmp);
|
|
+ FreePool(name);
|
|
+ name = newname;
|
|
+
|
|
+ goto redo;
|
|
+ }
|
|
+ *result = AllocatePool((StrLen(name) + len + 2)*sizeof(CHAR16));
|
|
+ if (*result) {
|
|
+ StrCpy(*result, name);
|
|
+ if (name[StrLen(name) - 1] != '\\')
|
|
+ StrCat(*result, L"\\");
|
|
+ StrCat(*result, selected);
|
|
+ }
|
|
+
|
|
+ out_free:
|
|
+ FreePool(dmp);
|
|
+ if (entries)
|
|
+ FreePool(entries);
|
|
+ out_free_name:
|
|
+ FreePool(name);
|
|
+}
|
|
diff --git a/lib/variables.c b/lib/variables.c
|
|
new file mode 100644
|
|
index 0000000..9db6480
|
|
--- /dev/null
|
|
+++ b/lib/variables.c
|
|
@@ -0,0 +1,340 @@
|
|
+/*
|
|
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
|
+ *
|
|
+ * see COPYING file
|
|
+ *
|
|
+ * Portions of this file are a direct cut and paste from Tianocore
|
|
+ * (http://tianocore.sf.net)
|
|
+ *
|
|
+ * SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
|
|
+ *
|
|
+ * Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
|
|
+ * This program and the accompanying materials
|
|
+ * are licensed and made available under the terms and conditions of the BSD License
|
|
+ * which accompanies this distribution. The full text of the license may be found
|
|
+ * at
|
|
+ * http://opensource.org/licenses/bsd-license.php
|
|
+ *
|
|
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
+ *
|
|
+ */
|
|
+#include <efi.h>
|
|
+#include <efilib.h>
|
|
+
|
|
+#include <efiauthenticated.h>
|
|
+
|
|
+#include <variables.h>
|
|
+#include <guid.h>
|
|
+#include <console.h>
|
|
+#include <sha256.h>
|
|
+#include <errors.h>
|
|
+
|
|
+EFI_STATUS
|
|
+variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner,
|
|
+ void **out, int *outlen)
|
|
+{
|
|
+ *outlen = cert_len + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
|
|
+
|
|
+ *out = AllocateZeroPool(*outlen);
|
|
+ if (!*out)
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+
|
|
+ EFI_SIGNATURE_LIST *sl = *out;
|
|
+
|
|
+ sl->SignatureHeaderSize = 0;
|
|
+ sl->SignatureType = *type;
|
|
+ sl->SignatureSize = cert_len + sizeof(EFI_GUID);
|
|
+ sl->SignatureListSize = *outlen;
|
|
+
|
|
+ EFI_SIGNATURE_DATA *sd = *out + sizeof(EFI_SIGNATURE_LIST);
|
|
+
|
|
+ if (owner)
|
|
+ sd->SignatureOwner = *owner;
|
|
+
|
|
+ CopyMem(sd->SignatureData, cert, cert_len);
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+
|
|
+EFI_STATUS
|
|
+CreateTimeBasedPayload (
|
|
+ IN OUT UINTN *DataSize,
|
|
+ IN OUT UINT8 **Data
|
|
+ )
|
|
+{
|
|
+ EFI_STATUS Status;
|
|
+ UINT8 *NewData;
|
|
+ UINT8 *Payload;
|
|
+ UINTN PayloadSize;
|
|
+ EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
|
|
+ UINTN DescriptorSize;
|
|
+ EFI_TIME Time;
|
|
+ EFI_GUID efi_cert_type = EFI_CERT_TYPE_PKCS7_GUID;
|
|
+
|
|
+ if (Data == NULL || DataSize == NULL) {
|
|
+ return EFI_INVALID_PARAMETER;
|
|
+ }
|
|
+
|
|
+ //
|
|
+ // In Setup mode or Custom mode, the variable does not need to be signed but the
|
|
+ // parameters to the SetVariable() call still need to be prepared as authenticated
|
|
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
|
|
+ // data in it.
|
|
+ //
|
|
+ Payload = *Data;
|
|
+ PayloadSize = *DataSize;
|
|
+
|
|
+ DescriptorSize = OFFSET_OF(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
|
|
+ NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);
|
|
+ if (NewData == NULL) {
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+ }
|
|
+
|
|
+ if ((Payload != NULL) && (PayloadSize != 0)) {
|
|
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
|
|
+ }
|
|
+
|
|
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
|
|
+
|
|
+ ZeroMem (&Time, sizeof (EFI_TIME));
|
|
+ Status = uefi_call_wrapper(RT->GetTime,2, &Time, NULL);
|
|
+ if (EFI_ERROR (Status)) {
|
|
+ FreePool(NewData);
|
|
+ return Status;
|
|
+ }
|
|
+ Time.Pad1 = 0;
|
|
+ Time.Nanosecond = 0;
|
|
+ Time.TimeZone = 0;
|
|
+ Time.Daylight = 0;
|
|
+ Time.Pad2 = 0;
|
|
+ CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
|
|
+
|
|
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
|
|
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
|
|
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
|
|
+ DescriptorData->AuthInfo.CertType = efi_cert_type;
|
|
+
|
|
+ /* we're expecting an EFI signature list, so don't free the input since
|
|
+ * it might not be in a pool */
|
|
+#if 0
|
|
+ if (Payload != NULL) {
|
|
+ FreePool(Payload);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ *DataSize = DescriptorSize + PayloadSize;
|
|
+ *Data = NewData;
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+SetSecureVariable(CHAR16 *var, UINT8 *Data, UINTN len, EFI_GUID owner,
|
|
+ UINT32 options, int createtimebased)
|
|
+{
|
|
+ EFI_SIGNATURE_LIST *Cert;
|
|
+ UINTN DataSize;
|
|
+ EFI_STATUS efi_status;
|
|
+
|
|
+ /* Microsoft request: Bugs in some UEFI platforms mean that PK or any
|
|
+ * other secure variable can be updated or deleted programmatically,
|
|
+ * so prevent */
|
|
+ if (!variable_is_setupmode())
|
|
+ return EFI_SECURITY_VIOLATION;
|
|
+
|
|
+ if (createtimebased) {
|
|
+ int ds;
|
|
+ efi_status = variable_create_esl(Data, len, &X509_GUID, NULL,
|
|
+ (void **)&Cert, &ds);
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ Print(L"Failed to create %s certificate %d\n", var, efi_status);
|
|
+ return efi_status;
|
|
+ }
|
|
+
|
|
+ DataSize = ds;
|
|
+ } else {
|
|
+ /* we expect an efi signature list rather than creating it */
|
|
+ Cert = (EFI_SIGNATURE_LIST *)Data;
|
|
+ DataSize = len;
|
|
+ }
|
|
+ efi_status = CreateTimeBasedPayload(&DataSize, (UINT8 **)&Cert);
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ Print(L"Failed to create time based payload %d\n", efi_status);
|
|
+ return efi_status;
|
|
+ }
|
|
+
|
|
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner,
|
|
+ EFI_VARIABLE_NON_VOLATILE
|
|
+ | EFI_VARIABLE_RUNTIME_ACCESS
|
|
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
|
|
+ | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
|
|
+ | options,
|
|
+ DataSize, Cert);
|
|
+
|
|
+ return efi_status;
|
|
+}
|
|
+
|
|
+UINT64
|
|
+GetOSIndications(void)
|
|
+{
|
|
+ UINT64 indications;
|
|
+ UINTN DataSize = sizeof(indications);
|
|
+ EFI_STATUS efi_status;
|
|
+
|
|
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"OsIndicationsSupported", &GV_GUID, NULL, &DataSize, &indications);
|
|
+ if (efi_status != EFI_SUCCESS)
|
|
+ return 0;
|
|
+
|
|
+ return indications;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+SETOSIndicationsAndReboot(UINT64 indications)
|
|
+{
|
|
+ UINTN DataSize = sizeof(indications);
|
|
+ EFI_STATUS efi_status;
|
|
+
|
|
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"OsIndications",
|
|
+ &GV_GUID,
|
|
+ EFI_VARIABLE_NON_VOLATILE
|
|
+ | EFI_VARIABLE_RUNTIME_ACCESS
|
|
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
+ DataSize, &indications);
|
|
+
|
|
+ if (efi_status != EFI_SUCCESS)
|
|
+ return efi_status;
|
|
+
|
|
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL);
|
|
+ /* does not return */
|
|
+
|
|
+ return EFI_SUCCESS;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+get_variable_attr(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner,
|
|
+ UINT32 *attributes)
|
|
+{
|
|
+ EFI_STATUS efi_status;
|
|
+
|
|
+ *len = 0;
|
|
+
|
|
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner,
|
|
+ NULL, len, NULL);
|
|
+ if (efi_status != EFI_BUFFER_TOO_SMALL)
|
|
+ return efi_status;
|
|
+
|
|
+ *data = AllocateZeroPool(*len);
|
|
+ if (!data)
|
|
+ return EFI_OUT_OF_RESOURCES;
|
|
+
|
|
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner,
|
|
+ attributes, len, *data);
|
|
+
|
|
+ if (efi_status != EFI_SUCCESS) {
|
|
+ FreePool(*data);
|
|
+ *data = NULL;
|
|
+ }
|
|
+ return efi_status;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+get_variable(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner)
|
|
+{
|
|
+ return get_variable_attr(var, data, len, owner, NULL);
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+find_in_esl(UINT8 *Data, UINTN DataSize, UINT8 *key, UINTN keylen)
|
|
+{
|
|
+ EFI_SIGNATURE_LIST *CertList;
|
|
+
|
|
+ certlist_for_each_certentry(CertList, Data, DataSize, DataSize) {
|
|
+ if (CertList->SignatureSize != keylen + sizeof(EFI_GUID))
|
|
+ continue;
|
|
+ EFI_SIGNATURE_DATA *Cert;
|
|
+
|
|
+ certentry_for_each_cert(Cert, CertList)
|
|
+ if (CompareMem (Cert->SignatureData, key, keylen) == 0)
|
|
+ return EFI_SUCCESS;
|
|
+ }
|
|
+ return EFI_NOT_FOUND;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+find_in_variable_esl(CHAR16* var, EFI_GUID owner, UINT8 *key, UINTN keylen)
|
|
+{
|
|
+ UINTN DataSize;
|
|
+ UINT8 *Data;
|
|
+ EFI_STATUS status;
|
|
+
|
|
+ status = get_variable(var, &Data, &DataSize, owner);
|
|
+ if (status != EFI_SUCCESS)
|
|
+ return status;
|
|
+
|
|
+ status = find_in_esl(Data, DataSize, key, keylen);
|
|
+
|
|
+ FreePool(Data);
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+int
|
|
+variable_is_setupmode(void)
|
|
+{
|
|
+ /* set to 1 because we return true if SetupMode doesn't exist */
|
|
+ UINT8 SetupMode = 1;
|
|
+ UINTN DataSize = sizeof(SetupMode);
|
|
+
|
|
+ uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL,
|
|
+ &DataSize, &SetupMode);
|
|
+
|
|
+ return SetupMode;
|
|
+}
|
|
+
|
|
+int
|
|
+variable_is_secureboot(void)
|
|
+{
|
|
+ /* return false if variable doesn't exist */
|
|
+ UINT8 SecureBoot = 0;
|
|
+ UINTN DataSize;
|
|
+
|
|
+ DataSize = sizeof(SecureBoot);
|
|
+ uefi_call_wrapper(RT->GetVariable, 5, L"SecureBoot", &GV_GUID, NULL,
|
|
+ &DataSize, &SecureBoot);
|
|
+
|
|
+ return SecureBoot;
|
|
+}
|
|
+
|
|
+EFI_STATUS
|
|
+variable_enroll_hash(CHAR16 *var, EFI_GUID owner,
|
|
+ UINT8 hash[SHA256_DIGEST_SIZE])
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+
|
|
+ if (find_in_variable_esl(var, owner, hash, SHA256_DIGEST_SIZE)
|
|
+ == EFI_SUCCESS)
|
|
+ /* hash already present */
|
|
+ return EFI_ALREADY_STARTED;
|
|
+
|
|
+ UINT8 sig[sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + SHA256_DIGEST_SIZE];
|
|
+ EFI_SIGNATURE_LIST *l = (void *)sig;
|
|
+ EFI_SIGNATURE_DATA *d = (void *)sig + sizeof(EFI_SIGNATURE_LIST);
|
|
+ SetMem(sig, 0, sizeof(sig));
|
|
+ l->SignatureType = EFI_CERT_SHA256_GUID;
|
|
+ l->SignatureListSize = sizeof(sig);
|
|
+ l->SignatureSize = 16 +32; /* UEFI defined */
|
|
+ CopyMem(&d->SignatureData, hash, SHA256_DIGEST_SIZE);
|
|
+ d->SignatureOwner = MOK_OWNER;
|
|
+
|
|
+ if (CompareGuid(&owner, &SIG_DB) == 0)
|
|
+ status = SetSecureVariable(var, sig, sizeof(sig), owner,
|
|
+ EFI_VARIABLE_APPEND_WRITE, 0);
|
|
+ else
|
|
+ status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner,
|
|
+ EFI_VARIABLE_NON_VOLATILE
|
|
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
|
|
+ | EFI_VARIABLE_APPEND_WRITE,
|
|
+ sizeof(sig), sig);
|
|
+ return status;
|
|
+}
|
|
--
|
|
1.8.1.4
|
|
|