mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[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.
This commit is contained in:
parent
43764268de
commit
be5b590cfb
8 changed files with 207 additions and 2396 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
src/format.c
12
src/format.c
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
165
src/pki.c
165
src/pki.c
|
@ -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;
|
||||
}
|
||||
|
|
17
src/rufus.c
17
src/rufus.c
|
@ -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);
|
||||
|
|
14
src/rufus.h
14
src/rufus.h
|
@ -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);
|
||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -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.2051"
|
||||
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,2051,0
|
||||
PRODUCTVERSION 4,2,2051,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.2051"
|
||||
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.2051"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
Loading…
Reference in a new issue