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; }
/** * 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); }
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) 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; }