// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.pkix.jcajce;

import org.bouncycastle.util.Iterable;
import java.security.KeyStoreException;
import java.util.Enumeration;
import java.security.KeyStore;
import java.security.Provider;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
import org.bouncycastle.asn1.x509.ReasonFlags;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.DistributionPointName;
import java.security.cert.CertificateFactory;
import org.bouncycastle.asn1.x509.DistributionPoint;
import java.util.Collections;
import java.net.URI;
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.x509.GeneralNames;
import java.util.HashSet;
import org.bouncycastle.jcajce.PKIXCRLStoreSelector;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.util.Selector;
import java.security.cert.CertStoreException;
import java.security.cert.CRLSelector;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLSelector;
import java.util.Iterator;
import org.bouncycastle.util.CollectionStore;
import java.security.cert.X509Extension;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.jcajce.PKIXCRLStore;
import java.security.GeneralSecurityException;
import org.bouncycastle.jcajce.PKIXExtendedParameters;
import java.util.logging.Level;
import java.security.cert.PKIXParameters;
import java.security.cert.Certificate;
import java.security.cert.CertPathValidatorException;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import java.util.Collection;
import java.util.ArrayList;
import java.util.HashMap;
import java.security.cert.X509Certificate;
import java.security.PublicKey;
import java.util.Date;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import java.security.cert.CertStore;
import java.security.cert.CRL;
import org.bouncycastle.util.Store;
import java.util.List;
import java.security.cert.TrustAnchor;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import java.util.Map;
import java.util.logging.Logger;
import java.security.cert.PKIXCertPathChecker;

public class X509RevocationChecker extends PKIXCertPathChecker
{
    public static final int PKIX_VALIDITY_MODEL = 0;
    public static final int CHAIN_VALIDITY_MODEL = 1;
    private static Logger LOG;
    private final Map<X500Principal, Long> failures;
    private final Set<TrustAnchor> trustAnchors;
    private final boolean isCheckEEOnly;
    private final int validityModel;
    private final List<Store<CRL>> crls;
    private final List<CertStore> crlCertStores;
    private final JcaJceHelper helper;
    private final boolean canSoftFail;
    private final long failLogMaxTime;
    private final long failHardMaxTime;
    private final Date validationDate;
    private Date currentDate;
    private X500Principal workingIssuerName;
    private PublicKey workingPublicKey;
    private X509Certificate signingCert;
    protected static final String[] crlReasons;
    
    private X509RevocationChecker(final Builder builder) {
        this.failures = new HashMap<X500Principal, Long>();
        this.crls = new ArrayList<Store<CRL>>(builder.crls);
        this.crlCertStores = new ArrayList<CertStore>(builder.crlCertStores);
        this.isCheckEEOnly = builder.isCheckEEOnly;
        this.validityModel = builder.validityModel;
        this.trustAnchors = builder.trustAnchors;
        this.canSoftFail = builder.canSoftFail;
        this.failLogMaxTime = builder.failLogMaxTime;
        this.failHardMaxTime = builder.failHardMaxTime;
        this.validationDate = builder.validityDate;
        if (builder.provider != null) {
            this.helper = new ProviderJcaJceHelper(builder.provider);
        }
        else if (builder.providerName != null) {
            this.helper = new NamedJcaJceHelper(builder.providerName);
        }
        else {
            this.helper = new DefaultJcaJceHelper();
        }
    }
    
    @Override
    public void init(final boolean b) throws CertPathValidatorException {
        if (b) {
            throw new IllegalArgumentException("forward processing not supported");
        }
        this.currentDate = new Date();
        this.workingIssuerName = null;
    }
    
    @Override
    public boolean isForwardCheckingSupported() {
        return false;
    }
    
    @Override
    public Set<String> getSupportedExtensions() {
        return null;
    }
    
