diff options
| author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2020-10-16 14:34:15 +0000 |
|---|---|---|
| committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2020-10-16 14:34:15 +0000 |
| commit | b2b89ce65db2a5f62651cdc764051c0bb8412e52 (patch) | |
| tree | 27936b7dbfadf7fe55708b20a1ec7e9f7548779e /src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp | |
| parent | b779fb6fa4f75f7e3a9d58d09986e15455b1025c (diff) | |
| download | VirtualBox-svn-b2b89ce65db2a5f62651cdc764051c0bb8412e52.tar.gz | |
SUPHArdNt,IPRT: Recognize WHQL/attestation signatures from MS. Corrected RTCRX509TBSCERTIFICATE::T3::fExtKeyUsage type (32 -> 64 bit) as it has been to small for a while now. bugref:3103
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@86610 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp')
| -rw-r--r-- | src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp | 106 |
1 files changed, 78 insertions, 28 deletions
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp index c021ea619c4..4564d8f8931 100644 --- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp +++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp @@ -958,6 +958,51 @@ static DECLCALLBACK(void) supHardNtViAsn1DumpToErrInfo(void *pvUser, const char /** + * 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.} */ @@ -993,8 +1038,10 @@ static DECLCALLBACK(int) supHardNtViCertVerifyCallback(PCRTCRX509CERTIFICATE pCe && (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA)) { /* - * 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) { @@ -1017,36 +1064,37 @@ static DECLCALLBACK(int) supHardNtViCertVerifyCallback(PCRTCRX509CERTIFICATE pCe cValid++; /* - * 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); - AssertRCBreak(rc); - - PCRTCRCERTCTX pCertCtx; - while ((pCertCtx = RTCrStoreCertSearchNext(g_hNtKernelRootStore, &Search)) != NULL) + 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))) { - 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) + rc = supHardNtViCertVerifyFindRootCert(g_hSpcRootStore, pSubject, pPublicKeyInfo); + if (rc == VINF_SUCCESS) cFound++; - RTCrCertCtxRelease(pCertCtx); } - - int rc2 = RTCrStoreCertSearchDestroy(g_hNtKernelRootStore, &Search); AssertRC(rc2); + AssertRCBreak(rc); } } 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; } } @@ -1103,6 +1151,7 @@ static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREI PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pvUser; 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); AssertReturn(!pInfo->pvExternalData, VERR_INTERNAL_ERROR_5); @@ -1124,7 +1173,8 @@ static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREI &pSignerInfo->IssuerAndSerialNumber.Name, &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, g_BuildX509Cert.TbsCertificate.SerialNumber.Asn1Core.cb, @@ -1194,7 +1244,7 @@ static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREI { 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; } @@ -1209,7 +1259,7 @@ static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREI 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 { @@ -1221,7 +1271,7 @@ static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREI if ( rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME || 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)); @@ -1234,7 +1284,7 @@ static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREI } } 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; } |
