Skip to content

Commit

Permalink
Add a new [DETECT] mode for DB that reuses an existing cert if present
Browse files Browse the repository at this point in the history
* Also add Utf16ToUtf8() and replace UCS-2 references to UTS-16
  (since we are actually processing UTF-16 and not UCS-2).
* Also add SimpleFileExistsByPath() and update the README.
  • Loading branch information
pbatard committed Aug 21, 2024
1 parent 9378469 commit a9e40c5
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 62 deletions.
56 changes: 37 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,66 @@ Shell application designed to easily create and install a more secure (and more
default set of UEFI Secure Boot keys that includes your own Secure Boot signing credentials,
as well as a **unique**, non-exploitable, machine Primary Key (PK).

The motivation behind this is fourfold:

1. In 2023, Microsoft introduced a new Key Exchange Key (KEK) as well as two new Secure Boot
whitelisting certificates (DBs), that are not present (and especially for the KEK) cannot
be installed through standard key update or key restoration procedures.
The motivations behind this are as follows:

1. Two of the Secure Boot whitelisting (*DB*) certificates, commonly used for Secure Boot
validation (`Microsoft Windows Production PCA 2011` and `Microsoft Corporation UEFI CA 2011`)
as well as Microsoft's main Key Exchange Key (*KEK*) certificate
(`Microsoft Corporation KEK CA 2011`) **are set to expire in the second half of 2026**.
Whereas, in itself, this will not prevent **existing** Secure Boot signed bootloaders from
validating (as long as they haven't been revoked through other means) it will however
prevent any **newer** UEFI bootloader from doing so which basically means that, if your OS
or OS installater was produced after those DB certificates expire, and you don't have the
additional 2023 DB certificates installed (see below), then, come the second half of 2026,
you will not be able to boot or even install a Secure Boot compatible OS in a Secure Boot
enabled environment!
This application can remedy that.
2. In 2023, because of the expiration of the certificates listed above, Microsoft introduced
one new *KEK* and two new *DB* certificates, that are erefore not be commonly found in your
system manufacturer's default key (especially if your system has not received any firmware
update since 2024) and that (because a *KEK* can **only** be installed through updates
[that are signed by the platform manufacturer](https://uefi.org/specs/UEFI/2.9_A/32_Secure_Boot_and_Driver_Signing.html#enrolling-key-exchange-keys))
cannot be fully updated from the OS itself, even if the OS is Secure Boot compatible or
comes from Micosoft.
This application can remedy that.
2. As of the second half of 2024, and due to
3. As of the second half of 2024, and due to
[many](https://arstechnica.com/information-technology/2023/03/unkillable-uefi-malware-bypassing-secure-boot-enabled-by-unpatchable-windows-flaw/),
[many](https://wack0.github.io/dubiousdisk/) vulnerabilities uncovered in the UEFI Windows
bootloaders, Microsoft is in the process of **completely removing** one of the base DB
certificates that it has been using to sign its UEFI executables since 2011.
certificates that it has been using to sign its UEFI executables since 2011.
This application can make sure that this DB certificate is properly removed (as opposed to
what will happen if you use the native Secure Boot key restoration from your UEFI
firmware).
3. In 2024, it was disovered that some PC manufacturers [played fast and loose with the
Primary Key (PK) shipped with their hardware](https://arstechnica.com/security/2024/07/secure-boot-is-completely-compromised-on-200-models-from-5-big-device-makers/),
4. In 2024, it was disovered that some PC manufacturers [played fast and loose with the
Primary Key (*PK*) shipped with their hardware](https://arstechnica.com/security/2024/07/secure-boot-is-completely-compromised-on-200-models-from-5-big-device-makers/),
basically meaning that malicious actors could gain access to the secret key, and therefore
gain full trusted access of the affected machines. It is also very likely (though of
course it is in their interest not to reveal it) that, PC manufacturers have had more PK
course it is in their interest not to reveal it) that, PC manufacturers have had more *PK*
private key exfiltered into the hand of malicious actors (or, if you are living under an
authoritative regime, have been forced to hand them over to said regime), leading to the
same very real risk of a third parties exploiting this data to install UEFI rootkits on
users' computers.
users' computers.
With its default settings, this application can fully remedy that.
4. OS manufacturers, such as Microsoft, have long taken a very user-adverse stance against
5. OS manufacturers, such as Microsoft, have long taken a very user-adverse stance against
the ability of individuals to ultimately be in control the UEFI boot signing process, by,
to name just a few instances, using fake rethoric against some software licenses in order
to arbitrarily deny common Linux bootloaders such as GRUB from being Secure Boot signed,
trying to lock down hardware so that Secure Boot could not ever been disabled by the user,
making a two-tier version of Secure Boot signatures with one exclusive tier for Windows
and a lower tier for other OSes and application or even trying to prevent anybody that is
not an OS or hardware manufacturer from being allowed to redistribute the UEFI revocation
lists...
lists...
The end result is that it has become a lot more convoluted and daunting than it should
really be for end-users, to make Secure Boot work in their favour.
really be for end-users, to make Secure Boot work in their favour.
This application can also remedy that.

In short, the whole point of this application is to give control of the whole Secure Boot
process back to **YOU**, like it should always have been, instead of leaving it in control of
a select few, who may not have your interests in mind, and, over and over, have demonstrated
behaviour that should not warrant your blind trust. And it does so by making incredibly
**easy** to install your own set of Secure Boot keys.
In short, while making sure that all the Secure Boot keys used by your platform are up to
date, the whole point of this application is to give control of the whole Secure Boot process
back to **YOU**, like it should always have been, instead of leaving it in control of a
select few, who may not have your interests in mind, and, over and over, have demonstrated
behaviour that should not warrant your blind trust.

And it does so by making incredibly **easy** to install your own set of Secure Boot keys.

## Usage

Expand Down
8 changes: 5 additions & 3 deletions image/MosbyList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
# curl --create-dirs -L https://uefi.org/sites/default/files/resources/arm_DBXUpdate.bin -o dbx/dbx_arm.bin
# curl --create-dirs -L https://uefi.org/sites/default/files/resources/arm64_DBXUpdate.bin -o dbx/dbx_aa64.bin
PK [GENERATE]
# 'kek_ms1.cer' ("Microsoft Corporation KEK CA 2011") expires on 2026-06-24
KEK certs\kek_ms1.cer
KEK certs\kek_ms2.cer
# ms_db1.cer ("Microsoft Windows Production PCA 2011") should ultimately be commented out as it is being revoked by Microsoft
# 'ms_db1.cer' ("Microsoft Windows Production PCA 2011") should ultimately be commented out as it is being revoked by Microsoft
DB certs\db_ms1.cer
# 'db_ms2.cer' ("Microsoft Corporation UEFI CA 2011") expires on 2026.06.27
DB certs\db_ms2.cer
DB certs\db_ms3.cer
DB certs\db_ms4.cer
DB [GENERATE]
# %ARCH% will be replaced with the runtime arch ('x64', 'ia32', 'arm', 'aa64')
DB [DETECT]
# %ARCH% will be replaced with the actual runtime arch ('x64', 'ia32', 'arm', 'aa64')
DBX dbx\dbx_%ARCH%.bin
19 changes: 18 additions & 1 deletion src/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ STATIC CONST CHAR16* GetDeviceHandleFromPath(
UINTN ColumnPos;
CHAR16 DriveName[64];

// Default to using the same device as our current executable
// Default to using the same device the one from the Image passed as parameter
Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID**)&LoadedImage);
*DeviceHandle = EFI_ERROR(Status) ? NULL : LoadedImage->DeviceHandle;

Expand Down Expand Up @@ -697,3 +697,20 @@ EFI_STATUS SimpleFileWriteAllByPath(
SimpleFileClose(File);
return Status;
}

BOOLEAN SimpleFileExistsByPath(
IN CONST EFI_HANDLE Image,
IN CONST CHAR16* Path
)
{
EFI_STATUS Status;
EFI_HANDLE DeviceHandle;
EFI_FILE_HANDLE File = NULL;
CONST CHAR16 *PathStart;

PathStart = GetDeviceHandleFromPath(Image, Path, &DeviceHandle);
Status = SimpleFileOpen(DeviceHandle == NULL ? Image : DeviceHandle,
PathStart, &File, EFI_FILE_MODE_READ);
SimpleFileClose(File);
return (Status == EFI_SUCCESS);
}
5 changes: 5 additions & 0 deletions src/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,8 @@ EFI_STATUS SimpleFileWriteAllByPath(
IN CONST UINTN Size,
IN CONST VOID *Buffer
);

BOOLEAN SimpleFileExistsByPath(
IN CONST EFI_HANDLE Image,
IN CONST CHAR16* Path
);
30 changes: 22 additions & 8 deletions src/mosby.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ STATIC EFI_STATUS ConvertPath(
Old = *Ptr;
*Ptr = 0;
if (*Src != '\0') {
Status = Utf8ToUcs2(Src, Frag, ARRAY_SIZE(Frag));
Status = Utf8ToUtf16(Src, Frag, ARRAY_SIZE(Frag));
if (EFI_ERROR(Status))
ReportErrorAndExit(L"Failed to convert '%a'\n", Src);
Status = StrCatS(Dst, DstLen, Frag);
Expand All @@ -179,7 +179,7 @@ STATIC EFI_STATUS ConvertPath(
*Ptr = Old;
}
if (*Src != '\0') {
Status = Utf8ToUcs2(Src, Frag, ARRAY_SIZE(Frag));
Status = Utf8ToUtf16(Src, Frag, ARRAY_SIZE(Frag));
if (EFI_ERROR(Status))
ReportErrorAndExit(L"Failed to convert '%a'\n", Src);
Status = StrCatS(Dst, DstLen, Frag);
Expand Down Expand Up @@ -250,6 +250,7 @@ EFI_STATUS EFIAPI efi_main(
UINTN Size;
INTN Argc, Type, Entry;
VOID *Cert, *Key;
CHAR8 Utf8Path[MAX_PATH];
CHAR16 **Argv = NULL, **ArgvCopy, Path[MAX_PATH];
INSTALLABLE_COLLECTION Installable = { 0 };

Expand All @@ -268,16 +269,15 @@ EFI_STATUS EFIAPI efi_main(
gOptionSilent = TRUE;
ArgvCopy += 1;
Argc -= 1;
} else if (StrCmp(ArgvCopy[1], L"-v") == 0) {
Print(L"Mosby %s\n", VERSION_STRING);
goto exit;
} else {
// Unsupported argument
break;
}
}
}

Print(L"Mosby %s\n", VERSION_STRING);

/* 1. Verify that the platform is in Setup Mode */
if (!TestMode) {
Size = sizeof(SecureBoot);
Expand All @@ -288,7 +288,8 @@ EFI_STATUS EFIAPI efi_main(
Status = gRT->GetVariable(L"SetupMode", &gEfiGlobalVariableGuid, NULL, &Size, &SetupMode);
if (EFI_ERROR(Status) || SecureBoot != 0 || SetupMode == 0) {
Status = EFI_UNSUPPORTED;
ReportErrorAndExit(L"This platform is not in Setup Mode.\n");
ReportErrorAndExit(L"ERROR: This platform is not in Setup Mode.\n");
// TODO: More explanatory error message and possibly automate switch to Setup?
}
}

Expand Down Expand Up @@ -334,10 +335,22 @@ EFI_STATUS EFIAPI efi_main(
for (Type = 0; Type < MAX_TYPES; Type++) {
for (Entry = 0; Entry < Installable.List[Type].NumEntries && Installable.List[Type].Path[Entry] != NULL; Entry++) {

// DB/PK types have a special GENERATE and PROMPT mode
// DB/PK types have modes such as [DETECT], [GENERATE], [PROMPT]
if ((Type == DB || Type == PK) && AsciiStrCmp(Installable.List[Type].Path[Entry], "[GENERATE]") == 0)
continue;

if (Type == DB && AsciiStrCmp(Installable.List[Type].Path[Entry], "[DETECT]") == 0) {
// If we have an existing cert for a previously generated DB credential, try to reuse it
UnicodeSPrint(Path, ARRAY_SIZE(Path), L"%s.crt", MOSBY_CRED_NAME);
// Default to [PROMPT] if we can't access an exisiting cert
Installable.List[Type].Path[Entry] = "[PROMPT]";
if (SimpleFileExistsByPath(gBaseImageHandle, Path) &&
Utf16ToUtf8(Path, Utf8Path, ARRAY_SIZE(Path)) == EFI_SUCCESS) {
Print(L"Reusing existing '%s' certificate for DB\n", Path);
Installable.List[Type].Path[Entry] = Utf8Path;
}
}

if (Type == DB && AsciiStrCmp(Installable.List[Type].Path[Entry], "[PROMPT]") == 0) {
INTN Sel = ConsoleSelect(
(CONST CHAR16 *[]){
Expand All @@ -358,7 +371,8 @@ EFI_STATUS EFIAPI efi_main(
L"DON'T INSTALL",
NULL
}, 1);
// TODO: handle Esc
// TODO: Handle Esc
// TODO: Clear screen after selection
if (Sel == 0) {
Installable.List[Type].Path[Entry] = "[SELECT]";
} else if (Sel == 1) {
Expand Down
Loading

0 comments on commit a9e40c5

Please sign in to comment.