Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
/**
 * 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;
}