SUPHardenedVerifyImage-win.cpp revision fd658895339cb48b2ba581b1a1141aea39009ff7
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * VirtualBox Support Library/Driver - Hardened Image Verification, Windows.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Copyright (C) 2006-2014 Oracle Corporation
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * available from http://www.virtualbox.org. This file is free software;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * General Public License (GPL) as published by the Free Software
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * The contents of this file may alternatively be used under the terms
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * of the Common Development and Distribution License Version 1.0
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * VirtualBox OSE distribution, in which case the provisions of the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * CDDL are applicable instead of those of the GPL.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * You may elect to license modified versions of this file under the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * terms and conditions of either the GPL or the CDDL or both.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/*******************************************************************************
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync* Header Files *
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync*******************************************************************************/
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/*******************************************************************************
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync* Defined Constants And Macros *
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync*******************************************************************************/
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** The size of static hash (output) buffers.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Avoids dynamic allocations and cleanups for of small buffers as well as extra
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * calls for getting the appropriate buffer size. The largest digest in regular
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * use by current windows version is SHA-512, we double this and hope it's
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * enough a good while. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/*******************************************************************************
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync* Structures and Typedefs *
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync*******************************************************************************/
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * SUP image verifier loader reader instance.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef struct SUPHNTVIRDR
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /** The core reader structure. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /** The file handle . */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /** Current file offset. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /** The file size. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /** Flags for the verification callback, SUPHNTVI_F_XXX. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /** The executable timstamp in second since unix epoch. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /** Log name. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to an SUP image verifier loader reader instance. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef LONG (WINAPI * PFNWINVERIFYTRUST)(HWND hwnd, GUID const *pgActionID, PVOID pWVTData);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI * PFNCRYPTCATADMINACQUIRECONTEXT)(HCATADMIN *phCatAdmin, const GUID *pGuidSubsystem, DWORD dwFlags);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI * PFNCRYPTCATADMINACQUIRECONTEXT2)(HCATADMIN *phCatAdmin, const GUID *pGuidSubsystem, PCWSTR pwszHashAlgorithm,
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync struct _CERT_STRONG_SIGN_PARA const *pStrongHashPolicy, DWORD dwFlags);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI * PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE)(HANDLE hFile, DWORD *pcbHash, BYTE *pbHash, DWORD dwFlags);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI * PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2)(HCATADMIN hCatAdmin, HANDLE hFile, DWORD *pcbHash,
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef HCATINFO (WINAPI *PFNCRYPTCATADMINENUMCATALOGFROMHASH)(HCATADMIN hCatAdmin, BYTE *pbHash, DWORD cbHash,
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI * PFNCRYPTCATADMINRELEASECATALOGCONTEXT)(HCATADMIN hCatAdmin, HCATINFO hCatInfo, DWORD dwFlags);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI * PFNCRYPTCATDADMINRELEASECONTEXT)(HCATADMIN hCatAdmin, DWORD dwFlags);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI * PFNCRYPTCATCATALOGINFOFROMCONTEXT)(HCATINFO hCatInfo, CATALOG_INFO *psCatInfo, DWORD dwFlags);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef HCERTSTORE (WINAPI *PFNCERTOPENSTORE)(PCSTR pszStoreProvider, DWORD dwEncodingType, HCRYPTPROV_LEGACY hCryptProv,
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef BOOL (WINAPI *PFNCERTCLOSESTORE)(HCERTSTORE hCertStore, DWORD dwFlags);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsynctypedef PCCERT_CONTEXT (WINAPI *PFNCERTENUMCERTIFICATESINSTORE)(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/*******************************************************************************
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync* Global Variables *
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync*******************************************************************************/
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** The build certificate. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Store for root software publisher certificates. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Store for root NT kernel certificates. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic RTCRSTORE g_hNtKernelRootStore = NIL_RTCRSTORE;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Store containing SPC, NT kernel signing, and timestamp root certificates. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic RTCRSTORE g_hSpcAndNtKernelRootStore = NIL_RTCRSTORE;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Store for supplemental certificates for use with
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * g_hSpcAndNtKernelRootStore. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic RTCRSTORE g_hSpcAndNtKernelSuppStore = NIL_RTCRSTORE;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** The full \\SystemRoot\\System32 path. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** The full \\SystemRoot\\WinSxS path. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Set after we've retrived other SPC root certificates from the system. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic bool g_fHaveOtherRoots = false;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync#if defined(IN_RING3) && !defined(IN_SUP_HARDENED_R3)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED and
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * SUP_MAKE_NT_VER_SIMPLE. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Timestamp hack working around issues with old DLLs that we ship.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * See supHardenedWinVerifyImageByHandle() for details. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to WinVerifyTrust. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATAdminAcquireContext. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATADMINACQUIRECONTEXT g_pfnCryptCATAdminAcquireContext;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATAdminAcquireContext2 if available. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATADMINACQUIRECONTEXT2 g_pfnCryptCATAdminAcquireContext2;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATAdminCalcHashFromFileHandle. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATADMINCALCHASHFROMFILEHANDLE g_pfnCryptCATAdminCalcHashFromFileHandle;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATAdminCalcHashFromFileHandle2. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2 g_pfnCryptCATAdminCalcHashFromFileHandle2;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATAdminEnumCatalogFromHash. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATADMINENUMCATALOGFROMHASH g_pfnCryptCATAdminEnumCatalogFromHash;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATAdminReleaseCatalogContext. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATADMINRELEASECATALOGCONTEXT g_pfnCryptCATAdminReleaseCatalogContext;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATAdminReleaseContext. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATDADMINRELEASECONTEXT g_pfnCryptCATAdminReleaseContext;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** Pointer to CryptCATCatalogInfoFromContext. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncPFNCRYPTCATCATALOGINFOFROMCONTEXT g_pfnCryptCATCatalogInfoFromContext;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/*******************************************************************************
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync* Internal Functions *
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync*******************************************************************************/
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** @copydoc RTLDRREADER::pfnRead */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(int) supHardNtViRdrRead(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * For some reason I'm getting occational read error in an XP VM with
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * STATUS_FAILED_DRIVER_ENTRY. Redoing the call again works in the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * debugger, so try do that automatically.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync "supHardNtViRdrRead: Only got %#zx bytes when requesting %#zx bytes at %#llx in '%s'.\n",
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Delay a little before we retry?
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync Time.QuadPart = -1000000 / 100; /* 1ms in 100ns units, relative time. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Before we give up, we'll try split up the request in case the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * kernel is low on memory or similar. For simplicity reasons, we do
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * this in a recursion fashion.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync while (cb > 0)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync int rc = supHardNtViRdrRead(&pNtViRdr->Core, pvBuf, cbThisRead, off);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync supR3HardenedError(VERR_READ_ERROR, false, "supHardNtViRdrRead: Error %#x reading %#zx bytes at %#llx in '%s'.\n",
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** @copydoc RTLDRREADER::pfnTell */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(RTFOFF) supHardNtViRdrTell(PRTLDRREADER pReader)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** @copydoc RTLDRREADER::pfnSize */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(RTFOFF) supHardNtViRdrSize(PRTLDRREADER pReader)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** @copydoc RTLDRREADER::pfnLogName */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(const char *) supHardNtViRdrLogName(PRTLDRREADER pReader)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** @copydoc RTLDRREADER::pfnMap */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(int) supHardNtViRdrMap(PRTLDRREADER pReader, const void **ppvBits)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** @copydoc RTLDRREADER::pfnUnmap */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(int) supHardNtViRdrUnmap(PRTLDRREADER pReader, const void *pvBits)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/** @copydoc RTLDRREADER::pfnDestroy */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(int) supHardNtViRdrDestroy(PRTLDRREADER pReader)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Creates a loader reader instance for the given NT file handle.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @returns iprt status code.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param hFile Native NT file handle.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param pwszName Optional file name.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param fFlags Flags, SUPHNTVI_F_XXX.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param ppNtViRdr Where to store the reader instance on success.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic int supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Try determine the size of the file.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), FileStandardInformation);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Calc the file name length and allocate memory for the reader instance.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)RTMemAllocZ(sizeof(*pNtViRdr) + cchFilename);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Initialize the structure.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync rc = RTUtf16ToUtf8Ex(pwszName, RTSTR_MAX, &pszName, cchFilename + 1, NULL);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync AssertStmt(RT_SUCCESS(rc), pNtViRdr->szFilename[0] = '\0');
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Simple case insensitive UTF-16 / ASCII path compare.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @returns true if equal, false if not.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param pwszLeft The UTF-16 path string.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param pszRight The ascii string.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic bool supHardViUtf16PathIsEqual(PCRTUTF16 pwszLeft, const char *pszRight)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync return false;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync if (b == '/')
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync return false;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync return true;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Simple case insensitive UTF-16 / ASCII ends-with path predicate.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @returns true if equal, false if not.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param pwsz The UTF-16 path string.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param pszSuffix The ascii suffix string.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic bool supHardViUtf16PathEndsWith(PCRTUTF16 pwsz, const char *pszSuffix)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync return supHardViUtf16PathIsEqual(pwsz + cwc - cchSuffix, pszSuffix);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync return false;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Simple case insensitive UTF-16 / ASCII starts-with path predicate.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @returns true if starts with given string, false if not.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param pwsz The UTF-16 path string.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * @param pszPrefix The ascii prefix string.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic bool supHardViUtf16PathStartsWith(PCRTUTF16 pwszLeft, const char *pszRight)
if (b != wc)
if (wc != b)
b = RT_C_TO_LOWER(b);
if (wc != b)
if (wc != b)
cSlashes++;
return cSlashes;
#ifdef VBOX_PERMIT_MORE
static int supHardNtViCheckIfNotSignedOk(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, uint32_t fFlags, int rc)
return rc;
#define IS_W2K3() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(5, 2) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(5, 3) )
#define IS_VISTA() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 0) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 1) )
#define IS_W70() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 1) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 2) )
#define IS_W80() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 2) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 3) )
#define IS_W81() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 3) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 4) )
#ifdef VBOX_PERMIT_MORE
#ifndef IN_RING0
if (cSlashes > 0)
return VINF_LDRVI_NOT_SIGNED;
return rc;
return VINF_LDRVI_NOT_SIGNED;
return rc;
#ifndef IN_RING0
return rc;
# ifdef RT_ARCH_AMD64
return VINF_LDRVI_NOT_SIGNED;
# ifdef RT_ARCH_AMD64
return VINF_LDRVI_NOT_SIGNED;
return rc;
#ifdef VBOX_PERMIT_MORE
cwcOther = g_System32NtPath.UniStr.Length / sizeof(WCHAR); /* ASSUMES System32 is called System32. */
return VINF_LDRVI_NOT_SIGNED;
# ifdef RT_ARCH_AMD64
return VINF_LDRVI_NOT_SIGNED;
return VINF_LDRVI_NOT_SIGNED;
return rc;
return rc;
static DECLCALLBACK(int) supHardNtViCertVerifyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths,
return VINF_SUCCESS;
bool fTrusted;
int rcVerify;
rc = RTCrX509CertPathsQueryPathInfo(hCertPaths, iPath, &fTrusted, NULL /*pcNodes*/, &pSubject, &pPublicKeyInfo,
cValid++;
if ( pCertPubKeyInfo
cFound++;
rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE, "Not valid kernel code signature.");
return rc;
return RTErrInfoSet(pErrInfo, VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT, "Not signed with the build certificate.");
return RTCrPkcs7VerifySignedData(pContentInfo, 0, g_hSpcAndNtKernelSuppStore, g_hSpcAndNtKernelRootStore, &ValidationTime,
&& supHardViUtf16PathIsEqual(&pwszName[g_System32NtPath.UniStr.Length / sizeof(WCHAR)], "\\wintrust.dll"))
DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags,
if (pfCacheable)
*pfCacheable = false;
#ifdef IN_RING3
rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pNtViRdr->uTimestamp, sizeof(pNtViRdr->uTimestamp));
bool fEnforced = false;
int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, &fEnforced, sizeof(fEnforced));
rc = RTErrInfoSetF(pErrInfo, rc2, "Querying RTLDRPROP_SIGNATURE_CHECKS_ENFORCED failed on %ls: %Rrc.",
else if (!fEnforced)
RTErrInfoSetF(pErrInfo, rc, "RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on %ls: %Rrc", pwszName, rc);
#ifdef IN_RING3
if ( g_pfnWinVerifyTrust
if (pfCacheable)
AssertFailed();
if (pfCacheable)
*pfCacheable = true;
return rc;
#ifdef IN_RING3
DECLHIDDEN(int) supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo)
} uBuf;
&uBuf,
&cbIgn);
return supHardenedWinVerifyImageByHandle(hFile, uBuf.UniStr.Buffer, fFlags, NULL /*pfCacheable*/, pErrInfo);
DECLHIDDEN(int) supHardNtGetSystemRootDir(void *pvBuf, uint32_t cbBuf, SUPHARDNTSYSROOTDIR enmDir, PRTERRINFO pErrInfo)
switch (enmDir)
AssertFailed();
return VERR_INVALID_PARAMETER;
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
&cbIgn);
return VINF_SUCCESS;
return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH, "NtQueryObject failed on '%ls' dir: %#x", NtName.Buffer, rcNt);
return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH, "Failure to open '%ls': %#x", NtName.Buffer, rcNt);
static int supHardNtViCertInit(PRTCRX509CERTIFICATE pCert, unsigned char const *pabCert, unsigned cbCert,
RTErrInfoSetF(pErrInfo, VERR_INTERNAL_ERROR_3, "%s: cbCert=%#x out of range", pszErrorTag, cbCert));
RTAsn1CursorInitPrimary(&PrimaryCursor, pabCert, cbCert, pErrInfo, &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, NULL);
return rc;
static int supHardNtViCertStoreAddArray(RTCRSTORE hStore, PCSUPTAENTRY paCerts, unsigned cCerts, PRTERRINFO pErrInfo)
int rc = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_TAF_DER, paCerts[i].pch, paCerts[i].cb, pErrInfo);
return rc;
return VINF_SUCCESS;
return rc;
int rc = supHardNtGetSystemRootDir(&g_System32NtPath, sizeof(g_System32NtPath), kSupHardNtSysRootDir_System32, pErrInfo);
rc = supHardNtGetSystemRootDir(&g_WinSxSNtPath, sizeof(g_WinSxSNtPath), kSupHardNtSysRootDir_WinSxS, pErrInfo);
rc = supHardNtViCertInit(&g_BuildX509Cert, g_abSUPBuildCert, g_cbSUPBuildCert, pErrInfo, "BuildCertificate");
#if 0 /* For the time being, always trust the build certificate. It bypasses the timestamp issues of CRT and SDL. */
&& RTCrX509Name_Compare(&g_BuildX509Cert.TbsCertificate.Subject, &g_BuildX509Cert.TbsCertificate.Issuer) == 0)
return VINF_SUCCESS;
return rc;
#ifdef IN_RING3
if (pCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.cBits < 256) /* mostly for u64KeyId reading. */
const char *pszName;
} const s_aWanted[] =
{ UINT64_C(0xffffffffffffffff), "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority" },
{ UINT64_C(0xffffffffffffffff), "L=Internet, O=VeriSign, Inc., OU=VeriSign Commercial Software Publishers CA" },
{ UINT64_C(0x491857ead79dde00), "C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority" },
{ UINT64_C(0xffffffffffffffff), "O=Microsoft Trust Network, OU=Microsoft Corporation, OU=Microsoft Time Stamping Service Root, OU=Copyright (c) 1997 Microsoft Corp." },
{ UINT64_C(0xffffffffffffffff), "O=VeriSign Trust Network, OU=VeriSign, Inc., OU=VeriSign Time Stamping Service Root, OU=NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc." },
{ UINT64_C(0xffffffffffffffff), "C=ZA, ST=Western Cape, L=Durbanville, O=Thawte, OU=Thawte Certification, CN=Thawte Timestamping CA" },
{ UINT64_C(0x3be670c1bd02a900), "OU=Copyright (c) 1997 Microsoft Corp., OU=Microsoft Corporation, CN=Microsoft Root Authority" },
{ UINT64_C(0x4d3835aa4180b200), "C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2011" },
{ UINT64_C(0xece4e4289e08b900), "C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010" },
{ UINT64_C(0x59faf1086271bf00), "C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2" },
{ UINT64_C(0x91e3728b8b40d000), "C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Certification Authority" },
{ UINT64_C(0x61a3a33f81aace00), "C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Object" },
{ 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=premium-server@thawte.com" },
{ UINT64_C(0x8ff6fc03c1edbd00), "C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2" },
{ UINT64_C(0xa671e9fec832b700), "C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority" },
{ UINT64_C(0xa8de7211e13be200), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA" },
{ 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" },
{ UINT64_C(0x7ae89c50f0b6a00f), "C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root" },
{ 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" },
{ 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=premium-server@thawte.com" },
{ UINT64_C(0xd4fbe673e5ccc600), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA" },
{ 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" },
{ UINT64_C(0x6e2ba21058eedf00), "C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN - DATACorp SGC" },
{ 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)" },
{ 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" },
{ UINT64_C(0x466cbc09db88c100), "C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority" },
{ UINT64_C(0x9259c8abe5ca713a), "L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com/, Email=info@valicert.com" },
{ 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" },
{ UINT64_C(0x8043e4ce150ead00), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA" },
{ UINT64_C(0x00f2e6331af7b700), "C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root" },
uint64_t const u64KeyId = pCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.uBits.pu64[1];
#ifdef DEBUG_bird
HMODULE hCrypt32 = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\crypt32.dll", NULL, fLoadLibraryFlags);
if (!hCrypt32)
if (pfn##a_Name == NULL) supR3HardenedFatal("Error locating '" #a_Name "' in 'crypt32.dll': %u", GetLastError())
HCERTSTORE hStore = pfnCertOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
if (!hStore)
if (hStore)
RTAsn1CursorInitPrimary(&PrimaryCursor, pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded, NULL /*pErrInfo*/,
cAdded++;
g_fHaveOtherRoots = true;
# ifdef IN_SUP_HARDENED_R3
HMODULE hWintrust = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\Wintrust.dll", NULL, fFlags);
&& fFlags
fFlags = 0;
PFNWINVERIFYTRUST pfnWinVerifyTrust = (PFNWINVERIFYTRUST)GetProcAddress(hWintrust, "WinVerifyTrust");
if (!pfnWinVerifyTrust)
RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle2, PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2, SUP_NT_VER_W80);
# ifdef IN_SUP_HARDENED_R3
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. */
supR3HardNtViCallWinVerifyTrust(NULL, L"\\SystemRoot\\System32\\ntdll.dll", 0, NULL, pfnWinVerifyTrust);
supR3HardNtViCallWinVerifyTrustCatFile(NULL, L"\\SystemRoot\\System32\\ntdll.dll", 0, NULL, pfnWinVerifyTrust);
return VERR_FILENAME_TOO_LONG;
memcpy(&pwszWinPathBuf[sizeof(s_wszPrefix) / sizeof(RTUTF16) - 1], pwszNtName, (cwcNtName + 1) * sizeof(RTUTF16));
return VINF_SUCCESS;
static int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
int rc = supR3HardNtViNtToWinPath(pwszName, &pwszWinPath, wszWinPathBuf, RT_ELEMENTS(wszWinPathBuf));
return RTErrInfoSetF(pErrInfo, rc, "Bad path passed to supR3HardNtViCallWinVerifyTrust: rc=%Rrc '%ls'", rc, pwszName);
# ifdef DEBUG_bird
__debugbreak();
switch (hrc)
if (pszErrConst)
return rc;
static int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
int rc = supR3HardNtViNtToWinPath(pwszName, &pwszWinPath, wszWinPathBuf, RT_ELEMENTS(wszWinPathBuf));
return RTErrInfoSetF(pErrInfo, rc, "Bad path passed to supR3HardNtViCallWinVerifyTrustCatFile: rc=%Rrc '%ls'", rc, pwszName);
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
} s_aHashes[] =
bool fTryNextPolicy;
fTryNextPolicy = false;
if (hCatAdmin)
else if (g_pfnCryptCATAdminAcquireContext2)
fRc = g_pfnCryptCATAdminAcquireContext2(&hCatAdmin, &s_aPolicies[iPolicy], s_aHashes[i].pszAlgorithm,
if (fRc)
if (fRc)
int rc2 = RTUtf16PrintHexBytes(wszDigest, RT_ELEMENTS(wszDigest), abHash, cbHash, RTSTRPRINTHEXBYTES_F_UPPER);
SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: cbHash=%u wszDigest=%ls\n", cbHash, wszDigest));
HCATINFO hCatInfo = g_pfnCryptCATAdminEnumCatalogFromHash(hCatAdmin, abHash, cbHash, 0, &hCatInfoPrev);
if (!hCatInfo)
if (iCat == 0)
SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", GetLastError()));
SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: WinVerifyTrust => %#x; cat=%ls\n", hrc, CatInfo.wszCatalogFile));
iCat++;
AssertFailed();
AssertFailed();
iPolicy++;
} while ( fTryNextPolicy
return rc;