RTDECL(PCRTCRCERTCTX) RTCrStoreCertByIssuerAndSerialNo(RTCRSTORE hStore, PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNo) { PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore; AssertPtrReturn(pThis, NULL); AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, NULL); AssertPtrReturn(pIssuer, NULL); int rc; RTCRSTORECERTSEARCH Search; if (pThis->pProvider->pfnCertFindByIssuerAndSerialNo) rc = pThis->pProvider->pfnCertFindByIssuerAndSerialNo(pThis->pvProvider, pIssuer, pSerialNo, &Search); else rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search); PCRTCRCERTCTX pCertCtx = NULL; if (RT_SUCCESS(rc)) { for (;;) { pCertCtx = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search); if (!pCertCtx) break; if ( pCertCtx->pCert && RTCrX509Certificate_MatchIssuerAndSerialNumber(pCertCtx->pCert, pIssuer, pSerialNo)) break; RTCrCertCtxRelease(pCertCtx); } pThis->pProvider->pfnCertSearchDestroy(pThis->pvProvider, &Search); } else AssertMsg(rc == VERR_NOT_FOUND, ("%Rrc\n", rc)); return pCertCtx; }
RTDECL(int) RTCrStoreConvertToOpenSslCertStack(RTCRSTORE hStore, uint32_t fFlags, void **ppvOpenSslStack) { PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE); /* * Use the pfnCertFindAll method to add all certificates to the store we're returning. */ int rc; STACK_OF(X509) *pOsslStack = sk_X509_new_null(); if (pOsslStack) { RTCRSTORECERTSEARCH Search; rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search); if (RT_SUCCESS(rc)) { do { PCRTCRCERTCTX pCertCtx = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search); if (!pCertCtx) break; if (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_X509_DER) { X509 *pOsslCert = NULL; const unsigned char *pabEncoded = (const unsigned char *)pCertCtx->pabEncoded; if (d2i_X509(&pOsslCert, &pabEncoded, pCertCtx->cbEncoded) == pOsslCert) { if (!sk_X509_push(pOsslStack, pOsslCert)) { rc = VERR_NO_MEMORY; X509_free(pOsslCert); } } } RTCrCertCtxRelease(pCertCtx); } while (RT_SUCCESS(rc)); pThis->pProvider->pfnCertSearchDestroy(pThis->pvProvider, &Search); if (RT_SUCCESS(rc)) { *ppvOpenSslStack = pOsslStack; return VINF_SUCCESS; } } sk_X509_pop_free(pOsslStack, X509_free); } else rc = VERR_NO_MEMORY; return rc; }
RTDECL(PCRTCRCERTCTX) RTCrStoreCertSearchNext(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch) { PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore; AssertPtrReturn(pThis, NULL); AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, NULL); AssertPtrReturn(pSearch, NULL); PCRTCRCERTCTX pRet; switch (pSearch->auOpaque[2]) { default: pRet = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, pSearch); break; case RTCRSTORECERTSEARCH_BY_SUBECT_OR_ALT_SUBJECT_BY_RFC5280: { PCRTCRX509NAME pSubject = (PCRTCRX509NAME)pSearch->auOpaque[3]; AssertPtrReturn(pSubject, NULL); for (;;) { pRet = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, pSearch); if (!pRet) break; if (pRet->pCert) { if (RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(pRet->pCert, pSubject)) break; } else if (pRet->pTaInfo) { if ( RTCrTafCertPathControls_IsPresent(&pRet->pTaInfo->CertPath) && RTCrX509Name_MatchByRfc5280(&pRet->pTaInfo->CertPath.TaName, pSubject)) break; } RTCrCertCtxRelease(pRet); } break; } } return pRet; }
/** * 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) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename) { /* * Validate input. */ AssertReturn(!fFlags, VERR_INVALID_FLAGS); /* * Start the enumeration first as this validates the store handle. */ RTCRSTORECERTSEARCH Search; int rc = RTCrStoreCertFindAll(hStore, &Search); if (RT_SUCCESS(rc)) { /* * Open the file for writing. * * Note! We must use text and no binary here, because the base-64 API * below will use host specific EOL markers, not CRLF as PEM * specifies. */ PRTSTREAM hStrm; rc = RTStrmOpen(pszFilename, "w", &hStrm); if (RT_SUCCESS(rc)) { /* * Enumerate the certificates in the store, writing them out one by one. */ size_t cbBase64 = 0; char *pszBase64 = NULL; PCRTCRCERTCTX pCertCtx; while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL) { const char *pszMarker; switch (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) { case RTCRCERTCTX_F_ENC_X509_DER: pszMarker = "CERTIFICATE"; break; case RTCRCERTCTX_F_ENC_TAF_DER: pszMarker = "TRUST ANCHOR"; break; default: pszMarker = NULL; break; } if (pszMarker && pCertCtx->cbEncoded > 0) { /* * Do the base64 conversion first. */ size_t cchEncoded = RTBase64EncodedLength(pCertCtx->cbEncoded); if (cchEncoded < cbBase64) { /* likely */ } else { size_t cbNew = RT_ALIGN(cchEncoded + 64, 128); void *pvNew = RTMemRealloc(pszBase64, cbNew); if (!pvNew) { rc = VERR_NO_MEMORY; break; } cbBase64 = cbNew; pszBase64 = (char *)pvNew; } rc = RTBase64Encode(pCertCtx->pabEncoded, pCertCtx->cbEncoded, pszBase64, cbBase64, &cchEncoded); if (RT_FAILURE(rc)) break; RTStrmPrintf(hStrm, "-----BEGIN %s-----\n", pszMarker); RTStrmWrite(hStrm, pszBase64, cchEncoded); rc = RTStrmPrintf(hStrm, "\n-----END %s-----\n", pszMarker); if (RT_FAILURE(rc)) break; } RTCrCertCtxRelease(pCertCtx); } if (pCertCtx) RTCrCertCtxRelease(pCertCtx); RTMemFree(pszBase64); /* * Flush the output file before closing. */ int rc2 = RTStrmFlush(hStrm); if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; RTStrmClearError(hStrm); /** @todo fix RTStrmClose... */ rc2 = RTStrmClose(hStrm); if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; } int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search); AssertRC(rc2); } return rc; }