    @Override
    public void check(final Certificate certificate, final Collection<String> collection) throws CertPathValidatorException {
        final X509Certificate x509Certificate = (X509Certificate)certificate;
        if (this.isCheckEEOnly && x509Certificate.getBasicConstraints() != -1) {
            this.workingIssuerName = x509Certificate.getSubjectX500Principal();
            this.workingPublicKey = x509Certificate.getPublicKey();
            this.signingCert = x509Certificate;
            return;
        }
        TrustAnchor trustAnchor = null;
        if (this.workingIssuerName == null) {
            this.workingIssuerName = x509Certificate.getIssuerX500Principal();
            for (final TrustAnchor trustAnchor2 : this.trustAnchors) {
                if (this.workingIssuerName.equals(trustAnchor2.getCA()) || this.workingIssuerName.equals(trustAnchor2.getTrustedCert().getSubjectX500Principal())) {
                    trustAnchor = trustAnchor2;
                }
            }
            if (trustAnchor == null) {
                throw new CertPathValidatorException("no trust anchor found for " + this.workingIssuerName);
            }
            this.signingCert = trustAnchor.getTrustedCert();
            this.workingPublicKey = this.signingCert.getPublicKey();
        }
        final ArrayList list = new ArrayList<X500Principal>();
        PKIXExtendedParameters.Builder builder;
        try {
            final PKIXParameters pkixParameters = new PKIXParameters(this.trustAnchors);
            pkixParameters.setRevocationEnabled(false);
            pkixParameters.setDate(this.validationDate);
            for (int i = 0; i != this.crlCertStores.size(); ++i) {
                if (X509RevocationChecker.LOG.isLoggable(Level.INFO)) {
                    this.addIssuers(list, this.crlCertStores.get(i));
                }
                pkixParameters.addCertStore(this.crlCertStores.get(i));
            }
            builder = new PKIXExtendedParameters.Builder(pkixParameters);
            builder.setValidityModel(this.validityModel);
        }
        catch (final GeneralSecurityException ex) {
            throw new RuntimeException("error setting up baseParams: " + ex.getMessage());
        }
        for (int j = 0; j != this.crls.size(); ++j) {
            if (X509RevocationChecker.LOG.isLoggable(Level.INFO)) {
                this.addIssuers(list, this.crls.get(j));
            }
            builder.addCRLStore(new LocalCRLStore(this.crls.get(j)));
        }
        if (list.isEmpty()) {
            X509RevocationChecker.LOG.log(Level.INFO, "configured with 0 pre-loaded CRLs");
        }
        else if (X509RevocationChecker.LOG.isLoggable(Level.FINE)) {
            for (int k = 0; k != list.size(); ++k) {
                X509RevocationChecker.LOG.log(Level.FINE, "configuring with CRL for issuer \"" + list.get(k) + "\"");
            }
        }
        else {
            X509RevocationChecker.LOG.log(Level.INFO, "configured with " + list.size() + " pre-loaded CRLs");
        }
        final PKIXExtendedParameters build = builder.build();
        final Date validityDate = RevocationUtilities.getValidityDate(build, this.validationDate);
        Label_1005: {
            try {
                this.checkCRLs(build, this.currentDate, validityDate, x509Certificate, this.signingCert, this.workingPublicKey, new ArrayList(), this.helper);
            }
            catch (final AnnotatedException ex2) {
                throw new CertPathValidatorException(ex2.getMessage(), ex2.getCause());
            }
            catch (final CRLNotFoundException ex3) {
                if (null == x509Certificate.getExtensionValue(Extension.cRLDistributionPoints.getId())) {
                    throw ex3;
                }
                Set<CRL> downloadCRLs;
                try {
                    downloadCRLs = this.downloadCRLs(x509Certificate.getIssuerX500Principal(), validityDate, RevocationUtilities.getExtensionValue(x509Certificate, Extension.cRLDistributionPoints), this.helper);
                }
                catch (final AnnotatedException ex4) {
                    throw new CertPathValidatorException(ex4.getMessage(), ex4.getCause());
                }
                if (!downloadCRLs.isEmpty()) {
                    try {
                        builder.addCRLStore(new LocalCRLStore(new CollectionStore<CRL>(downloadCRLs)));
                        final PKIXExtendedParameters build2 = builder.build();
                        this.checkCRLs(build2, this.currentDate, RevocationUtilities.getValidityDate(build2, this.validationDate), x509Certificate, this.signingCert, this.workingPublicKey, new ArrayList(), this.helper);
                        break Label_1005;
                    }
                    catch (final AnnotatedException ex5) {
                        throw new CertPathValidatorException(ex5.getMessage(), ex5.getCause());
                    }
                }
                if (!this.canSoftFail) {
                    throw ex3;
                }
                final X500Principal issuerX500Principal = x509Certificate.getIssuerX500Principal();
                final Long n = this.failures.get(issuerX500Principal);
                if (n != null) {
                    final long n2 = System.currentTimeMillis() - n;
                    if (this.failHardMaxTime != -1L && this.failHardMaxTime < n2) {
                        throw ex3;
                    }
                    if (n2 < this.failLogMaxTime) {
                        X509RevocationChecker.LOG.log(Level.WARNING, "soft failing for issuer: \"" + issuerX500Principal + "\"");
                    }
                    else {
                        X509RevocationChecker.LOG.log(Level.SEVERE, "soft failing for issuer: \"" + issuerX500Principal + "\"");
                    }
                }
                else {
                    this.failures.put(issuerX500Principal, System.currentTimeMillis());
                }
            }
        }
        this.signingCert = x509Certificate;
        this.workingPublicKey = x509Certificate.getPublicKey();
        this.workingIssuerName = x509Certificate.getSubjectX500Principal();
    }
    
