/** * 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) RTCrPkixSignatureVerify(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, void const *pvSignature, size_t cbSignature) { PRTCRPKIXSIGNATUREINT pThis = hSignature; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTCRPKIXSIGNATUREINT_MAGIC, VERR_INVALID_HANDLE); AssertReturn(!pThis->fSigning, VERR_INVALID_FUNCTION); AssertReturn(pThis->uState == RTCRPKIXSIGNATURE_STATE_READY || pThis->uState == RTCRPKIXSIGNATURE_STATE_DONE, VERR_INVALID_STATE); uint32_t cRefs = RTCrDigestRetain(hDigest); AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE); int rc = rtCrPkxiSignatureReset(pThis); if (RT_SUCCESS(rc)) { rc = pThis->pDesc->pfnVerify(pThis->pDesc, pThis->abState, hDigest, pvSignature, cbSignature); pThis->uState = RTCRPKIXSIGNATURE_STATE_DONE; } RTCrDigestRelease(hDigest); 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; }