[misc] improve revoked UEFI bootloader reporting

* Also fix SBAT not being properly parsed for PE32 executables.
* Also fix signature truncation in GetIssuerCertificateInfo() and fall back to
  returning signer data if issuer is not available (which is typically the case
  for GRUB signed bootloaders).
* Also fix status messages on user cancellation/proceeding.
This commit is contained in:
Pete Batard 2024-10-09 20:18:42 +01:00
parent 6b5837dbb5
commit ede52c57e6
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
7 changed files with 98 additions and 71 deletions

View file

@ -610,6 +610,7 @@ t MSG_347 "Expert Mode"
t MSG_348 "Extracting archive files: %s" t MSG_348 "Extracting archive files: %s"
t MSG_349 "Use Rufus MBR" t MSG_349 "Use Rufus MBR"
t MSG_350 "Use 'Windows UEFI CA 2023' signed bootloaders [EXPERIMENTAL]" t MSG_350 "Use 'Windows UEFI CA 2023' signed bootloaders [EXPERIMENTAL]"
t MSG_351 "Checking for UEFI bootloader revocation..."
# The following messages are for the Windows Store listing only and are not used by the application # The following messages are for the Windows Store listing only and are not used by the application
t MSG_900 "Rufus is a utility that helps format and create bootable USB flash drives, such as USB keys/pendrives, memory sticks, etc." t MSG_900 "Rufus is a utility that helps format and create bootable USB flash drives, such as USB keys/pendrives, memory sticks, etc."
t MSG_901 "Official site: %s" t MSG_901 "Official site: %s"

View file

