1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

Compare commits

...

2 commits

Author SHA1 Message Date
Pete Batard
7eb9a6f16b
[misc] fix some benign Coverity warnings 2023-06-18 19:09:15 +02:00
Pete Batard
be5b590cfb
[uefi] add parsing and copying of the system's SkuSiPolicy.p7b
* Instead of embedding the content of the most recent revoked bootloader hashes in db.h
  we now parse the system's SkuSiPolicy.p7b to do so. This has the drawback of not alerting
  users running Rufus on systems where SkuSiPolicy.p7b is not up to date, but I believe the
  trade-off is worth it.
* We now also copy the system's SkuSiPolicy.p7b to the created media when possible (for
  Windows 10 or later), so that Microsoft's WDAC UEFI revocations can apply during boot.
2023-06-18 19:07:45 +02:00
11 changed files with 219 additions and 2413 deletions

View file

@ -13,7 +13,9 @@
[cmdletbinding()]
param(
# (Optional) The path to the .p7b to process
[string]$BinaryFilePath = "SkuSiPolicyp.p7b"
[string]$BinaryFilePath = "SkuSiPolicy.p7b",
# (Optional) Output the straight values
[switch]$Raw = $false
)
#endregion
@ -55,7 +57,7 @@ try {
$ContentType = $null
try {
$ContentType = [Security.Cryptography.Pkcs.ContentInfo]::GetContentType($CIPolicyBytes)
} catch { Write-Host "WTF!" }
} catch { }
# Check for PKCS#7 ASN.1 SignedData type
if ($ContentType -and $ContentType.Value -eq '1.2.840.113549.1.7.2') {
@ -183,14 +185,17 @@ try {
# Sort the array and remove duplicates
$HashArray.Sort()
$HashArray = $HashArray | Select-Object -Unique
# Output as C array data
foreach ($HashStr in $HashArray) {
$HashChars = $HashStr.ToCharArray()
$Line = "`t"
for ($i = 0; $i -lt $Pe256HashLength; $i++) {
$Line += "0x" + $HashChars[2 * $i] + $HashChars[2 * $i + 1] + ", "
if ($Raw) {
Write-Output $HashStr
} else {
$HashChars = $HashStr.ToCharArray()
$Line = "`t"
for ($i = 0; $i -lt $Pe256HashLength; $i++) {
$Line += "0x" + $HashChars[2 * $i] + $HashChars[2 * $i + 1] + ", "
}
Write-Output $Line
}
Write-Output $Line
}
}

2358
src/db.h

File diff suppressed because it is too large Load diff

View file

@ -1908,6 +1908,18 @@ DWORD WINAPI FormatThread(void* param)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
}
}
} else if ((target_type == TT_UEFI) && IS_WINDOWS_1X(img_report) && pe256ssp_size > 0) {
// Copy this system's SkuSiPolicy.p7b to the target drive so that UEFI bootloaders
// revoked by Windows through WDAC policy do get flagged as revoked.
char src[MAX_PATH], dst[MAX_PATH];
struct __stat64 stat64 = { 0 };
static_sprintf(src, "%s\\SecureBootUpdates\\SKUSiPolicy.p7b", system_dir);
static_sprintf(dst, "%s\\efi\\microsoft\\boot\\SKUSiPolicy.p7b", drive_name);
if ((_stat64U(dst, &stat64) != 0) && (_stat64U(src, &stat64) == 0)) {
uprintf("Copying: %s (%s) (from %s)", dst, SizeToHumanReadable(stat64.st_size, FALSE, FALSE), src);
if (!CopyFileU(src, dst, TRUE))
uprintf(" Error writing file: %s", WindowsErrorString());
}
}
if ( (target_type == TT_BIOS) && HAS_WINPE(img_report) ) {
// Apply WinPE fixup

View file

@ -123,6 +123,8 @@ DWORD read_size[NUM_BUFFERS];
BOOL enable_extra_hashes = FALSE;
uint8_t ALIGNED(64) buffer[NUM_BUFFERS][BUFFER_SIZE];
extern int default_thread_priority;
uint32_t pe256ssp_size = 0;
uint8_t* pe256ssp = NULL;
/*
* Rotate 32 or 64 bit integers by n bytes.
@ -2117,14 +2119,14 @@ BOOL IsFileInDB(const char* path)
int IsUefiBootloaderRevoked(const char* path)
{
int i;
uint32_t i;
uint8_t hash[SHA256_HASHSIZE];
if (!PE256File(path, hash))
return -1;
for (i = 0; i < ARRAYSIZE(pe256dbx); i += SHA256_HASHSIZE)
if (memcmp(hash, &pe256dbx[i], SHA256_HASHSIZE) == 0)
return 1;
for (i = 0; i < ARRAYSIZE(pe256ssp); i += SHA256_HASHSIZE)
for (i = 0; i < pe256ssp_size * SHA256_HASHSIZE; i += SHA256_HASHSIZE)
if (memcmp(hash, &pe256ssp[i], SHA256_HASHSIZE) == 0)
return 2;
return 0;

View file

@ -1274,7 +1274,6 @@ out:
to_windows_path(symlinked_syslinux);
uprintf("Created: %s\\%s → %s", symlinked_syslinux, efi_cfg_name[i], &path[2]);
to_unix_path(symlinked_syslinux);
fd = NULL;
}
}
} else if (HAS_BOOTMGR(img_report) && enable_ntfs_compression) {

View file

@ -344,23 +344,19 @@ static __inline int DrawTextU(HDC hDC, LPCSTR lpText, int nCount, LPRECT lpRect,
static __inline int GetWindowTextU(HWND hWnd, char* lpString, int nMaxCount)
{
int ret = 0;
DWORD err = ERROR_INVALID_DATA;
if (nMaxCount < 0)
return 0;
DWORD err = ERROR_INVALID_PARAMETER;
if (lpString == NULL || nMaxCount < 1)
goto out;
// Handle the empty string as GetWindowTextW() returns 0 then
if ((lpString != NULL) && (nMaxCount > 0))
lpString[0] = 0;
// coverity[returned_null]
lpString[0] = 0;
walloc(lpString, nMaxCount);
ret = GetWindowTextW(hWnd, wlpString, nMaxCount);
err = GetLastError();
// coverity[var_deref_model]
if ( (ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpString, lpString, nMaxCount)) == 0) ) {
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpString, lpString, nMaxCount)) == 0))
err = GetLastError();
}
wfree(lpString);
if (lpString != NULL)
lpString[nMaxCount - 1] = 0;
lpString[nMaxCount - 1] = 0;
out:
SetLastError(err);
return ret;
}

View file

@ -800,10 +800,8 @@ out:
fclose(fd_in);
fd_in = NULL;
}
if (fd_out != NULL) {
if (fd_out != NULL)
fclose(fd_out);
fd_out = NULL;
}
// If an insertion occurred, delete existing file and use the new one
if (ret != NULL) {
@ -821,8 +819,10 @@ out:
} else {
uprintf("Could not write '%s' - original file has been left unmodified\n", filename);
ret = NULL;
if (fd_in != NULL) fclose(fd_in);
if (fd_out != NULL) fclose(fd_out);
if (fd_in != NULL)
fclose(fd_in);
if (fd_out != NULL)
fclose(fd_out);
}
}
if (wtmpname != NULL)

165
src/pki.c
View file

@ -48,18 +48,62 @@ const char* cert_name[3] = { "Akeo Consulting", "Akeo Systems", "Pete Batard" };
const char* cert_country = "IE";
typedef struct {
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
} SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO;
// https://msdn.microsoft.com/en-us/library/ee442238.aspx
typedef struct {
BLOBHEADER BlobHeader;
RSAPUBKEY RsaHeader;
BYTE Modulus[256]; // 2048 bit modulus
BLOBHEADER BlobHeader;
RSAPUBKEY RsaHeader;
BYTE Modulus[256]; // 2048 bit modulus
} RSA_2048_PUBKEY;
// For PKCS7 WDAC Code Integrity processing
#define PE256_HASHSIZE 32
const GUID SKU_CODE_INTEGRITY_POLICY = { 0x976d12c8, 0xcb9f, 0x4730, { 0xbe, 0x52, 0x54, 0x60, 0x08, 0x43, 0x23, 0x8e} };
typedef struct {
WORD Nano;
WORD Micro;
WORD Minor;
WORD Major;
} CIVersion;
typedef struct {
DWORD PolicyFormatVersion;
GUID PolicyTypeGUID;
GUID PlatformGUID;
DWORD OptionFlags;
DWORD EKURuleEntryCount;
DWORD FileRuleEntryCount;
DWORD SignerRuleEntryCount;
DWORD SignerScenarioEntryCount;
CIVersion PolicyVersion;
DWORD HeaderLength;
} CIHeader;
typedef struct {
DWORD Type;
DWORD FileNameLength;
WCHAR FileName[0];
} CIFileRuleHeader;
typedef struct {
DWORD Unknown;
CIVersion Version;
DWORD HashLength;
BYTE Hash[0];
} CIFileRuleData;
typedef enum {
CI_DENY = 0,
CI_ALLOW,
CI_FILE_ATTRIBUTES,
};
// The RSA public key modulus for the private key we use to sign the files on the server.
// NOTE 1: This openssl modulus must be *REVERSED* to be usable with Microsoft APIs
// NOTE 2: Also, this modulus is 2052 bits, and not 2048, because openssl adds an extra
@ -747,3 +791,112 @@ out:
CryptReleaseContext(hProv, 0);
return r;
}
BOOL ParseSKUSiPolicy(void)
{
char path[MAX_PATH];
wchar_t* wpath = NULL;
BOOL r = FALSE;
DWORD i, dwEncoding, dwContentType, dwFormatType;
DWORD dwPolicySize = 0, dwBaseIndex = 0, dwSizeCount;
HCRYPTMSG hMsg = NULL;
CRYPT_DATA_BLOB pkcsData = { 0 };
DWORD* pdwEkuRules;
BYTE* pbRule;
CIHeader* Header;
CIFileRuleHeader* FileRuleHeader;
CIFileRuleData* FileRuleData;
pe256ssp_size = 0;
safe_free(pe256ssp);
static_sprintf(path, "%s\\SecureBootUpdates\\SKUSiPolicy.p7b", system_dir);
wpath = utf8_to_wchar(path);
if (wpath == NULL)
goto out;
r = CryptQueryObject(CERT_QUERY_OBJECT_FILE, wpath, CERT_QUERY_CONTENT_FLAG_ALL,
CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncoding, &dwContentType, &dwFormatType, NULL,
&hMsg, NULL);
if (!r || dwContentType != CERT_QUERY_CONTENT_PKCS7_SIGNED)
goto out;
r = CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &pkcsData.cbData);
if (!r || pkcsData.cbData == 0) {
uprintf("ParseSKUSiPolicy: Failed to retreive CMSG_CONTENT_PARAM size: %s", WindowsErrorString());
goto out;
}
pkcsData.pbData = malloc(pkcsData.cbData);
if (pkcsData.pbData == NULL)
goto out;
r = CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pkcsData.pbData, &pkcsData.cbData);
if (!r) {
uprintf("ParseSKUSiPolicy: Failed to retreive CMSG_CONTENT_PARAM: %s", WindowsErrorString());
goto out;
}
// Now process the actual Security Policy content
if (pkcsData.pbData[0] == 4) {
dwPolicySize = pkcsData.pbData[1];
dwBaseIndex = 2;
if ((dwPolicySize & 0x80) == 0x80) {
dwSizeCount = dwPolicySize & 0x7F;
dwBaseIndex += dwSizeCount;
dwPolicySize = 0;
for (i = 0; i < dwSizeCount; i++) {
dwPolicySize = dwPolicySize << 8;
dwPolicySize = dwPolicySize | pkcsData.pbData[2 + i];
}
}
}
// Sanity checks
Header = (CIHeader*)&pkcsData.pbData[dwBaseIndex];
if (Header->HeaderLength + sizeof(uint32_t) != sizeof(CIHeader)) {
uprintf("ParseSKUSiPolicy: Unexpected Code Integrity Header size (0x%02x)", Header->HeaderLength);
goto out;
}
if (!CompareGUID(&Header->PolicyTypeGUID, &SKU_CODE_INTEGRITY_POLICY)) {
uprintf("ParseSKUSiPolicy: Unexpected Policy Type GUID %s", GuidToString(&Header->PolicyTypeGUID));
goto out;
}
// Skip the EKU Rules
pdwEkuRules = (DWORD*) &pkcsData.pbData[dwBaseIndex + sizeof(CIHeader)];
for (i = 0; i < Header->EKURuleEntryCount; i++)
pdwEkuRules = &pdwEkuRules[(*pdwEkuRules + (2 * sizeof(DWORD) - 1)) / sizeof(DWORD)];
// Process the Files Rules
pbRule = (BYTE*)pdwEkuRules;
pe256ssp = malloc(Header->FileRuleEntryCount * PE256_HASHSIZE);
if (pe256ssp == NULL)
goto out;
for (i = 0; i < Header->FileRuleEntryCount; i++) {
FileRuleHeader = (CIFileRuleHeader*)pbRule;
pbRule = &pbRule[sizeof(CIFileRuleHeader)];
if (FileRuleHeader->FileNameLength != 0) {
// uprintf("%S", FileRuleHeader->FileName);
pbRule = &pbRule[((FileRuleHeader->FileNameLength + sizeof(DWORD) - 1) / sizeof(DWORD)) * sizeof(DWORD)];
}
FileRuleData = (CIFileRuleData*)pbRule;
if (FileRuleData->HashLength > 0x80) {
uprintf("ParseSKUSiPolicy: Unexpected hash length for entry %d (0x%02x)", i, FileRuleData->HashLength);
// We're probably screwed, so bail out
break;
}
// We are only interested in 'DENY' type with PE256 hashes
if (FileRuleHeader->Type == CI_DENY && FileRuleData->HashLength == PE256_HASHSIZE) {
memcpy(&pe256ssp[pe256ssp_size * PE256_HASHSIZE], FileRuleData->Hash, PE256_HASHSIZE);
pe256ssp_size++;
}
pbRule = &pbRule[sizeof(CIFileRuleData) + ((FileRuleData->HashLength + sizeof(DWORD) - 1) / sizeof(DWORD)) * sizeof(DWORD)];
}
r = TRUE;
out:
if (hMsg != NULL)
CryptMsgClose(hMsg);
free(pkcsData.pbData);
free(wpath);
return r;
}

View file

@ -2061,6 +2061,10 @@ static void InitDialog(HWND hDlg)
"one. Because of this, some messages will only be displayed in English.", selected_locale->txt[1]);
uprintf("If you think you can help update this translation, please e-mail the author of this application");
}
if (ParseSKUSiPolicy())
uprintf("Found %d revoked UEFI bootloaders from this system's SKUSiPolicy", pe256ssp_size);
else
uprintf("WARNING: Could not parse this system's SkuSiPolicy");
// Detect and report system limitations
if (ReadRegistryKeyBool(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Policies\\Microsoft\\FVE"))
uprintf("WARNING: This system has a policy set to prevent write access to FIXED drives not using BitLocker");
@ -3885,17 +3889,7 @@ extern int TestHashes(void);
// Ctrl-T => Alternate Test mode that doesn't require a full rebuild
if ((ctrl_without_focus || ((GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN)))
&& (msg.wParam == 'T')) {
uint8_t sum[32] = { 0 };
PE256File("C:\\Projects\\rufus\\winload_win10_1511.exe", sum);
DumpBufferHex(sum, 32);
int aya = IsUefiBootloaderRevoked("C:\\Projects\\WDACTools\\en_windows_10_multiple_editions_version_1607_updated_jan_2017_x64_dvd_9714399.iso\\efi\\boot\\bootx64.efi");
if (aya > 0) {
MessageBoxExU(hMainDialog, lmprintf(MSG_339,
(aya == 1) ? lmprintf(MSG_340) : lmprintf(MSG_341, "Error code: 0xc0000428")),
lmprintf(MSG_338), MB_ICONWARNING | MB_IS_RTL, selected_langid);
}
// TestHashes();
TestHashes();
continue;
}
#endif
@ -4236,6 +4230,7 @@ out:
safe_free(grub2_buf);
safe_free(fido_url);
safe_free(fido_script);
safe_free(pe256ssp);
if (argv != NULL) {
for (i=0; i<argc; i++) safe_free(argv[i]);
safe_free(argv);

View file

@ -577,16 +577,17 @@ extern RUFUS_UPDATE update;
extern RUFUS_IMG_REPORT img_report;
extern HINSTANCE hMainInstance;
extern HWND hMainDialog, hLogDialog, hStatus, hDeviceList, hCapacity, hImageOption;
extern HWND hPartitionScheme, hTargetSystem, hFileSystem, hClusterSize, hLabel, hBootType, hNBPasses, hLog;
extern HWND hInfo, hProgress, hDiskID;
extern HWND hPartitionScheme, hTargetSystem, hFileSystem, hClusterSize, hLabel, hBootType;
extern HWND hNBPasses, hLog, hInfo, hProgress, hDiskID;
extern WORD selected_langid;
extern DWORD FormatStatus, DownloadStatus, MainThreadId, LastWriteError;
extern BOOL use_own_c32[NB_OLD_C32], detect_fakes, op_in_progress, right_to_left_mode;
extern BOOL allow_dual_uefi_bios, large_drive, usb_debug;
extern int64_t iso_blocking_status;
extern uint8_t image_options;
extern uint8_t image_options, *pe256ssp;
extern uint16_t rufus_version[3], embedded_sl_version[2];
extern uint32_t pe256ssp_size;
extern uint64_t persistence_size;
extern int64_t iso_blocking_status;
extern size_t ubuffer_pos;
extern const int nb_steps[FS_MAX];
extern float fScale;
@ -594,8 +595,8 @@ extern windows_version_t WindowsVersion;
extern int dialog_showing, force_update, fs_type, boot_type, partition_type, target_type;
extern unsigned long syslinux_ldlinux_len[2];
extern char ubuffer[UBUFFER_SIZE], embedded_sl_version_str[2][12];
extern char szFolderPath[MAX_PATH], app_dir[MAX_PATH], temp_dir[MAX_PATH], system_dir[MAX_PATH], sysnative_dir[MAX_PATH];
extern char app_data_dir[MAX_PATH], *image_path, *fido_url;
extern char szFolderPath[MAX_PATH], app_dir[MAX_PATH], temp_dir[MAX_PATH], system_dir[MAX_PATH];
extern char sysnative_dir[MAX_PATH], app_data_dir[MAX_PATH], *image_path, *fido_url;
/*
* Shared prototypes
@ -690,6 +691,7 @@ extern char* GetSignatureName(const char* path, const char* country_code, BOOL b
extern uint64_t GetSignatureTimeStamp(const char* path);
extern LONG ValidateSignature(HWND hDlg, const char* path);
extern BOOL ValidateOpensslSignature(BYTE* pbBuffer, DWORD dwBufferLen, BYTE* pbSignature, DWORD dwSigLen);
extern BOOL ParseSKUSiPolicy(void);
extern BOOL IsFontAvailable(const char* font_name);
extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries);

View file

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