    private void addIssuers(final List<X500Principal> list, final CertStore certStore) throws CertStoreException {
        certStore.getCRLs(new X509CRLSelector() {
            @Override
            public boolean match(final CRL crl) {
                if (!(crl instanceof X509CRL)) {
                    return false;
                }
                list.add(((X509CRL)crl).getIssuerX500Principal());
                return false;
            }
        });
    }
    
    private void addIssuers(final List<X500Principal> list, final Store<CRL> store) {
        store.getMatches(new Selector<CRL>() {
            @Override
            public boolean match(final CRL crl) {
                if (!(crl instanceof X509CRL)) {
                    return false;
                }
                list.add(((X509CRL)crl).getIssuerX500Principal());
                return false;
            }
            
            @Override
            public Object clone() {
                return this;
            }
        });
    }
    
    private Set<CRL> downloadCRLs(final X500Principal issuer, final Date date, final ASN1Primitive asn1Primitive, final JcaJceHelper jcaJceHelper) {
        final DistributionPoint[] distributionPoints = CRLDistPoint.getInstance(asn1Primitive).getDistributionPoints();
        CertificateFactory certificateFactory;
        try {
            certificateFactory = jcaJceHelper.createCertificateFactory("X.509");
        }
        catch (final Exception thrown) {
            if (X509RevocationChecker.LOG.isLoggable(Level.FINE)) {
                X509RevocationChecker.LOG.log(Level.FINE, "could not create certFact: " + thrown.getMessage(), thrown);
            }
            else {
                X509RevocationChecker.LOG.log(Level.INFO, "could not create certFact: " + thrown.getMessage());
            }
            return null;
        }
        final X509CRLSelector x509CRLSelector = new X509CRLSelector();
        x509CRLSelector.addIssuer(issuer);
        final PKIXCRLStoreSelector<? extends CRL> build = new PKIXCRLStoreSelector.Builder(x509CRLSelector).build();
        final HashSet set = new HashSet();
        for (int i = 0; i != distributionPoints.length; ++i) {
            final DistributionPointName distributionPoint = distributionPoints[i].getDistributionPoint();
            if (distributionPoint != null && distributionPoint.getType() == 0) {
                final GeneralName[] names = GeneralNames.getInstance(distributionPoint.getName()).getNames();
                for (int j = 0; j != names.length; ++j) {
                    final GeneralName generalName = names[j];
                    if (generalName.getTagNo() == 6) {
                        URI uri = null;
                        try {
                            uri = new URI(((ASN1String)generalName.getName()).getString());
                            final PKIXCRLStore crl = CrlCache.getCrl(certificateFactory, this.validationDate, uri);
                            if (crl != null) {
                                set.addAll(PKIXCRLUtil.findCRLs(build, date, Collections.EMPTY_LIST, Collections.singletonList(crl)));
                            }
                        }
                        catch (final Exception thrown2) {
                            if (X509RevocationChecker.LOG.isLoggable(Level.FINE)) {
                                X509RevocationChecker.LOG.log(Level.FINE, "CrlDP " + uri + " ignored: " + thrown2.getMessage(), thrown2);
                            }
                            else {
                                X509RevocationChecker.LOG.log(Level.INFO, "CrlDP " + uri + " ignored: " + thrown2.getMessage());
                            }
                        }
                    }
                }
            }
        }
        return set;
    }
    
