0N/A/*
6037N/A * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.provider.certpath;
0N/A
0N/Aimport java.math.BigInteger;
0N/Aimport java.util.Arrays;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.Collection;
0N/Aimport java.util.Collections;
0N/Aimport java.util.Date;
0N/Aimport java.util.List;
0N/Aimport java.util.HashSet;
0N/Aimport java.util.Set;
0N/Aimport java.util.Iterator;
0N/Aimport java.security.InvalidAlgorithmParameterException;
0N/Aimport java.security.NoSuchAlgorithmException;
0N/Aimport java.security.PublicKey;
6106N/Aimport java.security.cert.Certificate;
6106N/Aimport java.security.cert.CertificateException;
6106N/Aimport java.security.cert.CertificateRevokedException;
6106N/Aimport java.security.cert.CertPathBuilder;
6106N/Aimport java.security.cert.CertPathBuilderException;
6106N/Aimport java.security.cert.CertPathValidatorException;
585N/Aimport java.security.cert.CertPathValidatorException.BasicReason;
6106N/Aimport java.security.cert.CertStore;
6106N/Aimport java.security.cert.CollectionCertStoreParameters;
6106N/Aimport java.security.cert.CRLException;
6106N/Aimport java.security.cert.CRLReason;
6106N/Aimport java.security.cert.PKIXBuilderParameters;
6106N/Aimport java.security.cert.PKIXCertPathBuilderResult;
6106N/Aimport java.security.cert.PKIXCertPathChecker;
6106N/Aimport java.security.cert.PKIXParameters;
6106N/Aimport java.security.cert.TrustAnchor;
6106N/Aimport java.security.cert.X509Certificate;
6106N/Aimport java.security.cert.X509CertSelector;
6106N/Aimport java.security.cert.X509CRL;
6106N/Aimport java.security.cert.X509CRLEntry;
6106N/Aimport java.security.cert.X509CRLSelector;
0N/Aimport java.security.interfaces.DSAPublicKey;
0N/Aimport javax.security.auth.x500.X500Principal;
0N/Aimport sun.security.util.Debug;
0N/Aimport sun.security.x509.AccessDescription;
0N/Aimport sun.security.x509.AuthorityInfoAccessExtension;
0N/Aimport sun.security.x509.CRLDistributionPointsExtension;
0N/Aimport sun.security.x509.DistributionPoint;
0N/Aimport sun.security.x509.GeneralName;
0N/Aimport sun.security.x509.GeneralNames;
0N/Aimport sun.security.x509.PKIXExtensions;
0N/Aimport sun.security.x509.X500Name;
0N/Aimport sun.security.x509.X509CertImpl;
0N/Aimport sun.security.x509.X509CRLEntryImpl;
0N/A
0N/A/**
0N/A * CrlRevocationChecker is a <code>PKIXCertPathChecker</code> that checks
0N/A * revocation status information on a PKIX certificate using CRLs obtained
0N/A * from one or more <code>CertStores</code>. This is based on section 6.3
0N/A * of RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt).
0N/A *
0N/A * @since 1.4
0N/A * @author Seth Proctor
0N/A * @author Steve Hanna
0N/A */
0N/Aclass CrlRevocationChecker extends PKIXCertPathChecker {
0N/A
0N/A private static final Debug debug = Debug.getInstance("certpath");
0N/A private final TrustAnchor mAnchor;
0N/A private final List<CertStore> mStores;
0N/A private final String mSigProvider;
0N/A private final Date mCurrentTime;
0N/A private PublicKey mPrevPubKey;
0N/A private boolean mCRLSignFlag;
0N/A private HashSet<X509CRL> mPossibleCRLs;
0N/A private HashSet<X509CRL> mApprovedCRLs;
0N/A private final PKIXParameters mParams;
0N/A private static final boolean [] mCrlSignUsage =
0N/A { false, false, false, false, false, false, true };
0N/A private static final boolean[] ALL_REASONS =
0N/A {true, true, true, true, true, true, true, true, true};
1652N/A private boolean mOnlyEECert = false;
0N/A
1421N/A // Maximum clock skew in milliseconds (15 minutes) allowed when checking
1421N/A // validity of CRLs
1421N/A private static final long MAX_CLOCK_SKEW = 900000;
1421N/A
0N/A /**
0N/A * Creates a <code>CrlRevocationChecker</code>.
0N/A *
0N/A * @param anchor anchor selected to validate the target certificate
0N/A * @param params <code>PKIXParameters</code> to be used for
0N/A * finding certificates and CRLs, etc.
0N/A */
0N/A CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params)
0N/A throws CertPathValidatorException
0N/A {
0N/A this(anchor, params, null);
0N/A }
0N/A
0N/A /**
0N/A * Creates a <code>CrlRevocationChecker</code>, allowing
0N/A * extra certificates to be supplied beyond those contained
0N/A * in the <code>PKIXParameters</code>.
0N/A *
0N/A * @param anchor anchor selected to validate the target certificate
0N/A * @param params <code>PKIXParameters</code> to be used for
0N/A * finding certificates and CRLs, etc.
0N/A * @param certs a <code>Collection</code> of certificates
0N/A * that may be useful, beyond those available
0N/A * through <code>params</code> (<code>null</code>
0N/A * if none)
0N/A */
0N/A CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
0N/A Collection<X509Certificate> certs) throws CertPathValidatorException
0N/A {
1652N/A this(anchor, params, certs, false);
1652N/A }
1652N/A
1652N/A CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
1652N/A Collection<X509Certificate> certs, boolean onlyEECert)
1652N/A throws CertPathValidatorException {
0N/A mAnchor = anchor;
0N/A mParams = params;
0N/A mStores = new ArrayList<CertStore>(params.getCertStores());
0N/A mSigProvider = params.getSigProvider();
0N/A if (certs != null) {
0N/A try {
0N/A mStores.add(CertStore.getInstance("Collection",
0N/A new CollectionCertStoreParameters(certs)));
0N/A } catch (Exception e) {
0N/A // should never occur but not necessarily fatal, so log it,
0N/A // ignore and continue
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker: " +
0N/A "error creating Collection CertStore: " + e);
0N/A }
0N/A }
0N/A }
0N/A Date testDate = params.getDate();
0N/A mCurrentTime = (testDate != null ? testDate : new Date());
1652N/A mOnlyEECert = onlyEECert;
0N/A init(false);
0N/A }
0N/A
0N/A /**
0N/A * Initializes the internal state of the checker from parameters
0N/A * specified in the constructor
0N/A */
0N/A public void init(boolean forward) throws CertPathValidatorException
0N/A {
0N/A if (!forward) {
0N/A if (mAnchor != null) {
0N/A if (mAnchor.getCAPublicKey() != null) {
0N/A mPrevPubKey = mAnchor.getCAPublicKey();
0N/A } else {
0N/A mPrevPubKey = mAnchor.getTrustedCert().getPublicKey();
0N/A }
0N/A } else {
0N/A mPrevPubKey = null;
0N/A }
0N/A mCRLSignFlag = true;
0N/A } else {
0N/A throw new CertPathValidatorException("forward checking "
0N/A + "not supported");
0N/A }
0N/A }
0N/A
0N/A public boolean isForwardCheckingSupported() {
0N/A return false;
0N/A }
0N/A
0N/A public Set<String> getSupportedExtensions() {
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Performs the revocation status check on the certificate using
0N/A * its internal state.
0N/A *
0N/A * @param cert the Certificate
0N/A * @param unresolvedCritExts a Collection of the unresolved critical
0N/A * extensions
0N/A * @exception CertPathValidatorException Exception thrown if
0N/A * certificate does not verify
0N/A */
0N/A public void check(Certificate cert, Collection<String> unresolvedCritExts)
0N/A throws CertPathValidatorException
0N/A {
0N/A X509Certificate currCert = (X509Certificate) cert;
0N/A verifyRevocationStatus(currCert, mPrevPubKey, mCRLSignFlag, true);
0N/A
0N/A // Make new public key if parameters are missing
0N/A PublicKey cKey = currCert.getPublicKey();
0N/A if (cKey instanceof DSAPublicKey &&
0N/A ((DSAPublicKey)cKey).getParams() == null) {
0N/A // cKey needs to inherit DSA parameters from prev key
0N/A cKey = BasicChecker.makeInheritedParamsKey(cKey, mPrevPubKey);
0N/A }
0N/A mPrevPubKey = cKey;
0N/A mCRLSignFlag = certCanSignCrl(currCert);
0N/A }
0N/A
0N/A /**
0N/A * Performs the revocation status check on the certificate using
0N/A * the provided state variables, as well as the constant internal
0N/A * data.
0N/A *
0N/A * @param currCert the Certificate
0N/A * @param prevKey the previous PublicKey in the chain
0N/A * @param signFlag a boolean as returned from the last call, or true
0N/A * if this is the first cert in the chain
0N/A * @return a boolean specifying if the cert is allowed to vouch for the
0N/A * validity of a CRL for the next iteration
0N/A * @exception CertPathValidatorException Exception thrown if
0N/A * certificate does not verify.
0N/A */
0N/A public boolean check(X509Certificate currCert, PublicKey prevKey,
0N/A boolean signFlag) throws CertPathValidatorException
0N/A {
0N/A verifyRevocationStatus(currCert, prevKey, signFlag, true);
0N/A return certCanSignCrl(currCert);
0N/A }
0N/A
0N/A /**
0N/A * Checks that a cert can be used to verify a CRL.
0N/A *
0N/A * @param currCert an X509Certificate to check
0N/A * @return a boolean specifying if the cert is allowed to vouch for the
0N/A * validity of a CRL
0N/A */
0N/A static boolean certCanSignCrl(X509Certificate currCert) {
0N/A // if the cert doesn't include the key usage ext, or
0N/A // the key usage ext asserts cRLSigning, return true,
0N/A // otherwise return false.
0N/A boolean[] kbools = currCert.getKeyUsage();
0N/A if (kbools != null) {
0N/A return kbools[6];
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Internal method to start the verification of a cert
0N/A */
0N/A private void verifyRevocationStatus(X509Certificate currCert,
0N/A PublicKey prevKey, boolean signFlag, boolean allowSeparateKey)
0N/A throws CertPathValidatorException
0N/A {
0N/A verifyRevocationStatus(currCert, prevKey, signFlag,
3998N/A allowSeparateKey, null, mParams.getTrustAnchors());
0N/A }
0N/A
0N/A /**
0N/A * Internal method to start the verification of a cert
0N/A * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
0N/A * whose revocation status depends on the
0N/A * non-revoked status of this cert. To avoid
0N/A * circular dependencies, we assume they're
0N/A * revoked while checking the revocation
0N/A * status of this cert.
3998N/A * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
0N/A */
0N/A private void verifyRevocationStatus(X509Certificate currCert,
0N/A PublicKey prevKey, boolean signFlag, boolean allowSeparateKey,
3998N/A Set<X509Certificate> stackedCerts,
3998N/A Set<TrustAnchor> trustAnchors) throws CertPathValidatorException {
0N/A
0N/A String msg = "revocation status";
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.verifyRevocationStatus()" +
0N/A " ---checking " + msg + "...");
0N/A }
0N/A
1652N/A if (mOnlyEECert && currCert.getBasicConstraints() != -1) {
1652N/A if (debug != null) {
1652N/A debug.println("Skipping revocation check, not end entity cert");
1652N/A }
1652N/A return;
1652N/A }
1652N/A
0N/A // reject circular dependencies - RFC 3280 is not explicit on how
0N/A // to handle this, so we feel it is safest to reject them until
0N/A // the issue is resolved in the PKIX WG.
0N/A if ((stackedCerts != null) && stackedCerts.contains(currCert)) {
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.verifyRevocationStatus()" +
0N/A " circular dependency");
0N/A }
0N/A throw new CertPathValidatorException
585N/A ("Could not determine revocation status", null, null, -1,
585N/A BasicReason.UNDETERMINED_REVOCATION_STATUS);
0N/A }
0N/A
0N/A // init the state for this run
0N/A mPossibleCRLs = new HashSet<X509CRL>();
0N/A mApprovedCRLs = new HashSet<X509CRL>();
0N/A boolean[] reasonsMask = new boolean[9];
0N/A
0N/A try {
0N/A X509CRLSelector sel = new X509CRLSelector();
0N/A sel.setCertificateChecking(currCert);
1421N/A CertPathHelper.setDateAndTime(sel, mCurrentTime, MAX_CLOCK_SKEW);
0N/A
0N/A for (CertStore mStore : mStores) {
0N/A for (java.security.cert.CRL crl : mStore.getCRLs(sel)) {
0N/A mPossibleCRLs.add((X509CRL)crl);
0N/A }
0N/A }
0N/A // all CRLs returned by the DP Fetcher have also been verified
6037N/A mApprovedCRLs.addAll(DistributionPointFetcher.getCRLs(sel, signFlag,
6037N/A prevKey, mSigProvider, mStores, reasonsMask, trustAnchors,
4114N/A mParams.getDate()));
0N/A } catch (Exception e) {
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.verifyRevocationStatus() "
0N/A + "unexpected exception: " + e.getMessage());
0N/A }
0N/A throw new CertPathValidatorException(e);
0N/A }
0N/A
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
0N/A "crls.size() = " + mPossibleCRLs.size());
0N/A }
0N/A if (!mPossibleCRLs.isEmpty()) {
0N/A // Now that we have a list of possible CRLs, see which ones can
0N/A // be approved
0N/A mApprovedCRLs.addAll(verifyPossibleCRLs(mPossibleCRLs, currCert,
3998N/A signFlag, prevKey, reasonsMask, trustAnchors));
0N/A }
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
0N/A "approved crls.size() = " + mApprovedCRLs.size());
0N/A }
0N/A
0N/A // make sure that we have at least one CRL that _could_ cover
0N/A // the certificate in question and all reasons are covered
0N/A if (mApprovedCRLs.isEmpty() ||
0N/A !Arrays.equals(reasonsMask, ALL_REASONS)) {
0N/A if (allowSeparateKey) {
0N/A verifyWithSeparateSigningKey(currCert, prevKey, signFlag,
0N/A stackedCerts);
0N/A return;
0N/A } else {
0N/A throw new CertPathValidatorException
585N/A ("Could not determine revocation status", null, null, -1,
585N/A BasicReason.UNDETERMINED_REVOCATION_STATUS);
0N/A }
0N/A }
0N/A
0N/A // See if the cert is in the set of approved crls.
0N/A if (debug != null) {
0N/A BigInteger sn = currCert.getSerialNumber();
3998N/A debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
3998N/A "starting the final sweep...");
0N/A debug.println("CrlRevocationChecker.verifyRevocationStatus" +
3998N/A " cert SN: " + sn.toString());
0N/A }
0N/A
0N/A CRLReason reasonCode = CRLReason.UNSPECIFIED;
0N/A X509CRLEntryImpl entry = null;
0N/A for (X509CRL crl : mApprovedCRLs) {
0N/A X509CRLEntry e = crl.getRevokedCertificate(currCert);
0N/A if (e != null) {
0N/A try {
0N/A entry = X509CRLEntryImpl.toImpl(e);
0N/A } catch (CRLException ce) {
0N/A throw new CertPathValidatorException(ce);
0N/A }
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.verifyRevocationStatus"
0N/A + " CRL entry: " + entry.toString());
0N/A }
0N/A
0N/A /*
0N/A * Abort CRL validation and throw exception if there are any
0N/A * unrecognized critical CRL entry extensions (see section
0N/A * 5.3 of RFC 3280).
0N/A */
0N/A Set<String> unresCritExts = entry.getCriticalExtensionOIDs();
0N/A if (unresCritExts != null && !unresCritExts.isEmpty()) {
0N/A /* remove any that we will process */
0N/A unresCritExts.remove
0N/A (PKIXExtensions.ReasonCode_Id.toString());
0N/A unresCritExts.remove
0N/A (PKIXExtensions.CertificateIssuer_Id.toString());
0N/A if (!unresCritExts.isEmpty()) {
0N/A if (debug != null) {
0N/A debug.println("Unrecognized "
0N/A + "critical extension(s) in revoked CRL entry: "
0N/A + unresCritExts);
0N/A }
0N/A throw new CertPathValidatorException
585N/A ("Could not determine revocation status", null, null,
585N/A -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
0N/A }
0N/A }
0N/A
0N/A reasonCode = entry.getRevocationReason();
0N/A if (reasonCode == null) {
0N/A reasonCode = CRLReason.UNSPECIFIED;
0N/A }
585N/A Throwable t = new CertificateRevokedException
585N/A (entry.getRevocationDate(), reasonCode,
585N/A crl.getIssuerX500Principal(), entry.getExtensions());
585N/A throw new CertPathValidatorException(t.getMessage(), t,
585N/A null, -1, BasicReason.REVOKED);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * We have a cert whose revocation status couldn't be verified by
0N/A * a CRL issued by the cert that issued the CRL. See if we can
0N/A * find a valid CRL issued by a separate key that can verify the
0N/A * revocation status of this certificate.
0N/A * <p>
0N/A * Note that this does not provide support for indirect CRLs,
0N/A * only CRLs signed with a different key (but the same issuer
0N/A * name) as the certificate being checked.
0N/A *
0N/A * @param currCert the <code>X509Certificate</code> to be checked
0N/A * @param prevKey the <code>PublicKey</code> that failed
0N/A * @param signFlag <code>true</code> if that key was trusted to sign CRLs
0N/A * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
0N/A * whose revocation status depends on the
0N/A * non-revoked status of this cert. To avoid
0N/A * circular dependencies, we assume they're
0N/A * revoked while checking the revocation
0N/A * status of this cert.
0N/A * @throws CertPathValidatorException if the cert's revocation status
0N/A * cannot be verified successfully with another key
0N/A */
0N/A private void verifyWithSeparateSigningKey(X509Certificate currCert,
0N/A PublicKey prevKey, boolean signFlag, Set<X509Certificate> stackedCerts)
0N/A throws CertPathValidatorException {
0N/A String msg = "revocation status";
0N/A if (debug != null) {
0N/A debug.println(
0N/A "CrlRevocationChecker.verifyWithSeparateSigningKey()" +
0N/A " ---checking " + msg + "...");
0N/A }
0N/A
0N/A // reject circular dependencies - RFC 3280 is not explicit on how
0N/A // to handle this, so we feel it is safest to reject them until
0N/A // the issue is resolved in the PKIX WG.
0N/A if ((stackedCerts != null) && stackedCerts.contains(currCert)) {
0N/A if (debug != null) {
0N/A debug.println(
0N/A "CrlRevocationChecker.verifyWithSeparateSigningKey()" +
0N/A " circular dependency");
0N/A }
0N/A throw new CertPathValidatorException
585N/A ("Could not determine revocation status", null, null,
585N/A -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
0N/A }
0N/A
0N/A // If prevKey wasn't trusted, maybe we just didn't have the right
0N/A // path to it. Don't rule that key out.
0N/A if (!signFlag) {
0N/A prevKey = null;
0N/A }
0N/A
0N/A // Try to find another key that might be able to sign
0N/A // CRLs vouching for this cert.
0N/A buildToNewKey(currCert, prevKey, stackedCerts);
0N/A }
0N/A
0N/A /**
0N/A * Tries to find a CertPath that establishes a key that can be
0N/A * used to verify the revocation status of a given certificate.
0N/A * Ignores keys that have previously been tried. Throws a
0N/A * CertPathValidatorException if no such key could be found.
0N/A *
0N/A * @param currCert the <code>X509Certificate</code> to be checked
0N/A * @param prevKey the <code>PublicKey</code> of the certificate whose key
0N/A * cannot be used to vouch for the CRL and should be ignored
0N/A * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
0N/A * whose revocation status depends on the
0N/A * establishment of this path.
0N/A * @throws CertPathValidatorException on failure
0N/A */
0N/A private void buildToNewKey(X509Certificate currCert,
0N/A PublicKey prevKey, Set<X509Certificate> stackedCerts)
0N/A throws CertPathValidatorException {
0N/A
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.buildToNewKey()" +
0N/A " starting work");
0N/A }
0N/A Set<PublicKey> badKeys = new HashSet<PublicKey>();
0N/A if (prevKey != null) {
0N/A badKeys.add(prevKey);
0N/A }
0N/A X509CertSelector certSel = new RejectKeySelector(badKeys);
0N/A certSel.setSubject(currCert.getIssuerX500Principal());
0N/A certSel.setKeyUsage(mCrlSignUsage);
0N/A
3998N/A Set<TrustAnchor> newAnchors =
3998N/A (mAnchor == null ? mParams.getTrustAnchors() :
3998N/A Collections.singleton(mAnchor));
0N/A
0N/A PKIXBuilderParameters builderParams;
0N/A if (mParams instanceof PKIXBuilderParameters) {
0N/A builderParams = (PKIXBuilderParameters) mParams.clone();
0N/A builderParams.setTargetCertConstraints(certSel);
0N/A // Policy qualifiers must be rejected, since we don't have
0N/A // any way to convey them back to the application.
0N/A builderParams.setPolicyQualifiersRejected(true);
0N/A try {
0N/A builderParams.setTrustAnchors(newAnchors);
0N/A } catch (InvalidAlgorithmParameterException iape) {
0N/A throw new RuntimeException(iape); // should never occur
0N/A }
0N/A } else {
0N/A // It's unfortunate that there's no easy way to make a
0N/A // PKIXBuilderParameters object from a PKIXParameters
0N/A // object. This might miss some things if parameters
0N/A // are added in the future or the validatorParams object
0N/A // is a custom class derived from PKIXValidatorParameters.
0N/A try {
0N/A builderParams = new PKIXBuilderParameters(newAnchors, certSel);
0N/A } catch (InvalidAlgorithmParameterException iape) {
0N/A throw new RuntimeException(iape); // should never occur
0N/A }
0N/A builderParams.setInitialPolicies(mParams.getInitialPolicies());
0N/A builderParams.setCertStores(mStores);
0N/A builderParams.setExplicitPolicyRequired
0N/A (mParams.isExplicitPolicyRequired());
0N/A builderParams.setPolicyMappingInhibited
0N/A (mParams.isPolicyMappingInhibited());
0N/A builderParams.setAnyPolicyInhibited(mParams.isAnyPolicyInhibited());
0N/A // Policy qualifiers must be rejected, since we don't have
0N/A // any way to convey them back to the application.
0N/A // That's the default, so no need to write code.
0N/A builderParams.setDate(mParams.getDate());
0N/A builderParams.setCertPathCheckers(mParams.getCertPathCheckers());
0N/A builderParams.setSigProvider(mParams.getSigProvider());
0N/A }
0N/A
0N/A // Skip revocation during this build to detect circular
0N/A // references. But check revocation afterwards, using the
0N/A // key (or any other that works).
0N/A builderParams.setRevocationEnabled(false);
0N/A
0N/A // check for AuthorityInformationAccess extension
0N/A if (Builder.USE_AIA == true) {
0N/A X509CertImpl currCertImpl = null;
0N/A try {
0N/A currCertImpl = X509CertImpl.toImpl(currCert);
0N/A } catch (CertificateException ce) {
0N/A // ignore but log it
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.buildToNewKey: " +
0N/A "error decoding cert: " + ce);
0N/A }
0N/A }
0N/A AuthorityInfoAccessExtension aiaExt = null;
0N/A if (currCertImpl != null) {
0N/A aiaExt = currCertImpl.getAuthorityInfoAccessExtension();
0N/A }
0N/A if (aiaExt != null) {
0N/A List<AccessDescription> adList = aiaExt.getAccessDescriptions();
0N/A if (adList != null) {
0N/A for (AccessDescription ad : adList) {
0N/A CertStore cs = URICertStore.getInstance(ad);
0N/A if (cs != null) {
0N/A if (debug != null) {
0N/A debug.println("adding AIAext CertStore");
0N/A }
0N/A builderParams.addCertStore(cs);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A CertPathBuilder builder = null;
0N/A try {
0N/A builder = CertPathBuilder.getInstance("PKIX");
0N/A } catch (NoSuchAlgorithmException nsae) {
0N/A throw new CertPathValidatorException(nsae);
0N/A }
0N/A while (true) {
0N/A try {
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.buildToNewKey()" +
0N/A " about to try build ...");
0N/A }
0N/A PKIXCertPathBuilderResult cpbr =
0N/A (PKIXCertPathBuilderResult) builder.build(builderParams);
0N/A
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.buildToNewKey()" +
0N/A " about to check revocation ...");
0N/A }
0N/A // Now check revocation of all certs in path, assuming that
0N/A // the stackedCerts are revoked.
0N/A if (stackedCerts == null) {
0N/A stackedCerts = new HashSet<X509Certificate>();
0N/A }
0N/A stackedCerts.add(currCert);
0N/A TrustAnchor ta = cpbr.getTrustAnchor();
0N/A PublicKey prevKey2 = ta.getCAPublicKey();
0N/A if (prevKey2 == null) {
0N/A prevKey2 = ta.getTrustedCert().getPublicKey();
0N/A }
0N/A boolean signFlag = true;
0N/A List<? extends Certificate> cpList =
0N/A cpbr.getCertPath().getCertificates();
0N/A try {
0N/A for (int i = cpList.size()-1; i >= 0; i-- ) {
0N/A X509Certificate cert = (X509Certificate) cpList.get(i);
0N/A
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.buildToNewKey()"
0N/A + " index " + i + " checking " + cert);
0N/A }
3998N/A verifyRevocationStatus(cert, prevKey2, signFlag, true,
3998N/A stackedCerts, newAnchors);
0N/A signFlag = certCanSignCrl(cert);
0N/A prevKey2 = cert.getPublicKey();
0N/A }
0N/A } catch (CertPathValidatorException cpve) {
0N/A // ignore it and try to get another key
0N/A badKeys.add(cpbr.getPublicKey());
0N/A continue;
0N/A }
0N/A
0N/A if (debug != null) {
0N/A debug.println("CrlRevocationChecker.buildToNewKey()" +
0N/A " got key " + cpbr.getPublicKey());
0N/A }
0N/A // Now check revocation on the current cert using that key.
0N/A // If it doesn't check out, try to find a different key.
0N/A // And if we can't find a key, then return false.
0N/A PublicKey newKey = cpbr.getPublicKey();
0N/A try {
0N/A verifyRevocationStatus(currCert, newKey, true, false);
0N/A // If that passed, the cert is OK!
0N/A return;
0N/A } catch (CertPathValidatorException cpve) {
0N/A // If it is revoked, rethrow exception
585N/A if (cpve.getReason() == BasicReason.REVOKED) {
0N/A throw cpve;
0N/A }
0N/A // Otherwise, ignore the exception and
0N/A // try to get another key.
0N/A }
0N/A badKeys.add(newKey);
0N/A } catch (InvalidAlgorithmParameterException iape) {
0N/A throw new CertPathValidatorException(iape);
0N/A } catch (CertPathBuilderException cpbe) {
0N/A throw new CertPathValidatorException
585N/A ("Could not determine revocation status", null, null,
585N/A -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * This inner class extends the X509CertSelector to add an additional
0N/A * check to make sure the subject public key isn't on a particular list.
0N/A * This class is used by buildToNewKey() to make sure the builder doesn't
0N/A * end up with a CertPath to a public key that has already been rejected.
0N/A */
0N/A private static class RejectKeySelector extends X509CertSelector {
0N/A private final Set<PublicKey> badKeySet;
0N/A
0N/A /**
0N/A * Creates a new <code>RejectKeySelector</code>.
0N/A *
0N/A * @param badPublicKeys a <code>Set</code> of
0N/A * <code>PublicKey</code>s that
0N/A * should be rejected (or <code>null</code>
0N/A * if no such check should be done)
0N/A */
0N/A RejectKeySelector(Set<PublicKey> badPublicKeys) {
0N/A this.badKeySet = badPublicKeys;
0N/A }
0N/A
0N/A /**
0N/A * Decides whether a <code>Certificate</code> should be selected.
0N/A *
0N/A * @param cert the <code>Certificate</code> to be checked
0N/A * @return <code>true</code> if the <code>Certificate</code> should be
0N/A * selected, <code>false</code> otherwise
0N/A */
0N/A public boolean match(Certificate cert) {
0N/A if (!super.match(cert))
0N/A return(false);
0N/A
0N/A if (badKeySet.contains(cert.getPublicKey())) {
0N/A if (debug != null)
0N/A debug.println("RejectCertSelector.match: bad key");
0N/A return false;
0N/A }
0N/A
0N/A if (debug != null)
0N/A debug.println("RejectCertSelector.match: returning true");
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Return a printable representation of the <code>CertSelector</code>.
0N/A *
0N/A * @return a <code>String</code> describing the contents of the
0N/A * <code>CertSelector</code>
0N/A */
0N/A public String toString() {
0N/A StringBuilder sb = new StringBuilder();
0N/A sb.append("RejectCertSelector: [\n");
0N/A sb.append(super.toString());
0N/A sb.append(badKeySet);
0N/A sb.append("]");
0N/A return sb.toString();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Internal method that verifies a set of possible_crls,
0N/A * and sees if each is approved, based on the cert.
0N/A *
0N/A * @param crls a set of possible CRLs to test for acceptability
0N/A * @param cert the certificate whose revocation status is being checked
0N/A * @param signFlag <code>true</code> if prevKey was trusted to sign CRLs
0N/A * @param prevKey the public key of the issuer of cert
0N/A * @param reasonsMask the reason code mask
3998N/A * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s>
0N/A * @return a collection of approved crls (or an empty collection)
0N/A */
0N/A private Collection<X509CRL> verifyPossibleCRLs(Set<X509CRL> crls,
0N/A X509Certificate cert, boolean signFlag, PublicKey prevKey,
3998N/A boolean[] reasonsMask,
3998N/A Set<TrustAnchor> trustAnchors) throws CertPathValidatorException {
3998N/A
0N/A try {
0N/A X509CertImpl certImpl = X509CertImpl.toImpl(cert);
0N/A if (debug != null) {
0N/A debug.println("CRLRevocationChecker.verifyPossibleCRLs: " +
0N/A "Checking CRLDPs for "
0N/A + certImpl.getSubjectX500Principal());
0N/A }
0N/A CRLDistributionPointsExtension ext =
0N/A certImpl.getCRLDistributionPointsExtension();
0N/A List<DistributionPoint> points = null;
0N/A if (ext == null) {
0N/A // assume a DP with reasons and CRLIssuer fields omitted
0N/A // and a DP name of the cert issuer.
0N/A // TODO add issuerAltName too
0N/A X500Name certIssuer = (X500Name)certImpl.getIssuerDN();
0N/A DistributionPoint point = new DistributionPoint
0N/A (new GeneralNames().add(new GeneralName(certIssuer)),
0N/A null, null);
0N/A points = Collections.singletonList(point);
0N/A } else {
0N/A points = (List<DistributionPoint>)ext.get(
0N/A CRLDistributionPointsExtension.POINTS);
0N/A }
0N/A Set<X509CRL> results = new HashSet<X509CRL>();
0N/A for (Iterator<DistributionPoint> t = points.iterator();
0N/A t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
0N/A DistributionPoint point = t.next();
0N/A for (X509CRL crl : crls) {
6037N/A if (DistributionPointFetcher.verifyCRL(certImpl, point, crl,
6037N/A reasonsMask, signFlag, prevKey, mSigProvider,
4114N/A trustAnchors, mStores, mParams.getDate())) {
0N/A results.add(crl);
0N/A }
0N/A }
0N/A }
0N/A return results;
0N/A } catch (Exception e) {
0N/A if (debug != null) {
0N/A debug.println("Exception while verifying CRL: "+e.getMessage());
0N/A e.printStackTrace();
0N/A }
0N/A return Collections.emptySet();
0N/A }
0N/A }
0N/A}