Skip to content

Commit 4d42b7a

Browse files
committed
[efi] further improve revoked UEFI bootloader reporting
* Do not report SBAT revocations unless we actually have a formal Secure Boot signed bootloader. * Also reduce verbose log pollution by libcdio.
1 parent 5439ca8 commit 4d42b7a

File tree

7 files changed

+145
-65
lines changed

7 files changed

+145
-65
lines changed

ChangeLog.txt

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
o Version 4.6 (2024.10.??)
2+
Add a new setup.exe wrapper to bypass Windows 11 24H2 in-place upgrade restrictions
3+
Add TimeZone to regional options replication
4+
Set local account passwords to not expire by default
5+
Fix an error when trying to write compressed VHD images
6+
Fix an error when invoking Rufus from the PowerShell commandline
7+
Improve revoked UEFI bootloaders check to support Linux SBAT, Windows SVN and cert DBX
8+
19
o Version 4.5 (2024.05.22)
210
Add new advanced option to perform runtime UEFI media validation of suitable images (Windows, most Linux)
311
Move the 'Use Rufus MBR' advanced option to a cheat mode (Alt-A)

src/db.h

+17-2
Original file line numberDiff line numberDiff line change
@@ -658,11 +658,26 @@ static uint8_t pe256dbx[] = {
658658
};
659659

660660
/*
661-
* Contains the SHA-1 thumbprint of certificates that are being revoked by DBX.
661+
* Contains the SHA-1 thumbprints of the issuer certificate of the official
662+
* Secure Boot signing authority (i.e. Microsoft).
663+
*/
664+
static uint8_t certauth[] = {
665+
// 'Microsoft Windows Production PCA 2011'
666+
0x58, 0x0a, 0x6f, 0x4c, 0xc4, 0xe4, 0xb6, 0x69, 0xb9, 0xeb, 0xdc, 0x1b, 0x2b, 0x3e, 0x08, 0x7b, 0x80, 0xd0, 0x67, 0x8d,
667+
// 'Microsoft Corporation UEFI CA 2011'
668+
0x46, 0xde, 0xf6, 0x3b, 0x5c, 0xe6, 0x1c, 0xf8, 0xba, 0x0d, 0xe2, 0xe6, 0x63, 0x9c, 0x10, 0x19, 0xd0, 0xed, 0x14, 0xf3,
669+
// 'Windows UEFI CA 2023'
670+
0x45, 0xa0, 0xfa, 0x32, 0x60, 0x47, 0x73, 0xc8, 0x24, 0x33, 0xc3, 0xb7, 0xd5, 0x9e, 0x74, 0x66, 0xb3, 0xac, 0x0c, 0x67,
671+
// 'Microsoft UEFI CA 2023'
672+
0xb5, 0xee, 0xb4, 0xa6, 0x70, 0x60, 0x48, 0x07, 0x3f, 0x0e, 0xd2, 0x96, 0xe7, 0xf5, 0x80, 0xa7, 0x90, 0xb5, 0x9e, 0xaa,
673+
};
674+
675+
/*
676+
* Contains the SHA-1 thumbprints of certificates that are being revoked by DBX.
662677
* This only includes the 'Microsoft Windows Production PCA 2011' for now.
663678
*/
664679
static uint8_t certdbx[] = {
665-
0x58, 0x0a, 0x6f, 0x4c, 0xc4, 0xe4, 0xb6, 0x69, 0xb9, 0xeb, 0xdc, 0x1b, 0x2b, 0x3e, 0x08, 0x7b, 0x80, 0xd0, 0x67, 0x8d
680+
0x58, 0x0a, 0x6f, 0x4c, 0xc4, 0xe4, 0xb6, 0x69, 0xb9, 0xeb, 0xdc, 0x1b, 0x2b, 0x3e, 0x08, 0x7b, 0x80, 0xd0, 0x67, 0x8d,
666681
};
667682