    static List<PKIXCRLStore> getAdditionalStoresFromCRLDistributionPoint(final CRLDistPoint crlDistPoint, final Map<GeneralName, PKIXCRLStore> map) throws AnnotatedException {
        if (crlDistPoint == null) {
            return (List<PKIXCRLStore>)Collections.emptyList();
        }
        DistributionPoint[] distributionPoints;
        try {
            distributionPoints = crlDistPoint.getDistributionPoints();
        }
        catch (final Exception ex) {
            throw new AnnotatedException("could not read distribution points could not be read", ex);
        }
        final ArrayList list = new ArrayList();
        for (int i = 0; i < distributionPoints.length; ++i) {
            final DistributionPointName distributionPoint = distributionPoints[i].getDistributionPoint();
            if (distributionPoint != null && distributionPoint.getType() == 0) {
                final GeneralName[] names = GeneralNames.getInstance(distributionPoint.getName()).getNames();
                for (int j = 0; j < names.length; ++j) {
                    final PKIXCRLStore pkixcrlStore = map.get(names[j]);
                    if (pkixcrlStore != null) {
                        list.add(pkixcrlStore);
                    }
                }
            }
        }
        return list;
    }
    
    protected void checkCRLs(final PKIXExtendedParameters pkixExtendedParameters, final Date date, final Date date2, final X509Certificate x509Certificate, final X509Certificate x509Certificate2, final PublicKey publicKey, final List list, final JcaJceHelper jcaJceHelper) throws AnnotatedException, CertPathValidatorException {
        CRLDistPoint instance;
        try {
            instance = CRLDistPoint.getInstance(RevocationUtilities.getExtensionValue(x509Certificate, Extension.cRLDistributionPoints));
        }
        catch (final Exception ex) {
            throw new AnnotatedException("cannot read CRL distribution point extension", ex);
        }
        final CertStatus certStatus = new CertStatus();
        final ReasonsMask reasonsMask = new ReasonsMask();
        Throwable t = null;
        boolean b = false;
        if (instance != null) {
            DistributionPoint[] distributionPoints;
            try {
                distributionPoints = instance.getDistributionPoints();
            }
            catch (final Exception ex2) {
                throw new AnnotatedException("cannot read distribution points", ex2);
            }
            if (distributionPoints != null) {
                final PKIXExtendedParameters.Builder builder = new PKIXExtendedParameters.Builder(pkixExtendedParameters);
                try {
                    final Iterator<PKIXCRLStore> iterator = (Iterator<PKIXCRLStore>)getAdditionalStoresFromCRLDistributionPoint(instance, pkixExtendedParameters.getNamedCRLStoreMap()).iterator();
                    while (iterator.hasNext()) {
                        builder.addCRLStore(iterator.next());
                    }
                }
                catch (final AnnotatedException ex3) {
                    throw new AnnotatedException("no additional CRL locations could be decoded from CRL distribution point extension", ex3);
                }
                final PKIXExtendedParameters build = builder.build();
                final Date validityDate = RevocationUtilities.getValidityDate(build, date);
                for (int n = 0; n < distributionPoints.length && certStatus.getCertStatus() == 11 && !reasonsMask.isAllReasons(); ++n) {
                    try {
                        RFC3280CertPathUtilities.checkCRL(distributionPoints[n], build, date, validityDate, x509Certificate, x509Certificate2, publicKey, certStatus, reasonsMask, list, jcaJceHelper);
                        b = true;
                    }
                    catch (final AnnotatedException ex4) {
                        t = ex4;
                    }
                }
            }
        }
        if (certStatus.getCertStatus() == 11 && !reasonsMask.isAllReasons()) {
            try {
                RFC3280CertPathUtilities.checkCRL(new DistributionPoint(new DistributionPointName(0, new GeneralNames(new GeneralName(4, X500Name.getInstance(x509Certificate.getIssuerX500Principal().getEncoded())))), null, null), (PKIXExtendedParameters)pkixExtendedParameters.clone(), date, date2, x509Certificate, x509Certificate2, publicKey, certStatus, reasonsMask, list, jcaJceHelper);
                b = true;
            }
            catch (final AnnotatedException ex5) {
                t = ex5;
            }
        }
        if (!b) {
            if (t instanceof AnnotatedException) {
                throw new CRLNotFoundException("no valid CRL found", t);
            }
            throw new CRLNotFoundException("no valid CRL found");
        }
        else {
            if (certStatus.getCertStatus() != 11) {
                final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
                simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                throw new AnnotatedException("certificate [issuer=\"" + x509Certificate.getIssuerX500Principal() + "\",serialNumber=" + x509Certificate.getSerialNumber() + ",subject=\"" + x509Certificate.getSubjectX500Principal() + "\"] revoked after " + simpleDateFormat.format(certStatus.getRevocationDate()) + ", reason: " + X509RevocationChecker.crlReasons[certStatus.getCertStatus()]);
            }
            if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == 11) {
                certStatus.setCertStatus(12);
            }
            if (certStatus.getCertStatus() == 12) {
                throw new AnnotatedException("certificate status could not be determined");
            }
        }
    }
    
    @Override
    public Object clone() {
        return this;
    }
    
    static {
        X509RevocationChecker.LOG = Logger.getLogger(X509RevocationChecker.class.getName());
        crlReasons = new String[] { "unspecified", "keyCompromise", "cACompromise", "affiliationChanged", "superseded", "cessationOfOperation", "certificateHold", "unknown", "removeFromCRL", "privilegeWithdrawn", "aACompromise" };
    }
    
    public static class Builder
    {
        private Set<TrustAnchor> trustAnchors;
        private List<CertStore> crlCertStores;
        private List<Store<CRL>> crls;
        private boolean isCheckEEOnly;
        private int validityModel;
        private Provider provider;
        private String providerName;
        private boolean canSoftFail;
        private long failLogMaxTime;
        private long failHardMaxTime;
        private Date validityDate;
        
        public Builder(final TrustAnchor o) {
            this.crlCertStores = new ArrayList<CertStore>();
            this.crls = new ArrayList<Store<CRL>>();
            this.validityModel = 0;
            this.validityDate = new Date();
            this.trustAnchors = Collections.singleton(o);
        }
        
        public Builder(final Set<TrustAnchor> c) {
            this.crlCertStores = new ArrayList<CertStore>();
            this.crls = new ArrayList<Store<CRL>>();
            this.validityModel = 0;
            this.validityDate = new Date();
            this.trustAnchors = new HashSet<TrustAnchor>(c);
        }
        
        public Builder(final KeyStore keyStore) throws KeyStoreException {
            this.crlCertStores = new ArrayList<CertStore>();
            this.crls = new ArrayList<Store<CRL>>();
            this.validityModel = 0;
            this.validityDate = new Date();
            this.trustAnchors = new HashSet<TrustAnchor>();
            final Enumeration<String> aliases = keyStore.aliases();
            while (aliases.hasMoreElements()) {
                final String s = aliases.nextElement();
                if (keyStore.isCertificateEntry(s)) {
                    this.trustAnchors.add(new TrustAnchor((X509Certificate)keyStore.getCertificate(s), null));
                }
            }
        }
        
        public Builder addCrls(final CertStore certStore) {
            this.crlCertStores.add(certStore);
            return this;
        }
        
        public Builder addCrls(final Store<CRL> store) {
            this.crls.add(store);
            return this;
        }
        
        public Builder setDate(final Date date) {
            this.validityDate = new Date(date.getTime());
            return this;
        }
        
        public Builder setCheckEndEntityOnly(final boolean isCheckEEOnly) {
            this.isCheckEEOnly = isCheckEEOnly;
            return this;
        }
        
        public Builder setSoftFail(final boolean canSoftFail, final long failLogMaxTime) {
            this.canSoftFail = canSoftFail;
            this.failLogMaxTime = failLogMaxTime;
            this.failHardMaxTime = -1L;
            return this;
        }
        
        public Builder setSoftFailHardLimit(final boolean canSoftFail, final long failHardMaxTime) {
            this.canSoftFail = canSoftFail;
            this.failLogMaxTime = failHardMaxTime * 3L / 4L;
            this.failHardMaxTime = failHardMaxTime;
            return this;
        }
        
        public Builder setValidityModel(final int validityModel) {
            this.validityModel = validityModel;
            return this;
        }
        
        public Builder usingProvider(final Provider provider) {
            this.provider = provider;
            return this;
        }
        
        public Builder usingProvider(final String providerName) {
            this.providerName = providerName;
            return this;
        }
        
        public X509RevocationChecker build() {
            return new X509RevocationChecker(this, null);
        }
    }
    
    private static class LocalCRLStore implements PKIXCRLStore<CRL>, Iterable<CRL>
    {
        private Collection<CRL> _local;
        
        public LocalCRLStore(final Store<CRL> store) {
            this._local = new ArrayList<CRL>(store.getMatches(null));
        }
        
        @Override
        public Collection<CRL> getMatches(final Selector<CRL> selector) {
            if (selector == null) {
                return new ArrayList<CRL>(this._local);
            }
            final ArrayList list = new ArrayList();
            for (final CRL crl : this._local) {
                if (selector.match(crl)) {
                    list.add(crl);
                }
            }
            return list;
        }
        
        @Override
        public Iterator<CRL> iterator() {
            return this.getMatches(null).iterator();
        }
    }
}
