/** * @callback_method_impl{RTCRPKCS7VERIFYCERTCALLBACK, * Standard code signing. Use this for Microsoft SPC.} */ RTDECL(int) RTCrPkcs7VerifyCertCallbackCodeSigning(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo) { int rc = VINF_SUCCESS; if (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA) { /* * If KeyUsage is present it must include digital signature. */ rc = rtCrPkcs7VerifyCertUsageDigitalSignature(pCert, pErrInfo); if (RT_SUCCESS(rc)) { /* * The extended usage 'code signing' must be present. */ if (!(pCert->TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_EXT_KEY_USAGE)) 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", pCert->TbsCertificate.T3.fExtKeyUsage, RTCRX509CERT_EKU_F_CODE_SIGNING); } } /* * Timestamping too? */ if ( (fFlags & RTCRPKCS7VCC_F_TIMESTAMP) && RT_SUCCESS(rc)) rc = rtCrPkcs7VerifyCertUsageTimstamping(pCert, pErrInfo); return rc; }
static int rtCrX509TbsCertificate_CheckSanityExtra(PCRTCRX509TBSCERTIFICATE pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { if ( RTAsn1Integer_IsPresent(&pThis->T0.Version) && RTAsn1Integer_UnsignedCompareWithU32(&pThis->T0.Version, RTCRX509TBSCERTIFICATE_V1) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pThis->T0.Version, RTCRX509TBSCERTIFICATE_V2) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pThis->T0.Version, RTCRX509TBSCERTIFICATE_V3) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_TBSCERT_UNSUPPORTED_VERSION, "%s: Unknown Version number: %llu", pszErrorTag, pThis->T0.Version.uValue.u); if ( pThis->SerialNumber.Asn1Core.cb < 1 || pThis->SerialNumber.Asn1Core.cb > 1024) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_TBSCERT_SERIAL_NUMBER_OUT_OF_BOUNDS, "%s: Bad SerialNumber length: %u", pszErrorTag, pThis->SerialNumber.Asn1Core.cb); if ( ( RTAsn1BitString_IsPresent(&pThis->T1.IssuerUniqueId) || RTAsn1BitString_IsPresent(&pThis->T2.SubjectUniqueId)) && RTAsn1Integer_UnsignedCompareWithU32(&pThis->T0.Version, RTCRX509TBSCERTIFICATE_V2) < 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_TBSCERT_UNIQUE_IDS_REQ_V2, "%s: IssuerUniqueId and SubjectUniqueId requires version 2", pszErrorTag); if ( RTCrX509Extensions_IsPresent(&pThis->T3.Extensions) && RTAsn1Integer_UnsignedCompareWithU32(&pThis->T0.Version, RTCRX509TBSCERTIFICATE_V3) < 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_TBSCERT_EXTS_REQ_V3, "%s: Extensions requires version 3", pszErrorTag); return VINF_SUCCESS; }
/** @callback_method_impl{FNVBOXEXTPACKREGISTER} */ extern "C" DECLEXPORT(int) VBoxExtPackRegister(PCVBOXEXTPACKHLP pHlp, PCVBOXEXTPACKREG *ppReg, PRTERRINFO pErrInfo) { /* * Check the VirtualBox version. */ if (!VBOXEXTPACK_IS_VER_COMPAT(pHlp->u32Version, VBOXEXTPACKHLP_VERSION)) return RTErrInfoSetF(pErrInfo, VERR_VERSION_MISMATCH, "Helper version mismatch - expected %#x got %#x", VBOXEXTPACKHLP_VERSION, pHlp->u32Version); if ( VBOX_FULL_VERSION_GET_MAJOR(pHlp->uVBoxFullVersion) != VBOX_VERSION_MAJOR || VBOX_FULL_VERSION_GET_MINOR(pHlp->uVBoxFullVersion) != VBOX_VERSION_MINOR) return RTErrInfoSetF(pErrInfo, VERR_VERSION_MISMATCH, "VirtualBox version mismatch - expected %u.%u got %u.%u", VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_FULL_VERSION_GET_MAJOR(pHlp->uVBoxFullVersion), VBOX_FULL_VERSION_GET_MINOR(pHlp->uVBoxFullVersion)); /* * We're good, save input and return the registration structure. */ g_pHlp = pHlp; *ppReg = &g_vboxSkeletonExtPackReg; return VINF_SUCCESS; }
static int rtCrPkcs7VerifyCertUsageTimstamping(PCRTCRX509CERTIFICATE pCert, PRTERRINFO pErrInfo) { if (!(pCert->TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_EXT_KEY_USAGE)) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_KEY_USAGE_MISMATCH, "No extended key usage certificate attribute."); if (!(pCert->TbsCertificate.T3.fExtKeyUsage & (RTCRX509CERT_EKU_F_TIMESTAMPING | RTCRX509CERT_EKU_F_MS_TIMESTAMP_SIGNING))) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_KEY_USAGE_MISMATCH, "fExtKeyUsage=%#x, missing %#x (time stamping)", pCert->TbsCertificate.T3.fExtKeyUsage, RTCRX509CERT_EKU_F_TIMESTAMPING | RTCRX509CERT_EKU_F_MS_TIMESTAMP_SIGNING); return VINF_SUCCESS; }
RTDECL(int) RTAsn1Integer_CheckSanity(PCRTASN1INTEGER pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { RT_NOREF_PV(fFlags); if (RT_UNLIKELY(!RTAsn1Integer_IsPresent(pThis))) return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (INTEGER).", pszErrorTag); return VINF_SUCCESS; }
RTDECL(int) RTAsn1Core_CheckSanity(PCRTASN1CORE pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { /* We can only check that it's present. */ if (!RTAsn1Core_IsPresent(pThis)) return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (RTASN1CORE).", pszErrorTag); return VINF_SUCCESS; }
static int rtCrX509Validity_CheckSanityExtra(PCRTCRX509VALIDITY pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { if (RTAsn1Time_Compare(&pThis->NotBefore, &pThis->NotAfter) > 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_VALIDITY_SWAPPED, "%s: NotBefore is after NotAfter", pszErrorTag); /** @todo check tag constraints? */ return VINF_SUCCESS; }
RTDECL(int) RTAsn1DynType_CheckSanity(PCRTASN1DYNTYPE pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { if (RT_UNLIKELY(!RTAsn1DynType_IsPresent(pThis))) return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (DYNTYPE).", pszErrorTag); int rc; switch (pThis->enmType) { case RTASN1TYPE_CORE: rc = RTAsn1Core_CheckSanity(&pThis->u.Core, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_NULL: rc = RTAsn1Null_CheckSanity(&pThis->u.Asn1Null, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_INTEGER: rc = RTAsn1Integer_CheckSanity(&pThis->u.Integer, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_BOOLEAN: rc = RTAsn1Boolean_CheckSanity(&pThis->u.Boolean, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_STRING: rc = RTAsn1String_CheckSanity(&pThis->u.String, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_OCTET_STRING: rc = RTAsn1OctetString_CheckSanity(&pThis->u.OctetString, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_BIT_STRING: rc = RTAsn1BitString_CheckSanity(&pThis->u.BitString, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_TIME: rc = RTAsn1Time_CheckSanity(&pThis->u.Time, fFlags, pErrInfo, pszErrorTag); break; #if 0 case RTASN1TYPE_SEQUENCE_CORE: rc = VINF_SUCCESS; //rc = RTAsn1SequenceCore_CheckSanity(&pThis->u.SeqCore, fFlags, pErrInfo, pszErrorTag); break; case RTASN1TYPE_SET_CORE: rc = VINF_SUCCESS; //rc = RTAsn1SetCore_CheckSanity(&pThis->u.SetCore, fFlags, pErrInfo, pszErrorTag); break; #endif case RTASN1TYPE_OBJID: rc = RTAsn1ObjId_CheckSanity(&pThis->u.ObjId, fFlags, pErrInfo, pszErrorTag); break; default: AssertFailedReturn(VERR_ASN1_INTERNAL_ERROR_2); } return rc; }
RTDECL(int) RTLdrLoadEx(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo) { LogFlow(("RTLdrLoadEx: pszFilename=%p:{%s} phLdrMod=%p fFlags=%#x pErrInfo=%p\n", pszFilename, pszFilename, phLdrMod, fFlags, pErrInfo)); /* * Validate and massage the input. */ RTErrInfoClear(pErrInfo); AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); AssertPtrReturn(phLdrMod, VERR_INVALID_POINTER); AssertReturn(!(fFlags & ~RTLDRLOAD_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); /* * Allocate and initialize module structure. */ int rc = VERR_NO_MEMORY; PRTLDRMODNATIVE pMod = (PRTLDRMODNATIVE)RTMemAlloc(sizeof(*pMod)); if (pMod) { pMod->Core.u32Magic = RTLDRMOD_MAGIC; pMod->Core.eState = LDR_STATE_LOADED; pMod->Core.pOps = &g_rtldrNativeOps; pMod->Core.pReader = NULL; pMod->Core.enmFormat = RTLDRFMT_NATIVE; pMod->Core.enmType = RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE; /* approx */ #ifdef RT_BIG_ENDIAN pMod->Core.enmEndian = RTLDRENDIAN_BIG; #else pMod->Core.enmEndian = RTLDRENDIAN_LITTLE; #endif #ifdef RT_ARCH_AMD64 pMod->Core.enmArch = RTLDRARCH_AMD64; #elif defined(RT_ARCH_X86) pMod->Core.enmArch = RTLDRARCH_X86_32; #else pMod->Core.enmArch = RTLDRARCH_HOST; #endif pMod->hNative = ~(uintptr_t)0; pMod->fFlags = fFlags; /* * Attempt to open the module. */ rc = rtldrNativeLoad(pszFilename, &pMod->hNative, fFlags, pErrInfo); if (RT_SUCCESS(rc)) { *phLdrMod = &pMod->Core; LogFlow(("RTLdrLoad: returns %Rrc *phLdrMod=%RTldrm\n", rc, *phLdrMod)); return rc; } RTMemFree(pMod); } else RTErrInfoSetF(pErrInfo, rc, "Failed to allocate %zu bytes for the module handle", sizeof(*pMod)); *phLdrMod = NIL_RTLDRMOD; LogFlow(("RTLdrLoad: returns %Rrc\n", rc)); return rc; }
static int rtCrPkcs7VerifyCertUsageDigitalSignature(PCRTCRX509CERTIFICATE pCert, PRTERRINFO pErrInfo) { if ( (pCert->TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_KEY_USAGE) && !(pCert->TbsCertificate.T3.fKeyUsage & RTCRX509CERT_KEY_USAGE_F_DIGITAL_SIGNATURE)) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_KEY_USAGE_MISMATCH, "fKeyUsage=%#x, missing %#x", pCert->TbsCertificate.T3.fKeyUsage, RTCRX509CERT_KEY_USAGE_F_DIGITAL_SIGNATURE); return VINF_SUCCESS; }
RTDECL(int) RTCrX509Certificate_VerifySignature(PCRTCRX509CERTIFICATE pThis, PCRTASN1OBJID pAlgorithm, PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey, PRTERRINFO pErrInfo) { /* * Validate the input a little. */ AssertPtrReturn(pThis, VERR_INVALID_POINTER); AssertReturn(RTCrX509Certificate_IsPresent(pThis), VERR_INVALID_PARAMETER); AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER); AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER); if (pParameters) { AssertPtrReturn(pParameters, VERR_INVALID_POINTER); if (pParameters->enmType == RTASN1TYPE_NULL) pParameters = NULL; } AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER); AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER); /* * Check if the algorithm matches. */ const char *pszCipherOid = RTCrPkixGetCiperOidFromSignatureAlgorithm(&pThis->SignatureAlgorithm.Algorithm); if (!pszCipherOid) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO, "Certificate signature algorithm not known: %s", pThis->SignatureAlgorithm.Algorithm.szObjId); if (RTAsn1ObjId_CompareWithString(pAlgorithm, pszCipherOid) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH, "Certificate signature cipher algorithm mismatch: cert uses %s (%s) while key uses %s", pszCipherOid, pThis->SignatureAlgorithm.Algorithm.szObjId, pAlgorithm->szObjId); /* * Here we should recode the to-be-signed part as DER, but we'll ASSUME * that it's already in DER encoding. This is safe. */ return RTCrPkixPubKeyVerifySignature(&pThis->SignatureAlgorithm.Algorithm, pParameters, pPublicKey, &pThis->SignatureValue, RTASN1CORE_GET_RAW_ASN1_PTR(&pThis->TbsCertificate.SeqCore.Asn1Core), RTASN1CORE_GET_RAW_ASN1_SIZE(&pThis->TbsCertificate.SeqCore.Asn1Core), pErrInfo); }
static int rtCrX509Name_CheckSanityExtra(PCRTCRX509NAME pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { RT_NOREF_PV(fFlags); if (pThis->cItems == 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_NAME_EMPTY_SET, "%s: Has no components.", pszErrorTag); for (uint32_t i = 0; i < pThis->cItems; i++) { PCRTCRX509RELATIVEDISTINGUISHEDNAME const pRdn = pThis->papItems[i]; if (pRdn->cItems == 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_NAME_EMPTY_SUB_SET, "%s: Items[%u] has no sub components.", pszErrorTag, i); for (uint32_t j = 0; j < pRdn->cItems; j++) { PCRTCRX509ATTRIBUTETYPEANDVALUE const pAttr = pRdn->papItems[j]; if (pAttr->Value.enmType != RTASN1TYPE_STRING) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_NAME_NOT_STRING, "%s: Items[%u].paItems[%u].enmType is %d instead of string (%d).", pszErrorTag, i, j, pAttr->Value.enmType, RTASN1TYPE_STRING); if (pAttr->Value.u.String.Asn1Core.cb == 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_NAME_EMPTY_STRING, "%s: Items[%u].paItems[%u] is an empty string", pszErrorTag, i, j); switch (pAttr->Value.u.String.Asn1Core.uTag) { case ASN1_TAG_PRINTABLE_STRING: case ASN1_TAG_UTF8_STRING: break; case ASN1_TAG_T61_STRING: case ASN1_TAG_UNIVERSAL_STRING: case ASN1_TAG_BMP_STRING: break; case ASN1_TAG_IA5_STRING: /* Used by "Microsoft Root Certificate Authority" in the "com" part of the Issuer. */ break; default: return RTErrInfoSetF(pErrInfo, VERR_CR_X509_INVALID_NAME_STRING_TAG, "%s: Items[%u].paItems[%u] invalid string type: %u", pszErrorTag, i, j, pAttr->Value.u.String.Asn1Core.uTag); } } } return VINF_SUCCESS; }
static int rtCrX509SubjectPublicKeyInfo_CheckSanityExtra(PCRTCRX509SUBJECTPUBLICKEYINFO pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { if (pThis->SubjectPublicKey.cBits <= 32) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_PUBLIC_KEY_TOO_SMALL, "%s: SubjectPublicKey is too small, only %u bits", pszErrorTag, pThis->SubjectPublicKey.cBits); return VINF_SUCCESS; }
static int rtCrX509Certificate_CheckSanityExtra(PCRTCRX509CERTIFICATE pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { if (RTCrX509AlgorithmIdentifier_Compare(&pThis->SignatureAlgorithm, &pThis->TbsCertificate.Signature) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_CERT_TBS_SIGN_ALGO_MISMATCH, "%s: SignatureAlgorithm (%s) does not match TbsCertificate.Signature (%s).", pszErrorTag, pThis->SignatureAlgorithm.Algorithm.szObjId, pThis->TbsCertificate.Signature.Algorithm.szObjId); return VINF_SUCCESS; }
/** * Verifies a counter signature. * * @returns IPRT status code. * @param pCounterSignerInfo The counter signature. * @param pPrimarySignerInfo The primary signature (can be a counter * signature too if nested). * @param pSignedData The SignedData. * @param fFlags Verficiation flags. * @param hAdditionalCerts Store containing optional certificates, * optional. * @param hTrustedCerts Store containing trusted certificates, required. * @param pValidationTime The time we're supposed to validate the * certificates chains at. * @param pfnVerifyCert Signing certificate verification callback. * @param fVccFlags Signing certificate verification callback flags. * @param pvUser Callback parameter. * @param pErrInfo Where to store additional error details, * optional. */ static int rtCrPkcs7VerifyCounterSignerInfo(PCRTCRPKCS7SIGNERINFO pCounterSignerInfo, PCRTCRPKCS7SIGNERINFO pPrimarySignerInfo, PCRTCRPKCS7SIGNEDDATA pSignedData, uint32_t fFlags, RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts, PCRTTIMESPEC pValidationTime, PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, uint32_t fVccFlags, void *pvUser, PRTERRINFO pErrInfo) { /* * Calculate the digest we need to verify. */ RTCRDIGEST hDigest; int rc = RTCrDigestCreateByObjId(&hDigest, &pCounterSignerInfo->DigestAlgorithm.Algorithm); if (RT_SUCCESS(rc)) { rc = RTCrDigestUpdate(hDigest, pPrimarySignerInfo->EncryptedDigest.Asn1Core.uData.pv, pPrimarySignerInfo->EncryptedDigest.Asn1Core.cb); if (RT_SUCCESS(rc)) rc = RTCrDigestFinal(hDigest, NULL, 0); if (RT_SUCCESS(rc)) { /* * Pass it on to the common SignerInfo verifier function. */ rc = rtCrPkcs7VerifySignerInfo(pCounterSignerInfo, pSignedData, hDigest, fFlags | RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE, hAdditionalCerts, hTrustedCerts, pValidationTime, pfnVerifyCert, fVccFlags, pvUser, pErrInfo); } else rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_CALC_ERROR, "Hashing for counter signature failed unexpectedly: %Rrc", rc); RTCrDigestRelease(hDigest); } else rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_CREATE_ERROR, "Error creating digest for '%s': %Rrc", pCounterSignerInfo->DigestAlgorithm.Algorithm.szObjId, rc); return rc; }
SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase, PRTERRINFO pErrInfo) { /* * Check that the module can be trusted. */ int rc = SUPR3HardenedVerifyPlugIn(pszFilename, pErrInfo); if (RT_SUCCESS(rc)) { rc = supLoadModule(pszFilename, pszModule, NULL, pErrInfo, ppvImageBase); if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo)) RTErrInfoSetF(pErrInfo, rc, "SUPR3LoadModule: supLoadModule returned %Rrc", rc); } return rc; }
/** * Find the handle to the digest given by the specified SignerInfo. * * @returns IPRT status code * @param phDigest Where to return a referenced digest handle on * success. * @param pSignedData The signed data structure. * @param pSignerInfo The signer info. * @param pahDigests Array of content digests that runs parallel to * pSignedData->DigestAlgorithms. * @param pErrInfo Where to store additional error details, * optional. */ static int rtCrPkcs7VerifyFindDigest(PRTCRDIGEST phDigest, PCRTCRPKCS7SIGNEDDATA pSignedData, PCRTCRPKCS7SIGNERINFO pSignerInfo, PRTCRDIGEST pahDigests, PRTERRINFO pErrInfo) { uint32_t iDigest = pSignedData->DigestAlgorithms.cItems; while (iDigest-- > 0) if (RTCrX509AlgorithmIdentifier_Compare(&pSignedData->DigestAlgorithms.paItems[iDigest], &pSignerInfo->DigestAlgorithm) == 0) { RTCRDIGEST hDigest = pahDigests[iDigest]; uint32_t cRefs = RTCrDigestRetain(hDigest); AssertReturn(cRefs != UINT32_MAX, VERR_CR_PKCS7_INTERNAL_ERROR); *phDigest = hDigest; return VINF_SUCCESS; } *phDigest = NIL_RTCRDIGEST; /* Make gcc happy. */ return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_ALGO_NOT_FOUND_IN_LIST, "SignerInfo.DigestAlgorithm %s not found.", pSignerInfo->DigestAlgorithm.Algorithm.szObjId); }
RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo) { AssertReturn(enmStoreId > RTCRSTOREID_INVALID && enmStoreId < RTCRSTOREID_END, VERR_INVALID_PARAMETER); /* * Create an empty in-memory store. */ RTCRSTORE hStore; int rc = RTCrStoreCreateInMem(&hStore, 128); if (RT_SUCCESS(rc)) { *phStore = hStore; /* * Resolve the APIs we need to do this job. */ RTLDRMOD hLdrMod; int rc2 = RTLdrLoadSystem("crypt32.dll", false /*NoUnload*/, &hLdrMod); if (RT_SUCCESS(rc2)) { PFNCERTOPENSTORE pfnOpenStore = NULL; rc2 = RTLdrGetSymbol(hLdrMod, "CertOpenStore", (void **)&pfnOpenStore); PFNCERTCLOSESTORE pfnCloseStore = NULL; if (RT_SUCCESS(rc2)) rc2 = RTLdrGetSymbol(hLdrMod, "CertCloseStore", (void **)&pfnCloseStore); PFNCERTENUMCERTIFICATESINSTORE pfnEnumCerts = NULL; if (RT_SUCCESS(rc2)) rc2 = RTLdrGetSymbol(hLdrMod, "CertEnumCertificatesInStore", (void **)&pfnEnumCerts); if (RT_SUCCESS(rc2)) { /* * Do the work. */ switch (enmStoreId) { case RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES: case RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES: { DWORD fStore = enmStoreId == RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES ? CERT_SYSTEM_STORE_CURRENT_USER : CERT_SYSTEM_STORE_LOCAL_MACHINE; static PCRTUTF16 const s_apwszStores[] = { L"AuthRoot", L"CA", L"MY", L"Root" }; for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszStores); i++) rc = rtCrStoreAddCertsFromNative(hStore, fStore, s_apwszStores[i], pfnOpenStore, pfnCloseStore, pfnEnumCerts, rc, pErrInfo); break; } default: AssertFailed(); /* implement me */ } } else rc = RTErrInfoSetF(pErrInfo, -rc2, "Error resolving crypt32.dll APIs"); RTLdrClose(hLdrMod); } else rc = RTErrInfoSetF(pErrInfo, -rc2, "Error loading crypt32.dll"); } else RTErrInfoSet(pErrInfo, rc, "RTCrStoreCreateInMem failed"); return rc; }
int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo) { /* * Make sure the image verifier is fully initialized. */ int rc = suplibOsHardenedVerifyInit(); if (RT_FAILURE(rc)) return RTErrInfoSetF(pErrInfo, rc, "suplibOsHardenedVerifyInit failed: %Rrc", rc); /* * Done if of pre-inited. */ if (fPreInited) { #if defined(VBOX_WITH_HARDENING) && !defined(IN_SUP_HARDENED_R3) # ifdef IN_SUP_R3_STATIC return VERR_NOT_SUPPORTED; # else return VINF_SUCCESS; # endif #else return VINF_SUCCESS; #endif } /* * Try open the device. */ #ifndef IN_SUP_HARDENED_R3 uint32_t cTry = 0; #endif HANDLE hDevice; for (;;) { IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; static const WCHAR s_wszName[] = L"\\Device\\VBoxDrvU"; UNICODE_STRING NtName; NtName.Buffer = (PWSTR)s_wszName; NtName.Length = sizeof(s_wszName) - sizeof(WCHAR) * (fUnrestricted ? 2 : 1); NtName.MaximumLength = NtName.Length; OBJECT_ATTRIBUTES ObjAttr; InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/); hDevice = RTNT_INVALID_HANDLE_VALUE; NTSTATUS rcNt = NtCreateFile(&hDevice, GENERIC_READ | GENERIC_WRITE, /* No SYNCHRONIZE. */ &ObjAttr, &Ios, NULL /* Allocation Size*/, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT! */ NULL /*EaBuffer*/, 0 /*EaLength*/); if (NT_SUCCESS(rcNt)) rcNt = Ios.Status; if (NT_SUCCESS(rcNt)) { /* * We're good. */ pThis->hDevice = hDevice; pThis->fUnrestricted = fUnrestricted; return VINF_SUCCESS; } #ifndef IN_SUP_HARDENED_R3 /* * Failed to open, try starting the service and reopen the device * exactly once. */ if (cTry == 0 && !NT_SUCCESS(rcNt)) { cTry++; suplibOsStartService(); continue; } #endif /* * Translate the error code. */ switch (rcNt) { /** @todo someone must test what is actually returned. */ case STATUS_DEVICE_DOES_NOT_EXIST: case STATUS_DEVICE_NOT_CONNECTED: //case ERROR_BAD_DEVICE: case STATUS_DEVICE_REMOVED: //case ERROR_DEVICE_NOT_AVAILABLE: rc = VERR_VM_DRIVER_LOAD_ERROR; break; case STATUS_OBJECT_PATH_NOT_FOUND: case STATUS_NO_SUCH_DEVICE: case STATUS_NO_SUCH_FILE: case STATUS_OBJECT_NAME_NOT_FOUND: rc = VERR_VM_DRIVER_NOT_INSTALLED; break; case STATUS_ACCESS_DENIED: case STATUS_SHARING_VIOLATION: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break; case STATUS_UNSUCCESSFUL: rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0; break; case STATUS_TRUST_FAILURE: rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1; break; case STATUS_TOO_LATE: rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE; break; default: if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */ rc = SUP_NT_STATUS_TO_VBOX(rcNt); else rc = VERR_VM_DRIVER_OPEN_ERROR; break; } #ifdef IN_SUP_HARDENED_R3 /* * Get more details from VBoxDrvErrorInfo if present. */ if (pErrInfo && pErrInfo->cbMsg > 32) { /* Prefix. */ size_t cchPrefix; const char *pszDefine = RTErrGetDefine(rc); if (strncmp(pszDefine, RT_STR_TUPLE("Unknown"))) cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%s): ", rcNt, pszDefine); else cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%d): ", rcNt, rc); /* Get error info. */ supR3HardenedWinReadErrorInfoDevice(pErrInfo->pszMsg + cchPrefix, pErrInfo->cbMsg - cchPrefix, ""); if (pErrInfo->pszMsg[cchPrefix] != '\0') { pErrInfo->fFlags |= RTERRINFO_FLAGS_SET; pErrInfo->rc = rc; *penmWhat = kSupInitOp_Integrity; } else pErrInfo->pszMsg[0] = '\0'; } #endif return rc; } }
RTDECL(int) RTCrX509Certificate_VerifySignature(PCRTCRX509CERTIFICATE pThis, PCRTASN1OBJID pAlgorithm, PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey, PRTERRINFO pErrInfo) { /* * Validate the input a little. */ AssertPtrReturn(pThis, VERR_INVALID_POINTER); AssertReturn(RTCrX509Certificate_IsPresent(pThis), VERR_INVALID_PARAMETER); AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER); AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER); if (pParameters) { AssertPtrReturn(pParameters, VERR_INVALID_POINTER); if (pParameters->enmType == RTASN1TYPE_NULL) pParameters = NULL; } AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER); AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER); /* * Check if the algorithm matches. */ const char *pszCipherOid = RTCrPkixGetCiperOidFromSignatureAlgorithm(&pThis->SignatureAlgorithm.Algorithm); if (!pszCipherOid) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO, "Certificate signature algorithm not known: %s", pThis->SignatureAlgorithm.Algorithm.szObjId); if (RTAsn1ObjId_CompareWithString(pAlgorithm, pszCipherOid) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH, "Certificate signature cipher algorithm mismatch: cert uses %s (%s) while key uses %s", pszCipherOid, pThis->SignatureAlgorithm.Algorithm.szObjId, pAlgorithm->szObjId); /* * Here we should recode the to-be-signed part as DER, but we'll ASSUME * that it's already in DER encoding and only does this if there the * encoded bits are missing. */ if ( pThis->TbsCertificate.SeqCore.Asn1Core.uData.pu8 && pThis->TbsCertificate.SeqCore.Asn1Core.cb > 0) return RTCrPkixPubKeyVerifySignature(&pThis->SignatureAlgorithm.Algorithm, pParameters, pPublicKey, &pThis->SignatureValue, RTASN1CORE_GET_RAW_ASN1_PTR(&pThis->TbsCertificate.SeqCore.Asn1Core), RTASN1CORE_GET_RAW_ASN1_SIZE(&pThis->TbsCertificate.SeqCore.Asn1Core), pErrInfo); uint32_t cbEncoded; int rc = RTAsn1EncodePrepare((PRTASN1CORE)&pThis->TbsCertificate.SeqCore.Asn1Core, RTASN1ENCODE_F_DER, &cbEncoded, pErrInfo); if (RT_SUCCESS(rc)) { void *pvTbsBits = RTMemTmpAlloc(cbEncoded); if (pvTbsBits) { rc = RTAsn1EncodeToBuffer(&pThis->TbsCertificate.SeqCore.Asn1Core, RTASN1ENCODE_F_DER, pvTbsBits, cbEncoded, pErrInfo); if (RT_SUCCESS(rc)) rc = RTCrPkixPubKeyVerifySignature(&pThis->SignatureAlgorithm.Algorithm, pParameters, pPublicKey, &pThis->SignatureValue, pvTbsBits, cbEncoded, pErrInfo); else AssertRC(rc); RTMemTmpFree(pvTbsBits); } else rc = VERR_NO_TMP_MEMORY; } return rc; }
/** * Deals with authenticated attributes. * * When authenticated attributes are present (checked by caller) we must: * - fish out the content type and check it against the content inof, * - fish out the message digest among and check it against *phDigest, * - compute the message digest of the authenticated attributes and * replace *phDigest with this for the signature verification. * * @returns IPRT status code. * @param pSignerInfo The signer info being verified. * @param pSignedData The signed data. * @param phDigest On input this is the digest of the content. On * output it will (on success) be a reference to * the message digest of the authenticated * attributes. The input reference is consumed. * The caller shall release the output reference. * @param fFlags Flags. * @param pErrInfo Extended error info, optional. */ static int rtCrPkcs7VerifySignerInfoAuthAttribs(PCRTCRPKCS7SIGNERINFO pSignerInfo, PCRTCRPKCS7SIGNEDDATA pSignedData, PRTCRDIGEST phDigest, uint32_t fFlags, PRTERRINFO pErrInfo) { /* * Scan the attributes and validate the two required attributes * (RFC-2315, chapter 9.2, fourth bullet). Checking that we've got exactly * one of each of them is checked by the santiy checker function, so we'll * just assert that it did it's job here. */ uint32_t cContentTypes = 0; uint32_t cMessageDigests = 0; uint32_t i = pSignerInfo->AuthenticatedAttributes.cItems; while (i-- > 0) { PCRTCRPKCS7ATTRIBUTE pAttrib = &pSignerInfo->AuthenticatedAttributes.paItems[i]; if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_CONTENT_TYPE_OID) == 0) { AssertReturn(!cContentTypes, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->uValues.pObjIds->cItems == 1, VERR_CR_PKCS7_INTERNAL_ERROR); if ( !(fFlags & RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE) /* See note about microsoft below. */ && RTAsn1ObjId_Compare(&pAttrib->uValues.pObjIds->paItems[0], &pSignedData->ContentInfo.ContentType) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_CONTENT_TYPE_ATTRIB_MISMATCH, "Expected content-type %s, found %s", &pAttrib->uValues.pObjIds->paItems[0], pSignedData->ContentInfo.ContentType.szObjId); cContentTypes++; } else if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_MESSAGE_DIGEST_OID) == 0) { AssertReturn(!cMessageDigests, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->uValues.pOctetStrings->cItems == 1, VERR_CR_PKCS7_INTERNAL_ERROR); if (!RTCrDigestMatch(*phDigest, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.uData.pv, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.cb)) { size_t cbHash = RTCrDigestGetHashSize(*phDigest); if (cbHash != pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.cb) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH, "Authenticated message-digest attribute mismatch: cbHash=%#zx cbValue=%#x", cbHash, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.cb); return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH, "Authenticated message-digest attribute mismatch (cbHash=%#zx):\n" "signed: %.*Rhxs\n" "our: %.*Rhxs\n", cbHash, cbHash, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.uData.pv, cbHash, RTCrDigestGetHash(*phDigest)); } cMessageDigests++; } } /* * Full error reporting here as we don't currently extensively santiy check * counter signatures. * Note! Microsoft includes content info in their timestamp counter signatures, * at least for vista, despite the RFC-3852 stating counter signatures * "MUST NOT contain a content-type". */ if (RT_UNLIKELY( cContentTypes != 1 && !(fFlags & RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE))) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB, "Missing authenticated content-type attribute."); if (RT_UNLIKELY(cMessageDigests != 1)) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB, "Missing authenticated message-digest attribute."); /* * Calculate the digest of the the authenticated attributes for use in the * signature validation. */ if ( pSignerInfo->DigestAlgorithm.Parameters.enmType != RTASN1TYPE_NULL && pSignerInfo->DigestAlgorithm.Parameters.enmType != RTASN1TYPE_NOT_PRESENT) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL, "Digest algorithm has unsupported parameters"); RTCRDIGEST hDigest; int rc = RTCrDigestCreateByObjId(&hDigest, &pSignerInfo->DigestAlgorithm.Algorithm); if (RT_SUCCESS(rc)) { RTCrDigestRelease(*phDigest); *phDigest = hDigest; /* ASSUMES that the attributes are encoded according to DER. */ uint8_t const *pbData = (uint8_t const *)RTASN1CORE_GET_RAW_ASN1_PTR(&pSignerInfo->AuthenticatedAttributes.SetCore.Asn1Core); uint32_t cbData = RTASN1CORE_GET_RAW_ASN1_SIZE(&pSignerInfo->AuthenticatedAttributes.SetCore.Asn1Core); uint8_t bSetOfTag = ASN1_TAG_SET | ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED; rc = RTCrDigestUpdate(hDigest, &bSetOfTag, sizeof(bSetOfTag)); /* Replace the implict tag with a SET-OF tag. */ if (RT_SUCCESS(rc)) rc = RTCrDigestUpdate(hDigest, pbData + sizeof(bSetOfTag), cbData - sizeof(bSetOfTag)); /* Skip the implicit tag. */ if (RT_SUCCESS(rc)) rc = RTCrDigestFinal(hDigest, NULL, 0); } return rc; }
static int rtCrPkcs7SignedData_CheckSanityExtra(PCRTCRPKCS7SIGNEDDATA pSignedData, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { bool const fAuthenticode = RT_BOOL(fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE); //RTAsn1Dump(&pSignedData->SeqCore.Asn1Core, 0, 0, RTAsn1DumpStrmPrintfV, g_pStdOut); if ( RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V1) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V3) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V4) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V5) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNED_DATA_VERSION, "SignedData version is %llu, expected %u", pSignedData->Version.uValue.u, RTCRPKCS7SIGNEDDATA_V1); /* * DigestAlgorithms. */ if (pSignedData->DigestAlgorithms.cItems == 0) /** @todo this might be too strict */ return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_SIGNED_DATA_NO_DIGEST_ALGOS, "SignedData.DigestAlgorithms is empty"); if (pSignedData->DigestAlgorithms.cItems != 1 && fAuthenticode) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_NOT_EXACTLY_ONE_DIGEST_ALGO, "SignedData.DigestAlgorithms has more than one algorithm (%u)", pSignedData->DigestAlgorithms.cItems); if (fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH) for (uint32_t i = 0; i < pSignedData->DigestAlgorithms.cItems; i++) { if (RTCrX509AlgorithmIdentifier_QueryDigestType(&pSignedData->DigestAlgorithms.paItems[i]) == RTDIGESTTYPE_INVALID) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_UNKNOWN_DIGEST_ALGORITHM, "SignedData.DigestAlgorithms[%i] is not known: %s", i, pSignedData->DigestAlgorithms.paItems[i].Algorithm.szObjId); if (pSignedData->DigestAlgorithms.paItems[i].Parameters.enmType != RTASN1TYPE_NULL) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL, "SignedData.DigestAlgorithms[%i] has parameters: tag=%u", i, pSignedData->DigestAlgorithms.paItems[i].Parameters.u.Core.uTag); } /* * Certificates. */ if ( (fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT) && pSignedData->Certificates.cItems == 0) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_NO_CERTIFICATES, "SignedData.Certifcates is empty, expected at least one certificate"); /* * Crls. */ if (fAuthenticode && RTAsn1Core_IsPresent(&pSignedData->Crls)) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_EXPECTED_NO_CRLS, "SignedData.Crls is not empty as expected for authenticode."); /** @todo check Crls when they become important. */ /* * SignerInfos. */ if (pSignedData->SignerInfos.cItems == 0) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_NO_SIGNER_INFOS, "SignedData.SignerInfos is empty?"); if (fAuthenticode && pSignedData->SignerInfos.cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_EXPECTED_ONE_SIGNER_INFO, "SignedData.SignerInfos should have one entry for authenticode: %u", pSignedData->SignerInfos.cItems); for (uint32_t i = 0; i < pSignedData->SignerInfos.cItems; i++) { PCRTCRPKCS7SIGNERINFO pSignerInfo = &pSignedData->SignerInfos.paItems[i]; if (RTAsn1Integer_UnsignedCompareWithU32(&pSignerInfo->Version, RTCRPKCS7SIGNERINFO_V1) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_INFO_VERSION, "SignedData.SignerInfos[%u] version is %llu, expected %u", pSignerInfo->Version.uValue.u, RTCRPKCS7SIGNERINFO_V1); /* IssuerAndSerialNumber. */ int rc = RTCrX509Name_CheckSanity(&pSignerInfo->IssuerAndSerialNumber.Name, 0, pErrInfo, "SignedData.SignerInfos[#].IssuerAndSerialNumber.Name"); if (RT_FAILURE(rc)) return rc; if (pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.cb == 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_INFO_NO_ISSUER_SERIAL_NO, "SignedData.SignerInfos[%u].IssuerAndSerialNumber.SerialNumber is missing (zero length)", i); PCRTCRX509CERTIFICATE pCert; pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSignedData->Certificates, &pSignerInfo->IssuerAndSerialNumber.Name, &pSignerInfo->IssuerAndSerialNumber.SerialNumber); if (!pCert && (fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT)) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_CERT_NOT_SHIPPED, "SignedData.SignerInfos[%u].IssuerAndSerialNumber not found in T0.Certificates", i); /* DigestAlgorithm */ uint32_t j = 0; while ( j < pSignedData->DigestAlgorithms.cItems && RTCrX509AlgorithmIdentifier_Compare(&pSignedData->DigestAlgorithms.paItems[j], &pSignerInfo->DigestAlgorithm) != 0) j++; if (j >= pSignedData->DigestAlgorithms.cItems) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_ALGO_NOT_FOUND_IN_LIST, "SignedData.SignerInfos[%u].DigestAlgorithm (%s) not found in SignedData.DigestAlgorithms", i, pSignerInfo->DigestAlgorithm.Algorithm.szObjId); /* Digest encryption algorithm. */ #if 0 /** @todo Unimportant: Seen timestamp signatures specifying pkcs1-Sha256WithRsaEncryption in SignerInfo and just RSA in the certificate. Figure out how to compare the two. */ if ( pCert && RTCrX509AlgorithmIdentifier_Compare(&pSignerInfo->DigestEncryptionAlgorithm, &pCert->TbsCertificate.SubjectPublicKeyInfo.Algorithm) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_INFO_DIGEST_ENCRYPT_MISMATCH, "SignedData.SignerInfos[%u].DigestEncryptionAlgorithm (%s) mismatch with certificate (%s)", i, pSignerInfo->DigestEncryptionAlgorithm.Algorithm.szObjId, pCert->TbsCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm.szObjId); #endif /* Authenticated attributes we know. */ if (RTCrPkcs7Attributes_IsPresent(&pSignerInfo->AuthenticatedAttributes)) { bool fFoundContentInfo = false; bool fFoundMessageDigest = false; for (j = 0; j < pSignerInfo->AuthenticatedAttributes.cItems; j++) { PCRTCRPKCS7ATTRIBUTE pAttrib = &pSignerInfo->AuthenticatedAttributes.paItems[j]; if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_CONTENT_TYPE_OID) == 0) { if (fFoundContentInfo) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB, "Multiple authenticated content-type attributes."); fFoundContentInfo = true; AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS, VERR_INTERNAL_ERROR_3); if (pAttrib->uValues.pObjIds->cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB, "Expected exactly one value for content-type attrib, found: %u", pAttrib->uValues.pObjIds->cItems); } else if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_MESSAGE_DIGEST_OID) == 0) { if (fFoundMessageDigest) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB, "Multiple authenticated message-digest attributes."); fFoundMessageDigest = true; AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS, VERR_INTERNAL_ERROR_3); if (pAttrib->uValues.pOctetStrings->cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB, "Expected exactly one value for message-digest attrib, found: %u", pAttrib->uValues.pOctetStrings->cItems); } else AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_UNKNOWN, VERR_INTERNAL_ERROR_3); } if (!fFoundContentInfo) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB, "Missing authenticated content-type attribute."); if (!fFoundMessageDigest) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB, "Missing authenticated message-digest attribute."); } } return VINF_SUCCESS; }
RTDECL(int) RTCrPkixPubKeyVerifySignature(PCRTASN1OBJID pAlgorithm, PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey, PCRTASN1BITSTRING pSignatureValue, const void *pvData, size_t cbData, PRTERRINFO pErrInfo) { /* * Valid input. */ AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER); AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER); if (pParameters) { AssertPtrReturn(pParameters, VERR_INVALID_POINTER); if (pParameters->enmType == RTASN1TYPE_NULL) pParameters = NULL; } AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER); AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER); AssertPtrReturn(pSignatureValue, VERR_INVALID_POINTER); AssertReturn(RTAsn1BitString_IsPresent(pSignatureValue), VERR_INVALID_POINTER); AssertPtrReturn(pvData, VERR_INVALID_POINTER); AssertReturn(cbData > 0, VERR_INVALID_PARAMETER); /* * Parameters are not currently supported (openssl code path). */ if (pParameters) return RTErrInfoSet(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL, "Cipher algorithm parameters are not yet supported."); /* * Validate using IPRT. */ RTCRPKIXSIGNATURE hSignature; int rcIprt = RTCrPkixSignatureCreateByObjId(&hSignature, pAlgorithm, false /*fSigning*/, pPublicKey, pParameters); if (RT_FAILURE(rcIprt)) return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN, "Unknown public key algorithm [IPRT]: %s", pAlgorithm->szObjId); RTCRDIGEST hDigest; rcIprt = RTCrDigestCreateByObjId(&hDigest, pAlgorithm); if (RT_SUCCESS(rcIprt)) { /* Calculate the digest. */ rcIprt = RTCrDigestUpdate(hDigest, pvData, cbData); if (RT_SUCCESS(rcIprt)) { rcIprt = RTCrPkixSignatureVerifyBitString(hSignature, hDigest, pSignatureValue); if (RT_FAILURE(rcIprt)) RTErrInfoSet(pErrInfo, rcIprt, "RTCrPkixSignatureVerifyBitString failed"); } else RTErrInfoSet(pErrInfo, rcIprt, "RTCrDigestUpdate failed"); RTCrDigestRelease(hDigest); } else RTErrInfoSetF(pErrInfo, rcIprt, "Unknown digest algorithm [IPRT]: %s", pAlgorithm->szObjId); RTCrPkixSignatureRelease(hSignature); #ifdef IPRT_WITH_OPENSSL /* * Validate using OpenSSL EVP. */ rtCrOpenSslInit(); /* Translate the algorithm ID into a EVP message digest type pointer. */ int iAlgoNid = OBJ_txt2nid(pAlgorithm->szObjId); if (iAlgoNid == NID_undef) return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN, "Unknown public key algorithm [OpenSSL]: %s", pAlgorithm->szObjId); const char *pszAlogSn = OBJ_nid2sn(iAlgoNid); const EVP_MD *pEvpMdType = EVP_get_digestbyname(pszAlogSn); if (!pEvpMdType) return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP, "EVP_get_digestbyname failed on %s (%s)", pszAlogSn, pAlgorithm->szObjId); /* Initialize the EVP message digest context. */ EVP_MD_CTX EvpMdCtx; EVP_MD_CTX_init(&EvpMdCtx); if (!EVP_VerifyInit_ex(&EvpMdCtx, pEvpMdType, NULL /*engine*/)) return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED, "EVP_VerifyInit_ex failed (algorithm type is %s / %s)", pszAlogSn, pAlgorithm->szObjId); /* Create an EVP public key. */ int rcOssl; EVP_PKEY *pEvpPublicKey = EVP_PKEY_new(); if (pEvpPublicKey) { pEvpPublicKey->type = EVP_PKEY_type(pEvpMdType->required_pkey_type[0]); if (pEvpPublicKey->type != NID_undef) { const unsigned char *puchPublicKey = RTASN1BITSTRING_GET_BIT0_PTR(pPublicKey); if (d2i_PublicKey(pEvpPublicKey->type, &pEvpPublicKey, &puchPublicKey, RTASN1BITSTRING_GET_BYTE_SIZE(pPublicKey))) { /* Digest the data. */ EVP_VerifyUpdate(&EvpMdCtx, pvData, cbData); /* Verify the signature. */ if (EVP_VerifyFinal(&EvpMdCtx, RTASN1BITSTRING_GET_BIT0_PTR(pSignatureValue), RTASN1BITSTRING_GET_BYTE_SIZE(pSignatureValue), pEvpPublicKey) > 0) rcOssl = VINF_SUCCESS; else rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED, "EVP_VerifyFinal failed"); } else rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED, "d2i_PublicKey failed"); } else rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_type(%d) failed", pEvpMdType->required_pkey_type[0]); /* Cleanup and return.*/ EVP_PKEY_free(pEvpPublicKey); } else rcOssl = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "EVP_PKEY_new(%d) failed", pEvpMdType->required_pkey_type[0]); EVP_MD_CTX_cleanup(&EvpMdCtx); /* * Check the result. */ if (RT_SUCCESS(rcIprt) && RT_SUCCESS(rcOssl)) return VINF_SUCCESS; if (RT_FAILURE_NP(rcIprt) && RT_FAILURE_NP(rcOssl)) return rcIprt; AssertMsgFailed(("rcIprt=%Rrc rcOssl=%Rrc\n", rcIprt, rcOssl)); if (RT_FAILURE_NP(rcOssl)) return rcOssl; #endif /* IPRT_WITH_OPENSSL */ return rcIprt; }
int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlags, PRTERRINFO pErrInfo) { Assert(sizeof(*phHandle) >= sizeof(HMODULE)); AssertReturn(!(fFlags & RTLDRLOAD_FLAGS_GLOBAL), VERR_INVALID_FLAGS); AssertLogRelMsgReturn(RTPathStartsWithRoot(pszFilename), /* Relative names will still be applied to the search path. */ ("pszFilename='%s'\n", pszFilename), VERR_INTERNAL_ERROR_2); /* * Convert to UTF-16 and make sure it got a .DLL suffix. */ int rc; RTUTF16 *pwszNative = NULL; if (RTPathHasSuffix(pszFilename)) rc = RTStrToUtf16(pszFilename, &pwszNative); else { size_t cwcAlloc; rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcAlloc); if (RT_SUCCESS(rc)) { cwcAlloc += sizeof(".DLL"); pwszNative = RTUtf16Alloc(cwcAlloc * sizeof(RTUTF16)); if (pwszNative) { size_t cwcNative; rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwszNative, cwcAlloc, &cwcNative); if (RT_SUCCESS(rc)) rc = RTUtf16CopyAscii(&pwszNative[cwcNative], cwcAlloc - cwcNative, ".DLL"); } else rc = VERR_NO_UTF16_MEMORY; } } if (RT_SUCCESS(rc)) { /* * Attempt load. */ HMODULE hmod; static int s_iSearchDllLoadDirSupported = 0; if ( !(fFlags & RTLDRLOAD_FLAGS_NT_SEARCH_DLL_LOAD_DIR) || s_iSearchDllLoadDirSupported < 0) hmod = LoadLibraryExW(pwszNative, NULL, 0); else { hmod = LoadLibraryExW(pwszNative, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_APPLICATION_DIR); if (s_iSearchDllLoadDirSupported == 0) { if (hmod != NULL || GetLastError() != ERROR_INVALID_PARAMETER) s_iSearchDllLoadDirSupported = 1; else { s_iSearchDllLoadDirSupported = -1; hmod = LoadLibraryExW(pwszNative, NULL, 0); } } } if (hmod) { *phHandle = (uintptr_t)hmod; RTUtf16Free(pwszNative); return VINF_SUCCESS; } /* * Try figure why it failed to load. */ DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); rc = RTErrInfoSetF(pErrInfo, rc, "GetLastError=%u", dwErr); } else rc = RTErrInfoSetF(pErrInfo, rc, "Error converting UTF-8 to UTF-16 string."); RTUtf16Free(pwszNative); return rc; }
/** * Verifies one signature on a PKCS \#7 SignedData. * * @returns IPRT status code. * @param pSignerInfo The signature. * @param pSignedData The SignedData. * @param hDigests The digest corresponding to * pSignerInfo->DigestAlgorithm. * @param fFlags Verficiation flags. * @param hAdditionalCerts Store containing optional certificates, * optional. * @param hTrustedCerts Store containing trusted certificates, required. * @param pValidationTime The time we're supposed to validate the * certificates chains at. * @param pfnVerifyCert Signing certificate verification callback. * @param fVccFlags Signing certificate verification callback flags. * @param pvUser Callback parameter. * @param pErrInfo Where to store additional error details, * optional. */ static int rtCrPkcs7VerifySignerInfo(PCRTCRPKCS7SIGNERINFO pSignerInfo, PCRTCRPKCS7SIGNEDDATA pSignedData, RTCRDIGEST hDigest, uint32_t fFlags, RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts, PCRTTIMESPEC pValidationTime, PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, uint32_t fVccFlags, void *pvUser, PRTERRINFO pErrInfo) { /* * Locate the certificate used for signing. */ PCRTCRCERTCTX pSignerCertCtx = NULL; PCRTCRX509CERTIFICATE pSignerCert = NULL; RTCRSTORE hSignerCertSrc = hTrustedCerts; if (hSignerCertSrc != NIL_RTCRSTORE) pSignerCertCtx = RTCrStoreCertByIssuerAndSerialNo(hSignerCertSrc, &pSignerInfo->IssuerAndSerialNumber.Name, &pSignerInfo->IssuerAndSerialNumber.SerialNumber); if (!pSignerCertCtx) { hSignerCertSrc = hAdditionalCerts; if (hSignerCertSrc != NIL_RTCRSTORE) pSignerCertCtx = RTCrStoreCertByIssuerAndSerialNo(hSignerCertSrc, &pSignerInfo->IssuerAndSerialNumber.Name, &pSignerInfo->IssuerAndSerialNumber.SerialNumber); } if (pSignerCertCtx) pSignerCert = pSignerCertCtx->pCert; else { hSignerCertSrc = NULL; pSignerCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSignedData->Certificates, &pSignerInfo->IssuerAndSerialNumber.Name, &pSignerInfo->IssuerAndSerialNumber.SerialNumber); if (!pSignerCert) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNED_DATA_CERT_NOT_FOUND, "Certificate not found: serial=%.*Rhxs", pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.cb, pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.uData.pv); } /* * If not a trusted certificate, we'll have to build certificate paths * and verify them. If no valid paths are found, this step will fail. */ int rc = VINF_SUCCESS; if ( hSignerCertSrc == NIL_RTCRSTORE || hSignerCertSrc != hTrustedCerts) { RTCRX509CERTPATHS hCertPaths; rc = RTCrX509CertPathsCreate(&hCertPaths, pSignerCert); if (RT_SUCCESS(rc)) { rc = RTCrX509CertPathsSetValidTimeSpec(hCertPaths, pValidationTime); if (hTrustedCerts != NIL_RTCRSTORE && RT_SUCCESS(rc)) rc = RTCrX509CertPathsSetTrustedStore(hCertPaths, hTrustedCerts); if (hAdditionalCerts != NIL_RTCRSTORE && RT_SUCCESS(rc)) rc = RTCrX509CertPathsSetUntrustedStore(hCertPaths, hAdditionalCerts); if (pSignedData->Certificates.cItems > 0 && RT_SUCCESS(rc)) rc = RTCrX509CertPathsSetUntrustedSet(hCertPaths, &pSignedData->Certificates); if (RT_SUCCESS(rc)) { rc = RTCrX509CertPathsBuild(hCertPaths, pErrInfo); if (RT_SUCCESS(rc)) rc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, pErrInfo); /* * Check that the certificate purpose and whatnot matches what * is being signed. */ if (RT_SUCCESS(rc)) rc = pfnVerifyCert(pSignerCert, hCertPaths, fVccFlags, pvUser, pErrInfo); } else RTErrInfoSetF(pErrInfo, rc, "Error configuring path builder: %Rrc", rc); RTCrX509CertPathsRelease(hCertPaths); } } /* * Check that the certificate purpose matches what is signed. */ else rc = pfnVerifyCert(pSignerCert, NIL_RTCRX509CERTPATHS, fVccFlags, pvUser, pErrInfo); /* * Reference the digest so we can safely replace with one on the * authenticated attributes below. */ if ( RT_SUCCESS(rc) && RTCrDigestRetain(hDigest) != UINT32_MAX) { /* * If there are authenticated attributes, we've got more work before we * can verify the signature. */ if ( RT_SUCCESS(rc) && RTCrPkcs7Attributes_IsPresent(&pSignerInfo->AuthenticatedAttributes)) rc = rtCrPkcs7VerifySignerInfoAuthAttribs(pSignerInfo, pSignedData, &hDigest, fFlags, pErrInfo); /* * Verify the signature. */ if (RT_SUCCESS(rc)) { RTCRPKIXSIGNATURE hSignature; rc = RTCrPkixSignatureCreateByObjId(&hSignature, &pSignerCert->TbsCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm, false /*fSigning*/, &pSignerCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey, &pSignerInfo->DigestEncryptionAlgorithm.Parameters); if (RT_SUCCESS(rc)) { /** @todo Check that DigestEncryptionAlgorithm is compatible with hSignature * (this is not vital). */ rc = RTCrPkixSignatureVerifyOctetString(hSignature, hDigest, &pSignerInfo->EncryptedDigest); if (RT_FAILURE(rc)) rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNATURE_VERIFICATION_FAILED, "Signature verficiation failed: %Rrc", rc); RTCrPkixSignatureRelease(hSignature); } else rc = RTErrInfoSetF(pErrInfo, rc, "Failure to instantiate public key algorithm [IPRT]: %s (%s)", pSignerCert->TbsCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm.szObjId, pSignerInfo->DigestEncryptionAlgorithm.Algorithm.szObjId); } RTCrDigestRelease(hDigest); } else if (RT_SUCCESS(rc)) rc = VERR_CR_PKCS7_INTERNAL_ERROR; RTCrCertCtxRelease(pSignerCertCtx); return rc; }
RTDECL(int) RTAsn1Time_CheckSanity(PCRTASN1TIME pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { if (RT_UNLIKELY(!RTAsn1Time_IsPresent(pThis))) return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (TIME).", pszErrorTag); return VINF_SUCCESS; }
RTDECL(int) RTCrSpcIndirectDataContent_CheckSanityEx(PCRTCRSPCINDIRECTDATACONTENT pIndData, PCRTCRPKCS7SIGNEDDATA pSignedData, uint32_t fFlags, PRTERRINFO pErrInfo) { /* * Match up the digest algorithms (page 8, v1.0). */ if (pSignedData->SignerInfos.cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_NOT_EXACTLY_ONE_SIGNER_INFOS, "SpcIndirectDataContent expects SignedData to have exactly one SignerInfos entries, found: %u", pSignedData->SignerInfos.cItems); if (pSignedData->DigestAlgorithms.cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_NOT_EXACTLY_ONE_DIGEST_ALGO, "SpcIndirectDataContent expects SignedData to have exactly one DigestAlgorithms entries, found: %u", pSignedData->DigestAlgorithms.cItems); if (RTCrX509AlgorithmIdentifier_Compare(&pIndData->DigestInfo.DigestAlgorithm, /** @todo not entirely sure about this check... */ &pSignedData->SignerInfos.paItems[0].DigestAlgorithm) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_SIGNED_IND_DATA_DIGEST_ALGO_MISMATCH, "SpcIndirectDataContent DigestInfo and SignerInfos algorithms mismatch: %s vs %s", pIndData->DigestInfo.DigestAlgorithm.Algorithm.szObjId, pSignedData->SignerInfos.paItems[0].DigestAlgorithm.Algorithm.szObjId); if (RTCrX509AlgorithmIdentifier_Compare(&pIndData->DigestInfo.DigestAlgorithm, &pSignedData->DigestAlgorithms.paItems[0]) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_IND_DATA_DIGEST_ALGO_NOT_IN_DIGEST_ALGOS, "SpcIndirectDataContent DigestInfo and SignedData.DigestAlgorithms[0] mismatch: %s vs %s", pIndData->DigestInfo.DigestAlgorithm.Algorithm.szObjId, pSignedData->DigestAlgorithms.paItems[0].Algorithm.szObjId); if (fFlags & RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH) { if (RTCrX509AlgorithmIdentifier_QueryDigestType(&pIndData->DigestInfo.DigestAlgorithm) == RTDIGESTTYPE_INVALID) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_UNKNOWN_DIGEST_ALGO, "SpcIndirectDataContent DigestAlgortihm is not known: %s", pIndData->DigestInfo.DigestAlgorithm.Algorithm.szObjId); } uint32_t cbDigest = RTCrX509AlgorithmIdentifier_QueryDigestSize(&pIndData->DigestInfo.DigestAlgorithm); if ( pIndData->DigestInfo.Digest.Asn1Core.cb != cbDigest && (cbDigest != UINT32_MAX || (fFlags & RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH))) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_IND_DATA_DIGEST_SIZE_MISMATCH, "SpcIndirectDataContent Digest size mismatch with algorithm: %u, expected %u (%s)", pIndData->DigestInfo.Digest.Asn1Core.cb, cbDigest, pIndData->DigestInfo.DigestAlgorithm.Algorithm.szObjId); /* * Data. */ if (fFlags & RTCRSPCINDIRECTDATACONTENT_SANITY_F_PE_IMAGE) { if ( pIndData->Data.enmType != RTCRSPCAAOVTYPE_PE_IMAGE_DATA || RTAsn1ObjId_CompareWithString(&pIndData->Data.Type, RTCRSPCPEIMAGEDATA_OID) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_EXPECTED_PE_IMAGE_DATA, "SpcIndirectDataContent.Data.Type is %s, expected %s (SpcPeImageData) [enmType=%d]", pIndData->Data.Type.szObjId, RTCRSPCPEIMAGEDATA_OID, pIndData->Data.enmType); if ( pIndData->Data.uValue.pPeImage || !RTCrSpcPeImageData_IsPresent(pIndData->Data.uValue.pPeImage) ) return RTErrInfoSet(pErrInfo, VERR_CR_SPC_PEIMAGE_DATA_NOT_PRESENT, "SpcIndirectDataContent.Data.uValue/PEImage is missing"); if ( pIndData->Data.uValue.pPeImage->T0.File.enmChoice == RTCRSPCLINKCHOICE_MONIKER && RTCrSpcSerializedObject_IsPresent(pIndData->Data.uValue.pPeImage->T0.File.u.pMoniker) ) { PCRTCRSPCSERIALIZEDOBJECT pObj = pIndData->Data.uValue.pPeImage->T0.File.u.pMoniker; if (pObj->Uuid.Asn1Core.cb != sizeof(RTUUID)) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_BAD_MONIKER_UUID, "SpcIndirectDataContent...MonikerT1.Uuid incorrect size: %u, expected %u.", pObj->Uuid.Asn1Core.cb, sizeof(RTUUID)); if (RTUuidCompareStr(pObj->Uuid.Asn1Core.uData.pUuid, RTCRSPCSERIALIZEDOBJECT_UUID_STR) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_UNKNOWN_MONIKER_UUID, "SpcIndirectDataContent...MonikerT1.Uuid mismatch: %RTuuid, expected %s.", pObj->Uuid.Asn1Core.uData.pUuid, RTCRSPCSERIALIZEDOBJECT_UUID_STR); if (pObj->enmType != RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_BAD_MONIKER_CHOICE, "SpcIndirectDataContent...pMoniker->enmType=%d, expected %d.", pObj->enmType, RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES); if (!pObj->u.pData) return RTErrInfoSet(pErrInfo, VERR_CR_SPC_MONIKER_BAD_DATA, "SpcIndirectDataContent...pMoniker->pData is NULL."); uint32_t cPageHashTabs = 0; for (uint32_t i = 0; i < pObj->u.pData->cItems; i++) { PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttr = &pObj->u.pData->paItems[i]; if ( RTAsn1ObjId_CompareWithString(&pAttr->Type, RTCRSPC_PE_IMAGE_HASHES_V1_OID) == 0 || RTAsn1ObjId_CompareWithString(&pAttr->Type, RTCRSPC_PE_IMAGE_HASHES_V2_OID) == 0 ) { cPageHashTabs++; AssertPtr(pAttr->u.pPageHashes->pData); } else return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_PEIMAGE_UNKNOWN_ATTRIBUTE, "SpcIndirectDataContent...MonikerT1 unknown attribute %u: %s.", i, pAttr->Type.szObjId); } if (cPageHashTabs > 0) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_PEIMAGE_MULTIPLE_HASH_TABS, "SpcIndirectDataContent...MonikerT1 multiple page hash attributes (%u).", cPageHashTabs); } else if ( pIndData->Data.uValue.pPeImage->T0.File.enmChoice == RTCRSPCLINKCHOICE_FILE && RTCrSpcString_IsPresent(&pIndData->Data.uValue.pPeImage->T0.File.u.pT2->File) ) { /* Could check for "<<<Obsolete>>>" here, but it's really irrelevant. */ } else if ( pIndData->Data.uValue.pPeImage->T0.File.enmChoice == RTCRSPCLINKCHOICE_URL && RTAsn1String_IsPresent(pIndData->Data.uValue.pPeImage->T0.File.u.pUrl) ) return RTErrInfoSet(pErrInfo, VERR_CR_SPC_PEIMAGE_URL_UNEXPECTED, "SpcIndirectDataContent.Data.uValue.pPeImage->File is an URL, expected object Moniker or File."); else return RTErrInfoSet(pErrInfo, VERR_CR_SPC_PEIMAGE_NO_CONTENT, "SpcIndirectDataContent.Data.uValue.pPeImage->File has no content"); } return VINF_SUCCESS; }
RTDECL(int) RTCrPkcs7VerifySignedData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags, RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts, PCRTTIMESPEC pValidationTime, PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser, PRTERRINFO pErrInfo) { /* * Check the input. */ if (pfnVerifyCert) AssertPtrReturn(pfnVerifyCert, VERR_INVALID_POINTER); else pfnVerifyCert = RTCrPkcs7VerifyCertCallbackDefault; if (!RTCrPkcs7ContentInfo_IsSignedData(pContentInfo)) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_NOT_SIGNED_DATA, "Not PKCS #7 SignedData."); PCRTCRPKCS7SIGNEDDATA pSignedData = pContentInfo->u.pSignedData; int rc = RTCrPkcs7SignedData_CheckSanity(pSignedData, 0, pErrInfo, ""); if (RT_FAILURE(rc)) return rc; /* * Hash the content info. */ /* Exactly what the content is, for some stupid reason unnecessarily complicated. Figure it out here as we'll need it for the OpenSSL code path as well. */ void const *pvContent = pSignedData->ContentInfo.Content.Asn1Core.uData.pv; uint32_t cbContent = pSignedData->ContentInfo.Content.Asn1Core.cb; if (pSignedData->ContentInfo.Content.pEncapsulated) { pvContent = pSignedData->ContentInfo.Content.pEncapsulated->uData.pv; cbContent = pSignedData->ContentInfo.Content.pEncapsulated->cb; } /* Check that there aren't too many or too few hash algorithms for our implementation and purposes. */ RTCRDIGEST ahDigests[2]; uint32_t const cDigests = pSignedData->DigestAlgorithms.cItems; if (!cDigests) /** @todo we might have to support this... */ return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS, "No digest algorithms"); if (cDigests > RT_ELEMENTS(ahDigests)) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_TOO_MANY_DIGEST_ALGORITHMS, "Too many digest algorithm: cAlgorithms=%u", cDigests); /* Create the message digest calculators. */ rc = VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS; uint32_t i; for (i = 0; i < cDigests; i++) { rc = RTCrDigestCreateByObjId(&ahDigests[i], &pSignedData->DigestAlgorithms.paItems[i].Algorithm); if (RT_FAILURE(rc)) { rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_CREATE_ERROR, "Error creating digest for '%s': %Rrc", pSignedData->DigestAlgorithms.paItems[i].Algorithm.szObjId, rc); break; } } if (RT_SUCCESS(rc)) { /* Hash the content. */ for (i = 0; i < cDigests && RT_SUCCESS(rc); i++) { rc = RTCrDigestUpdate(ahDigests[i], pvContent, cbContent); if (RT_SUCCESS(rc)) rc = RTCrDigestFinal(ahDigests[i], NULL, 0); } if (RT_SUCCESS(rc)) { /* * Validate the signed infos. */ uint32_t fPrimaryVccFlags = !(fFlags & RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING) ? RTCRPKCS7VCC_F_SIGNED_DATA : RTCRPKCS7VCC_F_TIMESTAMP; rc = VERR_CR_PKCS7_NO_SIGNER_INFOS; for (i = 0; i < pSignedData->SignerInfos.cItems; i++) { PCRTCRPKCS7SIGNERINFO pSignerInfo = &pSignedData->SignerInfos.paItems[i]; RTCRDIGEST hThisDigest = NIL_RTCRDIGEST; /* (gcc maybe incredible stupid.) */ rc = rtCrPkcs7VerifyFindDigest(&hThisDigest, pSignedData, pSignerInfo, ahDigests, pErrInfo); if (RT_FAILURE(rc)) break; /* * See if we can find a trusted signing time. * (Note that while it would make sense splitting up this function, * we need to carry a lot of arguments around, so better not.) */ bool fDone = false; PCRTCRPKCS7SIGNERINFO pSigningTimeSigner = NULL; PCRTASN1TIME pSignedTime; while ( !fDone && (pSignedTime = RTCrPkcs7SignerInfo_GetSigningTime(pSignerInfo, &pSigningTimeSigner)) != NULL) { RTTIMESPEC ThisValidationTime; if (RT_LIKELY(RTTimeImplode(&ThisValidationTime, &pSignedTime->Time))) { if (pSigningTimeSigner == pSignerInfo) { if (fFlags & RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY) continue; rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags, hAdditionalCerts, hTrustedCerts, &ThisValidationTime, pfnVerifyCert, fPrimaryVccFlags | RTCRPKCS7VCC_F_TIMESTAMP, pvUser, pErrInfo); } else { rc = VINF_SUCCESS; if (!(fFlags & RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED)) rc = rtCrPkcs7VerifyCounterSignerInfo(pSigningTimeSigner, pSignerInfo, pSignedData, fFlags, hAdditionalCerts, hTrustedCerts, &ThisValidationTime, pfnVerifyCert, RTCRPKCS7VCC_F_TIMESTAMP, pvUser, pErrInfo); if (RT_SUCCESS(rc)) rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags, hAdditionalCerts, hTrustedCerts, &ThisValidationTime, pfnVerifyCert, fPrimaryVccFlags, pvUser, pErrInfo); } fDone = RT_SUCCESS(rc) || (fFlags & RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT); } else { rc = RTErrInfoSet(pErrInfo, VERR_INTERNAL_ERROR_3, "RTTimeImplode failed"); fDone = true; } } /* * If not luck, check for microsoft timestamp counter signatures. */ if (!fDone && !(fFlags & RTCRPKCS7VERIFY_SD_F_IGNORE_MS_TIMESTAMP)) { PCRTCRPKCS7CONTENTINFO pSignedTimestamp = NULL; pSignedTime = RTCrPkcs7SignerInfo_GetMsTimestamp(pSignerInfo, &pSignedTimestamp); if (pSignedTime) { RTTIMESPEC ThisValidationTime; if (RT_LIKELY(RTTimeImplode(&ThisValidationTime, &pSignedTime->Time))) { rc = VINF_SUCCESS; if (!(fFlags & RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED)) rc = RTCrPkcs7VerifySignedData(pSignedTimestamp, fFlags | RTCRPKCS7VERIFY_SD_F_IGNORE_MS_TIMESTAMP | RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING, hAdditionalCerts, hTrustedCerts, &ThisValidationTime, pfnVerifyCert, pvUser, pErrInfo); if (RT_SUCCESS(rc)) rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags, hAdditionalCerts, hTrustedCerts, &ThisValidationTime, pfnVerifyCert, fPrimaryVccFlags, pvUser, pErrInfo); fDone = RT_SUCCESS(rc) || (fFlags & RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT); } else { rc = RTErrInfoSet(pErrInfo, VERR_INTERNAL_ERROR_3, "RTTimeImplode failed"); fDone = true; } } } /* * No valid signing time found, use the one specified instead. */ if (!fDone) rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags, hAdditionalCerts, hTrustedCerts, pValidationTime, pfnVerifyCert, fPrimaryVccFlags, pvUser, pErrInfo); RTCrDigestRelease(hThisDigest); if (RT_FAILURE(rc)) break; } } else rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_CALC_ERROR, "Hashing content failed unexpectedly (i=%u): %Rrc", i, rc); /* Clean up digests. */ i = cDigests; } while (i-- > 0) { int rc2 = RTCrDigestRelease(ahDigests[i]); AssertRC(rc2); } #ifdef IPRT_WITH_OPENSSL /* * Verify using OpenSSL and combine the results (should be identical). */ /** @todo figure out how to verify MS timstamp signatures using OpenSSL. */ if (fFlags & RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING) return rc; int rcOssl = rtCrPkcs7VerifySignedDataUsingOpenSsl(pContentInfo, fFlags, hAdditionalCerts, hTrustedCerts, pvContent, cbContent, RT_SUCCESS(rc) ? pErrInfo : NULL); if (RT_SUCCESS(rcOssl) && RT_SUCCESS(rc)) return rc; // AssertMsg(RT_FAILURE_NP(rcOssl) && RT_FAILURE_NP(rc), ("%Rrc, %Rrc\n", rcOssl, rc)); if (RT_FAILURE(rc)) return rc; return rcOssl; #else return rc; #endif }