@ -117,7 +117,7 @@ StrArray modified_files = { 0 };
extern int default_thread_priority; extern int default_thread_priority;
extern const char* efi_archname[ARCH_MAX]; extern const char* efi_archname[ARCH_MAX];
extern char* sbat_level_txt; extern char* sbat_level_txt;
extern BOOL expert_mode; extern BOOL expert_mode, usb_debug;
/* /*
* Rotate 32 or 64 bit integers by n bytes. * Rotate 32 or 64 bit integers by n bytes.
@ -2081,7 +2081,7 @@ BOOL IsFileInDB(const char* path)
return FALSE; return FALSE;
} }
BOOL IsRevokedBySbat(uint8_t* buf, uint32_t len) static BOOL IsRevokedBySbat(uint8_t* buf, uint32_t len)
{ {
char* sbat = NULL, *version_str; char* sbat = NULL, *version_str;
uint32_t i, j, sbat_len; uint32_t i, j, sbat_len;
@ -2109,6 +2109,7 @@ BOOL IsRevokedBySbat(uint8_t* buf, uint32_t len)
for (; sbat[i] != ',' && sbat[i] != '\0' && sbat[i] != '\n'; i++); for (; sbat[i] != ',' && sbat[i] != '\0' && sbat[i] != '\n'; i++);
sbat[i++] = '\0'; sbat[i++] = '\0';
entry.version = atoi(version_str); entry.version = atoi(version_str);
uuprintf(" SBAT: %s,%d", entry.product, entry.version);
for (; sbat[i] != '\0' && sbat[i] != '\n'; i++); for (; sbat[i] != '\0' && sbat[i] != '\n'; i++);
if (entry.version == 0) if (entry.version == 0)
continue; continue;
@ -2121,13 +2122,13 @@ BOOL IsRevokedBySbat(uint8_t* buf, uint32_t len)
return FALSE; return FALSE;
} }
BOOL IsRevokedBySvn(uint8_t* buf, uint32_t len) static BOOL IsRevokedBySvn(uint8_t* buf, uint32_t len)
{ {
wchar_t* rsrc_name = NULL; wchar_t* rsrc_name = NULL;
uint8_t *root; uint8_t *root;
uint32_t i, j, rsrc_rva, rsrc_len, *svn_ver; uint32_t i, j, rsrc_rva, rsrc_len, *svn_ver;
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf; IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf;
IMAGE_NT_HEADERS* pe_header; IMAGE_NT_HEADERS32* pe_header;
IMAGE_NT_HEADERS64* pe64_header; IMAGE_NT_HEADERS64* pe64_header;
IMAGE_DATA_DIRECTORY img_data_dir; IMAGE_DATA_DIRECTORY img_data_dir;
@ -2143,7 +2144,7 @@ BOOL IsRevokedBySvn(uint8_t* buf, uint32_t len)
if (rsrc_name == NULL) if (rsrc_name == NULL)
continue; continue;
pe_header = (IMAGE_NT_HEADERS*)&buf[dos_header->e_lfanew]; pe_header = (IMAGE_NT_HEADERS32*)&buf[dos_header->e_lfanew];
if (pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) { if (pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) {
img_data_dir = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]; img_data_dir = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
} else { } else {
@ -2157,6 +2158,7 @@ BOOL IsRevokedBySvn(uint8_t* buf, uint32_t len)
if (rsrc_rva != 0) { if (rsrc_rva != 0) {
if (rsrc_len == sizeof(uint32_t)) { if (rsrc_len == sizeof(uint32_t)) {
svn_ver = (uint32_t*)RvaToPhysical(buf, rsrc_rva); svn_ver = (uint32_t*)RvaToPhysical(buf, rsrc_rva);
uuprintf(" SVN version: %d.%d", *svn_ver >> 16, *svn_ver & 0xffff);
if (svn_ver != NULL && *svn_ver < sbat_entries[i].version) if (svn_ver != NULL && *svn_ver < sbat_entries[i].version)
return TRUE; return TRUE;
} else { } else {
@ -2167,18 +2169,20 @@ BOOL IsRevokedBySvn(uint8_t* buf, uint32_t len)
return FALSE; return FALSE;
} }
BOOL IsRevokedByCert(uint8_t* buf, uint32_t len) static BOOL IsRevokedByCert(uint8_t* buf, uint32_t len)
{ {
int i; int i;
uint8_t* cert; uint8_t* cert;
cert_info_t info; cert_info_t info;
cert = GetPeSignatureData(buf); cert = GetPeSignatureData(buf);
if (cert == NULL) i = GetIssuerCertificateInfo(cert, &info);
return FALSE; if (i == 0)
if (!GetIssuerCertificateInfo(cert, &info)) uuprintf(" (Unsigned Bootloader)");
if (i <= 0)
return FALSE; return FALSE;
uuprintf(" Signed by: %s", info.name);
for (i = 0; i < ARRAYSIZE(certdbx); i += SHA1_HASHSIZE) { for (i = 0; i < ARRAYSIZE(certdbx); i += SHA1_HASHSIZE) {
if (!expert_mode) if (!expert_mode)
continue; continue;
@ -2195,7 +2199,7 @@ int IsBootloaderRevoked(uint8_t* buf, uint32_t len)
uint32_t i; uint32_t i;
uint8_t hash[SHA256_HASHSIZE]; uint8_t hash[SHA256_HASHSIZE];
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf; IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf;
IMAGE_NT_HEADERS* pe_header; IMAGE_NT_HEADERS32* pe_header;
// Fall back to embedded sbat_level.txt if we couldn't access remote // Fall back to embedded sbat_level.txt if we couldn't access remote
if (sbat_entries == NULL) { if (sbat_entries == NULL) {
@ -2205,11 +2209,15 @@ int IsBootloaderRevoked(uint8_t* buf, uint32_t len)
if (buf == NULL || len < 0x100 || dos_header->e_magic != IMAGE_DOS_SIGNATURE) if (buf == NULL || len < 0x100 || dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return -2; return -2;
pe_header = (IMAGE_NT_HEADERS*)&buf[dos_header->e_lfanew]; pe_header = (IMAGE_NT_HEADERS32*)&buf[dos_header->e_lfanew];
if (pe_header->Signature != IMAGE_NT_SIGNATURE) if (pe_header->Signature != IMAGE_NT_SIGNATURE)
return -2; return -2;
if (!PE256Buffer(buf, len, hash)) if (!PE256Buffer(buf, len, hash))
return -1; return -1;
// Check for UEFI DBX certificate revocation
// This also displays the name of the signer/issuer cert if available
if (IsRevokedByCert(buf, len))
return 5;
// Check for UEFI DBX revocation // Check for UEFI DBX revocation
for (i = 0; i < ARRAYSIZE(pe256dbx); i += SHA256_HASHSIZE) for (i = 0; i < ARRAYSIZE(pe256dbx); i += SHA256_HASHSIZE)
if (memcmp(hash, &pe256dbx[i], SHA256_HASHSIZE) == 0) if (memcmp(hash, &pe256dbx[i], SHA256_HASHSIZE) == 0)
@ -2224,9 +2232,6 @@ int IsBootloaderRevoked(uint8_t* buf, uint32_t len)
// Check for Microsoft SVN revocation // Check for Microsoft SVN revocation
if (IsRevokedBySvn(buf, len)) if (IsRevokedBySvn(buf, len))
return 4; return 4;
// Check for DBX certificate revocation
if (IsRevokedByCert(buf, len))
return 5;
return 0; return 0;
} }

View file

@ -1643,12 +1643,12 @@ sbat_entry_t* GetSbatEntries(char* sbatlevel)
uint16_t GetPeArch(uint8_t* buf) uint16_t GetPeArch(uint8_t* buf)
{ {
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf; IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf;
IMAGE_NT_HEADERS* pe_header; IMAGE_NT_HEADERS32* pe_header;
if (buf == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE) if (buf == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return IMAGE_FILE_MACHINE_UNKNOWN; return IMAGE_FILE_MACHINE_UNKNOWN;
pe_header = (IMAGE_NT_HEADERS*)&buf[dos_header->e_lfanew]; pe_header = (IMAGE_NT_HEADERS32*)&buf[dos_header->e_lfanew];
if (pe_header->Signature != IMAGE_NT_SIGNATURE) if (pe_header->Signature != IMAGE_NT_SIGNATURE)
return IMAGE_FILE_MACHINE_UNKNOWN; return IMAGE_FILE_MACHINE_UNKNOWN;
return pe_header->FileHeader.Machine; return pe_header->FileHeader.Machine;
@ -1660,7 +1660,7 @@ uint8_t* GetPeSection(uint8_t* buf, const char* name, uint32_t* len)
char section_name[IMAGE_SIZEOF_SHORT_NAME] = { 0 }; char section_name[IMAGE_SIZEOF_SHORT_NAME] = { 0 };
uint32_t i, nb_sections; uint32_t i, nb_sections;
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf; IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf;
IMAGE_NT_HEADERS* pe_header; IMAGE_NT_HEADERS32* pe_header;
IMAGE_NT_HEADERS64* pe64_header; IMAGE_NT_HEADERS64* pe64_header;
IMAGE_SECTION_HEADER* section_header; IMAGE_SECTION_HEADER* section_header;
@ -1669,7 +1669,7 @@ uint8_t* GetPeSection(uint8_t* buf, const char* name, uint32_t* len)
if (buf == NULL || name == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE) if (buf == NULL || name == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return NULL; return NULL;
pe_header = (IMAGE_NT_HEADERS*)&buf[dos_header->e_lfanew]; pe_header = (IMAGE_NT_HEADERS32*)&buf[dos_header->e_lfanew];
if (pe_header->Signature != IMAGE_NT_SIGNATURE) if (pe_header->Signature != IMAGE_NT_SIGNATURE)
return NULL; return NULL;
if (pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) { if (pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) {
@ -1695,14 +1695,14 @@ uint8_t* RvaToPhysical(uint8_t* buf, uint32_t rva)
{ {
uint32_t i, nb_sections; uint32_t i, nb_sections;
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf; IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf;
IMAGE_NT_HEADERS* pe_header; IMAGE_NT_HEADERS32* pe_header;
IMAGE_NT_HEADERS64* pe64_header; IMAGE_NT_HEADERS64* pe64_header;
IMAGE_SECTION_HEADER* section_header; IMAGE_SECTION_HEADER* section_header;
if (buf == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE) if (buf == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return NULL; return NULL;
pe_header = (IMAGE_NT_HEADERS*)&buf[dos_header->e_lfanew]; pe_header = (IMAGE_NT_HEADERS32*)&buf[dos_header->e_lfanew];
if (pe_header->Signature != IMAGE_NT_SIGNATURE) if (pe_header->Signature != IMAGE_NT_SIGNATURE)
return NULL; return NULL;
if (pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) { if (pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) {
@ -1767,18 +1767,24 @@ uint32_t FindResourceRva(const wchar_t* name, uint8_t* root, uint8_t* dir, uint3
uint8_t* GetPeSignatureData(uint8_t* buf) uint8_t* GetPeSignatureData(uint8_t* buf)
{ {
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf; IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)buf;
IMAGE_NT_HEADERS* pe_header; IMAGE_NT_HEADERS32* pe_header;
IMAGE_NT_HEADERS64* pe64_header;
IMAGE_DATA_DIRECTORY sec_dir; IMAGE_DATA_DIRECTORY sec_dir;
WIN_CERTIFICATE* cert; WIN_CERTIFICATE* cert;
if (buf == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE) if (buf == NULL || dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return NULL; return NULL;
pe_header = (IMAGE_NT_HEADERS*)&buf[dos_header->e_lfanew]; pe_header = (IMAGE_NT_HEADERS32*)&buf[dos_header->e_lfanew];
if (pe_header->Signature != IMAGE_NT_SIGNATURE) if (pe_header->Signature != IMAGE_NT_SIGNATURE)
return NULL; return NULL;
if (pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || pe_header->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) {
sec_dir = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; sec_dir = pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
} else {
pe64_header = (IMAGE_NT_HEADERS64*)pe_header;
sec_dir = pe64_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
}
if (sec_dir.VirtualAddress == 0 || sec_dir.Size == 0) if (sec_dir.VirtualAddress == 0 || sec_dir.Size == 0)
return NULL; return NULL;

View file

@ -384,27 +384,31 @@ out:
return p; return p;
} }
// Return the issuer certificate's name and thumbprint // Fills the certificate's name and thumbprint.
BOOL GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info) // Tries the issuer first, and if none is available, falls back to current cert.
// Returns 0 for unsigned, -1 on error, 1 for signer or 2 for issuer.
int GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info)
{ {
BOOL ret = FALSE; int ret = 0;
DWORD dwSize, dwEncoding, dwContentType, dwFormatType, dwSignerInfoSize = 0; DWORD dwSize, dwEncoding, dwContentType, dwFormatType, dwSignerInfoSize = 0;
WIN_CERTIFICATE* pWinCert = (WIN_CERTIFICATE*)cert; WIN_CERTIFICATE* pWinCert = (WIN_CERTIFICATE*)cert;
CRYPT_DATA_BLOB signedDataBlob; CRYPT_DATA_BLOB signedDataBlob;
HCERTSTORE hStore = NULL; HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL; HCRYPTMSG hMsg = NULL;
PCMSG_SIGNER_INFO pSignerInfo = NULL; PCMSG_SIGNER_INFO pSignerInfo = NULL;
PCCERT_CONTEXT pCertContext = NULL, pIssuerCertContext = NULL; PCCERT_CONTEXT pCertContext[2] = { NULL, NULL };
PCCERT_CHAIN_CONTEXT pChainContext = NULL; PCCERT_CHAIN_CONTEXT pChainContext = NULL;
CERT_CHAIN_PARA chainPara; CERT_CHAIN_PARA chainPara;
int CertIndex = 0;
if (cert == NULL || info == NULL || pWinCert->dwLength == 0) if (info == NULL)
return FALSE; return -1;
if (pWinCert == NULL || pWinCert->dwLength == 0)
signedDataBlob.cbData = pWinCert->dwLength - sizeof(WIN_CERTIFICATE); return 0;
signedDataBlob.pbData = pWinCert->bCertificate;
// Get message handle and store handle from the signed file. // Get message handle and store handle from the signed file.
signedDataBlob.cbData = pWinCert->dwLength;
signedDataBlob.pbData = pWinCert->bCertificate;
if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &signedDataBlob, if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &signedDataBlob,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, CERT_QUERY_FORMAT_FLAG_BINARY, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, CERT_QUERY_FORMAT_FLAG_BINARY,
0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL)) { 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL)) {
@ -420,7 +424,7 @@ BOOL GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info)
// Allocate memory for signer information. // Allocate memory for signer information.
pSignerInfo = (PCMSG_SIGNER_INFO)calloc(dwSignerInfoSize, 1); pSignerInfo = (PCMSG_SIGNER_INFO)calloc(dwSignerInfoSize, 1);
if (!pSignerInfo) { if (pSignerInfo == NULL) {
uprintf("PKI: Could not allocate memory for signer information"); uprintf("PKI: Could not allocate memory for signer information");
goto out; goto out;
} }
@ -432,8 +436,8 @@ BOOL GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info)
} }
// Search for the signer certificate in the temporary certificate store. // Search for the signer certificate in the temporary certificate store.
pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)pSignerInfo, NULL); pCertContext[0] = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)pSignerInfo, NULL);
if (!pCertContext) { if (pCertContext[0] == NULL) {
uprintf("PKI: Failed to locate signer certificate in store: %s", WinPKIErrorString()); uprintf("PKI: Failed to locate signer certificate in store: %s", WinPKIErrorString());
goto out; goto out;
} }
@ -441,21 +445,19 @@ BOOL GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info)
// Build a certificate chain to get the issuer (CA) certificate. // Build a certificate chain to get the issuer (CA) certificate.
memset(&chainPara, 0, sizeof(chainPara)); memset(&chainPara, 0, sizeof(chainPara));
chainPara.cbSize = sizeof(CERT_CHAIN_PARA); chainPara.cbSize = sizeof(CERT_CHAIN_PARA);
if (!CertGetCertificateChain(NULL, pCertContext, NULL, hStore, &chainPara, 0, NULL, &pChainContext)) { if (!CertGetCertificateChain(NULL, pCertContext[0], NULL, hStore, &chainPara, 0, NULL, &pChainContext)) {
uprintf("PKI: Failed to build certificate chain. Error code: %s", WinPKIErrorString()); uprintf("PKI: Failed to build certificate chain. Error code: %s", WinPKIErrorString());
goto out; goto out;
} }
// Get the issuer's certificate (second certificate in the chain) // Try to get the issuer's certificate (second certificate in the chain) if available
if (pChainContext->cChain > 0 && pChainContext->rgpChain[0]->cElement > 1) { if (pChainContext->cChain > 0 && pChainContext->rgpChain[0]->cElement > 1) {
pIssuerCertContext = pChainContext->rgpChain[0]->rgpElement[1]->pCertContext; pCertContext[1] = pChainContext->rgpChain[0]->rgpElement[1]->pCertContext;
} else { CertIndex = 1;
uprintf("PKI: Failed to retrieve issuer's certificate: %s", WinPKIErrorString());
goto out;
} }
// Isolate the signing certificate subject name // Isolate the signing certificate subject name
dwSize = CertGetNameStringA(pIssuerCertContext, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, dwSize = CertGetNameStringA(pCertContext[CertIndex], CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME,
info->name, sizeof(info->name)); info->name, sizeof(info->name));
if (dwSize <= 1) { if (dwSize <= 1) {
uprintf("PKI: Failed to get Subject Name"); uprintf("PKI: Failed to get Subject Name");
@ -463,19 +465,19 @@ BOOL GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info)
} }
dwSize = SHA1_HASHSIZE; dwSize = SHA1_HASHSIZE;
if (!CryptHashCertificate(0, CALG_SHA1, 0, pIssuerCertContext->pbCertEncoded, if (!CryptHashCertificate(0, CALG_SHA1, 0, pCertContext[CertIndex]->pbCertEncoded,
pIssuerCertContext->cbCertEncoded, info->thumbprint, &dwSize)) { pCertContext[CertIndex]->cbCertEncoded, info->thumbprint, &dwSize)) {
uprintf("PKI: Failed to compute the thumbprint: %s", WinPKIErrorString()); uprintf("PKI: Failed to compute the thumbprint: %s", WinPKIErrorString());
goto out; goto out;
} }
ret = TRUE; ret = CertIndex + 1;
out: out:
safe_free(pSignerInfo); safe_free(pSignerInfo);
if (pIssuerCertContext != NULL) if (pCertContext[1] != NULL)
CertFreeCertificateContext(pIssuerCertContext); CertFreeCertificateContext(pCertContext[1]);
if (pCertContext != NULL) if (pCertContext[0] != NULL)
CertFreeCertificateContext(pCertContext); CertFreeCertificateContext(pCertContext[0]);
if (hStore != NULL) if (hStore != NULL)
CertCloseStore(hStore, 0); CertCloseStore(hStore, 0);
if (hMsg != NULL) if (hMsg != NULL)

View file

@ -1399,7 +1399,7 @@ out:
// Likewise, boot check will block message processing => use a thread // Likewise, boot check will block message processing => use a thread
static DWORD WINAPI BootCheckThread(LPVOID param) static DWORD WINAPI BootCheckThread(LPVOID param)
{ {
int i, r, username_index = -1; int i, r, rr, username_index = -1;
FILE *fd; FILE *fd;
uint32_t len; uint32_t len;
uint8_t* buf = NULL; uint8_t* buf = NULL;
@ -1609,20 +1609,32 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
// Check UEFI bootloaders for revocation // Check UEFI bootloaders for revocation
if (IS_EFI_BOOTABLE(img_report)) { if (IS_EFI_BOOTABLE(img_report)) {
assert(ARRAYSIZE(img_report.efi_boot_path) > 0);
PrintStatus(0, MSG_351);
uuprintf("UEFI Secure Boot revocation checks:");
rr = 0;
for (i = 0; i < ARRAYSIZE(img_report.efi_boot_path) && img_report.efi_boot_path[i][0] != 0; i++) { for (i = 0; i < ARRAYSIZE(img_report.efi_boot_path) && img_report.efi_boot_path[i][0] != 0; i++) {
static const char* revocation_type[] = { "UEFI DBX", "Windows SSP", "Linux SBAT", "Windows SVN", "Cert DBX" }; static const char* revocation_type[] = { "UEFI DBX", "Windows SSP", "Linux SBAT", "Windows SVN", "Cert DBX" };
cdio_loglevel_default = CDIO_LOG_WARN;
len = ReadISOFileToBuffer(image_path, img_report.efi_boot_path[i], &buf); len = ReadISOFileToBuffer(image_path, img_report.efi_boot_path[i], &buf);
cdio_loglevel_default = usb_debug ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
if (len == 0) { if (len == 0) {
uprintf("Warning: Failed to extract '%s' to check for UEFI revocation", img_report.efi_boot_path[i]); uprintf("Warning: Failed to extract '%s' to check for UEFI revocation", img_report.efi_boot_path[i]);
continue; continue;
} }
uuprintf("• %s", img_report.efi_boot_path[i]);
r = IsBootloaderRevoked(buf, len); r = IsBootloaderRevoked(buf, len);
safe_free(buf); safe_free(buf);
if (r > 0) { if (r > 0) {
assert(r <= ARRAYSIZE(revocation_type)); assert(r <= ARRAYSIZE(revocation_type));
if (rr == 0)
rr = r;
uprintf("Warning: '%s' has been revoked by %s", img_report.efi_boot_path[i], revocation_type[r - 1]); uprintf("Warning: '%s' has been revoked by %s", img_report.efi_boot_path[i], revocation_type[r - 1]);
is_bootloader_revoked = TRUE; is_bootloader_revoked = TRUE;
switch (r) { }
}
if (rr > 0) {
switch (rr) {
case 2: case 2:
msg = lmprintf(MSG_341, "Error code: 0xc0000428"); msg = lmprintf(MSG_341, "Error code: 0xc0000428");
break; break;
@ -1634,8 +1646,6 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid); MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid);
if (r == IDCANCEL) if (r == IDCANCEL)
goto out; goto out;
break;
}
} }
} }
@ -1691,7 +1701,6 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
IGNORE_RETVAL(_chdir(tmp)); IGNORE_RETVAL(_chdir(tmp));
// The following loops through the grub2 version (which may have the ISO label appended) // The following loops through the grub2 version (which may have the ISO label appended)
// and breaks it according to '.' or '-' until it finds a match on the server. // and breaks it according to '.' or '-' until it finds a match on the server.
//
for (i = (int)strlen(img_report.grub2_version), grub2_len = 0; i > 0 && grub2_len <= 0; i--) { for (i = (int)strlen(img_report.grub2_version), grub2_len = 0; i > 0 && grub2_len <= 0; i--) {
c = img_report.grub2_version[i]; c = img_report.grub2_version[i];
if (c != 0 && c != '.' && c != '-') if (c != 0 && c != '.' && c != '-')
@ -2970,6 +2979,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
if (!Notification(MSG_WARNING_QUESTION, NULL, NULL, title, lmprintf(MSG_132))) if (!Notification(MSG_WARNING_QUESTION, NULL, NULL, title, lmprintf(MSG_132)))
goto aborted_start; goto aborted_start;
} }
PrintStatus(0, MSG_142);
GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp));
if (MessageBoxExU(hMainDialog, lmprintf(MSG_003, tmp), if (MessageBoxExU(hMainDialog, lmprintf(MSG_003, tmp),
@ -3005,6 +3015,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
if (queued_hotplug_event) if (queued_hotplug_event)
SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0); SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0);
if (wParam == BOOTCHECK_CANCEL) { if (wParam == BOOTCHECK_CANCEL) {
nb_devices = ComboBox_GetCount(hDeviceList);
PrintStatus(0, (nb_devices == 1) ? MSG_208 : MSG_209, nb_devices);
PrintStatus(5000, MSG_041);
if (unattend_xml_path != NULL) { if (unattend_xml_path != NULL) {
DeleteFileU(unattend_xml_path); DeleteFileU(unattend_xml_path);
unattend_xml_path = NULL; unattend_xml_path = NULL;

View file

@ -805,7 +805,7 @@ extern void* get_data_from_asn1(const uint8_t* buf, size_t buf_len, const char*
extern int sanitize_label(char* label); extern int sanitize_label(char* label);
extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid); extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid);
extern char* GetSignatureName(const char* path, const char* country_code, BOOL bSilent); extern char* GetSignatureName(const char* path, const char* country_code, BOOL bSilent);
extern BOOL GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info); extern int GetIssuerCertificateInfo(uint8_t* cert, cert_info_t* info);
extern uint64_t GetSignatureTimeStamp(const char* path); extern uint64_t GetSignatureTimeStamp(const char* path);
extern LONG ValidateSignature(HWND hDlg, const char* path); extern LONG ValidateSignature(HWND hDlg, const char* path);
extern BOOL ValidateOpensslSignature(BYTE* pbBuffer, DWORD dwBufferLen, BYTE* pbSignature, DWORD dwSigLen); extern BOOL ValidateOpensslSignature(BYTE* pbBuffer, DWORD dwBufferLen, BYTE* pbSignature, DWORD dwSigLen);

View file

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326 IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 4.6.2202" CAPTION "Rufus 4.6.2203"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0 FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -399,8 +399,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,6,2202,0 FILEVERSION 4,6,2203,0
PRODUCTVERSION 4,6,2202,0 PRODUCTVERSION 4,6,2203,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -418,13 +418,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie" VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting" VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.6.2202" VALUE "FileVersion", "4.6.2203"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2024 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2024 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.6.exe" VALUE "OriginalFilename", "rufus-4.6.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.6.2202" VALUE "ProductVersion", "4.6.2203"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"