VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp@ 51819

Last change on this file since 51819 was 51819, checked in by vboxsync, 11 years ago

timestamp tweak.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 81.9 KB
Line 
1/* $Id: SUPHardenedVerifyImage-win.cpp 51819 2014-07-02 18:20:33Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library/Driver - Hardened Image Verification, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#ifdef IN_RING0
31# define IPRT_NT_MAP_TO_ZW
32# include <iprt/nt/nt.h>
33# include <ntimage.h>
34#else
35# include <iprt/nt/nt-and-windows.h>
36# include "Wintrust.h"
37# include "Softpub.h"
38# include "mscat.h"
39# ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR
40# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x800
41# endif
42#endif
43
44#include <VBox/sup.h>
45#include <VBox/err.h>
46#include <iprt/ctype.h>
47#include <iprt/ldr.h>
48#include <iprt/log.h>
49#include <iprt/path.h>
50#include <iprt/string.h>
51#include <iprt/crypto/pkcs7.h>
52#include <iprt/crypto/store.h>
53
54#ifdef IN_RING0
55# include "SUPDrvInternal.h"
56#else
57# include "SUPLibInternal.h"
58#endif
59#include "win/SUPHardenedVerify-win.h"
60
61
62/*******************************************************************************
63* Defined Constants And Macros *
64*******************************************************************************/
65/** The size of static hash (output) buffers.
66 * Avoids dynamic allocations and cleanups for of small buffers as well as extra
67 * calls for getting the appropriate buffer size. The largest digest in regular
68 * use by current windows version is SHA-512, we double this and hope it's
69 * enough a good while. */
70#define SUPHARDNTVI_MAX_CAT_HASH_SIZE 128
71
72
73/*******************************************************************************
74* Structures and Typedefs *
75*******************************************************************************/
76/**
77 * SUP image verifier loader reader instance.
78 */
79typedef struct SUPHNTVIRDR
80{
81 /** The core reader structure. */
82 RTLDRREADER Core;
83 /** The file handle . */
84 HANDLE hFile;
85 /** Current file offset. */
86 RTFOFF off;
87 /** The file size. */
88 RTFOFF cbFile;
89 /** Flags for the verification callback, SUPHNTVI_F_XXX. */
90 uint32_t fFlags;
91 /** The executable timstamp in second since unix epoch. */
92 uint64_t uTimestamp;
93 /** Log name. */
94 char szFilename[1];
95} SUPHNTVIRDR;
96/** Pointer to an SUP image verifier loader reader instance. */
97typedef SUPHNTVIRDR *PSUPHNTVIRDR;
98
99
100#ifdef IN_RING3
101typedef LONG (WINAPI * PFNWINVERIFYTRUST)(HWND hwnd, GUID const *pgActionID, PVOID pWVTData);
102typedef BOOL (WINAPI * PFNCRYPTCATADMINACQUIRECONTEXT)(HCATADMIN *phCatAdmin, const GUID *pGuidSubsystem, DWORD dwFlags);
103typedef BOOL (WINAPI * PFNCRYPTCATADMINACQUIRECONTEXT2)(HCATADMIN *phCatAdmin, const GUID *pGuidSubsystem, PCWSTR pwszHashAlgorithm,
104 struct _CERT_STRONG_SIGN_PARA const *pStrongHashPolicy, DWORD dwFlags);
105typedef BOOL (WINAPI * PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE)(HANDLE hFile, DWORD *pcbHash, BYTE *pbHash, DWORD dwFlags);
106typedef BOOL (WINAPI * PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2)(HCATADMIN hCatAdmin, HANDLE hFile, DWORD *pcbHash,
107 BYTE *pbHash, DWORD dwFlags);
108typedef HCATINFO (WINAPI *PFNCRYPTCATADMINENUMCATALOGFROMHASH)(HCATADMIN hCatAdmin, BYTE *pbHash, DWORD cbHash,
109 DWORD dwFlags, HCATINFO *phPrevCatInfo);
110typedef BOOL (WINAPI * PFNCRYPTCATADMINRELEASECATALOGCONTEXT)(HCATADMIN hCatAdmin, HCATINFO hCatInfo, DWORD dwFlags);
111typedef BOOL (WINAPI * PFNCRYPTCATDADMINRELEASECONTEXT)(HCATADMIN hCatAdmin, DWORD dwFlags);
112typedef BOOL (WINAPI * PFNCRYPTCATCATALOGINFOFROMCONTEXT)(HCATINFO hCatInfo, CATALOG_INFO *psCatInfo, DWORD dwFlags);
113
114typedef HCERTSTORE (WINAPI *PFNCERTOPENSTORE)(PCSTR pszStoreProvider, DWORD dwEncodingType, HCRYPTPROV_LEGACY hCryptProv,
115 DWORD dwFlags, const void *pvParam);
116typedef BOOL (WINAPI *PFNCERTCLOSESTORE)(HCERTSTORE hCertStore, DWORD dwFlags);
117typedef PCCERT_CONTEXT (WINAPI *PFNCERTENUMCERTIFICATESINSTORE)(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext);
118#endif
119
120
121/*******************************************************************************
122* Global Variables *
123*******************************************************************************/
124/** The build certificate. */
125static RTCRX509CERTIFICATE g_BuildX509Cert;
126
127/** Store for root software publisher certificates. */
128static RTCRSTORE g_hSpcRootStore = NIL_RTCRSTORE;
129/** Store for root NT kernel certificates. */
130static RTCRSTORE g_hNtKernelRootStore = NIL_RTCRSTORE;
131
132/** Store containing SPC, NT kernel signing, and timestamp root certificates. */
133static RTCRSTORE g_hSpcAndNtKernelRootStore = NIL_RTCRSTORE;
134/** Store for supplemental certificates for use with
135 * g_hSpcAndNtKernelRootStore. */
136static RTCRSTORE g_hSpcAndNtKernelSuppStore = NIL_RTCRSTORE;
137
138/** The full \\SystemRoot\\System32 path. */
139SUPSYSROOTDIRBUF g_System32NtPath;
140/** The full \\SystemRoot\\WinSxS path. */
141SUPSYSROOTDIRBUF g_WinSxSNtPath;
142
143/** Set after we've retrived other SPC root certificates from the system. */
144static bool g_fHaveOtherRoots = false;
145
146#if defined(IN_RING3) && !defined(IN_SUP_HARDENED_R3)
147/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED and
148 * SUP_MAKE_NT_VER_SIMPLE. */
149uint32_t g_uNtVerCombined;
150#endif
151
152#ifdef IN_RING3
153/** Timestamp hack working around issues with old DLLs that we ship. */
154static uint64_t g_uBuildTimestampHack = 0;
155#endif
156
157#ifdef IN_RING3
158/** Pointer to WinVerifyTrust. */
159PFNWINVERIFYTRUST g_pfnWinVerifyTrust;
160/** Pointer to CryptCATAdminAcquireContext. */
161PFNCRYPTCATADMINACQUIRECONTEXT g_pfnCryptCATAdminAcquireContext;
162/** Pointer to CryptCATAdminAcquireContext2 if available. */
163PFNCRYPTCATADMINACQUIRECONTEXT2 g_pfnCryptCATAdminAcquireContext2;
164/** Pointer to CryptCATAdminCalcHashFromFileHandle. */
165PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE g_pfnCryptCATAdminCalcHashFromFileHandle;
166/** Pointer to CryptCATAdminCalcHashFromFileHandle2. */
167PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2 g_pfnCryptCATAdminCalcHashFromFileHandle2;
168/** Pointer to CryptCATAdminEnumCatalogFromHash. */
169PFNCRYPTCATADMINENUMCATALOGFROMHASH g_pfnCryptCATAdminEnumCatalogFromHash;
170/** Pointer to CryptCATAdminReleaseCatalogContext. */
171PFNCRYPTCATADMINRELEASECATALOGCONTEXT g_pfnCryptCATAdminReleaseCatalogContext;
172/** Pointer to CryptCATAdminReleaseContext. */
173PFNCRYPTCATDADMINRELEASECONTEXT g_pfnCryptCATAdminReleaseContext;
174/** Pointer to CryptCATCatalogInfoFromContext. */
175PFNCRYPTCATCATALOGINFOFROMCONTEXT g_pfnCryptCATCatalogInfoFromContext;
176#endif
177
178
179/*******************************************************************************
180* Internal Functions *
181*******************************************************************************/
182#ifdef IN_RING3
183static int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
184 PFNWINVERIFYTRUST pfnWinVerifyTrust);
185static int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
186 PFNWINVERIFYTRUST pfnWinVerifyTrust);
187#endif
188
189
190
191
192/** @copydoc RTLDRREADER::pfnRead */
193static DECLCALLBACK(int) supHardNtViRdrRead(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off)
194{
195 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
196 Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
197
198 if ((ULONG)cb != cb)
199 return VERR_OUT_OF_RANGE;
200
201
202 /*
203 * For some reason I'm getting occational read error in an XP VM with
204 * STATUS_FAILED_DRIVER_ENTRY. Redoing the call again works in the
205 * debugger, so try do that automatically.
206 */
207 for (uint32_t iTry = 0;; iTry++)
208 {
209 LARGE_INTEGER offNt;
210 offNt.QuadPart = off;
211
212 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
213 NTSTATUS rcNt = NtReadFile(pNtViRdr->hFile,
214 NULL /*hEvent*/,
215 NULL /*ApcRoutine*/,
216 NULL /*ApcContext*/,
217 &Ios,
218 pvBuf,
219 (ULONG)cb,
220 &offNt,
221 NULL);
222 if (NT_SUCCESS(rcNt))
223 rcNt = Ios.Status;
224 if (NT_SUCCESS(rcNt))
225 {
226 if (Ios.Information == cb)
227 {
228 pNtViRdr->off = off + cb;
229 return VINF_SUCCESS;
230 }
231#ifdef IN_RING3
232 supR3HardenedError(VERR_READ_ERROR, false,
233 "supHardNtViRdrRead: Only got %#zx bytes when requesting %#zx bytes at %#llx in '%s'.\n",
234 Ios.Information, off, cb, pNtViRdr->szFilename);
235#endif
236 pNtViRdr->off = -1;
237 return VERR_READ_ERROR;
238 }
239
240 /*
241 * Delay a little before we retry?
242 */
243#ifdef IN_RING3
244 if (iTry == 0)
245 NtYieldExecution();
246 else if (iTry >= 1)
247 {
248 LARGE_INTEGER Time;
249 Time.QuadPart = -1000000 / 100; /* 1ms in 100ns units, relative time. */
250 NtDelayExecution(TRUE, &Time);
251 }
252#endif
253 /*
254 * Before we give up, we'll try split up the request in case the
255 * kernel is low on memory or similar. For simplicity reasons, we do
256 * this in a recursion fashion.
257 */
258 if (iTry >= 2)
259 {
260 if (cb >= _8K)
261 {
262 size_t const cbBlock = RT_ALIGN_Z(cb / 4, 512);
263 while (cb > 0)
264 {
265 size_t cbThisRead = RT_MIN(cb, cbBlock);
266 int rc = supHardNtViRdrRead(&pNtViRdr->Core, pvBuf, cbThisRead, off);
267 if (RT_FAILURE(rc))
268 return rc;
269 off += cbThisRead;
270 cb -= cbThisRead;
271 pvBuf = (uint8_t *)pvBuf + cbThisRead;
272 }
273 return VINF_SUCCESS;
274 }
275
276#ifdef IN_RING3
277 supR3HardenedError(VERR_READ_ERROR, false, "supHardNtViRdrRead: Error %#x reading %#zx bytes at %#llx in '%s'.\n",
278 rcNt, off, cb, pNtViRdr->szFilename);
279#endif
280 pNtViRdr->off = -1;
281 return VERR_READ_ERROR;
282 }
283 }
284}
285
286
287/** @copydoc RTLDRREADER::pfnTell */
288static DECLCALLBACK(RTFOFF) supHardNtViRdrTell(PRTLDRREADER pReader)
289{
290 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
291 Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
292 return pNtViRdr->off;
293}
294
295
296/** @copydoc RTLDRREADER::pfnSize */
297static DECLCALLBACK(RTFOFF) supHardNtViRdrSize(PRTLDRREADER pReader)
298{
299 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
300 Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
301 return pNtViRdr->cbFile;
302}
303
304
305/** @copydoc RTLDRREADER::pfnLogName */
306static DECLCALLBACK(const char *) supHardNtViRdrLogName(PRTLDRREADER pReader)
307{
308 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
309 return pNtViRdr->szFilename;
310}
311
312
313/** @copydoc RTLDRREADER::pfnMap */
314static DECLCALLBACK(int) supHardNtViRdrMap(PRTLDRREADER pReader, const void **ppvBits)
315{
316 return VERR_NOT_SUPPORTED;
317}
318
319
320/** @copydoc RTLDRREADER::pfnUnmap */
321static DECLCALLBACK(int) supHardNtViRdrUnmap(PRTLDRREADER pReader, const void *pvBits)
322{
323 return VERR_NOT_SUPPORTED;
324}
325
326
327/** @copydoc RTLDRREADER::pfnDestroy */
328static DECLCALLBACK(int) supHardNtViRdrDestroy(PRTLDRREADER pReader)
329{
330 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
331 Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
332
333 pNtViRdr->Core.uMagic = ~RTLDRREADER_MAGIC;
334 pNtViRdr->hFile = NULL;
335
336 RTMemFree(pNtViRdr);
337 return VINF_SUCCESS;
338}
339
340
341/**
342 * Creates a loader reader instance for the given NT file handle.
343 *
344 * @returns iprt status code.
345 * @param hFile Native NT file handle.
346 * @param pwszName Optional file name.
347 * @param fFlags Flags, SUPHNTVI_F_XXX.
348 * @param ppNtViRdr Where to store the reader instance on success.
349 */
350static int supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr)
351{
352 /*
353 * Try determine the size of the file.
354 */
355 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
356 FILE_STANDARD_INFORMATION StdInfo;
357 NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), FileStandardInformation);
358 if (!NT_SUCCESS(rcNt) || !NT_SUCCESS(Ios.Status))
359 return VERR_LDRVI_FILE_LENGTH_ERROR;
360
361 /*
362 * Calc the file name length and allocate memory for the reader instance.
363 */
364 size_t cchFilename = 0;
365 if (pwszName)
366 cchFilename = RTUtf16CalcUtf8Len(pwszName);
367
368 int rc = VERR_NO_MEMORY;
369 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)RTMemAllocZ(sizeof(*pNtViRdr) + cchFilename);
370 if (!pNtViRdr)
371 return VERR_NO_MEMORY;
372
373 /*
374 * Initialize the structure.
375 */
376 if (cchFilename)
377 {
378 char *pszName = &pNtViRdr->szFilename[0];
379 rc = RTUtf16ToUtf8Ex(pwszName, RTSTR_MAX, &pszName, cchFilename + 1, NULL);
380 AssertStmt(RT_SUCCESS(rc), pNtViRdr->szFilename[0] = '\0');
381 }
382 else
383 pNtViRdr->szFilename[0] = '\0';
384
385 pNtViRdr->Core.uMagic = RTLDRREADER_MAGIC;
386 pNtViRdr->Core.pfnRead = supHardNtViRdrRead;
387 pNtViRdr->Core.pfnTell = supHardNtViRdrTell;
388 pNtViRdr->Core.pfnSize = supHardNtViRdrSize;
389 pNtViRdr->Core.pfnLogName = supHardNtViRdrLogName;
390 pNtViRdr->Core.pfnMap = supHardNtViRdrMap;
391 pNtViRdr->Core.pfnUnmap = supHardNtViRdrUnmap;
392 pNtViRdr->Core.pfnDestroy = supHardNtViRdrDestroy;
393 pNtViRdr->hFile = hFile;
394 pNtViRdr->off = 0;
395 pNtViRdr->cbFile = StdInfo.EndOfFile.QuadPart;
396 pNtViRdr->fFlags = fFlags;
397 *ppNtViRdr = pNtViRdr;
398 return VINF_SUCCESS;
399}
400
401
402/**
403 * Simple case insensitive UTF-16 / ASCII path compare.
404 *
405 * @returns true if equal, false if not.
406 * @param pwszLeft The UTF-16 path string.
407 * @param pszRight The ascii string.
408 */
409static bool supHardViUtf16PathIsEqual(PCRTUTF16 pwszLeft, const char *pszRight)
410{
411 for (;;)
412 {
413 RTUTF16 wc = *pwszLeft++;
414 uint8_t b = *pszRight++;
415 if (b != wc)
416 {
417 if (wc >= 0x80)
418 return false;
419 wc = RT_C_TO_LOWER(wc);
420 if (wc != b)
421 {
422 b = RT_C_TO_LOWER(b);
423 if (wc != b)
424 {
425 if (wc == '/')
426 wc = '\\';
427 if (b == '/')
428 b = '\\';
429 if (wc != b)
430 return false;
431 }
432 }
433 }
434 if (!b)
435 return true;
436 }
437}
438
439
440/**
441 * Simple case insensitive UTF-16 / ASCII ends-with path predicate.
442 *
443 * @returns true if equal, false if not.
444 * @param pwsz The UTF-16 path string.
445 * @param pszSuffix The ascii suffix string.
446 */
447static bool supHardViUtf16PathEndsWith(PCRTUTF16 pwsz, const char *pszSuffix)
448{
449 size_t cwc = RTUtf16Len(pwsz);
450 size_t cchSuffix = strlen(pszSuffix);
451 if (cwc >= cchSuffix)
452 return supHardViUtf16PathIsEqual(pwsz + cwc - cchSuffix, pszSuffix);
453 return false;
454}
455
456
457/**
458 * Simple case insensitive UTF-16 / ASCII starts-with path predicate.
459 *
460 * @returns true if starts with given string, false if not.
461 * @param pwsz The UTF-16 path string.
462 * @param pszPrefix The ascii prefix string.
463 */
464static bool supHardViUtf16PathStartsWith(PCRTUTF16 pwszLeft, const char *pszRight)
465{
466 for (;;)
467 {
468 RTUTF16 wc = *pwszLeft++;
469 uint8_t b = *pszRight++;
470 if (b != wc)
471 {
472 if (!b)
473 return true;
474 if (wc >= 0x80 || wc == 0)
475 return false;
476 wc = RT_C_TO_LOWER(wc);
477 if (wc != b)
478 {
479 b = RT_C_TO_LOWER(b);
480 if (wc != b)
481 {
482 if (wc == '/')
483 wc = '\\';
484 if (b == '/')
485 b = '\\';
486 if (wc != b)
487 return false;
488 }
489 }
490 }
491 }
492}
493
494
495/**
496 * Counts slashes in the given UTF-8 path string.
497 *
498 * @returns Number of slashes.
499 * @param pwsz The UTF-16 path string.
500 */
501static uint32_t supHardViUtf16PathCountSlashes(PCRTUTF16 pwsz)
502{
503 uint32_t cSlashes = 0;
504 RTUTF16 wc;
505 while ((wc = *pwsz++) != '\0')
506 if (wc == '/' || wc == '\\')
507 cSlashes++;
508 return cSlashes;
509}
510
511
512/**
513 * Checks if the unsigned DLL is fine or not.
514 *
515 * @returns VINF_LDRVI_NOT_SIGNED or @a rc.
516 * @param hLdrMod The loader module handle.
517 * @param pwszName The NT name of the DLL/EXE.
518 * @param fFlags Flags.
519 * @param rc The status code..
520 */
521static int supHardNtViCheckIfNotSignedOk(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, uint32_t fFlags, int rc)
522{
523 if (fFlags & (SUPHNTVI_F_REQUIRE_BUILD_CERT | SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING))
524 return rc;
525
526 /*
527 * Version macros.
528 */
529 uint32_t const uNtVer = g_uNtVerCombined;
530#define IS_XP() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(5, 1) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(5, 2) )
531#define IS_W2K3() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(5, 2) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(5, 3) )
532#define IS_VISTA() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 0) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 1) )
533#define IS_W70() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 1) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 2) )
534#define IS_W80() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 2) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 3) )
535#define IS_W81() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 3) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 4) )
536
537 /*
538 * The System32 directory.
539 *
540 * System32 is full of unsigned DLLs shipped by microsoft, graphics
541 * hardware vendors, input device/method vendors and whatnot else that
542 * actually needs to be loaded into a process for it to work correctly.
543 * We have to ASSUME that anything our process attempts to load from
544 * System32 is trustworthy and that the Windows system with the help of
545 * anti-virus software make sure there is nothing evil lurking in System32
546 * or being loaded from it.
547 *
548 * A small measure of protection is to list DLLs we know should be signed
549 * and decline loading unsigned versions of them, assuming they have been
550 * replaced by an adversary with evil intentions.
551 */
552 PCRTUTF16 pwsz;
553 uint32_t cwcName = (uint32_t)RTUtf16Len(pwszName);
554 uint32_t cwcOther = g_System32NtPath.UniStr.Length / sizeof(WCHAR);
555 if ( cwcName > cwcOther
556 && RTPATH_IS_SLASH(pwszName[cwcOther])
557 && memcmp(pwszName, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length) == 0)
558 {
559 pwsz = pwszName + cwcOther + 1;
560
561 /* Core DLLs. */
562 if (supHardViUtf16PathIsEqual(pwsz, "ntdll.dll"))
563 return uNtVer < SUP_NT_VER_VISTA ? VINF_LDRVI_NOT_SIGNED : rc;
564 if (supHardViUtf16PathIsEqual(pwsz, "kernel32.dll"))
565 return uNtVer < SUP_NT_VER_W81 ? VINF_LDRVI_NOT_SIGNED : rc;
566 if (supHardViUtf16PathIsEqual(pwsz, "kernelbase.dll"))
567 return IS_W80() || IS_W70() ? VINF_LDRVI_NOT_SIGNED : rc;
568 if (supHardViUtf16PathIsEqual(pwsz, "apisetschema.dll"))
569 return IS_W70() ? VINF_LDRVI_NOT_SIGNED : rc;
570 if (supHardViUtf16PathIsEqual(pwsz, "apphelp.dll"))
571 return uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 4) ? VINF_LDRVI_NOT_SIGNED : rc;
572
573#ifndef IN_RING0
574 /* The ATI drivers load system drivers into the process, allow this,
575 but reject anything else from a subdirectory. */
576 uint32_t cSlashes = supHardViUtf16PathCountSlashes(pwsz);
577 if (cSlashes > 0)
578 {
579 if ( cSlashes == 1
580 && supHardViUtf16PathStartsWith(pwsz, "drivers\\ati")
581 && ( supHardViUtf16PathEndsWith(pwsz, ".sys")
582 || supHardViUtf16PathEndsWith(pwsz, ".dll") ) )
583 return VINF_LDRVI_NOT_SIGNED;
584 return rc;
585 }
586
587 /* Check that this DLL isn't supposed to be signed on this windows
588 version. If it should, it's likely to be a fake. */
589 /** @todo list of signed dlls for various windows versions. */
590
591 /** @todo check file permissions? TrustedInstaller is supposed to be involved
592 * with all of them. */
593 return VINF_LDRVI_NOT_SIGNED;
594#else
595 return rc;
596#endif
597 }
598
599#ifndef IN_RING0
600 /*
601 * The WinSxS white list.
602 *
603 * Just like with System32 there are potentially a number of DLLs that
604 * could be required from WinSxS. However, so far only comctl32.dll
605 * variations have been required. So, we limit ourselves to explicit
606 * whitelisting of unsigned families of DLLs.
607 */
608 cwcOther = g_WinSxSNtPath.UniStr.Length / sizeof(WCHAR);
609 if ( cwcName > cwcOther
610 && RTPATH_IS_SLASH(pwszName[cwcOther])
611 && memcmp(pwszName, g_WinSxSNtPath.UniStr.Buffer, g_WinSxSNtPath.UniStr.Length) == 0)
612 {
613 pwsz = pwszName + cwcOther + 1;
614 cwcName -= cwcOther + 1;
615
616 /* The WinSxS layout means everything worth loading is exactly one level down. */
617 uint32_t cSlashes = supHardViUtf16PathCountSlashes(pwsz);
618 if (cSlashes != 1)
619 return rc;
620
621# if 0 /* See below */
622 /* The common controls mess. */
623# ifdef RT_ARCH_AMD64
624 if (supHardViUtf16PathStartsWith(pwsz, "amd64_microsoft.windows.common-controls_"))
625# elif defined(RT_ARCH_X86)
626 if (supHardViUtf16PathStartsWith(pwsz, "x86_microsoft.windows.common-controls_"))
627# else
628# error "Unsupported architecture"
629# endif
630 {
631 if (supHardViUtf16PathEndsWith(pwsz, "\\comctl32.dll"))
632 return VINF_LDRVI_NOT_SIGNED;
633 }
634# endif
635
636 /* Allow anything slightly microsoftish from WinSxS. W2K3 wanted winhttp.dll early on... */
637# ifdef RT_ARCH_AMD64
638 if (supHardViUtf16PathStartsWith(pwsz, "amd64_microsoft."))
639# elif defined(RT_ARCH_X86)
640 if (supHardViUtf16PathStartsWith(pwsz, "x86_microsoft."))
641# else
642# error "Unsupported architecture"
643# endif
644 {
645 return VINF_LDRVI_NOT_SIGNED;
646 }
647
648 return rc;
649 }
650#endif
651
652 return rc;
653}
654
655
656/**
657 * @callback_method_impl{RTCRPKCS7VERIFYCERTCALLBACK,
658 * Standard code signing. Use this for Microsoft SPC.}
659 */
660static DECLCALLBACK(int) supHardNtViCertVerifyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths,
661 void *pvUser, PRTERRINFO pErrInfo)
662{
663 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pvUser;
664 Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
665
666 /*
667 * If there is no certificate path build & validator associated with this
668 * callback, it must be because of the build certificate. We trust the
669 * build certificate without any second thoughts.
670 */
671 if (hCertPaths == NIL_RTCRX509CERTPATHS)
672 {
673 if (RTCrX509Certificate_Compare(pCert, &g_BuildX509Cert) == 0) /* healthy paranoia */
674 return VINF_SUCCESS;
675 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_BUILD_CERT_IPE, "Not valid kernel code signature.");
676 }
677
678 /*
679 * Standard code signing capabilites required.
680 */
681 int rc = RTCrPkcs7VerifyCertCallbackCodeSigning(pCert, hCertPaths, NULL, pErrInfo);
682 if (RT_SUCCESS(rc))
683 {
684 /*
685 * If kernel signing, a valid certificate path must be anchored by the
686 * microsoft kernel signing root certificate.
687 */
688 if (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
689 {
690 uint32_t cPaths = RTCrX509CertPathsGetPathCount(hCertPaths);
691 uint32_t cFound = 0;
692 uint32_t cValid = 0;
693 for (uint32_t iPath = 0; iPath < cPaths; iPath++)
694 {
695 bool fTrusted;
696 PCRTCRX509NAME pSubject;
697 PCRTCRX509SUBJECTPUBLICKEYINFO pPublicKeyInfo;
698 int rcVerify;
699 rc = RTCrX509CertPathsQueryPathInfo(hCertPaths, iPath, &fTrusted, NULL /*pcNodes*/, &pSubject, &pPublicKeyInfo,
700 NULL, NULL /*pCertCtx*/, &rcVerify);
701 AssertRCBreak(rc);
702
703 if (RT_SUCCESS(rcVerify))
704 {
705 Assert(fTrusted);
706 cValid++;
707
708 /*
709 * Search the kernel signing root store for a matching anchor.
710 */
711 RTCRSTORECERTSEARCH Search;
712 rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(g_hNtKernelRootStore, pSubject, &Search);
713 AssertRCBreak(rc);
714
715 PCRTCRCERTCTX pCertCtx;
716 while ((pCertCtx = RTCrStoreCertSearchNext(g_hNtKernelRootStore, &Search)) != NULL)
717 {
718 PCRTCRX509SUBJECTPUBLICKEYINFO pCertPubKeyInfo = NULL;
719 if (pCertCtx->pCert)
720 pCertPubKeyInfo = &pCertCtx->pCert->TbsCertificate.SubjectPublicKeyInfo;
721 else if (pCertCtx->pTaInfo)
722 pCertPubKeyInfo = &pCertCtx->pTaInfo->PubKey;
723 else
724 pCertPubKeyInfo = NULL;
725 if ( pCertPubKeyInfo
726 && RTCrX509SubjectPublicKeyInfo_Compare(pCertPubKeyInfo, pPublicKeyInfo) == 0)
727 cFound++;
728 RTCrCertCtxRelease(pCertCtx);
729 }
730
731 int rc2 = RTCrStoreCertSearchDestroy(g_hNtKernelRootStore, &Search); AssertRC(rc2);
732 }
733 }
734 if (RT_SUCCESS(rc) && cFound == 0)
735 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE, "Not valid kernel code signature.");
736 if (RT_SUCCESS(rc) && cValid < 2 && g_fHaveOtherRoots)
737 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_UNEXPECTED_VALID_PATH_COUNT,
738 "Expected at least %u valid paths, not %u.", 2, cValid);
739 }
740 }
741
742 /*
743 * More requirements? NT5 build lab?
744 */
745
746 return rc;
747}
748
749
750static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, RTLDRSIGNATURETYPE enmSignature,
751 void const *pvSignature, size_t cbSignature,
752 PRTERRINFO pErrInfo, void *pvUser)
753{
754 /*
755 * Check out the input.
756 */
757 PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pvUser;
758 Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
759
760 AssertReturn(cbSignature == sizeof(RTCRPKCS7CONTENTINFO), VERR_INTERNAL_ERROR_5);
761 PCRTCRPKCS7CONTENTINFO pContentInfo = (PCRTCRPKCS7CONTENTINFO)pvSignature;
762 AssertReturn(RTCrPkcs7ContentInfo_IsSignedData(pContentInfo), VERR_INTERNAL_ERROR_5);
763 AssertReturn(pContentInfo->u.pSignedData->SignerInfos.cItems == 1, VERR_INTERNAL_ERROR_5);
764 PCRTCRPKCS7SIGNERINFO pSignerInfo = &pContentInfo->u.pSignedData->SignerInfos.paItems[0];
765
766 /*
767 * If special certificate requirements, check them out before validating
768 * the signature.
769 */
770 if (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT)
771 {
772 if (!RTCrX509Certificate_MatchIssuerAndSerialNumber(&g_BuildX509Cert,
773 &pSignerInfo->IssuerAndSerialNumber.Name,
774 &pSignerInfo->IssuerAndSerialNumber.SerialNumber))
775 return RTErrInfoSet(pErrInfo, VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT, "Not signed with the build certificate.");
776 }
777
778 /*
779 * Verify the signature.
780 */
781 RTTIMESPEC ValidationTime;
782 RTTimeSpecSetSeconds(&ValidationTime, pNtViRdr->uTimestamp);
783
784 return RTCrPkcs7VerifySignedData(pContentInfo, 0, g_hSpcAndNtKernelSuppStore, g_hSpcAndNtKernelRootStore, &ValidationTime,
785 supHardNtViCertVerifyCallback, pNtViRdr, pErrInfo);
786}
787
788
789/**
790 * Checks if it's safe to call WinVerifyTrust or whether we might end up in an
791 * infinite recursion.
792 *
793 * @returns true if ok, false if not.
794 * @param hFile The file name.
795 * @param pwszName The executable name.
796 */
797static bool supR3HardNtViCanCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName)
798{
799 /*
800 * Recursion preventions hacks:
801 * - Don't try call WinVerifyTrust on Wintrust.dll when called from the
802 * create section hook. CRYPT32.DLL tries to load WinTrust.DLL in some cases.
803 */
804 size_t cwcName = RTUtf16Len(pwszName);
805 if ( hFile != NULL
806 && cwcName > g_System32NtPath.UniStr.Length / sizeof(WCHAR)
807 && !memcmp(pwszName, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length)
808 && supHardViUtf16PathIsEqual(&pwszName[g_System32NtPath.UniStr.Length / sizeof(WCHAR)], "\\wintrust.dll"))
809 return false;
810
811 return true;
812}
813
814
815/**
816 * Verifies the given executable image.
817 *
818 * @returns IPRT status code.
819 * @param hFile File handle to the executable file.
820 * @param pwszName Full NT path to the DLL in question, used for dealing
821 * with unsigned system dlls as well as for error/logging.
822 * @param fFlags Flags, SUPHNTVI_F_XXX.
823 * @param pfCacheable Where to return whether the result can be cached. A
824 * valid value is always returned. Optional.
825 * @param pErrInfo Pointer to error info structure. Optional.
826 */
827DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags,
828 bool *pfCacheable, PRTERRINFO pErrInfo)
829{
830 /* Clear the cacheable indicator as it needs to be valid in all return paths. */
831 if (pfCacheable)
832 *pfCacheable = false;
833
834 /*
835 * Create a reader instance.
836 */
837 PSUPHNTVIRDR pNtViRdr;
838 int rc = supHardNtViRdrCreate(hFile, pwszName, fFlags, &pNtViRdr);
839 if (RT_SUCCESS(rc))
840 {
841 /*
842 * Open the image.
843 */
844 RTLDRMOD hLdrMod;
845 rc = RTLdrOpenWithReader(&pNtViRdr->Core, RTLDR_O_FOR_VALIDATION,
846 fFlags & SUPHNTVI_F_RC_IMAGE ? RTLDRARCH_X86_32 : RTLDRARCH_HOST,
847 &hLdrMod, pErrInfo);
848 if (RT_SUCCESS(rc))
849 {
850 /*
851 * Verify it.
852 *
853 * The PKCS #7 SignedData signature is checked in the callback. Any
854 * signing certificate restrictions are also enforced there.
855 *
856 * For the time being, we use the executable timestamp as the
857 * certificate validation date. We must query that first to avoid
858 * potential issues re-entering the loader code from the callback.
859 *
860 * Update: Save the first timestamp we validate with build cert and
861 * use this as a minimum timestamp for further build cert
862 * validations. This works around issues with old DLLs that
863 * we sign against with our certificate (crt, sdl, qt).
864 */
865 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pNtViRdr->uTimestamp, sizeof(pNtViRdr->uTimestamp));
866 if (RT_SUCCESS(rc))
867 {
868#ifdef IN_RING3
869 if ((fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT) && pNtViRdr->uTimestamp < g_uBuildTimestampHack)
870 pNtViRdr->uTimestamp = g_uBuildTimestampHack;
871#endif
872
873 rc = RTLdrVerifySignature(hLdrMod, supHardNtViCallback, pNtViRdr, pErrInfo);
874
875#ifdef IN_RING3
876 if ((fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT) && g_uBuildTimestampHack == 0 && RT_SUCCESS(rc))
877 g_uBuildTimestampHack = pNtViRdr->uTimestamp;
878#endif
879
880
881 /*
882 * Microsoft doesn't sign a whole bunch of DLLs, so we have to
883 * ASSUME that a bunch of system DLLs are fine.
884 */
885 if (rc == VERR_LDRVI_NOT_SIGNED)
886 rc = supHardNtViCheckIfNotSignedOk(hLdrMod, pwszName, fFlags, rc);
887 if (RT_FAILURE(rc))
888 RTErrInfoAddF(pErrInfo, rc, ": %ls", pwszName);
889
890 /*
891 * Check for the signature checking enforcement, if requested to do so.
892 */
893 if (RT_SUCCESS(rc) && (fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT))
894 {
895 bool fEnforced = false;
896 int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, &fEnforced, sizeof(fEnforced));
897 if (RT_FAILURE(rc2))
898 rc = RTErrInfoSetF(pErrInfo, rc2, "Querying RTLDRPROP_SIGNATURE_CHECKS_ENFORCED failed on %ls: %Rrc.",
899 pwszName, rc2);
900 else if (!fEnforced)
901 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED,
902 "The image '%ls' was not linked with /IntegrityCheck.", pwszName);
903 }
904 }
905 else
906 RTErrInfoSetF(pErrInfo, rc, "RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on %ls: %Rrc", pwszName, rc);
907
908 int rc2 = RTLdrClose(hLdrMod); AssertRC(rc2);
909
910#ifdef IN_RING3
911 /*
912 * Call the windows verify trust API if we've resolved it.
913 */
914 if ( g_pfnWinVerifyTrust
915 && supR3HardNtViCanCallWinVerifyTrust(hFile, pwszName))
916 {
917 if (pfCacheable)
918 *pfCacheable = g_pfnWinVerifyTrust != NULL;
919 if (rc != VERR_LDRVI_NOT_SIGNED)
920 {
921 if (rc == VINF_LDRVI_NOT_SIGNED)
922 {
923 if (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION)
924 {
925 int rc2 = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo,
926 g_pfnWinVerifyTrust);
927 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (org %d)\n", rc2, rc));
928 rc = rc2;
929 }
930 else
931 {
932 AssertFailed();
933 rc = VERR_LDRVI_NOT_SIGNED;
934 }
935 }
936 else if (RT_SUCCESS(rc))
937 rc = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
938 else
939 {
940 int rc2 = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
941 AssertMsg(RT_FAILURE_NP(rc2),
942 ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
943 }
944 }
945 }
946#else
947 if (pfCacheable)
948 *pfCacheable = true;
949#endif /* IN_RING3 */
950 }
951 else
952 supHardNtViRdrDestroy(&pNtViRdr->Core);
953 }
954 SUP_DPRINTF(("supHardenedWinVerifyImageByHandle: -> %d (%ls)\n", rc, pwszName));
955 return rc;
956}
957
958
959#ifdef IN_RING3
960/**
961 * supHardenedWinVerifyImageByHandle version without the name.
962 *
963 * The name is derived from the handle.
964 *
965 * @returns IPRT status code.
966 * @param hFile File handle to the executable file.
967 * @param fFlags Flags, SUPHNTVI_F_XXX.
968 * @param pErrInfo Pointer to error info structure. Optional.
969 */
970DECLHIDDEN(int) supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo)
971{
972 /*
973 * Determine the NT name and call the verification function.
974 */
975 union
976 {
977 UNICODE_STRING UniStr;
978 uint8_t abBuffer[(MAX_PATH + 8 + 1) * 2];
979 } uBuf;
980
981 ULONG cbIgn;
982 NTSTATUS rcNt = NtQueryObject(hFile,
983 ObjectNameInformation,
984 &uBuf,
985 sizeof(uBuf) - sizeof(WCHAR),
986 &cbIgn);
987 if (NT_SUCCESS(rcNt))
988 uBuf.UniStr.Buffer[uBuf.UniStr.Length / sizeof(WCHAR)] = '\0';
989 else
990 uBuf.UniStr.Buffer = (WCHAR *)L"TODO3";
991
992 return supHardenedWinVerifyImageByHandle(hFile, uBuf.UniStr.Buffer, fFlags, NULL /*pfCacheable*/, pErrInfo);
993}
994#endif /* IN_RING3 */
995
996
997/**
998 * Retrieves the full official path to the system root or one of it's sub
999 * directories.
1000 *
1001 * This code is also used by the support driver.
1002 *
1003 * @returns VBox status code.
1004 * @param pvBuf The output buffer. This will contain a
1005 * UNICODE_STRING followed (at the kernel's
1006 * discretion) the string buffer.
1007 * @param cbBuf The size of the buffer @a pvBuf points to.
1008 * @param enmDir Which directory under the system root we're
1009 * interested in.
1010 * @param pErrInfo Pointer to error info structure. Optional.
1011 */
1012DECLHIDDEN(int) supHardNtGetSystemRootDir(void *pvBuf, uint32_t cbBuf, SUPHARDNTSYSROOTDIR enmDir, PRTERRINFO pErrInfo)
1013{
1014 HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
1015 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1016
1017 UNICODE_STRING NtName;
1018 switch (enmDir)
1019 {
1020 case kSupHardNtSysRootDir_System32:
1021 {
1022 static const WCHAR s_wszNameSystem32[] = L"\\SystemRoot\\System32\\";
1023 NtName.Buffer = (PWSTR)s_wszNameSystem32;
1024 NtName.Length = sizeof(s_wszNameSystem32) - sizeof(WCHAR);
1025 NtName.MaximumLength = sizeof(s_wszNameSystem32);
1026 break;
1027 }
1028 case kSupHardNtSysRootDir_WinSxS:
1029 {
1030 static const WCHAR s_wszNameWinSxS[] = L"\\SystemRoot\\WinSxS\\";
1031 NtName.Buffer = (PWSTR)s_wszNameWinSxS;
1032 NtName.Length = sizeof(s_wszNameWinSxS) - sizeof(WCHAR);
1033 NtName.MaximumLength = sizeof(s_wszNameWinSxS);
1034 break;
1035 }
1036 default:
1037 AssertFailed();
1038 return VERR_INVALID_PARAMETER;
1039 }
1040
1041 OBJECT_ATTRIBUTES ObjAttr;
1042 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
1043
1044 NTSTATUS rcNt = NtCreateFile(&hFile,
1045 FILE_READ_DATA | SYNCHRONIZE,
1046 &ObjAttr,
1047 &Ios,
1048 NULL /* Allocation Size*/,
1049 FILE_ATTRIBUTE_NORMAL,
1050 FILE_SHARE_READ | FILE_SHARE_WRITE,
1051 FILE_OPEN,
1052 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
1053 NULL /*EaBuffer*/,
1054 0 /*EaLength*/);
1055 if (NT_SUCCESS(rcNt))
1056 rcNt = Ios.Status;
1057 if (NT_SUCCESS(rcNt))
1058 {
1059 ULONG cbIgn;
1060 rcNt = NtQueryObject(hFile,
1061 ObjectNameInformation,
1062 pvBuf,
1063 cbBuf - sizeof(WCHAR),
1064 &cbIgn);
1065 NtClose(hFile);
1066 if (NT_SUCCESS(rcNt))
1067 {
1068 PUNICODE_STRING pUniStr = (PUNICODE_STRING)pvBuf;
1069 if (pUniStr->Length > 0)
1070 {
1071 /* Make sure it's terminated so it can safely be printed.*/
1072 pUniStr->Buffer[pUniStr->Length / sizeof(WCHAR)] = '\0';
1073 return VINF_SUCCESS;
1074 }
1075
1076 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH,
1077 "NtQueryObject returned an empty path for '%ls'", NtName.Buffer);
1078 }
1079 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH, "NtQueryObject failed on '%ls' dir: %#x", NtName.Buffer, rcNt);
1080 }
1081 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH, "Failure to open '%ls': %#x", NtName.Buffer, rcNt);
1082}
1083
1084
1085/**
1086 * Initialize one certificate entry.
1087 *
1088 * @returns VBox status code.
1089 * @param pCert The X.509 certificate representation to init.
1090 * @param pabCert The raw DER encoded certificate.
1091 * @param cbCert The size of the raw certificate.
1092 * @param pErrInfo Where to return extended error info. Optional.
1093 * @param pszErrorTag Error tag.
1094 */
1095static int supHardNtViCertInit(PRTCRX509CERTIFICATE pCert, unsigned char const *pabCert, unsigned cbCert,
1096 PRTERRINFO pErrInfo, const char *pszErrorTag)
1097{
1098 AssertReturn(cbCert > 16 && cbCert < _128K,
1099 RTErrInfoSetF(pErrInfo, VERR_INTERNAL_ERROR_3, "%s: cbCert=%#x out of range", pszErrorTag, cbCert));
1100 AssertReturn(!RTCrX509Certificate_IsPresent(pCert),
1101 RTErrInfoSetF(pErrInfo, VERR_WRONG_ORDER, "%s: Certificate already decoded?", pszErrorTag));
1102
1103 RTASN1CURSORPRIMARY PrimaryCursor;
1104 RTAsn1CursorInitPrimary(&PrimaryCursor, pabCert, cbCert, pErrInfo, &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, NULL);
1105 int rc = RTCrX509Certificate_DecodeAsn1(&PrimaryCursor.Cursor, 0, pCert, pszErrorTag);
1106 if (RT_SUCCESS(rc))
1107 rc = RTCrX509Certificate_CheckSanity(pCert, 0, pErrInfo, pszErrorTag);
1108 return rc;
1109}
1110
1111
1112static int supHardNtViCertStoreAddArray(RTCRSTORE hStore, PCSUPTAENTRY paCerts, unsigned cCerts, PRTERRINFO pErrInfo)
1113{
1114 for (uint32_t i = 0; i < cCerts; i++)
1115 {
1116 int rc = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_TAF_DER, paCerts[i].pch, paCerts[i].cb, pErrInfo);
1117 if (RT_FAILURE(rc))
1118 return rc;
1119 }
1120 return VINF_SUCCESS;
1121}
1122
1123
1124/**
1125 * Initialize a certificate table.
1126 *
1127 * @param phStore Where to return the store pointer.
1128 * @param paCerts1 Pointer to the first certificate table.
1129 * @param cCerts1 Entries in the first certificate table.
1130 * @param paCerts2 Pointer to the second certificate table.
1131 * @param cCerts2 Entries in the second certificate table.
1132 * @param paCerts3 Pointer to the third certificate table.
1133 * @param cCerts3 Entries in the third certificate table.
1134 * @param pErrInfo Where to return extended error info. Optional.
1135 * @param pszErrorTag Error tag.
1136 */
1137static int supHardNtViCertStoreInit(PRTCRSTORE phStore,
1138 PCSUPTAENTRY paCerts1, unsigned cCerts1,
1139 PCSUPTAENTRY paCerts2, unsigned cCerts2,
1140 PCSUPTAENTRY paCerts3, unsigned cCerts3,
1141 PRTERRINFO pErrInfo, const char *pszErrorTag)
1142{
1143 AssertReturn(*phStore == NIL_RTCRSTORE, VERR_WRONG_ORDER);
1144
1145 int rc = RTCrStoreCreateInMem(phStore, cCerts1 + cCerts2);
1146 if (RT_FAILURE(rc))
1147 return RTErrInfoSetF(pErrInfo, rc, "RTCrStoreCreateMemoryStore failed: %Rrc", rc);
1148
1149 rc = supHardNtViCertStoreAddArray(*phStore, paCerts1, cCerts1, pErrInfo);
1150 if (RT_SUCCESS(rc))
1151 rc = supHardNtViCertStoreAddArray(*phStore, paCerts2, cCerts2, pErrInfo);
1152 if (RT_SUCCESS(rc))
1153 rc = supHardNtViCertStoreAddArray(*phStore, paCerts3, cCerts3, pErrInfo);
1154 return rc;
1155}
1156
1157
1158/**
1159 * This initializes the certificates globals so we don't have to reparse them
1160 * every time we need to verify an image.
1161 *
1162 * @returns IPRT status code.
1163 * @param pErrInfo Where to return extended error info. Optional.
1164 */
1165DECLHIDDEN(int) supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo)
1166{
1167 AssertReturn(!RTCrX509Certificate_IsPresent(&g_BuildX509Cert), VERR_WRONG_ORDER);
1168
1169 /*
1170 * Get the system root paths.
1171 */
1172 int rc = supHardNtGetSystemRootDir(&g_System32NtPath, sizeof(g_System32NtPath), kSupHardNtSysRootDir_System32, pErrInfo);
1173 if (RT_SUCCESS(rc))
1174 rc = supHardNtGetSystemRootDir(&g_WinSxSNtPath, sizeof(g_WinSxSNtPath), kSupHardNtSysRootDir_WinSxS, pErrInfo);
1175 if (RT_SUCCESS(rc))
1176 {
1177 /*
1178 * Initialize it, leaving the cleanup to the termination call.
1179 */
1180 rc = supHardNtViCertInit(&g_BuildX509Cert, g_abSUPBuildCert, g_cbSUPBuildCert, pErrInfo, "BuildCertificate");
1181 if (RT_SUCCESS(rc))
1182 rc = supHardNtViCertStoreInit(&g_hSpcRootStore, g_aSUPSpcRootTAs, g_cSUPSpcRootTAs,
1183 NULL, 0, NULL, 0, pErrInfo, "SpcRoot");
1184 if (RT_SUCCESS(rc))
1185 rc = supHardNtViCertStoreInit(&g_hNtKernelRootStore, g_aSUPNtKernelRootTAs, g_cSUPNtKernelRootTAs,
1186 NULL, 0, NULL, 0, pErrInfo, "NtKernelRoot");
1187 if (RT_SUCCESS(rc))
1188 rc = supHardNtViCertStoreInit(&g_hSpcAndNtKernelRootStore,
1189 g_aSUPSpcRootTAs, g_cSUPSpcRootTAs,
1190 g_aSUPNtKernelRootTAs, g_cSUPNtKernelRootTAs,
1191 g_aSUPTimestampTAs, g_cSUPTimestampTAs,
1192 pErrInfo, "SpcAndNtKernelRoot");
1193 if (RT_SUCCESS(rc))
1194 rc = supHardNtViCertStoreInit(&g_hSpcAndNtKernelSuppStore,
1195 NULL, 0, NULL, 0, NULL, 0,
1196 pErrInfo, "SpcAndNtKernelSupplemental");
1197
1198 /* If the build certificate is a test singing certificate, it must be a
1199 trusted root or we'll fail to validate anything. */
1200 if ( RT_SUCCESS(rc)
1201 && RTCrX509Name_Compare(&g_BuildX509Cert.TbsCertificate.Subject, &g_BuildX509Cert.TbsCertificate.Issuer) == 0)
1202 rc = RTCrStoreCertAddEncoded(g_hSpcAndNtKernelRootStore, RTCRCERTCTX_F_ENC_X509_DER,
1203 g_abSUPBuildCert, g_cbSUPBuildCert, pErrInfo);
1204
1205 if (RT_SUCCESS(rc))
1206 return VINF_SUCCESS;
1207 supHardenedWinTermImageVerifier();
1208 }
1209 return rc;
1210}
1211
1212
1213/**
1214 * Releases resources allocated by supHardenedWinInitImageVerifier.
1215 */
1216DECLHIDDEN(void) supHardenedWinTermImageVerifier(void)
1217{
1218 if (RTCrX509Certificate_IsPresent(&g_BuildX509Cert))
1219 RTAsn1VtDelete(&g_BuildX509Cert.SeqCore.Asn1Core);
1220
1221 RTCrStoreRelease(g_hSpcAndNtKernelSuppStore);
1222 g_hSpcAndNtKernelSuppStore = NIL_RTCRSTORE;
1223 RTCrStoreRelease(g_hSpcAndNtKernelRootStore);
1224 g_hSpcAndNtKernelRootStore = NIL_RTCRSTORE;
1225
1226 RTCrStoreRelease(g_hNtKernelRootStore);
1227 g_hNtKernelRootStore = NIL_RTCRSTORE;
1228 RTCrStoreRelease(g_hSpcRootStore);
1229 g_hSpcRootStore = NIL_RTCRSTORE;
1230}
1231
1232#ifdef IN_RING3
1233
1234/**
1235 * This is a hardcoded list of certificates we thing we might need.
1236 *
1237 * @returns true if wanted, false if not.
1238 * @param pCert The certificate.
1239 */
1240static bool supR3HardenedWinIsDesiredRootCA(PCRTCRX509CERTIFICATE pCert)
1241{
1242 /*
1243 * Check that it's a plausible root certificate.
1244 */
1245 if (!RTCrX509Certificate_IsSelfSigned(pCert))
1246 return false;
1247 if (RTAsn1Integer_UnsignedCompareWithU32(&pCert->TbsCertificate.T0.Version, 3) > 0)
1248 {
1249 if ( !(pCert->TbsCertificate.T3.fExtKeyUsage & RTCRX509CERT_KEY_USAGE_F_KEY_CERT_SIGN)
1250 && (pCert->TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_KEY_USAGE) )
1251 return false;
1252 if ( pCert->TbsCertificate.T3.pBasicConstraints
1253 && !pCert->TbsCertificate.T3.pBasicConstraints->CA.fValue)
1254 return false;
1255 }
1256 if (pCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.cBits < 256) /* mostly for u64KeyId reading. */
1257 return false;
1258
1259 /*
1260 * Array of names and key clues of the certificates we want.
1261 */
1262 static struct
1263 {
1264 uint64_t u64KeyId;
1265 const char *pszName;
1266 } const s_aWanted[] =
1267 {
1268 /* SPC */
1269 { UINT64_C(0xffffffffffffffff), "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority" },
1270 { UINT64_C(0xffffffffffffffff), "L=Internet, O=VeriSign, Inc., OU=VeriSign Commercial Software Publishers CA" },
1271 { UINT64_C(0x491857ead79dde00), "C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority" },
1272
1273 /* TS */
1274 { UINT64_C(0xffffffffffffffff), "O=Microsoft Trust Network, OU=Microsoft Corporation, OU=Microsoft Time Stamping Service Root, OU=Copyright (c) 1997 Microsoft Corp." },
1275 { UINT64_C(0xffffffffffffffff), "O=VeriSign Trust Network, OU=VeriSign, Inc., OU=VeriSign Time Stamping Service Root, OU=NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc." },
1276 { UINT64_C(0xffffffffffffffff), "C=ZA, ST=Western Cape, L=Durbanville, O=Thawte, OU=Thawte Certification, CN=Thawte Timestamping CA" },
1277
1278 /* Additional Windows 8.1 list: */
1279 { UINT64_C(0x5ad46780fa5df300), "DC=com, DC=microsoft, CN=Microsoft Root Certificate Authority" },
1280 { UINT64_C(0x3be670c1bd02a900), "OU=Copyright (c) 1997 Microsoft Corp., OU=Microsoft Corporation, CN=Microsoft Root Authority" },
1281 { UINT64_C(0x4d3835aa4180b200), "C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2011" },
1282 { UINT64_C(0x646e3fe3ba08df00), "C=US, O=MSFT, CN=Microsoft Authenticode(tm) Root Authority" },
1283 { UINT64_C(0xece4e4289e08b900), "C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010" },
1284 { UINT64_C(0x59faf1086271bf00), "C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2" },
1285 { UINT64_C(0x3d98ab22bb04a300), "C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root" },
1286 { UINT64_C(0x91e3728b8b40d000), "C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Certification Authority" },
1287 { UINT64_C(0x61a3a33f81aace00), "C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Object" },
1288 { UINT64_C(0x9e5bc2d78b6a3636), "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA, [email protected]" },
1289 { UINT64_C(0xf4fd306318ccda00), "C=US, O=GeoTrust Inc., CN=GeoTrust Global CA" },
1290 { UINT64_C(0xa0ee62086758b15d), "C=US, O=Equifax, OU=Equifax Secure Certificate Authority" },
1291 { UINT64_C(0x8ff6fc03c1edbd00), "C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2" },
1292 { UINT64_C(0xa3ce8d99e60eda00), "C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA" },
1293 { UINT64_C(0xa671e9fec832b700), "C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority" },
1294 { UINT64_C(0xa8de7211e13be200), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA" },
1295 { UINT64_C(0x0ff3891b54348328), "C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.netSecure Server Certification Authority" },
1296 { UINT64_C(0x7ae89c50f0b6a00f), "C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root" },
1297 { UINT64_C(0xd45980fbf0a0ac00), "C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA" },
1298 { UINT64_C(0x9e5bc2d78b6a3636), "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA, [email protected]" },
1299 { UINT64_C(0x7c4fd32ec1b1ce00), "C=PL, O=Unizeto Sp. z o.o., CN=Certum CA" },
1300 { UINT64_C(0xd4fbe673e5ccc600), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA" },
1301 { UINT64_C(0x16e64d2a56ccf200), "C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., OU=http://certificates.starfieldtech.com/repository/, CN=Starfield Services Root Certificate Authority" },
1302 { UINT64_C(0x6e2ba21058eedf00), "C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN - DATACorp SGC" },
1303 { UINT64_C(0xb28612a94b4dad00), "O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.netCertification Authority (2048)" },
1304 { UINT64_C(0x357a29080824af00), "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class3 Public Primary Certification Authority - G5" },
1305 { UINT64_C(0x466cbc09db88c100), "C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority" },
1306 { UINT64_C(0x9259c8abe5ca713a), "L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com/, [email protected]" },
1307 { UINT64_C(0x1f78fc529cbacb00), "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class3 Public Primary Certification Authority - G3" },
1308 { UINT64_C(0x8043e4ce150ead00), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA" },
1309 { UINT64_C(0x00f2e6331af7b700), "C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root" },
1310 };
1311
1312
1313 uint64_t const u64KeyId = pCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.uBits.pu64[1];
1314 uint32_t i = RT_ELEMENTS(s_aWanted);
1315 while (i-- > 0)
1316 if ( s_aWanted[i].u64KeyId == u64KeyId
1317 || s_aWanted[i].u64KeyId == UINT64_MAX)
1318 if (RTCrX509Name_MatchWithString(&pCert->TbsCertificate.Subject, s_aWanted[i].pszName))
1319 return true;
1320
1321#ifdef DEBUG_bird
1322 char szTmp[512];
1323 szTmp[sizeof(szTmp) - 1] = '\0';
1324 RTCrX509Name_FormatAsString(&pCert->TbsCertificate.Issuer, szTmp, sizeof(szTmp) - 1, NULL);
1325 SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: %#llx %s\n", u64KeyId, szTmp));
1326#endif
1327 return false;
1328}
1329
1330/**
1331 * Called by supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation to
1332 * import selected root CAs from the system certificate store.
1333 *
1334 * These certificates permits us to correctly validate third party DLLs.
1335 *
1336 * @param fLoadLibraryFlags The LoadLibraryExW flags that the caller
1337 * found to work. Avoids us having to retry on
1338 * ERROR_INVALID_PARAMETER.
1339 */
1340static void supR3HardenedWinRetrieveTrustedRootCAs(DWORD fLoadLibraryFlags)
1341{
1342 uint32_t cAdded = 0;
1343
1344 /*
1345 * Load crypt32.dll and resolve the APIs we need.
1346 */
1347 HMODULE hCrypt32 = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\crypt32.dll", NULL, fLoadLibraryFlags);
1348 if (!hCrypt32)
1349 supR3HardenedFatal("Error loading 'crypt32.dll': %u", GetLastError());
1350
1351#define RESOLVE_CRYPT32_API(a_Name, a_pfnType) \
1352 a_pfnType pfn##a_Name = (a_pfnType)GetProcAddress(hCrypt32, #a_Name); \
1353 if (pfn##a_Name == NULL) supR3HardenedFatal("Error locating '" #a_Name "' in 'crypt32.dll': %u", GetLastError())
1354 RESOLVE_CRYPT32_API(CertOpenStore, PFNCERTOPENSTORE);
1355 RESOLVE_CRYPT32_API(CertCloseStore, PFNCERTCLOSESTORE);
1356 RESOLVE_CRYPT32_API(CertEnumCertificatesInStore, PFNCERTENUMCERTIFICATESINSTORE);
1357#undef RESOLVE_CRYPT32_API
1358
1359 /*
1360 * Open the root store and look for the certificates we wish to use.
1361 */
1362 DWORD fOpenStore = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG;
1363 HCERTSTORE hStore = pfnCertOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1364 NULL /* hCryptProv = default */, CERT_SYSTEM_STORE_LOCAL_MACHINE | fOpenStore, L"Root");
1365 if (!hStore)
1366 hStore = pfnCertOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1367 NULL /* hCryptProv = default */, CERT_SYSTEM_STORE_CURRENT_USER | fOpenStore, L"Root");
1368 if (hStore)
1369 {
1370 PCCERT_CONTEXT pCurCtx = NULL;
1371 while ((pCurCtx = pfnCertEnumCertificatesInStore(hStore, pCurCtx)) != NULL)
1372 {
1373 if (pCurCtx->dwCertEncodingType & X509_ASN_ENCODING)
1374 {
1375 RTASN1CURSORPRIMARY PrimaryCursor;
1376 RTAsn1CursorInitPrimary(&PrimaryCursor, pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded, NULL /*pErrInfo*/,
1377 &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "CurCtx");
1378 RTCRX509CERTIFICATE MyCert;
1379 int rc = RTCrX509Certificate_DecodeAsn1(&PrimaryCursor.Cursor, 0, &MyCert, "Cert");
1380 AssertRC(rc);
1381 if (RT_SUCCESS(rc))
1382 {
1383 if (supR3HardenedWinIsDesiredRootCA(&MyCert))
1384 {
1385 rc = RTCrStoreCertAddEncoded(g_hSpcRootStore, RTCRCERTCTX_F_ENC_X509_DER,
1386 pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded, NULL /*pErrInfo*/);
1387 AssertRC(rc);
1388
1389 rc = RTCrStoreCertAddEncoded(g_hSpcAndNtKernelRootStore, RTCRCERTCTX_F_ENC_X509_DER,
1390 pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded, NULL /*pErrInfo*/);
1391 AssertRC(rc);
1392 cAdded++;
1393 }
1394
1395 RTCrX509Certificate_Delete(&MyCert);
1396 }
1397 }
1398 }
1399 pfnCertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
1400 g_fHaveOtherRoots = true;
1401 }
1402 SUP_DPRINTF(("supR3HardenedWinRetrieveTrustedRootCAs: cAdded=%u\n", cAdded));
1403}
1404
1405
1406/**
1407 * Resolves the WinVerifyTrust API after the process has been verified and
1408 * installs a thread creation hook.
1409 *
1410 * The WinVerifyTrust API is used in addition our own Authenticode verification
1411 * code. If the image has the IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY flag
1412 * set, it will be checked again by the kernel. All our image has this flag set
1413 * and we require all VBox extensions to have it set as well. In effect, the
1414 * authenticode signature will be checked two or three times.
1415 */
1416DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(void)
1417{
1418# ifdef IN_SUP_HARDENED_R3
1419 /*
1420 * Load our the support library DLL that does the thread hooking as the
1421 * security API may trigger the creation of COM worker threads (or
1422 * whatever they are).
1423 *
1424 * The thread creation hook makes the threads very slippery to debuggers by
1425 * irreversably disabling most (if not all) debug events for them.
1426 */
1427 char szPath[RTPATH_MAX];
1428 supR3HardenedPathSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxSupLib.DLL"));
1429 suplibHardenedStrCat(szPath, "/VBoxSupLib.DLL");
1430 HMODULE hSupLibMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, true /*fSystem32Only*/);
1431 if (hSupLibMod == NULL)
1432 supR3HardenedFatal("Error loading '%s': %u", szPath, GetLastError());
1433# endif
1434
1435 /*
1436 * Resolve it.
1437 */
1438 DWORD fFlags = 0;
1439 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
1440 fFlags = LOAD_LIBRARY_SEARCH_SYSTEM32;
1441 HMODULE hWintrust = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\Wintrust.dll", NULL, fFlags);
1442 if ( hWintrust == NULL
1443 && fFlags
1444 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
1445 && GetLastError() == ERROR_INVALID_PARAMETER)
1446 {
1447 fFlags = 0;
1448 hWintrust = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\Wintrust.dll", NULL, fFlags);
1449 }
1450 if (hWintrust == NULL)
1451 supR3HardenedFatal("Error loading 'Wintrust.dll': %u", GetLastError());
1452
1453#define RESOLVE_CRYPT_API(a_Name, a_pfnType, a_uMinWinVer) \
1454 do { \
1455 g_pfn##a_Name = (a_pfnType)GetProcAddress(hWintrust, #a_Name); \
1456 if (g_pfn##a_Name == NULL && (a_uMinWinVer) < g_uNtVerCombined) \
1457 supR3HardenedFatal("Error locating '" #a_Name "' in 'Wintrust.dll': %u", GetLastError()); \
1458 } while (0)
1459
1460 PFNWINVERIFYTRUST pfnWinVerifyTrust = (PFNWINVERIFYTRUST)GetProcAddress(hWintrust, "WinVerifyTrust");
1461 if (!pfnWinVerifyTrust)
1462 supR3HardenedFatal("Error locating 'WinVerifyTrust' in 'Wintrust.dll': %u", GetLastError());
1463
1464 RESOLVE_CRYPT_API(CryptCATAdminAcquireContext, PFNCRYPTCATADMINACQUIRECONTEXT, 0);
1465 RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle, PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE, 0);
1466 RESOLVE_CRYPT_API(CryptCATAdminEnumCatalogFromHash, PFNCRYPTCATADMINENUMCATALOGFROMHASH, 0);
1467 RESOLVE_CRYPT_API(CryptCATAdminReleaseCatalogContext, PFNCRYPTCATADMINRELEASECATALOGCONTEXT, 0);
1468 RESOLVE_CRYPT_API(CryptCATAdminReleaseContext, PFNCRYPTCATDADMINRELEASECONTEXT, 0);
1469 RESOLVE_CRYPT_API(CryptCATCatalogInfoFromContext, PFNCRYPTCATCATALOGINFOFROMCONTEXT, 0);
1470
1471 RESOLVE_CRYPT_API(CryptCATAdminAcquireContext2, PFNCRYPTCATADMINACQUIRECONTEXT2, SUP_NT_VER_W80);
1472 RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle2, PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2, SUP_NT_VER_W80);
1473
1474 /*
1475 * Call it on ourselves and ntdll to make sure it loads all the providers
1476 * now, we would otherwise geting into recursive trouble in the
1477 * NtCreateSection hook.
1478 */
1479# ifdef IN_SUP_HARDENED_R3
1480 RTERRINFOSTATIC ErrInfoStatic;
1481 RTErrInfoInitStatic(&ErrInfoStatic);
1482 int rc = supR3HardNtViCallWinVerifyTrust(NULL, g_SupLibHardenedExeNtPath.UniStr.Buffer, 0,
1483 &ErrInfoStatic.Core, pfnWinVerifyTrust);
1484 if (RT_FAILURE(rc))
1485 supR3HardenedFatal("WinVerifyTrust failed on stub executable: %s", ErrInfoStatic.szMsg);
1486# endif
1487
1488 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* ntdll isn't signed on XP, assuming this is the case on W2K3 for now. */
1489 supR3HardNtViCallWinVerifyTrust(NULL, L"\\SystemRoot\\System32\\ntdll.dll", 0, NULL, pfnWinVerifyTrust);
1490 supR3HardNtViCallWinVerifyTrustCatFile(NULL, L"\\SystemRoot\\System32\\ntdll.dll", 0, NULL, pfnWinVerifyTrust);
1491
1492 g_pfnWinVerifyTrust = pfnWinVerifyTrust;
1493
1494 /*
1495 * Now, get trusted root CAs so we can verify a broader scope of signatures.
1496 */
1497 supR3HardenedWinRetrieveTrustedRootCAs(fFlags);
1498}
1499
1500
1501static int supR3HardNtViNtToWinPath(PCRTUTF16 pwszNtName, PCRTUTF16 *ppwszWinPath,
1502 PRTUTF16 pwszWinPathBuf, size_t cwcWinPathBuf)
1503{
1504 static const RTUTF16 s_wszPrefix[] = L"\\\\.\\GLOBALROOT";
1505
1506 if (*pwszNtName != '\\' && *pwszNtName != '/')
1507 return VERR_PATH_DOES_NOT_START_WITH_ROOT;
1508
1509 size_t cwcNtName = RTUtf16Len(pwszNtName);
1510 if (RT_ELEMENTS(s_wszPrefix) + cwcNtName > cwcWinPathBuf)
1511 return VERR_FILENAME_TOO_LONG;
1512
1513 memcpy(pwszWinPathBuf, s_wszPrefix, sizeof(s_wszPrefix));
1514 memcpy(&pwszWinPathBuf[sizeof(s_wszPrefix) / sizeof(RTUTF16) - 1], pwszNtName, (cwcNtName + 1) * sizeof(RTUTF16));
1515 *ppwszWinPath = pwszWinPathBuf;
1516 return VINF_SUCCESS;
1517}
1518
1519
1520/**
1521 * Calls WinVerifyTrust to verify an PE image.
1522 *
1523 * @returns VBox status code.
1524 * @param hFile File handle to the executable file.
1525 * @param pwszName Full NT path to the DLL in question, used for
1526 * dealing with unsigned system dlls as well as for
1527 * error/logging.
1528 * @param fFlags Flags, SUPHNTVI_F_XXX.
1529 * @param pErrInfo Pointer to error info structure. Optional.
1530 * @param pfnWinVerifyTrust Pointer to the API.
1531 */
1532static int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
1533 PFNWINVERIFYTRUST pfnWinVerifyTrust)
1534{
1535 /*
1536 * Convert the name into a Windows name.
1537 */
1538 RTUTF16 wszWinPathBuf[MAX_PATH];
1539 PCRTUTF16 pwszWinPath;
1540 int rc = supR3HardNtViNtToWinPath(pwszName, &pwszWinPath, wszWinPathBuf, RT_ELEMENTS(wszWinPathBuf));
1541 if (RT_FAILURE(rc))
1542 return RTErrInfoSetF(pErrInfo, rc, "Bad path passed to supR3HardNtViCallWinVerifyTrust: rc=%Rrc '%ls'", rc, pwszName);
1543
1544 /*
1545 * Construct input parameters and call the API.
1546 */
1547 WINTRUST_FILE_INFO FileInfo;
1548 RT_ZERO(FileInfo);
1549 FileInfo.cbStruct = sizeof(FileInfo);
1550 FileInfo.pcwszFilePath = pwszWinPath;
1551 FileInfo.hFile = hFile;
1552
1553 GUID PolicyActionGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
1554
1555 WINTRUST_DATA TrustData;
1556 RT_ZERO(TrustData);
1557 TrustData.cbStruct = sizeof(TrustData);
1558 TrustData.fdwRevocationChecks = WTD_REVOKE_NONE; /* Keep simple for now. */
1559 TrustData.dwStateAction = WTD_STATEACTION_VERIFY;
1560 TrustData.dwUIChoice = WTD_UI_NONE;
1561 TrustData.dwProvFlags = 0;
1562 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
1563 TrustData.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL;
1564 else
1565 TrustData.dwProvFlags = WTD_REVOCATION_CHECK_NONE;
1566 TrustData.dwUnionChoice = WTD_CHOICE_FILE;
1567 TrustData.pFile = &FileInfo;
1568
1569 HRESULT hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &PolicyActionGuid, &TrustData);
1570 if (hrc == S_OK)
1571 rc = VINF_SUCCESS;
1572 else
1573 {
1574 /*
1575 * Failed. Format a nice error message.
1576 */
1577# ifdef DEBUG_bird
1578 __debugbreak();
1579# endif
1580 const char *pszErrConst = NULL;
1581 switch (hrc)
1582 {
1583 case TRUST_E_SYSTEM_ERROR: pszErrConst = "TRUST_E_SYSTEM_ERROR"; break;
1584 case TRUST_E_NO_SIGNER_CERT: pszErrConst = "TRUST_E_NO_SIGNER_CERT"; break;
1585 case TRUST_E_COUNTER_SIGNER: pszErrConst = "TRUST_E_COUNTER_SIGNER"; break;
1586 case TRUST_E_CERT_SIGNATURE: pszErrConst = "TRUST_E_CERT_SIGNATURE"; break;
1587 case TRUST_E_TIME_STAMP: pszErrConst = "TRUST_E_TIME_STAMP"; break;
1588 case TRUST_E_BAD_DIGEST: pszErrConst = "TRUST_E_BAD_DIGEST"; break;
1589 case TRUST_E_BASIC_CONSTRAINTS: pszErrConst = "TRUST_E_BASIC_CONSTRAINTS"; break;
1590 case TRUST_E_FINANCIAL_CRITERIA: pszErrConst = "TRUST_E_FINANCIAL_CRITERIA"; break;
1591 case TRUST_E_PROVIDER_UNKNOWN: pszErrConst = "TRUST_E_PROVIDER_UNKNOWN"; break;
1592 case TRUST_E_ACTION_UNKNOWN: pszErrConst = "TRUST_E_ACTION_UNKNOWN"; break;
1593 case TRUST_E_SUBJECT_FORM_UNKNOWN: pszErrConst = "TRUST_E_SUBJECT_FORM_UNKNOWN"; break;
1594 case TRUST_E_SUBJECT_NOT_TRUSTED: pszErrConst = "TRUST_E_SUBJECT_NOT_TRUSTED"; break;
1595 case TRUST_E_NOSIGNATURE: pszErrConst = "TRUST_E_NOSIGNATURE"; break;
1596 case TRUST_E_FAIL: pszErrConst = "TRUST_E_FAIL"; break;
1597 case TRUST_E_EXPLICIT_DISTRUST: pszErrConst = "TRUST_E_EXPLICIT_DISTRUST"; break;
1598 }
1599 if (pszErrConst)
1600 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_UNSUPPORTED_ARCH,
1601 "WinVerifyTrust failed with hrc=%s on '%ls'", pszErrConst, pwszName);
1602 else
1603 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_UNSUPPORTED_ARCH,
1604 "WinVerifyTrust failed with hrc=%Rhrc on '%ls'", hrc, pwszName);
1605 }
1606
1607 /* clean up state data. */
1608 TrustData.dwStateAction = WTD_STATEACTION_CLOSE;
1609 FileInfo.hFile = NULL;
1610 hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &PolicyActionGuid, &TrustData);
1611
1612 return rc;
1613}
1614
1615
1616/**
1617 * Calls WinVerifyTrust to verify an PE image via catalog files.
1618 *
1619 * @returns VBox status code.
1620 * @param hFile File handle to the executable file.
1621 * @param pwszName Full NT path to the DLL in question, used for
1622 * dealing with unsigned system dlls as well as for
1623 * error/logging.
1624 * @param fFlags Flags, SUPHNTVI_F_XXX.
1625 * @param pErrInfo Pointer to error info structure. Optional.
1626 * @param pfnWinVerifyTrust Pointer to the API.
1627 */
1628static int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
1629 PFNWINVERIFYTRUST pfnWinVerifyTrust)
1630{
1631 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: hFile=%p pwszName=%ls\n", hFile, pwszName));
1632
1633 /*
1634 * Convert the name into a Windows name.
1635 */
1636 RTUTF16 wszWinPathBuf[MAX_PATH];
1637 PCRTUTF16 pwszWinPath;
1638 int rc = supR3HardNtViNtToWinPath(pwszName, &pwszWinPath, wszWinPathBuf, RT_ELEMENTS(wszWinPathBuf));
1639 if (RT_FAILURE(rc))
1640 return RTErrInfoSetF(pErrInfo, rc, "Bad path passed to supR3HardNtViCallWinVerifyTrustCatFile: rc=%Rrc '%ls'", rc, pwszName);
1641
1642 /*
1643 * Open the file if we didn't get a handle.
1644 */
1645 HANDLE hFileClose = NULL;
1646 if (hFile == RTNT_INVALID_HANDLE_VALUE || hFile == NULL)
1647 {
1648 hFile = RTNT_INVALID_HANDLE_VALUE;
1649 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1650
1651 UNICODE_STRING NtName;
1652 NtName.Buffer = (PWSTR)pwszName;
1653 NtName.Length = (USHORT)(RTUtf16Len(pwszName) * sizeof(WCHAR));
1654 NtName.MaximumLength = NtName.Length + sizeof(WCHAR);
1655
1656 OBJECT_ATTRIBUTES ObjAttr;
1657 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
1658
1659 NTSTATUS rcNt = NtCreateFile(&hFile,
1660 FILE_READ_DATA | SYNCHRONIZE,
1661 &ObjAttr,
1662 &Ios,
1663 NULL /* Allocation Size*/,
1664 FILE_ATTRIBUTE_NORMAL,
1665 FILE_SHARE_READ,
1666 FILE_OPEN,
1667 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1668 NULL /*EaBuffer*/,
1669 0 /*EaLength*/);
1670 if (NT_SUCCESS(rcNt))
1671 rcNt = Ios.Status;
1672 if (!NT_SUCCESS(rcNt))
1673 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
1674 "NtCreateFile returned %#x opening '%ls'.", rcNt, pwszName);
1675 hFileClose = hFile;
1676 }
1677
1678 /*
1679 * On Windows 8.0 and later there are more than one digest choice.
1680 */
1681 rc = VERR_LDRVI_NOT_SIGNED;
1682 static struct
1683 {
1684 /** The digest algorithm name. */
1685 const WCHAR *pszAlgorithm;
1686 /** Cached catalog admin handle. */
1687 HCATADMIN volatile hCachedCatAdmin;
1688 } s_aHashes[] =
1689 {
1690 { NULL, NULL },
1691 { L"SHA256", NULL },
1692 };
1693 for (uint32_t i = 0; i < RT_ELEMENTS(s_aHashes); i++)
1694 {
1695 /*
1696 * Another loop for dealing with different trust provider policies
1697 * required for successfully validating different catalog signatures.
1698 */
1699 bool fTryNextPolicy;
1700 uint32_t iPolicy = 0;
1701 static const GUID s_aPolicies[] =
1702 {
1703 DRIVER_ACTION_VERIFY, /* Works with microsoft bits. Most frequently used, thus first. */
1704 WINTRUST_ACTION_GENERIC_VERIFY_V2, /* Works with ATI and other SPC kernel-code signed stuff. */
1705 };
1706 do
1707 {
1708 /*
1709 * Create a context.
1710 */
1711 fTryNextPolicy = false;
1712 BOOL fRc;
1713 HCATADMIN hCatAdmin = ASMAtomicXchgPtr(&s_aHashes[i].hCachedCatAdmin, NULL);
1714 if (hCatAdmin)
1715 fRc = TRUE;
1716 else if (g_pfnCryptCATAdminAcquireContext2)
1717 fRc = g_pfnCryptCATAdminAcquireContext2(&hCatAdmin, &s_aPolicies[iPolicy], s_aHashes[i].pszAlgorithm,
1718 NULL /*pStrongHashPolicy*/, 0 /*dwFlags*/);
1719 else
1720 fRc = g_pfnCryptCATAdminAcquireContext(&hCatAdmin, &s_aPolicies[iPolicy], 0 /*dwFlags*/);
1721 if (fRc)
1722 {
1723 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: hCatAdmin=%p\n", hCatAdmin));
1724
1725 /*
1726 * Hash the file.
1727 */
1728 BYTE abHash[SUPHARDNTVI_MAX_CAT_HASH_SIZE];
1729 DWORD cbHash = sizeof(abHash);
1730 if (g_pfnCryptCATAdminCalcHashFromFileHandle2)
1731 fRc = g_pfnCryptCATAdminCalcHashFromFileHandle2(hCatAdmin, hFile, &cbHash, abHash, 0 /*dwFlags*/);
1732 else
1733 fRc = g_pfnCryptCATAdminCalcHashFromFileHandle(hFile, &cbHash, abHash, 0 /*dwFlags*/);
1734 if (fRc)
1735 {
1736 /* Produce a string version of it that we can pass to WinVerifyTrust. */
1737 RTUTF16 wszDigest[SUPHARDNTVI_MAX_CAT_HASH_SIZE * 2 + 1];
1738 int rc2 = RTUtf16PrintHexBytes(wszDigest, RT_ELEMENTS(wszDigest), abHash, cbHash, RTSTRPRINTHEXBYTES_F_UPPER);
1739 if (RT_SUCCESS(rc2))
1740 {
1741 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: cbHash=%u wszDigest=%ls\n", cbHash, wszDigest));
1742
1743 /*
1744 * Enumerate catalog information that matches the hash.
1745 */
1746 uint32_t iCat = 0;
1747 HCATINFO hCatInfoPrev = NULL;
1748 do
1749 {
1750 /* Get the next match. */
1751 HCATINFO hCatInfo = g_pfnCryptCATAdminEnumCatalogFromHash(hCatAdmin, abHash, cbHash, 0, &hCatInfoPrev);
1752 if (!hCatInfo)
1753 {
1754 if (iCat == 0)
1755 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", GetLastError()));
1756 break;
1757 }
1758 Assert(hCatInfoPrev == NULL);
1759 hCatInfoPrev = hCatInfo;
1760
1761 /*
1762 * Call WinVerifyTrust.
1763 */
1764 CATALOG_INFO CatInfo;
1765 CatInfo.cbStruct = sizeof(CatInfo);
1766 CatInfo.wszCatalogFile[0] = '\0';
1767 if (g_pfnCryptCATCatalogInfoFromContext(hCatInfo, &CatInfo, 0 /*dwFlags*/))
1768 {
1769 WINTRUST_CATALOG_INFO WtCatInfo;
1770 RT_ZERO(WtCatInfo);
1771 WtCatInfo.cbStruct = sizeof(WtCatInfo);
1772 WtCatInfo.dwCatalogVersion = 0;
1773 WtCatInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
1774 WtCatInfo.pcwszMemberTag = wszDigest;
1775 WtCatInfo.pcwszMemberFilePath = pwszWinPath;
1776 WtCatInfo.pbCalculatedFileHash = abHash;
1777 WtCatInfo.cbCalculatedFileHash = cbHash;
1778 WtCatInfo.pcCatalogContext = NULL;
1779
1780 WINTRUST_DATA TrustData;
1781 RT_ZERO(TrustData);
1782 TrustData.cbStruct = sizeof(TrustData);
1783 TrustData.fdwRevocationChecks = WTD_REVOKE_NONE; /* Keep simple for now. */
1784 TrustData.dwStateAction = WTD_STATEACTION_VERIFY;
1785 TrustData.dwUIChoice = WTD_UI_NONE;
1786 TrustData.dwProvFlags = 0;
1787 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
1788 TrustData.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL;
1789 else
1790 TrustData.dwProvFlags = WTD_REVOCATION_CHECK_NONE;
1791 TrustData.dwUnionChoice = WTD_CHOICE_CATALOG;
1792 TrustData.pCatalog = &WtCatInfo;
1793
1794 HRESULT hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &s_aPolicies[iPolicy], &TrustData);
1795 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: WinVerifyTrust => %#x; cat=%ls\n", hrc, CatInfo.wszCatalogFile));
1796
1797 if (SUCCEEDED(hrc))
1798 rc = VINF_SUCCESS;
1799 else if (hrc == TRUST_E_NOSIGNATURE)
1800 { /* ignore because it's useless. */ }
1801 else if (hrc == ERROR_INVALID_PARAMETER)
1802 { /* This is returned if the given file isn't found in the catalog, it seems. */ }
1803 else
1804 {
1805 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_WINTRUST_CAT_FAILURE,
1806 "WinVerifyTrust failed with hrc=%#x on '%ls' and .cat-file='%ls'.",
1807 hrc, pwszWinPath, CatInfo.wszCatalogFile);
1808 fTryNextPolicy = (hrc == CERT_E_UNTRUSTEDROOT);
1809 }
1810
1811 /* clean up state data. */
1812 TrustData.dwStateAction = WTD_STATEACTION_CLOSE;
1813 hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &s_aPolicies[iPolicy], &TrustData);
1814 Assert(SUCCEEDED(hrc));
1815 }
1816 else
1817 {
1818 rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
1819 "CryptCATCatalogInfoFromContext failed: %d [file=%s]",
1820 GetLastError(), pwszName);
1821 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATCatalogInfoFromContext failed\n"));
1822 }
1823 iCat++;
1824 } while (rc == VERR_LDRVI_NOT_SIGNED && iCat < 128);
1825
1826 if (hCatInfoPrev != NULL)
1827 if (!g_pfnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfoPrev, 0 /*dwFlags*/))
1828 AssertFailed();
1829 }
1830 else
1831 rc = RTErrInfoSetF(pErrInfo, rc2, "RTUtf16PrintHexBytes failed: %Rrc", rc);
1832 }
1833 else
1834 rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
1835 "CryptCATAdminCalcHashFromFileHandle[2] failed: %d [file=%s]", GetLastError(), pwszName);
1836
1837 if (!ASMAtomicCmpXchgPtr(&s_aHashes[i].hCachedCatAdmin, hCatAdmin, NULL))
1838 if (!g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/))
1839 AssertFailed();
1840 }
1841 else
1842 rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
1843 "CryptCATAdminAcquireContext[2] failed: %d [file=%s]", GetLastError(), pwszName);
1844 iPolicy++;
1845 } while ( fTryNextPolicy
1846 && iPolicy < RT_ELEMENTS(s_aPolicies));
1847
1848 /*
1849 * Only repeat if we've got g_pfnCryptCATAdminAcquireContext2 and can specify the hash algorithm.
1850 */
1851 if (!g_pfnCryptCATAdminAcquireContext2)
1852 break;
1853 if (rc != VERR_LDRVI_NOT_SIGNED)
1854 break;
1855 }
1856
1857 if (hFileClose != NULL)
1858 NtClose(hFileClose);
1859
1860 return rc;
1861}
1862
1863
1864/**
1865 * Initializes g_uNtVerCombined and g_NtVerInfo.
1866 * Called from suplibHardenedWindowsMain and suplibOsInit.
1867 */
1868DECLHIDDEN(void) supR3HardenedWinInitVersion(void)
1869{
1870 /*
1871 * Get the windows version. Use RtlGetVersion as GetVersionExW and
1872 * GetVersion might not be telling the whole truth (8.0 on 8.1 depending on
1873 * the application manifest).
1874 */
1875 OSVERSIONINFOEXW NtVerInfo;
1876
1877 suplibHardenedMemSet(&NtVerInfo, 0, sizeof(NtVerInfo));
1878 NtVerInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
1879 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&NtVerInfo)))
1880 {
1881 suplibHardenedMemSet(&NtVerInfo, 0, sizeof(NtVerInfo));
1882 NtVerInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
1883 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&NtVerInfo)))
1884 {
1885 NtVerInfo.dwOSVersionInfoSize = sizeof(NtVerInfo);
1886 if (!GetVersionExW((OSVERSIONINFOW *)&NtVerInfo))
1887 {
1888 suplibHardenedMemSet(&NtVerInfo, 0, sizeof(NtVerInfo));
1889 DWORD dwVer = GetVersion();
1890 NtVerInfo.dwMajorVersion = RT_BYTE1(dwVer);
1891 NtVerInfo.dwMinorVersion = RT_BYTE2(dwVer);
1892 NtVerInfo.dwBuildNumber = RT_BIT_32(31) & dwVer ? 0 : RT_HI_U16(dwVer);
1893 }
1894 }
1895 }
1896 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(NtVerInfo.dwMajorVersion, NtVerInfo.dwMinorVersion, NtVerInfo.dwBuildNumber,
1897 NtVerInfo.wServicePackMajor, NtVerInfo.wServicePackMinor);
1898}
1899
1900#endif /* IN_RING3 */
1901
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette