All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.jce.provider.RFC3281CertPathUtilities Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.6.

There is a newer version: 1.46
Show newest version
package org.bouncycastle.jce.provider;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
import org.bouncycastle.asn1.x509.TargetInformation;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
import org.bouncycastle.util.Selector;
import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
import org.bouncycastle.x509.ExtendedPKIXParameters;
import org.bouncycastle.x509.PKIXAttrCertChecker;
import org.bouncycastle.x509.X509AttributeCertificate;
import org.bouncycastle.x509.X509CRLStoreSelector;
import org.bouncycastle.x509.X509CertStoreSelector;

import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Principal;
import java.security.PublicKey;
import java.security.cert.CertPath;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertPathBuilderResult;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorResult;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

class RFC3281CertPathUtilities
    extends CertPathValidatorUtilities
{
    private static final String TARGET_INFORMATION = X509Extensions.TargetInformation.getId();

    private static final String NO_REV_AVAIL = X509Extensions.NoRevAvail.getId();

    private static final String AUTHORITY_INFO_ACCESS = X509Extensions.AuthorityInfoAccess.getId();

    protected static void processAttrCert7(X509AttributeCertificate attrCert, CertPath certPath,
        CertPath holderCertPath, ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
    {
        // TODO:
        // AA Controls
        // Attribute encryption
        // Proxy
        Set set = attrCert.getCriticalExtensionOIDs();
        // 7.1
        // process extensions

        // target information checked in step 6 / X509AttributeCertStoreSelector
        if (set.contains(TARGET_INFORMATION))
        {
            try
            {
                TargetInformation.getInstance(CertPathValidatorUtilities
                    .getExtensionValue(attrCert, TARGET_INFORMATION));
            }
            catch (AnnotatedException e)
            {
                throw new ExtCertPathValidatorException(
                    "Target information extension could not be read.", e);
            }
            catch (IllegalArgumentException e)
            {
                throw new ExtCertPathValidatorException(
                    "Target information extension could not be read.", e);
            }
        }
        set.remove(TARGET_INFORMATION);
        for (Iterator it = pkixParams.getAttrCertCheckers().iterator(); it.hasNext();)
        {
            ((PKIXAttrCertChecker) it.next()).check(attrCert, certPath, holderCertPath, set);
        }
        if (!set.isEmpty())
        {
            throw new CertPathValidatorException(
                "Attribute certificate contains unsupported critical extensions: "
                    + set);
        }
    }

    /**
     * Checks if an attribute certificate is revoked.
     * 
     * @param attrCert Attribute certificate to check if it is revoked.
     * @param paramsPKIX PKIX parameters.
     * @param issuerCert The issuer certificate of the attribute certificate
     *            attrCert.
     * @param validDate The date when the certificate revocation status should
     *            be checked.
     * 
     * @throws CertPathValidatorException if the certificate is revoked or the
     *             status cannot be checked or some error occurs.
     */
    protected static void checkCRLs(X509AttributeCertificate attrCert,
        ExtendedPKIXParameters paramsPKIX, X509Certificate issuerCert,
        Date validDate) throws CertPathValidatorException
    {
        if (paramsPKIX.isRevocationEnabled())
        {
            // check if revocation is available
            if (attrCert.getExtensionValue(NO_REV_AVAIL) == null)
            {
                CRLDistPoint crldp = null;
                try
                {
                    crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities
                        .getExtensionValue(attrCert, CRL_DISTRIBUTION_POINTS));
                }
                catch (AnnotatedException e)
                {
                    throw new CertPathValidatorException(
                        "CRL distribution point extension could not be read.", e);
                }
                try
                {
                    CertPathValidatorUtilities
                        .addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX);
                }
                catch (AnnotatedException e)
                {
                    throw new CertPathValidatorException(
                        "No additional CRL locations could be decoded from CRL distribution point extension.",
                        e);
                }
                CertStatus certStatus = new CertStatus();
                ReasonsMask reasonsMask = new ReasonsMask();

                AnnotatedException lastException = null;
                boolean validCrlFound = false;
                // for each distribution point
                if (crldp != null)
                {
                    DistributionPoint dps[] = null;
                    try
                    {
                        dps = crldp.getDistributionPoints();
                    }
                    catch (Exception e)
                    {
                        throw new ExtCertPathValidatorException(
                            "Distribution points could not be read.", e);
                    }
                    try
                    {
                        for (int i = 0; i < dps.length
                            && certStatus.getCertStatus() == CertStatus.UNREVOKED
                            && !reasonsMask.isAllReasons(); i++)
                        {
                            ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX
                                .clone();
                            checkCRL(dps[i], attrCert, paramsPKIXClone,
                                validDate, issuerCert, certStatus, reasonsMask);
                            validCrlFound = true;
                        }
                    }
                    catch (AnnotatedException e)
                    {
                        lastException = new AnnotatedException(
                            "No valid CRL for distribution point found.", e);
                    }
                }

                /*
                 * If the revocation status has not been determined, repeat the
                 * process above with any available CRLs not specified in a
                 * distribution point but issued by the certificate issuer.
                 */

                if (certStatus.getCertStatus() == CertStatus.UNREVOKED
                    && !reasonsMask.isAllReasons())
                {
                    try
                    {
                        /*
                         * assume a DP with both the reasons and the cRLIssuer
                         * fields omitted and a distribution point name of the
                         * certificate issuer.
                         */
                        DERObject issuer = null;
                        try
                        {

                            issuer = new ASN1InputStream(
                                ((X500Principal) attrCert.getIssuer()
                                    .getPrincipals()[0]).getEncoded())
                                .readObject();
                        }
                        catch (Exception e)
                        {
                            throw new AnnotatedException(
                                "Issuer from certificate for CRL could not be reencoded.",
                                e);
                        }
                        DistributionPoint dp = new DistributionPoint(
                            new DistributionPointName(0, new GeneralNames(
                                new GeneralName(GeneralName.directoryName,
                                    issuer))), null, null);
                        ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX
                            .clone();
                        checkCRL(dp, attrCert, paramsPKIXClone, validDate,
                            issuerCert, certStatus, reasonsMask);
                        validCrlFound = true;
                    }
                    catch (AnnotatedException e)
                    {
                        lastException = new AnnotatedException(
                            "No valid CRL for distribution point found.", e);
                    }
                }

                if (!validCrlFound)
                {
                    throw new ExtCertPathValidatorException(
                        "No valid CRL found.", lastException);
                }
                if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
                {
                    String message = "Attribute certificate revocation after "
                        + certStatus.getRevocationDate();
                    message += ", reason: "
                        + crlReasons[certStatus.getCertStatus()];
                    throw new CertPathValidatorException(message);
                }
                if (!reasonsMask.isAllReasons()
                    && certStatus.getCertStatus() == CertStatus.UNREVOKED)
                {
                    certStatus.setCertStatus(CertStatus.UNDETERMINED);
                }
                if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
                {
                    throw new CertPathValidatorException(
                        "Attribute certificate status could not be determined.");
                }

            }
            else
            {
                if (attrCert.getExtensionValue(CRL_DISTRIBUTION_POINTS) != null
                    || attrCert.getExtensionValue(AUTHORITY_INFO_ACCESS) != null)
                {
                    throw new CertPathValidatorException(
                        "No rev avail extension is set, but also an AC revocation pointer.");
                }
            }
        }
    }

    protected static void additionalChecks(X509AttributeCertificate attrCert,
        ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
    {
        // 1
        for (Iterator it = pkixParams.getProhibitedACAttributes().iterator(); it
            .hasNext();)
        {
            String oid = (String) it.next();
            if (attrCert.getAttributes(oid) != null)
            {
                throw new CertPathValidatorException(
                    "Attribute certificate contains prohibited attribute: "
                        + oid + ".");
            }
        }
        for (Iterator it = pkixParams.getNecessaryACAttributes().iterator(); it
            .hasNext();)
        {
            String oid = (String) it.next();
            if (attrCert.getAttributes(oid) == null)
            {
                throw new CertPathValidatorException(
                    "Attribute certificate does not contain necessary attribute: "
                        + oid + ".");
            }
        }
    }

    protected static void processAttrCert5(X509AttributeCertificate attrCert,
        ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
    {
        try
        {
            attrCert.checkValidity(CertPathValidatorUtilities
                .getValidDate(pkixParams));
        }
        catch (CertificateExpiredException e)
        {
            throw new ExtCertPathValidatorException(
                "Attribute certificate is not valid.", e);
        }
        catch (CertificateNotYetValidException e)
        {
            throw new ExtCertPathValidatorException(
                "Attribute certificate is not valid.", e);
        }
    }

    protected static void processAttrCert4(X509Certificate acIssuerCert,
        ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
    {
        Set set = pkixParams.getTrustedACIssuers();
        boolean trusted = false;
        for (Iterator it = set.iterator(); it.hasNext();)
        {
            TrustAnchor anchor = (TrustAnchor) it.next();
            if (acIssuerCert.getSubjectX500Principal().getName("RFC2253")
                .equals(anchor.getCAName())
                || acIssuerCert.equals(anchor.getTrustedCert()))
            {
                trusted = true;
            }
        }
        if (!trusted)
        {
            throw new CertPathValidatorException(
                "Attribute certificate issuer is not directly trusted.");
        }
    }

    protected static void processAttrCert3(X509Certificate acIssuerCert,
        ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
    {
        if (acIssuerCert.getKeyUsage() != null
            && (!acIssuerCert.getKeyUsage()[0] && !acIssuerCert.getKeyUsage()[1]))
        {
            throw new CertPathValidatorException(
                "Attribute certificate issuer public key cannot be used to validate digital signatures.");
        }
        if (acIssuerCert.getBasicConstraints() != -1)
        {
            throw new CertPathValidatorException(
                "Attribute certificate issuer is also a public key certificate issuer.");
        }
    }

    protected static CertPathValidatorResult processAttrCert2(
        CertPath certPath, ExtendedPKIXParameters pkixParams)
        throws CertPathValidatorException
    {
        CertPathValidator validator = null;
        try
        {
            validator = CertPathValidator.getInstance("PKIX", "BC");
        }
        catch (NoSuchProviderException e)
        {
            throw new ExtCertPathValidatorException(
                "Support class could not be created.", e);
        }
        catch (NoSuchAlgorithmException e)
        {
            throw new ExtCertPathValidatorException(
                "Support class could not be created.", e);
        }
        try
        {
            return validator.validate(certPath, pkixParams);
        }
        catch (CertPathValidatorException e)
        {
            throw new ExtCertPathValidatorException(
                "Certification path for issuer certificate of attribute certificate could not be validated.",
                e);
        }
        catch (InvalidAlgorithmParameterException e)
        {
            // must be a programming error
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * Searches for a holder public key certificate and verifies its
     * certification path.
     * 
     * @param attrCert the attribute certificate.
     * @param pkixParams The PKIX parameters.
     * @return The certificate path of the holder certificate.
     * @throws AnnotatedException if
     *             
    *
  • no public key certificate can be found although holder * information is given by an entity name or a base certificate * ID *
  • support classes cannot be created *
  • no certification path for the public key certificate can * be built *
*/ protected static CertPath processAttrCert1(X509AttributeCertificate attrCert, ExtendedPKIXParameters pkixParams) throws CertPathValidatorException { CertPathBuilderResult result = null; // find holder PKCs Set holderPKCs = new HashSet(); if (attrCert.getHolder().getIssuer() != null) { X509CertStoreSelector selector = new X509CertStoreSelector(); selector.setSerialNumber(attrCert.getHolder().getSerialNumber()); Principal[] principals = attrCert.getHolder().getIssuer(); for (int i = 0; i < principals.length; i++) { try { if (principals[i] instanceof X500Principal) { selector.setIssuer(((X500Principal)principals[i]).getEncoded()); } holderPKCs.addAll(CertPathValidatorUtilities .findCertificates((Selector) selector, pkixParams .getStores())); } catch (AnnotatedException e) { throw new ExtCertPathValidatorException( "Public key certificate for attribute certificate cannot be searched.", e); } catch (IOException e) { throw new ExtCertPathValidatorException( "Unable to encode X500 principal.", e); } } if (holderPKCs.isEmpty()) { throw new CertPathValidatorException( "Public key certificate specified in base certificate ID for attribute certificate cannot be found."); } } if (attrCert.getHolder().getEntityNames() != null) { X509CertStoreSelector selector = new X509CertStoreSelector(); Principal[] principals = attrCert.getHolder().getEntityNames(); for (int i = 0; i < principals.length; i++) { try { if (principals[i] instanceof X500Principal) { selector.setIssuer(((X500Principal)principals[i]).getEncoded()); } holderPKCs.addAll(CertPathValidatorUtilities .findCertificates((Selector) selector, pkixParams .getStores())); } catch (AnnotatedException e) { throw new ExtCertPathValidatorException( "Public key certificate for attribute certificate cannot be searched.", e); } catch (IOException e) { throw new ExtCertPathValidatorException( "Unable to encode X500 principal.", e); } } if (holderPKCs.isEmpty()) { throw new CertPathValidatorException( "Public key certificate specified in entity name for attribute certificate cannot be found."); } } // verify cert paths for PKCs ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters .getInstance(pkixParams); CertPathValidatorException lastException = null; for (Iterator it = holderPKCs.iterator(); it.hasNext();) { X509CertStoreSelector selector = new X509CertStoreSelector(); selector.setCertificate((X509Certificate) it.next()); params.setTargetConstraints(selector); CertPathBuilder builder = null; try { builder = CertPathBuilder.getInstance("PKIX", "BC"); } catch (NoSuchProviderException e) { throw new ExtCertPathValidatorException( "Support class could not be created.", e); } catch (NoSuchAlgorithmException e) { throw new ExtCertPathValidatorException( "Support class could not be created.", e); } try { result = builder .build(ExtendedPKIXBuilderParameters.getInstance(params)); } catch (CertPathBuilderException e) { lastException = new ExtCertPathValidatorException( "Certification path for public key certificate of attribute certificate could not be build.", e); } catch (InvalidAlgorithmParameterException e) { // must be a programming error throw new RuntimeException(e.getMessage()); } } if (lastException != null) { throw lastException; } return result.getCertPath(); } /** * * Checks a distribution point for revocation information for the * certificate cert. * * @param dp The distribution point to consider. * @param attrCert The attribute certificate which should be checked. * @param paramsPKIX PKIX parameters. * @param validDate The date when the certificate revocation status should * be checked. * @param issuerCert Certificate to check if it is revoked. * @param reasonMask The reasons mask which is already checked. * @throws AnnotatedException if the certificate is revoked or the status * cannot be checked or some error occurs. */ private static void checkCRL(DistributionPoint dp, X509AttributeCertificate attrCert, ExtendedPKIXParameters paramsPKIX, Date validDate, X509Certificate issuerCert, CertStatus certStatus, ReasonsMask reasonMask) throws AnnotatedException { /* * 4.3.6 No Revocation Available * * The noRevAvail extension, defined in [X.509-2000], allows an AC * issuer to indicate that no revocation information will be made * available for this AC. */ if (attrCert.getExtensionValue(X509Extensions.NoRevAvail.getId()) != null) { return; } Date currentDate = new Date(System.currentTimeMillis()); if (validDate.getTime() > currentDate.getTime()) { throw new AnnotatedException("Validation time is in future."); } // (a) /* * We always get timely valid CRLs, so there is no step (a) (1). * "locally cached" CRLs are assumed to be in getStore(), additional * CRLs must be enabled in the ExtendedPKIXParameters and are in * getAdditionalStore() */ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, attrCert, currentDate, paramsPKIX); boolean validCrlFound = false; AnnotatedException lastException = null; Iterator crl_iter = crls.iterator(); while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons()) { try { X509CRL crl = (X509CRL) crl_iter.next(); // (d) ReasonsMask interimReasonsMask = processCRLD(crl, dp); // (e) /* * The reasons mask is updated at the end, so only valid CRLs * can update it. If this CRL does not contain new reasons it * must be ignored. */ if (!interimReasonsMask.hasNewReasons(reasonMask)) { continue; } // (f) Set keys = processCRLF(crl, attrCert, null, null, paramsPKIX); // (g) PublicKey key = processCRLG(crl, keys); X509CRL deltaCRL = null; if (paramsPKIX.isUseDeltasEnabled()) { // get delta CRLs Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs( currentDate, paramsPKIX, crl); // we only want one valid delta CRL // (h) deltaCRL = processCRLH(deltaCRLs, key); } /* * CRL must be be valid at the current time, not the validation * time. If a certificate is revoked with reason keyCompromise, * cACompromise, it can be used for forgery, also for the past. * This reason may not be contained in older CRLs. */ /* * in the chain model signatures stay valid also after the * certificate has been expired, so they do not have to be in * the CRL vality time */ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL) { /* * if a certificate has expired, but was revoked, it is not * more in the CRL, so it would be regarded as valid if the * first check is not done */ if (attrCert.getNotAfter().getTime() < crl.getThisUpdate() .getTime()) { throw new AnnotatedException( "No valid CRL for current time found."); } } processCRLB1(dp, attrCert, crl); // (b) (2) processCRLB2(dp, attrCert, crl); // (c) processCRLC(deltaCRL, crl, paramsPKIX); // (i) processCRLI(validDate, deltaCRL, attrCert.getSerialNumber(), certStatus, paramsPKIX); // (j) processCRLJ(validDate, crl, attrCert .getSerialNumber(), certStatus); // (k) if (certStatus.getCertStatus() == CRLReason.removeFromCRL) { certStatus.setCertStatus(CertStatus.UNREVOKED); } // update reasons mask reasonMask.addReasons(interimReasonsMask); validCrlFound = true; } catch (AnnotatedException e) { lastException = e; } } if (!validCrlFound) { throw lastException; } } protected static void processCRLB2(DistributionPoint dp, Object cert, X509CRL crl) throws AnnotatedException { IssuingDistributionPoint idp = null; try { idp = IssuingDistributionPoint .getInstance(CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException( "Issuing distribution point extension could not be decoded.", e); } // distribution point name is present if (idp != null && idp.getDistributionPoint() != null) { // make list of names DistributionPointName dpName = IssuingDistributionPoint .getInstance(idp).getDistributionPoint(); List names = new ArrayList(); if (dpName.getType() == DistributionPointName.FULL_NAME) { GeneralName[] genNames = GeneralNames.getInstance( dpName.getName()).getNames(); for (int j = 0; j < genNames.length; j++) { names.add(genNames[j].getDEREncoded()); } } boolean matches = false; // verify that one of the names in the IDP matches one // of the names in the DP. if (dp.getDistributionPoint() != null) { dpName = dp.getDistributionPoint(); if (dpName.getType() == DistributionPointName.FULL_NAME) { GeneralName[] genNames = GeneralNames.getInstance( dpName.getName()).getNames(); for (int j = 0; j < genNames.length; j++) { if (names.contains(genNames[j])) { matches = true; break; } } } if (!matches) { throw new AnnotatedException( "None of the names in the CRL issuing distribution point matches one " + "of the names in a distributionPoint field of the certificate CRL distribution point."); } } // verify that one of the names in // the IDP matches one of the names in the cRLIssuer field of // the DP else { if (dp.getCRLIssuer() == null) { throw new AnnotatedException( "Either the cRLIssuer or the distributionPoint field must " + "be contained in DistributionPoint."); } GeneralName[] genNames = dp.getCRLIssuer().getNames(); for (int j = 0; j < genNames.length; j++) { if (names.contains(genNames[j])) { matches = true; break; } } if (!matches) { throw new AnnotatedException( "None of the names in the CRL issuing distribution point matches one " + "of the names in a cRLIssuer field of the certificate CRL distribution point."); } } BasicConstraints bc = null; try { bc = BasicConstraints.getInstance(CertPathValidatorUtilities .getExtensionValue((java.security.cert.X509Extension)cert, BASIC_CONSTRAINTS)); } catch (Exception e) { throw new AnnotatedException( "Basic constraints extension could not be decoded.", e); } if (cert instanceof X509Certificate) { // (b) (ii) if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA())) { throw new AnnotatedException( "CA Cert CRL only contains user certificates."); } // (b) (iii) if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA())) { throw new AnnotatedException( "End CRL only contains CA certificates."); } } // (b) (iv) if (idp.onlyContainsAttributeCerts()) { throw new AnnotatedException( "onlyContainsAttributeCerts boolean is asserted."); } } } protected static void processCRLB1(DistributionPoint dp, Object cert, X509CRL crl) throws AnnotatedException { DERObject idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT); boolean isIndirect = false; if (idp != null) { if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL()) { isIndirect = true; } } byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl) .getEncoded(); boolean matchIssuer = false; if (dp.getCRLIssuer() != null) { GeneralName genNames[] = dp.getCRLIssuer().getNames(); for (int j = 0; j < genNames.length; j++) { if (genNames[j].getTagNo() == GeneralName.directoryName) { try { if (genNames[j].getName().getDERObject().getEncoded() .equals(issuerBytes)) { matchIssuer = true; } } catch (IOException e) { throw new AnnotatedException( "CRL issuer information from distribution point cannot be decoded.", e); } } } if (matchIssuer && !isIndirect) { throw new AnnotatedException( "Distribution point contains cRLIssuer field but CRL is not indirect."); } if (!matchIssuer) { throw new AnnotatedException( "CRL issuer of CRL does not match CRL issuer of distribution point."); } } else { if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals( CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert))) { matchIssuer = true; } } if (!matchIssuer) { throw new AnnotatedException( "Cannot find matching CRL issuer for certificate."); } } protected static ReasonsMask processCRLD(X509CRL crl, DistributionPoint dp) throws AnnotatedException { IssuingDistributionPoint idp = null; try { idp = IssuingDistributionPoint .getInstance(CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException( "Issuing distribution point extension could not be decoded.", e); } // (d) (1) if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null) { return new ReasonsMask(dp.getReasons().intValue()) .intersect(new ReasonsMask(idp.getOnlySomeReasons().intValue())); } // (d) (4) if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null) { return ReasonsMask.allReasons; } // (d) (2) and (d)(3) return (dp.getReasons() == null ? ReasonsMask.allReasons : new ReasonsMask(dp.getReasons().intValue())) .intersect(idp == null ? ReasonsMask.allReasons : new ReasonsMask( idp.getOnlySomeReasons().intValue())); } /** * Obtain and validate the certification path for the complete CRL issuer. * If a key usage extension is present in the CRL issuer's certificate, * verify that the cRLSign bit is set. * * @param crl CRL which contains revocation information for the certificate * cert. * @param cert The attribute certificate or certificate to check if it is * revoked. * @param defaultCRLSignCert The issuer certificate of the certificate * cert. May be null. * @param defaultCRLSignKey The public key of the issuer certificate * defaultCRLSignCert. May be null. * @param paramsPKIX paramsPKIX PKIX parameters. * @return A Set with all keys of possible CRL issuer * certificates. * @throws AnnotatedException if the CRL is no valid or the status cannot be * checked or some error occurs. */ protected static Set processCRLF(X509CRL crl, Object cert, X509Certificate defaultCRLSignCert, PublicKey defaultCRLSignKey, ExtendedPKIXParameters paramsPKIX) throws AnnotatedException { // (f) // get issuer from CRL X509CertStoreSelector selector = new X509CertStoreSelector(); try { selector.setSubject(CertPathValidatorUtilities.getIssuerPrincipal( crl).getEncoded()); } catch (IOException e) { throw new AnnotatedException( "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e); } // get CRL signing certs Collection coll = null; try { coll = CertPathValidatorUtilities.findCertificates( (Selector) selector, paramsPKIX.getStores()); coll = CertPathValidatorUtilities.findCertificates( (Selector) selector, paramsPKIX.getAddionalStores()); } catch (AnnotatedException e) { throw new AnnotatedException( "Issuer certificate for CRL cannot be searched.", e); } if (defaultCRLSignCert != null) { coll.add(defaultCRLSignCert); } Iterator cert_it = coll.iterator(); Set validCerts = new HashSet(); while (cert_it.hasNext()) { X509Certificate signingCert = (X509Certificate) cert_it.next(); /* * CA of certificate, for which this CRL is checked, also signed * CRL, so skip path validation, because is already checked in way * from trusted CA to end certificate. */ // double check with key, because name could be thereotical the same if (CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert) .equals(signingCert.getSubjectX500Principal()) && signingCert.getPublicKey().equals(defaultCRLSignKey)) { validCerts.add(signingCert); continue; } try { CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC"); selector = new X509CertStoreSelector(); selector.setCertificate(signingCert); ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters .getInstance(paramsPKIX); params.setTargetConstraints(selector); /* * CRL for CA cannot be signed from CA lower in PKI path * (compromised key of upper CA could be used to forge this CA.) * (and we run in an endless loop aside from this.) */ // cert is not allowed to appear in PKI path Set excluded = new HashSet(); excluded.add(cert); params.setExcludedCerts(excluded); builder.build(params); validCerts.add(signingCert); } catch (Exception e) { } } Set checkKeys = new HashSet(); // trivially included if cert cannot be checked for key usage extension if (defaultCRLSignCert == null && defaultCRLSignKey != null) { checkKeys.add(defaultCRLSignKey); } AnnotatedException lastException = null; for (Iterator it = validCerts.iterator(); it.hasNext();) { X509Certificate signCert = (X509Certificate) it.next(); boolean[] keyusage = signCert.getKeyUsage(); if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN])) { lastException = new AnnotatedException( "Issuer certificate key usage extension does not permit CRL signing."); } else { checkKeys.add(signCert.getPublicKey()); } } if (checkKeys.isEmpty() && lastException == null) { throw new AnnotatedException( "Cannot find a valid issuer certificate."); } if (checkKeys.isEmpty() && lastException != null) { throw lastException; } return checkKeys; } protected static PublicKey processCRLG(X509CRL crl, Set keys) throws AnnotatedException { Exception lastException = null; try { for (Iterator it = keys.iterator(); it.hasNext();) { PublicKey key = (PublicKey) it.next(); crl.verify(key); return key; } } catch (Exception e) { lastException = e; } throw new AnnotatedException("Cannot verify CRL.", lastException); } protected static X509CRL processCRLH(Set deltacrls, PublicKey key) throws AnnotatedException { Exception lastException = null; try { for (Iterator it = deltacrls.iterator(); it.hasNext();) { X509CRL crl = (X509CRL) it.next(); crl.verify(key); return crl; } } catch (Exception e) { lastException = e; } throw new AnnotatedException("Cannot verify delta CRL.", lastException); } protected static Set processCRLA1i(Date currentDate, ExtendedPKIXParameters paramsPKIX, X509Certificate cert, X509CRL crl) throws AnnotatedException { Set set = new HashSet(); if (paramsPKIX.isUseDeltasEnabled()) { CRLDistPoint freshestCRL = null; try { freshestCRL = CRLDistPoint .getInstance(CertPathValidatorUtilities.getExtensionValue( cert, FRESHEST_CRL)); } catch (AnnotatedException e) { throw new AnnotatedException( "Freshest CRL extension could not be decoded from certificate.", e); } if (freshestCRL == null) { try { freshestCRL = CRLDistPoint .getInstance(CertPathValidatorUtilities .getExtensionValue(crl, FRESHEST_CRL)); } catch (AnnotatedException e) { throw new AnnotatedException( "Freshest CRL extension could not be decoded from CRL.", e); } } if (freshestCRL != null) { try { CertPathValidatorUtilities .addAdditionalStoresFromCRLDistributionPoint( freshestCRL, paramsPKIX); } catch (AnnotatedException e) { throw new AnnotatedException( "No new delta CRL locations could be added from Freshest CRL extension.", e); } // get delta CRL(s) try { set.addAll(CertPathValidatorUtilities.getDeltaCRLs( currentDate, paramsPKIX, crl)); } catch (AnnotatedException e) { throw new AnnotatedException( "Exception obtaining delta CRLs.", e); } } } return set; } protected static Set[] processCRLA1ii(Date currentDate, ExtendedPKIXParameters paramsPKIX, X509Certificate cert, X509CRL crl) throws AnnotatedException { Set completeSet = new HashSet(); Set deltaSet = new HashSet(); X509CRLStoreSelector crlselect = new X509CRLStoreSelector(); crlselect.setCertificateChecking(cert); crlselect.setCompleteCRLEnabled(true); crlselect.setDateAndTime(currentDate); try { crlselect.addIssuerName(crl.getIssuerX500Principal().getEncoded()); } catch (IOException e) { throw new AnnotatedException( "Cannot extract issuer from CRL." + e, e); } // get complete CRL(s) try { completeSet.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getAddionalStores())); completeSet.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getStores())); } catch (AnnotatedException e) { throw new AnnotatedException( "Exception obtaining complete CRLs.", e); } if (paramsPKIX.isUseDeltasEnabled()) { // get delta CRL(s) try { deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs( currentDate, paramsPKIX, crl)); } catch (AnnotatedException e) { throw new AnnotatedException( "Exception obtaining delta CRLs.", e); } } return new Set[] { completeSet, deltaSet }; } /** * If use-deltas is set, verify the issuer and scope of the delta CRL. * * @param deltaCRL The delta CRL. * @param completeCRL The complete CRL. * @param pkixParams The PKIX paramaters. * @throws AnnotatedException if an exception occurs. */ protected static void processCRLC(X509CRL deltaCRL, X509CRL completeCRL, ExtendedPKIXParameters pkixParams) throws AnnotatedException { IssuingDistributionPoint completeidp = null; try { completeidp = IssuingDistributionPoint .getInstance(CertPathValidatorUtilities.getExtensionValue( completeCRL, ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException( "Issuing distribution point extension could not be decoded.", e); } if (pkixParams.isUseDeltasEnabled()) { // (c) (1) if (!deltaCRL.getIssuerX500Principal().equals( completeCRL.getIssuerX500Principal())) { throw new AnnotatedException( "Complete CRL issuer does not match delta CRL issuer."); } // (c) (2) if (completeidp != null) { IssuingDistributionPoint deltaidp = null; try { deltaidp = IssuingDistributionPoint .getInstance(CertPathValidatorUtilities .getExtensionValue(deltaCRL, ISSUING_DISTRIBUTION_POINT)); } catch (Exception e) { throw new AnnotatedException( "Issuing distribution point extension from delta CRL could not be decoded.", e); } boolean match = false; if (completeidp == null) { if (deltaidp == null) { match = true; } } else { if (completeidp.equals(deltaidp)) { match = true; } } if (!match) { throw new AnnotatedException( "Issuing distribution point extension from delta CRL and complete CRL does not match."); } } // (c) (3) DERObject completeKeyIdentifier = null; try { completeKeyIdentifier = CertPathValidatorUtilities .getExtensionValue(deltaCRL, AUTHORITY_KEY_IDENTIFIER); } catch (AnnotatedException e) { throw new AnnotatedException( "Authority key identifier extension could not be extracted from complete CRL.", e); } DERObject deltaKeyIdentifier = null; try { deltaKeyIdentifier = CertPathValidatorUtilities .getExtensionValue(deltaCRL, AUTHORITY_KEY_IDENTIFIER); } catch (AnnotatedException e) { throw new AnnotatedException( "Authority key identifier extension could not be extracted from delta CRL.", e); } if (!completeKeyIdentifier.equals(deltaKeyIdentifier)) { throw new AnnotatedException( "Delta CRL authority key identifier does not match complete CRL authority key identifier."); } } } protected static void processCRLI(Date validDate, X509CRL deltacrl, BigInteger serialNumber, CertStatus certStatus, ExtendedPKIXParameters pkixParams) throws AnnotatedException { if (pkixParams.isUseDeltasEnabled()) { CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, serialNumber, certStatus); } } protected static void processCRLJ(Date validDate, X509CRL completecrl, BigInteger serialNumber, CertStatus certStatus) throws AnnotatedException { CertPathValidatorUtilities.getCertStatus(validDate, completecrl, serialNumber, certStatus); } /** * * Checks a distribution point for revocation information for the * certificate cert. * * @param dp The distribution point to consider. * @param paramsPKIX PKIX parameters. * @param cert Certificate to check if it is revoked. * @param validDate The date when the certificate revocation status should * be checked. * @param defaultCRLSignCert The issuer certificate of the certificate * cert. * @param defaultCRLSignKey The public key of the issuer certificate * defaultCRLSignCert. * @param certStatus The current certificate revocation status. * @param reasonMask The reasons mask which is already checked. * @param certPathCerts The certificates of the certification path. * @throws AnnotatedException if the certificate is revoked or the status * cannot be checked or some error occurs. */ private static void checkCRL(DistributionPoint dp, ExtendedPKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate defaultCRLSignCert, PublicKey defaultCRLSignKey, CertStatus certStatus, ReasonsMask reasonMask, List certPathCerts) throws AnnotatedException { Date currentDate = new Date(System.currentTimeMillis()); if (validDate.getTime() > currentDate.getTime()) { throw new AnnotatedException("Validation time is in future."); } // (a) /* * We always get timely valid CRLs, so there is no step (a) (1). * "locally cached" CRLs are assumed to be in getStore(), additional * CRLs must be enabled in the ExtendedPKIXParameters and are in * getAdditionalStore() */ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX); boolean validCrlFound = false; AnnotatedException lastException = null; Iterator crl_iter = crls.iterator(); while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons()) { try { X509CRL crl = (X509CRL) crl_iter.next(); // (d) ReasonsMask interimReasonsMask = processCRLD(crl, dp); // (e) /* * The reasons mask is updated at the end, so only valid CRLs * can update it. If this CRL does not contain new reasons it * must be ignored. */ if (!interimReasonsMask.hasNewReasons(reasonMask)) { continue; } // (f) Set keys = processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey, paramsPKIX); // (g) PublicKey key = processCRLG(crl, keys); X509CRL deltaCRL = null; if (paramsPKIX.isUseDeltasEnabled()) { // get delta CRLs Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs( currentDate, paramsPKIX, crl); // we only want one valid delta CRL // (h) deltaCRL = processCRLH(deltaCRLs, key); } /* * CRL must be be valid at the current time, not the validation * time. If a certificate is revoked with reason keyCompromise, * cACompromise, it can be used for forgery, also for the past. * This reason may not be contained in older CRLs. */ /* * in the chain model signatures stay valid also after the * certificate has been expired, so they do not have to be in * the CRL vality time */ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL) { /* * if a certificate has expired, but was revoked, it is not * more in the CRL, so it would be regarded as valid if the * first check is not done */ if (cert.getNotAfter().getTime() < crl.getThisUpdate() .getTime()) { throw new AnnotatedException( "No valid CRL for current time found."); } } processCRLB1(dp, cert, crl); // (b) (2) processCRLB2(dp, cert, crl); // (c) processCRLC(deltaCRL, crl, paramsPKIX); // (i) processCRLI(validDate, deltaCRL, cert.getSerialNumber(), certStatus, paramsPKIX); // (j) processCRLJ(validDate, crl, cert.getSerialNumber(), certStatus); // (k) if (certStatus.getCertStatus() == CRLReason.removeFromCRL) { certStatus.setCertStatus(CertStatus.UNREVOKED); } // update reasons mask reasonMask.addReasons(interimReasonsMask); validCrlFound = true; } catch (AnnotatedException e) { lastException = e; } } if (!validCrlFound) { throw lastException; } } /** * Checks a certificate if it is revoked. * * @param paramsPKIX PKIX parameters. * @param cert Certificate to check if it is revoked. * @param validDate The date when the certificate revocation status should * be checked. * * @param sign The issuer certificate of the certificate cert. * @param workingPublicKey The public key of the issuer certificate * sign. * @param certPathCerts The certificates of the certification path. * @throws AnnotatedException if the certificate is revoked or the status * cannot be checked or some error occurs. */ private static void checkCRLs(ExtendedPKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate sign, PublicKey workingPublicKey, List certPathCerts) throws AnnotatedException { AnnotatedException lastException = null; CRLDistPoint crldp = null; try { crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities .getExtensionValue(cert, CRL_DISTRIBUTION_POINTS)); } catch (Exception e) { throw new AnnotatedException( "CRL distribution point extension could not be read.", e); } try { CertPathValidatorUtilities .addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX); } catch (AnnotatedException e) { throw new AnnotatedException( "No additional CRL locations could be decoded from CRL distribution point extension.", e); } CertStatus certStatus = new CertStatus(); ReasonsMask reasonsMask = new ReasonsMask(); boolean validCrlFound = false; // for each distribution point if (crldp != null) { DistributionPoint dps[] = null; try { dps = crldp.getDistributionPoints(); } catch (Exception e) { throw new AnnotatedException( "Distribution points could not be read.", e); } try { for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++) { ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX .clone(); checkCRL(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts); validCrlFound = true; } } catch (AnnotatedException e) { lastException = new AnnotatedException( "No valid CRL for distribution point found.", e); } } /* * If the revocation status has not been determined, repeat the process * above with any available CRLs not specified in a distribution point * but issued by the certificate issuer. */ if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons()) { try { /* * assume a DP with both the reasons and the cRLIssuer fields * omitted and a distribution point name of the certificate * issuer. */ DERObject issuer = null; try { issuer = new ASN1InputStream(CertPathValidatorUtilities .getEncodedIssuerPrincipal(cert).getEncoded()) .readObject(); } catch (Exception e) { throw new AnnotatedException( "Issuer from certificate for CRL could not be reencoded.", e); } DistributionPoint dp = new DistributionPoint( new DistributionPointName(0, new GeneralNames( new GeneralName(GeneralName.directoryName, issuer))), null, null); ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX .clone(); checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts); validCrlFound = true; } catch (AnnotatedException e) { lastException = new AnnotatedException( "No valid CRL for distribution point found.", e); } } if (!validCrlFound) { throw new AnnotatedException("No valid CRL found.", lastException); } if (certStatus.getCertStatus() != CertStatus.UNREVOKED) { String message = "Certificate revocation after " + certStatus.getRevocationDate(); message += ", reason: " + crlReasons[certStatus.getCertStatus()]; throw new AnnotatedException(message); } if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED) { certStatus.setCertStatus(CertStatus.UNDETERMINED); } if (certStatus.getCertStatus() == CertStatus.UNDETERMINED) { throw new AnnotatedException( "Certificate status could not be determined."); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy