VirtualBox

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

Last change on this file since 51812 was 51812, checked in by vboxsync, 10 years ago

Fixed a pCert use that I'd missed (pCert / pTaInfo).

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

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