mirror of
https://github.com/pbatard/rufus.git
synced 2025-06-01 23:38:30 -04:00
[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:
parent
6b5837dbb5
commit
ede52c57e6
7 changed files with 98 additions and 71 deletions
|
@ -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"
|
||||||
|
|
33
src/hash.c
33
src/hash.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
src/parser.c
22
src/parser.c
|
@ -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;
|
||||||
|
|
||||||
|
|
54
src/pki.c
54
src/pki.c
|
@ -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)
|
||||||
|
|
23
src/rufus.c
23
src/rufus.c
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -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"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue