Index: /trunk/include/iprt/crypto/x509.h
===================================================================
--- /trunk/include/iprt/crypto/x509.h	(revision 86609)
+++ /trunk/include/iprt/crypto/x509.h	(revision 86610)
@@ -779,10 +779,10 @@
         /** The unique identifier value. */
         RTCRX509EXTENSIONS              Extensions;
-        /** Extensions summary flags. */
+        /** Extensions summary flags (RTCRX509TBSCERTIFICATE_F_PRESENT_XXX). */
         uint32_t                        fFlags;
-        /** Key usage flags. */
+        /** Key usage flags (RTCRX509CERT_KEY_USAGE_F_XXX). */
         uint32_t                        fKeyUsage;
-        /** Extended key usage flags. */
-        uint32_t                        fExtKeyUsage;
+        /** Extended key usage flags (RTCRX509CERT_EKU_F_XXX). */
+        uint64_t                        fExtKeyUsage;
 
         /** Pointer to the authority key ID extension if present. */
@@ -899,4 +899,6 @@
 #define RTCRX509CERT_EKU_F_MS_DRM                           RT_BIT_64(38)
 #define RTCRX509CERT_EKU_F_MS_DRM_INDIVIDUALIZATION         RT_BIT_64(39)
+#define RTCRX509CERT_EKU_F_MS_WHQL_CRYPTO                   RT_BIT_64(40)
+#define RTCRX509CERT_EKU_F_MS_ATTEST_WHQL_CRYPTO            RT_BIT_64(41)
 /** @} */
 
@@ -928,4 +930,5 @@
 #define RTCRX509_MS_EKU_ENCRYPTED_FILE_SYSTEM_OID           "1.3.6.1.4.1.311.10.3.4"
 #define RTCRX509_MS_EKU_WHQL_CRYPTO_OID                     "1.3.6.1.4.1.311.10.3.5"
+#define RTCRX509_MS_EKU_ATTEST_WHQL_CRYPTO_OID              "1.3.6.1.4.1.311.10.3.5.1"
 #define RTCRX509_MS_EKU_NT5_CRYPTO_OID                      "1.3.6.1.4.1.311.10.3.6"
 #define RTCRX509_MS_EKU_OEM_WHQL_CRYPTO_OID                 "1.3.6.1.4.1.311.10.3.7"
Index: /trunk/src/VBox/HostDrivers/Support/testcase/tstSupVerify.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/testcase/tstSupVerify.cpp	(revision 86609)
+++ /trunk/src/VBox/HostDrivers/Support/testcase/tstSupVerify.cpp	(revision 86610)
@@ -40,4 +40,53 @@
 
 
+//#define DYNAMIC
+#ifdef DYNAMIC
+# include <iprt/win/windows.h>
+
+# define DYNAMIC_IMPORTS() \
+    ONE_IMPORT(RTR3InitExe); \
+    ONE_IMPORT(RTMsgInitFailure); \
+    ONE_IMPORT(RTGetOpt); \
+    ONE_IMPORT(RTGetOptInit); \
+    ONE_IMPORT(RTGetOptPrintError); \
+    ONE_IMPORT(RTMsgError); \
+    ONE_IMPORT(RTMsgErrorExit); \
+    ONE_IMPORT(RTMsgInfo); \
+    ONE_IMPORT(RTPrintf); \
+    ONE_IMPORT(SUPR3HardenedVerifyInit); \
+    ONE_IMPORT(SUPR3HardenedVerifyPlugIn)
+
+# define ONE_IMPORT(a_fnName) static decltype(a_fnName) *g_pfn##a_fnName
+DYNAMIC_IMPORTS();
+# undef ONE_IMPORT
+
+static void resolve(void)
+{
+    HMODULE hmod = LoadLibrary("VBoxRT.dll");
+    DWORD cbWritten = 0;
+
+# define ONE_IMPORT(a_fnName) do { \
+            g_pfn##a_fnName = (decltype(a_fnName) *)GetProcAddress(hmod, #a_fnName); \
+            if (!g_pfn##a_fnName) \
+                WriteFile(GetStdHandle(STD_ERROR_HANDLE), RT_STR_TUPLE("Failed to resolve: " #a_fnName "\r\n"), &cbWritten, NULL); \
+        } while (0)
+    DYNAMIC_IMPORTS();
+# undef ONE_IMPORT
+}
+
+#define RTR3InitExe                  g_pfnRTR3InitExe
+#define RTMsgInitFailure             g_pfnRTMsgInitFailure
+#define RTGetOpt                     g_pfnRTGetOpt
+#define RTGetOptInit                 g_pfnRTGetOptInit
+#define RTGetOptPrintError           g_pfnRTGetOptPrintError
+#define RTMsgError                   g_pfnRTMsgError
+#define RTMsgErrorExit               g_pfnRTMsgErrorExit
+#define RTMsgInfo                    g_pfnRTMsgInfo
+#define RTPrintf                     g_pfnRTPrintf
+#define SUPR3HardenedVerifyInit      g_pfnSUPR3HardenedVerifyInit
+#define SUPR3HardenedVerifyPlugIn    g_pfnSUPR3HardenedVerifyPlugIn
+
+#endif /* DYNAMIC */
+
 int main(int argc, char **argv)
 {
@@ -45,4 +94,7 @@
      * Init.
      */
+#ifdef DYNAMIC
+    resolve();
+#endif
     int rc = RTR3InitExe(argc, &argv, 0);
     if (RT_FAILURE(rc))
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h	(revision 86609)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h	(revision 86610)
@@ -113,4 +113,6 @@
     /** Total number of signatures. */
     uint16_t    cTotalSignatures;
+    /** The current signature (for passing to supHardNtViCertVerifyCallback). */
+    uint16_t    iCurSignature;
     /** The last non-fatal signature failure. */
     int         rcLastSignatureFailure;
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 86609)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 86610)
@@ -959,4 +959,49 @@
 
 /**
+ * Attempts to locate a root certificate in the specified store.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_SUCCESS if found.
+ * @retval  VWRN_NOT_FOUND if not found.
+ *
+ * @param   hRootStore      The root certificate store to search.
+ * @param   pSubject        The root certificate subject.
+ * @param   pPublicKeyInfo  The public key of the root certificate to find.
+ */
+static int supHardNtViCertVerifyFindRootCert(RTCRSTORE hRootStore, PCRTCRX509NAME pSubject,
+                                             PCRTCRX509SUBJECTPUBLICKEYINFO pPublicKeyInfo)
+{
+    RTCRSTORECERTSEARCH Search;
+    int rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(hRootStore, pSubject, &Search);
+    AssertRCReturn(rc, rc);
+
+    rc = VWRN_NOT_FOUND;
+    PCRTCRCERTCTX pCertCtx;
+    while ((pCertCtx = RTCrStoreCertSearchNext(hRootStore, &Search)) != NULL)
+    {
+        PCRTCRX509SUBJECTPUBLICKEYINFO pCertPubKeyInfo = NULL;
+        if (pCertCtx->pCert)
+            pCertPubKeyInfo = &pCertCtx->pCert->TbsCertificate.SubjectPublicKeyInfo;
+        else if (pCertCtx->pTaInfo)
+            pCertPubKeyInfo = &pCertCtx->pTaInfo->PubKey;
+        else
+            pCertPubKeyInfo = NULL;
+        if (   pCertPubKeyInfo
+            && RTCrX509SubjectPublicKeyInfo_Compare(pCertPubKeyInfo, pPublicKeyInfo) == 0)
+        {
+            RTCrCertCtxRelease(pCertCtx);
+            rc = VINF_SUCCESS;
+            break;
+        }
+        RTCrCertCtxRelease(pCertCtx);
+    }
+
+    int rc2 = RTCrStoreCertSearchDestroy(hRootStore, &Search);
+    AssertRC(rc2);
+    return rc;
+}
+
+
+/**
  * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
  * Standard code signing.  Use this for Microsoft SPC.}
@@ -994,6 +1039,8 @@
     {
         /*
-         * If kernel signing, a valid certificate path must be anchored by the
-         * microsoft kernel signing root certificate.
+         * For kernel code signing there are two options for a valid certificate path:
+         *  1. Anchored by the microsoft kernel signing root certificate (g_hNtKernelRootStore).
+         *  2. Anchored by an SPC root and signing entity including a 1.3.6.1.4.1.311.10.3.5 (WHQL)
+         *     or 1.3.6.1.4.1.311.10.3.5.1 (WHQL attestation) extended usage key.
          */
         if (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
@@ -1018,34 +1065,35 @@
 
                     /*
-                     * Search the kernel signing root store for a matching anchor.
+                     * 1. Search the kernel signing root store for a matching anchor.
                      */
-                    RTCRSTORECERTSEARCH Search;
-                    rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(g_hNtKernelRootStore, pSubject, &Search);
+                    rc = supHardNtViCertVerifyFindRootCert(g_hNtKernelRootStore, pSubject, pPublicKeyInfo);
+                    if (rc == VINF_SUCCESS)
+                        cFound++;
+                    /*
+                     * 2. Check for WHQL EKU and make sure it has a SPC root.
+                     */
+                    else if (   rc == VWRN_NOT_FOUND
+                             && (  pCert->TbsCertificate.T3.fExtKeyUsage
+                                 & (RTCRX509CERT_EKU_F_MS_ATTEST_WHQL_CRYPTO | RTCRX509CERT_EKU_F_MS_WHQL_CRYPTO)))
+                    {
+                        rc = supHardNtViCertVerifyFindRootCert(g_hSpcRootStore, pSubject, pPublicKeyInfo);
+                        if (rc == VINF_SUCCESS)
+                            cFound++;
+                    }
                     AssertRCBreak(rc);
-
-                    PCRTCRCERTCTX pCertCtx;
-                    while ((pCertCtx = RTCrStoreCertSearchNext(g_hNtKernelRootStore, &Search)) != NULL)
-                    {
-                        PCRTCRX509SUBJECTPUBLICKEYINFO pCertPubKeyInfo = NULL;
-                        if (pCertCtx->pCert)
-                            pCertPubKeyInfo = &pCertCtx->pCert->TbsCertificate.SubjectPublicKeyInfo;
-                        else if (pCertCtx->pTaInfo)
-                            pCertPubKeyInfo = &pCertCtx->pTaInfo->PubKey;
-                        else
-                            pCertPubKeyInfo = NULL;
-                        if (   pCertPubKeyInfo
-                            && RTCrX509SubjectPublicKeyInfo_Compare(pCertPubKeyInfo, pPublicKeyInfo) == 0)
-                            cFound++;
-                        RTCrCertCtxRelease(pCertCtx);
-                    }
-
-                    int rc2 = RTCrStoreCertSearchDestroy(g_hNtKernelRootStore, &Search); AssertRC(rc2);
                 }
             }
             if (RT_SUCCESS(rc) && cFound == 0)
-                rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE, "Not valid kernel code signature.");
+                rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE,
+                                   "Signature #%u/%u: Not valid kernel code signature.",
+                                   pNtViRdr->iCurSignature + 1, pNtViRdr->cTotalSignatures);
+
+
             if (RT_SUCCESS(rc) && cValid < 2 && g_fHaveOtherRoots)
                 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_UNEXPECTED_VALID_PATH_COUNT,
-                                   "Expected at least %u valid paths, not %u.", 2, cValid);
+                                   "Signature #%u/%u: Expected at least %u valid paths, not %u.",
+                                   pNtViRdr->iCurSignature + 1, pNtViRdr->cTotalSignatures, 2, cValid);
+            if (rc == VWRN_NOT_FOUND)
+                rc = VINF_SUCCESS;
         }
     }
@@ -1104,4 +1152,5 @@
     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
     pNtViRdr->cTotalSignatures = pInfo->cSignatures;
+    pNtViRdr->iCurSignature    = pInfo->iSignature;
 
     AssertReturn(pInfo->enmType == RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA, VERR_INTERNAL_ERROR_5);
@@ -1125,5 +1174,6 @@
                                                             &pSignerInfo->IssuerAndSerialNumber.SerialNumber))
             return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT,
-                                 "Not signed with the build certificate (serial %.*Rhxs, expected %.*Rhxs)",
+                                 "Signature #%u/%u: Not signed with the build certificate (serial %.*Rhxs, expected %.*Rhxs)",
+                                 pInfo->iSignature + 1, pInfo->cSignatures,
                                  pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.cb,
                                  pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.uData.pv,
@@ -1195,5 +1245,5 @@
             if (rc != VINF_SUCCESS)
             {
-                SUP_DPRINTF(("%s: Signature #%u/%u: info status: %d\n", pNtViRdr->szFilename, pInfo->iSignature, pInfo->cbSignature, rc));
+                SUP_DPRINTF(("%s: Signature #%u/%u: info status: %d\n", pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures, rc));
                 if (pNtViRdr->rcLastSignatureFailure == VINF_SUCCESS)
                     pNtViRdr->rcLastSignatureFailure = rc;
@@ -1210,5 +1260,5 @@
         if (rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME && i + 1 < cTimes)
             SUP_DPRINTF(("%s: Signature #%u/%u: VERR_CR_X509_CPV_NOT_VALID_AT_TIME for %#RX64; retrying against current time: %#RX64.\n",
-                         pNtViRdr->szFilename, pInfo->iSignature, pInfo->cbSignature,
+                         pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures,
                          RTTimeSpecGetSeconds(&aTimes[0].TimeSpec), RTTimeSpecGetSeconds(&aTimes[1].TimeSpec)));
         else
@@ -1222,5 +1272,5 @@
                 || rc == VERR_CR_X509_CPV_NO_TRUSTED_PATHS)
             {
-                SUP_DPRINTF(("%s: Signature #%u/%u: %s (%d) w/ timestamp=%#RX64/%s.\n", pNtViRdr->szFilename, pInfo->iSignature, pInfo->cbSignature,
+                SUP_DPRINTF(("%s: Signature #%u/%u: %s (%d) w/ timestamp=%#RX64/%s.\n", pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures,
                              rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME ? "VERR_CR_X509_CPV_NOT_VALID_AT_TIME" : "VERR_CR_X509_CPV_NO_TRUSTED_PATHS", rc,
                              RTTimeSpecGetSeconds(&aTimes[i].TimeSpec), aTimes[i].pszDesc));
@@ -1235,5 +1285,5 @@
             }
             else
-                SUP_DPRINTF(("%s: Signature #%u/%u: %Rrc w/ timestamp=%#RX64/%s.\n", pNtViRdr->szFilename, pInfo->iSignature, pInfo->cbSignature,
+                SUP_DPRINTF(("%s: Signature #%u/%u: %Rrc w/ timestamp=%#RX64/%s.\n", pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures,
                              rc, RTTimeSpecGetSeconds(&aTimes[i].TimeSpec), aTimes[i].pszDesc));
             return rc;
Index: /trunk/src/VBox/Runtime/common/crypto/pkcs7-verify.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/pkcs7-verify.cpp	(revision 86609)
+++ /trunk/src/VBox/Runtime/common/crypto/pkcs7-verify.cpp	(revision 86610)
@@ -204,5 +204,5 @@
                 return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_KEY_USAGE_MISMATCH, "No extended key usage certificate attribute.");
             if (!(pCert->TbsCertificate.T3.fExtKeyUsage & RTCRX509CERT_EKU_F_CODE_SIGNING))
-                return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_KEY_USAGE_MISMATCH, "fExtKeyUsage=%#x, missing %#x",
+                return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_KEY_USAGE_MISMATCH, "fExtKeyUsage=%#RX64, missing CODE_SIGNING (%#RX64)",
                                      pCert->TbsCertificate.T3.fExtKeyUsage, RTCRX509CERT_EKU_F_CODE_SIGNING);
         }
Index: /trunk/src/VBox/Runtime/common/crypto/x509-core.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/x509-core.cpp	(revision 86609)
+++ /trunk/src/VBox/Runtime/common/crypto/x509-core.cpp	(revision 86610)
@@ -1456,4 +1456,8 @@
             if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_TIMESTAMP_SIGNING_OID) == 0)
                 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_TIMESTAMP_SIGNING;
+            else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_WHQL_CRYPTO_OID) == 0)
+                pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_WHQL_CRYPTO;
+            else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_ATTEST_WHQL_CRYPTO_OID) == 0)
+                pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_ATTEST_WHQL_CRYPTO;
             else if (RTAsn1ObjId_CompareWithString(pObjIds->papItems[i], RTCRX509_MS_EKU_NT5_CRYPTO_OID) == 0)
                 pThis->T3.fExtKeyUsage |= RTCRX509CERT_EKU_F_MS_NT5_CRYPTO;
