RTCrSpcIndirectDataContent_GetPeImageObjAttrib(PCRTCRSPCINDIRECTDATACONTENT pThis, RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE enmType) { if (pThis->Data.enmType == RTCRSPCAAOVTYPE_PE_IMAGE_DATA) { Assert(RTAsn1ObjId_CompareWithString(&pThis->Data.Type, RTCRSPCPEIMAGEDATA_OID) == 0); if ( pThis->Data.uValue.pPeImage && pThis->Data.uValue.pPeImage->T0.File.enmChoice == RTCRSPCLINKCHOICE_MONIKER && RTCrSpcSerializedObject_IsPresent(pThis->Data.uValue.pPeImage->T0.File.u.pMoniker) ) { if (pThis->Data.uValue.pPeImage->T0.File.u.pMoniker->enmType == RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES) { Assert(RTUuidCompareStr(pThis->Data.uValue.pPeImage->T0.File.u.pMoniker->Uuid.Asn1Core.uData.pUuid, RTCRSPCSERIALIZEDOBJECT_UUID_STR) == 0); PCRTCRSPCSERIALIZEDOBJECTATTRIBUTES pData = pThis->Data.uValue.pPeImage->T0.File.u.pMoniker->u.pData; if (pData) for (uint32_t i = 0; i < pData->cItems; i++) if (pData->paItems[i].enmType == enmType) return &pData->paItems[i]; } } } return NULL; }
RTDECL(PCRTASN1TIME) RTCrPkcs7SignerInfo_GetMsTimestamp(PCRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7CONTENTINFO *ppContentInfo) { /* * Assume there is only one, so no need to enumerate anything here. */ uint32_t cAttrsLeft = pThis->UnauthenticatedAttributes.cItems; PCRTCRPKCS7ATTRIBUTE pAttr = pThis->UnauthenticatedAttributes.paItems; while (cAttrsLeft-- > 0) { if (pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP) { uint32_t cLeft = pAttr->uValues.pContentInfos->cItems; PCRTCRPKCS7CONTENTINFO pContentInfo = &pAttr->uValues.pContentInfos->paItems[0]; while (cLeft-- > 0) { if (RTAsn1ObjId_CompareWithString(&pContentInfo->ContentType, RTCRPKCS7SIGNEDDATA_OID) == 0) { if (RTAsn1ObjId_CompareWithString(&pContentInfo->u.pSignedData->ContentInfo.ContentType, RTCRTSPTSTINFO_OID) == 0) { if (ppContentInfo) *ppContentInfo = pContentInfo; return &pContentInfo->u.pSignedData->ContentInfo.u.pTstInfo->GenTime; } } pContentInfo++; } } pAttr++; } /* * No signature was found. */ if (ppContentInfo) *ppContentInfo = NULL; return NULL; }
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 rtCrPkcs7ContentInfo_DecodeExtra(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTCRPKCS7CONTENTINFO pThis, const char *pszErrorTag) { pThis->u.pCore = NULL; /* * Figure the type. */ RTCRPKCS7CONTENTINFOCHOICE enmChoice; size_t cbContent = 0; if (RTAsn1ObjId_CompareWithString(&pThis->ContentType, RTCRPKCS7SIGNEDDATA_OID) == 0) { enmChoice = RTCRPKCS7CONTENTINFOCHOICE_SIGNED_DATA; cbContent = sizeof(*pThis->u.pSignedData); } else if (RTAsn1ObjId_CompareWithString(&pThis->ContentType, RTCRSPCINDIRECTDATACONTENT_OID) == 0) { enmChoice = RTCRPKCS7CONTENTINFOCHOICE_SPC_INDIRECT_DATA_CONTENT; cbContent = sizeof(*pThis->u.pIndirectDataContent); } else if (RTAsn1ObjId_CompareWithString(&pThis->ContentType, RTCRTSPTSTINFO_OID) == 0) { enmChoice = RTCRPKCS7CONTENTINFOCHOICE_TSP_TST_INFO; cbContent = sizeof(*pThis->u.pTstInfo); } else { enmChoice = RTCRPKCS7CONTENTINFOCHOICE_UNKNOWN; cbContent = 0; } int rc = VINF_SUCCESS; if (enmChoice != RTCRPKCS7CONTENTINFOCHOICE_UNKNOWN) { /* * Detect CMS octet string and open the content cursor. * Current we don't have work with any contet which is octet string, * they're all sequences, which make detection so much simpler. */ PRTASN1OCTETSTRING pOctetString = &pThis->Content; RTASN1CURSOR ContentCursor; rc = RTAsn1CursorInitSubFromCore(pCursor, &pThis->Content.Asn1Core, &ContentCursor, "Content"); if ( RT_SUCCESS(rc) && RTAsn1CursorIsNextEx(&ContentCursor, ASN1_TAG_OCTET_STRING, ASN1_TAGFLAG_PRIMITIVE | ASN1_TAGCLASS_UNIVERSAL)) { rc = RTAsn1MemAllocZ(&pThis->Content.EncapsulatedAllocation, (void **)&pThis->Content.pEncapsulated, sizeof(*pOctetString)); if (RT_SUCCESS(rc)) { pThis->pCmsContent = pOctetString = (PRTASN1OCTETSTRING)pThis->Content.pEncapsulated; rc = RTAsn1OctetString_DecodeAsn1(&ContentCursor, 0, pOctetString, "CmsContent"); if (RT_SUCCESS(rc)) rc = RTAsn1CursorCheckEnd(&ContentCursor); if (RT_SUCCESS(rc)) rc = RTAsn1CursorInitSubFromCore(pCursor, &pOctetString->Asn1Core, &ContentCursor, "CmsContent"); } } if (RT_SUCCESS(rc)) { /* * Allocate memory for the decoded content. */ rc = RTAsn1MemAllocZ(&pOctetString->EncapsulatedAllocation, (void **)&pOctetString->pEncapsulated, cbContent); if (RT_SUCCESS(rc)) { pThis->u.pCore = pOctetString->pEncapsulated; /* * Decode it. */ switch (enmChoice) { case RTCRPKCS7CONTENTINFOCHOICE_SIGNED_DATA: rc = RTCrPkcs7SignedData_DecodeAsn1(&ContentCursor, 0, pThis->u.pSignedData, "SignedData"); break; case RTCRPKCS7CONTENTINFOCHOICE_SPC_INDIRECT_DATA_CONTENT: rc = RTCrSpcIndirectDataContent_DecodeAsn1(&ContentCursor, 0, pThis->u.pIndirectDataContent, "IndirectDataContent"); break; case RTCRPKCS7CONTENTINFOCHOICE_TSP_TST_INFO: rc = RTCrTspTstInfo_DecodeAsn1(&ContentCursor, 0, pThis->u.pTstInfo, "TstInfo"); break; default: AssertFailed(); rc = VERR_IPE_NOT_REACHED_DEFAULT_CASE; break; } if (RT_SUCCESS(rc)) rc = RTAsn1CursorCheckEnd(&ContentCursor); if (RT_SUCCESS(rc)) return VINF_SUCCESS; RTAsn1MemFree(&pOctetString->EncapsulatedAllocation, pOctetString->pEncapsulated); pOctetString->pEncapsulated = NULL; pThis->u.pCore = NULL; } } } 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; }
/* * One X.509 Extension. */ RTDECL(int) RTCrX509Extension_ExtnValue_DecodeAsn1(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTCRX509EXTENSION pThis, const char *pszErrorTag) { pThis->enmValue = RTCRX509EXTENSIONVALUE_UNKNOWN; /* * Decode the encapsulated extension bytes if know the format. */ RTASN1CURSOR ValueCursor; int rc = RTAsn1CursorInitSubFromCore(pCursor, &pThis->ExtnValue.Asn1Core, &ValueCursor, "ExtnValue"); if (RT_FAILURE(rc)) return rc; pCursor = &ValueCursor; if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_AUTHORITY_KEY_IDENTIFIER_OID) == 0) { /* 4.2.1.1 Authority Key Identifier */ PRTCRX509AUTHORITYKEYIDENTIFIER pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_AUTHORITY_KEY_IDENTIFIER; rc = RTCrX509AuthorityKeyIdentifier_DecodeAsn1(&ValueCursor, 0, pThat, "AuthorityKeyIdentifier"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_OLD_AUTHORITY_KEY_IDENTIFIER_OID) == 0) { /* Old and obsolete version of the above, still found in microsoft certificates. */ PRTCRX509OLDAUTHORITYKEYIDENTIFIER pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_OLD_AUTHORITY_KEY_IDENTIFIER; rc = RTCrX509OldAuthorityKeyIdentifier_DecodeAsn1(&ValueCursor, 0, pThat, "OldAuthorityKeyIdentifier"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_SUBJECT_KEY_IDENTIFIER_OID) == 0) { /* 4.2.1.2 Subject Key Identifier */ PRTASN1OCTETSTRING pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_OCTET_STRING; rc = RTAsn1CursorGetOctetString(&ValueCursor, 0, pThat, "SubjectKeyIdentifier"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_KEY_USAGE_OID) == 0) { /* 4.2.1.3 Key Usage */ PRTASN1BITSTRING pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_BIT_STRING; rc = RTAsn1CursorGetBitStringEx(&ValueCursor, 0, 9, pThat, "KeyUsage"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_CERTIFICATE_POLICIES_OID) == 0) { /* 4.2.1.4 Certificate Policies */ PRTCRX509CERTIFICATEPOLICIES pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_CERTIFICATE_POLICIES; rc = RTCrX509CertificatePolicies_DecodeAsn1(&ValueCursor, 0, pThat, "CertPolicies"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_POLICY_MAPPINGS_OID) == 0) { /* 4.2.1.5 Policy Mappings */ PRTCRX509POLICYMAPPINGS pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_POLICY_MAPPINGS; rc = RTCrX509PolicyMappings_DecodeAsn1(&ValueCursor, 0, pThat, "PolicyMapppings"); } } else if ( RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_SUBJECT_ALT_NAME_OID) == 0 || RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_ISSUER_ALT_NAME_OID) == 0) { /* 4.2.1.6 Subject Alternative Name / 4.2.1.7 Issuer Alternative Name */ PRTCRX509GENERALNAMES pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_GENERAL_NAMES; rc = RTCrX509GeneralNames_DecodeAsn1(&ValueCursor, 0, pThat, "AltName"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_BASIC_CONSTRAINTS_OID) == 0) { /* 4.2.1.9 Basic Constraints */ PRTCRX509BASICCONSTRAINTS pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_BASIC_CONSTRAINTS; rc = RTCrX509BasicConstraints_DecodeAsn1(&ValueCursor, 0, pThat, "BasicConstraints"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_NAME_CONSTRAINTS_OID) == 0) { /* 4.2.1.10 Name Constraints */ PRTCRX509NAMECONSTRAINTS pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_NAME_CONSTRAINTS; rc = RTCrX509NameConstraints_DecodeAsn1(&ValueCursor, 0, pThat, "NameConstraints"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_POLICY_CONSTRAINTS_OID) == 0) { /* 4.2.1.11 Policy Constraints */ PRTCRX509POLICYCONSTRAINTS pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_POLICY_CONSTRAINTS; rc = RTCrX509PolicyConstraints_DecodeAsn1(&ValueCursor, 0, pThat, "PolicyConstraints"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_EXT_KEY_USAGE_OID) == 0) { /* 4.2.1.12 Extended Key Usage */ PRTASN1SEQOFOBJIDS pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->SeqCore.Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_SEQ_OF_OBJ_IDS; rc = RTAsn1SeqOfObjIds_DecodeAsn1(&ValueCursor, 0, pThat, "ExKeyUsage"); } } else if (RTAsn1ObjId_CompareWithString(&pThis->ExtnId, RTCRX509_ID_CE_EXT_KEY_USAGE_OID) == 0) { /* 4.2.1.14 Inhibit anyPolicy */ PRTASN1INTEGER pThat; rc = RTAsn1MemAllocZ(&pThis->ExtnValue.EncapsulatedAllocation, (void **)&pThat, sizeof(*pThat)); if (RT_SUCCESS(rc)) { pThis->ExtnValue.pEncapsulated = &pThat->Asn1Core; pThis->enmValue = RTCRX509EXTENSIONVALUE_INTEGER; rc = RTAsn1CursorGetInteger(&ValueCursor, 0, pThat, "InhibitAnyPolicy"); } } else return VINF_SUCCESS; if (RT_SUCCESS(rc)) rc = RTAsn1CursorCheckEnd(&ValueCursor); if (RT_SUCCESS(rc)) return VINF_SUCCESS; return rc; }
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(bool) RTCrPkcs7ContentInfo_IsSignedData(PCRTCRPKCS7CONTENTINFO pThis) { return RTAsn1ObjId_CompareWithString(&pThis->ContentType, RTCRPKCS7SIGNEDDATA_OID) == 0; }
/** * 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; }
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; }