668683
/*

src/hash.c

+39-17
Original file line numberDiff line numberDiff line change
@@ -2171,37 +2171,51 @@ static BOOL IsRevokedBySvn(uint8_t* buf, uint32_t len)
21712171
return FALSE;
21722172
}
21732173

2174-
static BOOL IsRevokedByCert(uint8_t* buf, uint32_t len)
2174+
static BOOL IsRevokedByCert(cert_info_t* info)
21752175
{
21762176
int i;
2177-
uint8_t* cert;
2178-
cert_info_t info;
2179-
2180-
cert = GetPeSignatureData(buf);
2181-
i = GetIssuerCertificateInfo(cert, &info);
2182-
if (i == 0)
2183-
uuprintf(" (Unsigned Bootloader)");
2184-
if (i <= 0)
2185-
return FALSE;
21862177

2187-
uuprintf(" Signed by: %s", info.name);
21882178
for (i = 0; i < ARRAYSIZE(certdbx); i += SHA1_HASHSIZE) {
21892179
if (!expert_mode)
21902180
continue;
2191-
if (memcmp(info.thumbprint, &certdbx[i], SHA1_HASHSIZE) == 0) {
2192-
uprintf("Found '%s' revoked certificate", info.name);
2181+
if (memcmp(info->thumbprint, &certdbx[i], SHA1_HASHSIZE) == 0) {
2182+
uprintf("Found '%s' revoked certificate", info->name);
21932183
return TRUE;
21942184
}
21952185
}
21962186
return FALSE;
21972187
}
21982188

2189+
BOOL IsSignedBySecureBootAuthority(uint8_t* buf, uint32_t len)
2190+
{
2191+
int i;
2192+
uint8_t* cert;
2193+
cert_info_t info;
2194+
2195+
if (buf == NULL || len < 0x100)
2196+
return FALSE;
2197+
2198+
// Get the signer/issuer info
2199+
cert = GetPeSignatureData(buf);
2200+
// Secure Boot Authority is always an issuer
2201+
if (GetIssuerCertificateInfo(cert, &info) != 2)
2202+
return FALSE;
2203+
for (i = 0; i < ARRAYSIZE(certauth); i += SHA1_HASHSIZE) {
2204+
if (memcmp(info.thumbprint, &certauth[i], SHA1_HASHSIZE) == 0)
2205+
return TRUE;
2206+
}
2207+
return FALSE;
2208+
}
2209+
21992210
int IsBootloaderRevoked(uint8_t* buf, uint32_t len)
22002211
{
22012212
uint32_t i;
22022213
uint8_t hash[SHA256_HASHSIZE];
22032214
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf;
22042215
IMAGE_NT_HEADERS32* pe_header;
2216+
uint8_t* cert;
2217+
cert_info_t info;
2218+
int r;
22052219

22062220
// Fall back to embedded sbat_level.txt if we couldn't access remote
22072221
if (sbat_entries == NULL) {
@@ -2214,12 +2228,17 @@ int IsBootloaderRevoked(uint8_t* buf, uint32_t len)
22142228
pe_header = (IMAGE_NT_HEADERS32*)&buf[dos_header->e_lfanew];
22152229
if (pe_header->Signature != IMAGE_NT_SIGNATURE)
22162230
return -2;
2231+
2232+
// Get the signer/issuer info
2233+
cert = GetPeSignatureData(buf);
2234+
r = GetIssuerCertificateInfo(cert, &info);
2235+
if (r == 0)
2236+
uuprintf(" (Unsigned Bootloader)");
2237+
else if (r > 0)
2238+
uuprintf(" Signed by: %s", info.name);
2239+
22172240
if (!PE256Buffer(buf, len, hash))
22182241
return -1;
2219-
// Check for UEFI DBX certificate revocation
2220-
// This also displays the name of the signer/issuer cert if available
2221-
if (IsRevokedByCert(buf, len))
2222-
return 5;
22232242
// Check for UEFI DBX revocation
22242243
for (i = 0; i < ARRAYSIZE(pe256dbx); i += SHA256_HASHSIZE)
22252244
if (memcmp(hash, &pe256dbx[i], SHA256_HASHSIZE) == 0)
@@ -2234,6 +2253,9 @@ int IsBootloaderRevoked(uint8_t* buf, uint32_t len)
22342253
// Check for Microsoft SVN revocation
22352254
if (IsRevokedBySvn(buf, len))
22362255
return 4;
2256+
// Check for UEFI DBX certificate revocation
2257+
if (IsRevokedByCert(&info))
2258+
return 5;
22372259
return 0;
22382260
}
22392261

src/iso.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,10 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const
249249
// We may extract the bootloaders for revocation validation later but
250250
// to do so, since we're working with case sensitive file systems, we
251251
// must store all found UEFI bootloader paths with the right case.
252-
for (j = 0; j < ARRAYSIZE(img_report.efi_boot_path); j++) {
253-
if (img_report.efi_boot_path[j][0] == 0) {
254-
static_strcpy(img_report.efi_boot_path[j], psz_fullpath);
252+
for (j = 0; j < ARRAYSIZE(img_report.efi_boot_entry); j++) {
253+
if (img_report.efi_boot_entry[j].path[0] == 0) {
254+
img_report.efi_boot_entry[j].type = EBT_BOOTMGR;
255+
static_strcpy(img_report.efi_boot_entry[j].path, psz_fullpath);
255256
break;
256257
}
257258
}
@@ -291,9 +292,10 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const
291292
if (safe_stricmp(psz_basename, bootloader_name) == 0) {
292293
if (k == 0)
293294
img_report.has_efi |= (2 << i); // start at 2 since "bootmgr.efi" is bit 0
294-
for (j = 0; j < ARRAYSIZE(img_report.efi_boot_path); j++) {
295-
if (img_report.efi_boot_path[j][0] == 0) {
296-
static_strcpy(img_report.efi_boot_path[j], psz_fullpath);
295+
for (j = 0; j < ARRAYSIZE(img_report.efi_boot_entry); j++) {
296+
if (img_report.efi_boot_entry[j].path[0] == 0) {
297+
img_report.efi_boot_entry[j].type = (uint8_t)k;
298+
static_strcpy(img_report.efi_boot_entry[j].path, psz_fullpath);
297299
break;
298300
}
299301
}
@@ -1559,6 +1561,7 @@ uint32_t ReadISOFileToBuffer(const char* iso, const char* iso_file, uint8_t** bu
15591561
iso9660_stat_t* p_statbuf = NULL;
15601562

15611563
*buf = NULL;
1564+
cdio_loglevel_default = CDIO_LOG_WARN;
15621565

15631566
// First try to open as UDF - fallback to ISO if it failed
15641567
p_udf = udf_open(iso);
@@ -1632,6 +1635,7 @@ uint32_t ReadISOFileToBuffer(const char* iso, const char* iso_file, uint8_t** bu
16321635
udf_dirent_free(p_udf_file);
16331636
iso9660_close(p_iso);
16341637
udf_close(p_udf);
1638+
cdio_loglevel_default = usb_debug ? CDIO_LOG_INFO : CDIO_LOG_WARN;
16351639
if (ret == 0)
16361640
safe_free(*buf);
16371641
return ret;

src/rufus.c

+52-34
Original file line numberDiff line numberDiff line change
@@ -1609,43 +1609,61 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
16091609

16101610
// Check UEFI bootloaders for revocation
16111611
if (IS_EFI_BOOTABLE(img_report)) {
1612-
assert(ARRAYSIZE(img_report.efi_boot_path) > 0);
1612+
BOOL has_secureboot_signed_bootloader = FALSE;
1613+
assert(ARRAYSIZE(img_report.efi_boot_entry) > 0);
16131614
PrintStatus(0, MSG_351);
16141615
uuprintf("UEFI Secure Boot revocation checks:");
1615-
rr = 0;
1616-
for (i = 0; i < ARRAYSIZE(img_report.efi_boot_path) && img_report.efi_boot_path[i][0] != 0; i++) {
1617-
static const char* revocation_type[] = { "UEFI DBX", "Windows SSP", "Linux SBAT", "Windows SVN", "Cert DBX" };
1618-
cdio_loglevel_default = CDIO_LOG_WARN;
1619-
len = ReadISOFileToBuffer(image_path, img_report.efi_boot_path[i], &buf);
1620-
cdio_loglevel_default = usb_debug ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
1621-
if (len == 0) {
1622-
uprintf("Warning: Failed to extract '%s' to check for UEFI revocation", img_report.efi_boot_path[i]);
1623-
continue;
1624-
}
1625-
uuprintf("• %s", img_report.efi_boot_path[i]);
1626-
r = IsBootloaderRevoked(buf, len);
1627-
safe_free(buf);
1628-
if (r > 0) {
1629-
assert(r <= ARRAYSIZE(revocation_type));
1630-
if (rr == 0)
1631-
rr = r;
1632-
uprintf("Warning: '%s' has been revoked by %s", img_report.efi_boot_path[i], revocation_type[r - 1]);
1633-
is_bootloader_revoked = TRUE;
1616+
// Make sure we have at least one regular EFI bootloader that is formally signed
1617+
// for Secure Boot, since it doesn't make sense to report revocation otherwise.
1618+
for (i = 0; !has_secureboot_signed_bootloader && i < ARRAYSIZE(img_report.efi_boot_entry) &&
1619+
img_report.efi_boot_entry[i].path[0] != 0; i++) {
1620+
if (img_report.efi_boot_entry[i].type == EBT_MAIN) {
1621+
len = ReadISOFileToBuffer(image_path, img_report.efi_boot_entry[i].path, &buf);
1622+
if (len == 0) {
1623+
uprintf("Warning: Failed to extract '%s' to check for UEFI revocation", img_report.efi_boot_entry[i].path);
1624+
continue;
1625+
}
1626+
if (IsSignedBySecureBootAuthority(buf, len))
1627+
has_secureboot_signed_bootloader = TRUE;
1628+
free(buf);
16341629
}
16351630
}
1636-
if (rr > 0) {
1637-
switch (rr) {
1638-
case 2:
1639-
msg = lmprintf(MSG_341, "Error code: 0xc0000428");
1640-
break;
1641-
default:
1642-
msg = lmprintf(MSG_340);
1643-
break;
1631+
if (!has_secureboot_signed_bootloader) {
1632+
uuprintf(" No Secure Boot signed bootloader found -- skipping");
1633+
} else {
1634+
rr = 0;
1635+
for (i = 0; i < ARRAYSIZE(img_report.efi_boot_entry) && img_report.efi_boot_entry[i].path[0] != 0; i++) {
1636+
static const char* revocation_type[] = { "UEFI DBX", "Windows SSP", "Linux SBAT", "Windows SVN", "Cert DBX" };
1637+
len = ReadISOFileToBuffer(image_path, img_report.efi_boot_entry[i].path, &buf);
1638+
if (len == 0) {
1639+
uprintf("Warning: Failed to extract '%s' to check for UEFI revocation", img_report.efi_boot_entry[i].path);
1640+
continue;
1641+
}
1642+
uuprintf("• %s", img_report.efi_boot_entry[i].path);
1643+
r = IsBootloaderRevoked(buf, len);
1644+
safe_free(buf);
1645+
if (r > 0) {
1646+
assert(r <= ARRAYSIZE(revocation_type));
1647+
if (rr == 0)
1648+
rr = r;
1649+
uprintf("Warning: '%s' has been revoked by %s", img_report.efi_boot_entry[i].path, revocation_type[r - 1]);
1650+
is_bootloader_revoked = TRUE;
1651+
}
1652+
}
1653+
if (rr > 0) {
1654+
switch (rr) {
1655+
case 2:
1656+
msg = lmprintf(MSG_341, "Error code: 0xc0000428");
1657+
break;
1658+
default:
1659+
msg = lmprintf(MSG_340);
1660+
break;
1661+
}
1662+
r = MessageBoxExU(hMainDialog, lmprintf(MSG_339, msg), lmprintf(MSG_338),
1663+
MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid);
1664+
if (r == IDCANCEL)
1665+
goto out;
16441666
}
1645-
r = MessageBoxExU(hMainDialog, lmprintf(MSG_339, msg), lmprintf(MSG_338),
1646-
MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid);
1647-
if (r == IDCANCEL)
1648-
goto out;
16491667
}
16501668
}
16511669

@@ -3516,7 +3534,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
35163534
is_vds_available = IsVdsAvailable(FALSE);
35173535
use_vds = ReadSettingBool(SETTING_USE_VDS) && is_vds_available;
35183536
usb_debug = ReadSettingBool(SETTING_ENABLE_USB_DEBUG);
3519-
cdio_loglevel_default = usb_debug ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
3537+
cdio_loglevel_default = usb_debug ? CDIO_LOG_INFO : CDIO_LOG_WARN;
35203538
use_rufus_mbr = !ReadSettingBool(SETTING_DISABLE_RUFUS_MBR);
35213539
// validate_md5sum = ReadSettingBool(SETTING_ENABLE_RUNTIME_VALIDATION);
35223540
detect_fakes = !ReadSettingBool(SETTING_DISABLE_FAKE_DRIVES_CHECK);
@@ -3807,7 +3825,7 @@ extern int TestHashes(void);
38073825
// Alt-. => Enable USB enumeration debug
38083826
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_PERIOD)) {
38093827
usb_debug = !usb_debug;
3810-
cdio_loglevel_default = usb_debug ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
3828+
cdio_loglevel_default = usb_debug ? CDIO_LOG_INFO : CDIO_LOG_WARN;
38113829
WriteSettingBool(SETTING_ENABLE_USB_DEBUG, usb_debug);
38123830
PrintStatusTimeout(lmprintf(MSG_270), usb_debug);
38133831
GetDevices(0);

src/rufus.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,13 @@ enum file_io_type {
327327
FILE_IO_APPEND
328328
};
329329

330+
enum EFI_BOOT_TYPE {
331+
EBT_MAIN = 0,
332+
EBT_GRUB,
333+
EBT_MOKMANAGER,
334+
EBT_BOOTMGR
335+
};
336+
330337
/* Special handling for old .c32 files we need to replace */
331338
#define NB_OLD_C32 2
332339
#define OLD_C32_NAMES { "menu.c32", "vesamenu.c32" }
@@ -383,13 +390,18 @@ enum ArchType {
383390
ARCH_MAX
384391
};
385392

