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