VirtualBox

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

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

Refuse symantec sysfer.dll; accept microsoft sfc.dll.

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