393+
typedef struct {
394+
uint8_t type;
395+
char path[64];
396+
} efi_boot_entry_t;
397+
386398
typedef struct {
387399
char label[192]; // 3*64 to account for UTF-8
388400
char usb_label[192]; // converted USB label for workaround
389401
char cfg_path[128]; // path to the ISO's isolinux.cfg
390402
char reactos_path[128]; // path to the ISO's freeldr.sys or setupldr.sys
391403
char wininst_path[MAX_WININST][64]; // path to the Windows install image(s)
392-
char efi_boot_path[64][32]; // paths of detected UEFI bootloaders
404+
efi_boot_entry_t efi_boot_entry[64];// types and paths of detected UEFI bootloaders
393405
char efi_img_path[128]; // path to an efi.img file
394406
uint64_t image_size;
395407
uint64_t projected_size;
@@ -823,6 +835,7 @@ extern BOOL PE256Buffer(uint8_t* buf, uint32_t len, uint8_t* hash);
823835
extern void UpdateMD5Sum(const char* dest_dir, const char* md5sum_name);
824836
extern BOOL HashBuffer(const unsigned type, const uint8_t* buf, const size_t len, uint8_t* sum);
825837
extern BOOL IsFileInDB(const char* path);
838+
extern BOOL IsSignedBySecureBootAuthority(uint8_t* buf, uint32_t len);
826839
extern int IsBootloaderRevoked(uint8_t* buf, uint32_t len);
827840
extern void PrintRevokedBootloaderInfo(void);
828841
extern BOOL IsBufferInDB(const unsigned char* buf, const size_t len);

src/rufus.rc

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
3333
IDD_DIALOG DIALOGEX 12, 12, 232, 326
3434
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
3535
EXSTYLE WS_EX_ACCEPTFILES
36-
CAPTION "Rufus 4.6.2204"
36+
CAPTION "Rufus 4.6.2205"
3737
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
3838
BEGIN
3939
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@@ -399,8 +399,8 @@ END
399399
//
400400

401401
VS_VERSION_INFO VERSIONINFO
402-
FILEVERSION 4,6,2204,0
403-
PRODUCTVERSION 4,6,2204,0
402+
FILEVERSION 4,6,2205,0
403+
PRODUCTVERSION 4,6,2205,0
404404
FILEFLAGSMASK 0x3fL
405405
#ifdef _DEBUG
406406
FILEFLAGS 0x1L
@@ -418,13 +418,13 @@ BEGIN
418418
VALUE "Comments", "https://rufus.ie"
419419
VALUE "CompanyName", "Akeo Consulting"
420420
VALUE "FileDescription", "Rufus"
421-
VALUE "FileVersion", "4.6.2204"
421+
VALUE "FileVersion", "4.6.2205"
422422
VALUE "InternalName", "Rufus"
423423
VALUE "LegalCopyright", "� 2011-2024 Pete Batard (GPL v3)"
424424
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
425425
VALUE "OriginalFilename", "rufus-4.6.exe"
426426
VALUE "ProductName", "Rufus"
427-
VALUE "ProductVersion", "4.6.2204"
427+
VALUE "ProductVersion", "4.6.2205"
428428
END
429429
END
430430
BLOCK "VarFileInfo"

0 commit comments

Comments
 (0)