package sun.security.provider.certpath;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedAction;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.Extension;
import java.security.cert.*;
import java.util.*;
import javax.security.auth.x500.X500Principal;
import static sun.security.provider.certpath.OCSP.*;
import static sun.security.provider.certpath.PKIX.*;
import sun.security.x509.*;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.util.Debug;
class RevocationChecker extends PKIXRevocationChecker {
private static final Debug debug = Debug.getInstance("certpath");
private TrustAnchor anchor;
private ValidatorParams params;
private boolean onlyEE;
private boolean softFail;
private boolean crlDP;
private URI responderURI;
private X509Certificate responderCert;
private List<CertStore> certStores;
private Map<X509Certificate, byte[]> ocspResponses;
private List<Extension> ocspExtensions;
private final boolean legacy;
private LinkedList<CertPathValidatorException> softFailExceptions =
new LinkedList<>();
private OCSPResponse.IssuerInfo issuerInfo;
private PublicKey prevPubKey;
private boolean crlSignFlag;
private int certIndex;
private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS, ONLY_OCSP };
private Mode mode = Mode.PREFER_OCSP;
private static class RevocationProperties {
boolean onlyEE;
boolean ocspEnabled;
boolean crlDPEnabled;
String ocspUrl;
String ocspSubject;
String ocspIssuer;
String ocspSerial;
}
RevocationChecker() {
legacy = false;
}
RevocationChecker(TrustAnchor anchor, ValidatorParams params)
throws CertPathValidatorException
{
legacy = true;
init(anchor, params);
}
void init(TrustAnchor anchor, ValidatorParams params)
throws CertPathValidatorException
{
RevocationProperties rp = getRevocationProperties();
URI uri = getOcspResponder();
responderURI = (uri == null) ? toURI(rp.ocspUrl) : uri;
X509Certificate cert = getOcspResponderCert();
responderCert = (cert == null)
? getResponderCert(rp, params.trustAnchors(),
params.certStores())
: cert;
Set<Option> options = getOptions();
for (Option option : options) {
switch (option) {
case ONLY_END_ENTITY:
case PREFER_CRLS:
case SOFT_FAIL:
case NO_FALLBACK:
break;
default:
throw new CertPathValidatorException(
"Unrecognized revocation parameter option: " + option);
}
}
softFail = options.contains(Option.SOFT_FAIL);
if (legacy) {
mode = (rp.ocspEnabled) ? Mode.PREFER_OCSP : Mode.ONLY_CRLS;
onlyEE = rp.onlyEE;
} else {
if (options.contains(Option.NO_FALLBACK)) {
if (options.contains(Option.PREFER_CRLS)) {
mode = Mode.ONLY_CRLS;
} else {
mode = Mode.ONLY_OCSP;
}
} else if (options.contains(Option.PREFER_CRLS)) {
mode = Mode.PREFER_CRLS;
}
onlyEE = options.contains(Option.ONLY_END_ENTITY);
}
if (legacy) {
crlDP = rp.crlDPEnabled;
} else {
crlDP = true;
}
ocspResponses = getOcspResponses();
ocspExtensions = getOcspExtensions();
this.anchor = anchor;
this.params = params;
this.certStores = new ArrayList<>(params.certStores());
try {
this.certStores.add(CertStore.getInstance("Collection",
new CollectionCertStoreParameters(params.certificates())));
} catch (InvalidAlgorithmParameterException |
NoSuchAlgorithmException e) {
if (debug != null) {
debug.println("RevocationChecker: " +
"error creating Collection CertStore: " + e);
}
}
}
private static URI toURI(String uriString)
throws CertPathValidatorException
{
try {
if (uriString != null) {
return new URI(uriString);
}
return null;
} catch (URISyntaxException e) {
throw new CertPathValidatorException(
"cannot parse ocsp.responderURL property", e);
}
}
private static RevocationProperties getRevocationProperties() {
return AccessController.doPrivileged(
new PrivilegedAction<RevocationProperties>() {
public RevocationProperties run() {
RevocationProperties rp = new RevocationProperties();
String onlyEE = Security.getProperty(
"com.sun.security.onlyCheckRevocationOfEECert");
rp.onlyEE = onlyEE != null
&& onlyEE.equalsIgnoreCase("true");
String ocspEnabled = Security.getProperty("ocsp.enable");
rp.ocspEnabled = ocspEnabled != null
&& ocspEnabled.equalsIgnoreCase("true");
rp.ocspUrl = Security.getProperty("ocsp.responderURL");
rp.ocspSubject
= Security.getProperty("ocsp.responderCertSubjectName");
rp.ocspIssuer
= Security.getProperty("ocsp.responderCertIssuerName");
rp.ocspSerial
= Security.getProperty("ocsp.responderCertSerialNumber");
rp.crlDPEnabled
= Boolean.getBoolean("com.sun.security.enableCRLDP");
return rp;
}
}
);
}
private static X509Certificate getResponderCert(RevocationProperties rp,
Set<TrustAnchor> anchors,
List<CertStore> stores)
throws CertPathValidatorException
{
if (rp.ocspSubject != null) {
return getResponderCert(rp.ocspSubject, anchors, stores);
} else if (rp.ocspIssuer != null && rp.ocspSerial != null) {
return getResponderCert(rp.ocspIssuer, rp.ocspSerial,
anchors, stores);
} else if (rp.ocspIssuer != null || rp.ocspSerial != null) {
throw new CertPathValidatorException(
"Must specify both ocsp.responderCertIssuerName and " +
"ocsp.responderCertSerialNumber properties");
}
return null;
}
private static X509Certificate getResponderCert(String subject,
Set<TrustAnchor> anchors,
List<CertStore> stores)
throws CertPathValidatorException
{
X509CertSelector sel = new X509CertSelector();
try {
sel.setSubject(new X500Principal(subject));
} catch (IllegalArgumentException e) {
throw new CertPathValidatorException(
"cannot parse ocsp.responderCertSubjectName property", e);
}
return getResponderCert(sel, anchors, stores);
}
private static X509Certificate getResponderCert(String issuer,
String serial,
Set<TrustAnchor> anchors,
List<CertStore> stores)
throws CertPathValidatorException
{
X509CertSelector sel = new X509CertSelector();
try {
sel.setIssuer(new X500Principal(issuer));
} catch (IllegalArgumentException e) {
throw new CertPathValidatorException(
"cannot parse ocsp.responderCertIssuerName property", e);
}
try {
sel.setSerialNumber(new BigInteger(stripOutSeparators(serial), 16));
} catch (NumberFormatException e) {
throw new CertPathValidatorException(
"cannot parse ocsp.responderCertSerialNumber property", e);
}
return getResponderCert(sel, anchors, stores);
}
private static X509Certificate getResponderCert(X509CertSelector sel,
Set<TrustAnchor> anchors,
List<CertStore> stores)
throws CertPathValidatorException
{
for (TrustAnchor anchor : anchors) {
X509Certificate cert = anchor.getTrustedCert();
if (cert == null) {
continue;
}
if (sel.match(cert)) {
return cert;
}
}
for (CertStore store : stores) {
try {
Collection<? extends Certificate> certs =
store.getCertificates(sel);
if (!certs.isEmpty()) {
return (X509Certificate)certs.iterator().next();
}
} catch (CertStoreException e) {
if (debug != null) {
debug.println("CertStore exception:" + e);
}
continue;
}
}
throw new CertPathValidatorException(
"Cannot find the responder's certificate " +
"(set using the OCSP security properties).");
}
@Override
public void init(boolean forward) throws CertPathValidatorException {
if (forward) {
throw new
CertPathValidatorException("forward checking not supported");
}
if (anchor != null) {
issuerInfo = new OCSPResponse.IssuerInfo(anchor);
prevPubKey = issuerInfo.getPublicKey();
}
crlSignFlag = true;
if (params != null && params.certPath() != null) {
certIndex = params.certPath().getCertificates().size() - 1;
} else {
certIndex = -1;
}
softFailExceptions.clear();
}
@Override
public boolean isForwardCheckingSupported() {
return false;
}
@Override
public Set<String> getSupportedExtensions() {
return null;
}
@Override
public List<CertPathValidatorException> getSoftFailExceptions() {
return Collections.unmodifiableList(softFailExceptions);
}
@Override
public void check(Certificate cert, Collection<String> unresolvedCritExts)
throws CertPathValidatorException
{
check((X509Certificate)cert, unresolvedCritExts,
prevPubKey, crlSignFlag);
}
private void check(X509Certificate xcert,
Collection<String> unresolvedCritExts,
PublicKey pubKey, boolean crlSignFlag)
throws CertPathValidatorException
{
if (debug != null) {
debug.println("RevocationChecker.check: checking cert" +
"\n SN: " + Debug.toHexString(xcert.getSerialNumber()) +
"\n Subject: " + xcert.getSubjectX500Principal() +
"\n Issuer: " + xcert.getIssuerX500Principal());
}
try {
if (onlyEE && xcert.getBasicConstraints() != -1) {
if (debug != null) {
debug.println("Skipping revocation check; cert is not " +
"an end entity cert");
}
return;
}
switch (mode) {
case PREFER_OCSP:
case ONLY_OCSP:
checkOCSP(xcert, unresolvedCritExts);
break;
case PREFER_CRLS:
case ONLY_CRLS:
checkCRLs(xcert, unresolvedCritExts, null,
pubKey, crlSignFlag);
break;
}
} catch (CertPathValidatorException e) {
if (e.getReason() == BasicReason.REVOKED) {
throw e;
}
boolean eSoftFail = isSoftFailException(e);
if (eSoftFail) {
if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) {
return;
}
} else {
if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) {
throw e;
}
}
CertPathValidatorException cause = e;
if (debug != null) {
debug.println("RevocationChecker.check() " + e.getMessage());
debug.println("RevocationChecker.check() preparing to failover");
}
try {
switch (mode) {
case PREFER_OCSP:
checkCRLs(xcert, unresolvedCritExts, null,
pubKey, crlSignFlag);
break;
case PREFER_CRLS:
checkOCSP(xcert, unresolvedCritExts);
break;
}
} catch (CertPathValidatorException x) {
if (debug != null) {
debug.println("RevocationChecker.check() failover failed");
debug.println("RevocationChecker.check() " + x.getMessage());
}
if (x.getReason() == BasicReason.REVOKED) {
throw x;
}
if (!isSoftFailException(x)) {
cause.addSuppressed(x);
throw cause;
} else {
if (!eSoftFail) {
throw cause;
}
}
}
} finally {
updateState(xcert);
}
}
private boolean isSoftFailException(CertPathValidatorException e) {
if (softFail &&
e.getReason() == BasicReason.UNDETERMINED_REVOCATION_STATUS)
{
CertPathValidatorException e2 = new CertPathValidatorException(
e.getMessage(), e.getCause(), params.certPath(), certIndex,
e.getReason());
softFailExceptions.addFirst(e2);
return true;
}
return false;
}
private void updateState(X509Certificate cert)
throws CertPathValidatorException
{
issuerInfo = new OCSPResponse.IssuerInfo(anchor, cert);
PublicKey pubKey = cert.getPublicKey();
if (PKIX.isDSAPublicKeyWithoutParams(pubKey)) {
pubKey = BasicChecker.makeInheritedParamsKey(pubKey, prevPubKey);
}
prevPubKey = pubKey;
crlSignFlag = certCanSignCrl(cert);
if (certIndex > 0) {
certIndex--;
}
}
private static final long MAX_CLOCK_SKEW = 900000;
private void checkCRLs(X509Certificate cert,
Collection<String> unresolvedCritExts,
Set<X509Certificate> stackedCerts,
PublicKey pubKey, boolean signFlag)
throws CertPathValidatorException
{
checkCRLs(cert, pubKey, null, signFlag, true,
stackedCerts, params.trustAnchors());
}
static boolean isCausedByNetworkIssue(String type, CertStoreException cse) {
boolean result;
Throwable t = cse.getCause();
switch (type) {
case "LDAP":
if (t != null) {
String cn = t.getClass().getName();
result = (cn.equals("javax.naming.ServiceUnavailableException") ||
cn.equals("javax.naming.CommunicationException"));
} else {
result = false;
}
break;
case "SSLServer":
result = (t != null && t instanceof IOException);
break;
case "URI":
result = (t != null && t instanceof IOException);
break;
default:
return false;
}
return result;
}
private void checkCRLs(X509Certificate cert, PublicKey prevKey,
X509Certificate prevCert, boolean signFlag,
boolean allowSeparateKey,
Set<X509Certificate> stackedCerts,
Set<TrustAnchor> anchors)
throws CertPathValidatorException
{
if (debug != null) {
debug.println("RevocationChecker.checkCRLs()" +
" ---checking revocation status ...");
}
if (stackedCerts != null && stackedCerts.contains(cert)) {
if (debug != null) {
debug.println("RevocationChecker.checkCRLs()" +
" circular dependency");
}
throw new CertPathValidatorException
("Could not determine revocation status", null, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
Set<X509CRL> possibleCRLs = new HashSet<>();
Set<X509CRL> approvedCRLs = new HashSet<>();
X509CRLSelector sel = new X509CRLSelector();
sel.setCertificateChecking(cert);
CertPathHelper.setDateAndTime(sel, params.date(), MAX_CLOCK_SKEW);
CertPathValidatorException networkFailureException = null;
for (CertStore store : certStores) {
try {
for (CRL crl : store.getCRLs(sel)) {
possibleCRLs.add((X509CRL)crl);
}
} catch (CertStoreException e) {
if (debug != null) {
debug.println("RevocationChecker.checkCRLs() " +
"CertStoreException: " + e.getMessage());
}
if (networkFailureException == null &&
isCausedByNetworkIssue(store.getType(),e)) {
networkFailureException = new CertPathValidatorException(
"Unable to determine revocation status due to " +
"network error", e, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
}
}
if (debug != null) {
debug.println("RevocationChecker.checkCRLs() " +
"possible crls.size() = " + possibleCRLs.size());
}
boolean[] reasonsMask = new boolean[9];
if (!possibleCRLs.isEmpty()) {
approvedCRLs.addAll(verifyPossibleCRLs(possibleCRLs, cert, prevKey,
signFlag, reasonsMask,
anchors));
}
if (debug != null) {
debug.println("RevocationChecker.checkCRLs() " +
"approved crls.size() = " + approvedCRLs.size());
}
if (!approvedCRLs.isEmpty() &&
Arrays.equals(reasonsMask, ALL_REASONS))
{
checkApprovedCRLs(cert, approvedCRLs);
} else {
try {
if (crlDP) {
approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
sel, signFlag, prevKey, prevCert,
params.sigProvider(), certStores,
reasonsMask, anchors, null, params.variant()));
}
} catch (CertStoreException e) {
if (e instanceof CertStoreTypeException) {
CertStoreTypeException cste = (CertStoreTypeException)e;
if (isCausedByNetworkIssue(cste.getType(), e)) {
throw new CertPathValidatorException(
"Unable to determine revocation status due to " +
"network error", e, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
}
throw new CertPathValidatorException(e);
}
if (!approvedCRLs.isEmpty() &&
Arrays.equals(reasonsMask, ALL_REASONS))
{
checkApprovedCRLs(cert, approvedCRLs);
} else {
if (allowSeparateKey) {
try {
verifyWithSeparateSigningKey(cert, prevKey, signFlag,
stackedCerts);
return;
} catch (CertPathValidatorException cpve) {
if (networkFailureException != null) {
throw networkFailureException;
}
throw cpve;
}
} else {
if (networkFailureException != null) {
throw networkFailureException;
}
throw new CertPathValidatorException(
"Could not determine revocation status", null, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
}
}
}
private void checkApprovedCRLs(X509Certificate cert,
Set<X509CRL> approvedCRLs)
throws CertPathValidatorException
{
if (debug != null) {
BigInteger sn = cert.getSerialNumber();
debug.println("RevocationChecker.checkApprovedCRLs() " +
"starting the final sweep...");
debug.println("RevocationChecker.checkApprovedCRLs()" +
" cert SN: " + sn.toString());
}
CRLReason reasonCode = CRLReason.UNSPECIFIED;
X509CRLEntryImpl entry = null;
for (X509CRL crl : approvedCRLs) {
X509CRLEntry e = crl.getRevokedCertificate(cert);
if (e != null) {
try {
entry = X509CRLEntryImpl.toImpl(e);
} catch (CRLException ce) {
throw new CertPathValidatorException(ce);
}
if (debug != null) {
debug.println("RevocationChecker.checkApprovedCRLs()"
+ " CRL entry: " + entry.toString());
}
Set<String> unresCritExts = entry.getCriticalExtensionOIDs();
if (unresCritExts != null && !unresCritExts.isEmpty()) {
unresCritExts.remove(ReasonCode_Id.toString());
unresCritExts.remove(CertificateIssuer_Id.toString());
if (!unresCritExts.isEmpty()) {
throw new CertPathValidatorException(
"Unrecognized critical extension(s) in revoked " +
"CRL entry");
}
}
reasonCode = entry.getRevocationReason();
if (reasonCode == null) {
reasonCode = CRLReason.UNSPECIFIED;
}
Date revocationDate = entry.getRevocationDate();
if (revocationDate.before(params.date())) {
Throwable t = new CertificateRevokedException(
revocationDate, reasonCode,
crl.getIssuerX500Principal(), entry.getExtensions());
throw new CertPathValidatorException(
t.getMessage(), t, null, -1, BasicReason.REVOKED);
}
}
}
}
private void checkOCSP(X509Certificate cert,
Collection<String> unresolvedCritExts)
throws CertPathValidatorException
{
X509CertImpl currCert = null;
try {
currCert = X509CertImpl.toImpl(cert);
} catch (CertificateException ce) {
throw new CertPathValidatorException(ce);
}
OCSPResponse response = null;
CertId certId = null;
try {
certId = new CertId(issuerInfo.getName(), issuerInfo.getPublicKey(),
currCert.getSerialNumberObject());
byte[] responseBytes = ocspResponses.get(cert);
if (responseBytes != null) {
if (debug != null) {
debug.println("Found cached OCSP response");
}
response = new OCSPResponse(responseBytes);
byte[] nonce = null;
for (Extension ext : ocspExtensions) {
if (ext.getId().equals("1.3.6.1.5.5.7.48.1.2")) {
nonce = ext.getValue();
}
}
response.verify(Collections.singletonList(certId), issuerInfo,
responderCert, params.date(), nonce, params.variant());
} else {
URI responderURI = (this.responderURI != null)
? this.responderURI
: OCSP.getResponderURI(currCert);
if (responderURI == null) {
throw new CertPathValidatorException(
"Certificate does not specify OCSP responder", null,
null, -1);
}
response = OCSP.check(Collections.singletonList(certId),
responderURI, issuerInfo, responderCert, null,
ocspExtensions, params.variant());
}
} catch (IOException e) {
throw new CertPathValidatorException(
"Unable to determine revocation status due to network error",
e, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
RevocationStatus rs =
(RevocationStatus)response.getSingleResponse(certId);
RevocationStatus.CertStatus certStatus = rs.getCertStatus();
if (certStatus == RevocationStatus.CertStatus.REVOKED) {
Date revocationTime = rs.getRevocationTime();
if (revocationTime.before(params.date())) {
Throwable t = new CertificateRevokedException(
revocationTime, rs.getRevocationReason(),
response.getSignerCertificate().getSubjectX500Principal(),
rs.getSingleExtensions());
throw new CertPathValidatorException(t.getMessage(), t, null,
-1, BasicReason.REVOKED);
}
} else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
throw new CertPathValidatorException(
"Certificate's revocation status is unknown", null,
params.certPath(), -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
}
private static final String HEX_DIGITS = "0123456789ABCDEFabcdef";
private static String stripOutSeparators(String value) {
char[] chars = value.toCharArray();
StringBuilder hexNumber = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
if (HEX_DIGITS.indexOf(chars[i]) != -1) {
hexNumber.append(chars[i]);
}
}
return hexNumber.toString();
}
static boolean certCanSignCrl(X509Certificate cert) {
boolean[] keyUsage = cert.getKeyUsage();
if (keyUsage != null) {
return keyUsage[6];
}
return false;
}
private static final boolean[] ALL_REASONS =
{true, true, true, true, true, true, true, true, true};
private Collection<X509CRL> verifyPossibleCRLs(Set<X509CRL> crls,
X509Certificate cert,
PublicKey prevKey,
boolean signFlag,
boolean[] reasonsMask,
Set<TrustAnchor> anchors)
throws CertPathValidatorException
{
try {
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
if (debug != null) {
debug.println("RevocationChecker.verifyPossibleCRLs: " +
"Checking CRLDPs for "
+ certImpl.getSubjectX500Principal());
}
CRLDistributionPointsExtension ext =
certImpl.getCRLDistributionPointsExtension();
List<DistributionPoint> points = null;
if (ext == null) {
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<>();
for (DistributionPoint point : points) {
for (X509CRL crl : crls) {
if (DistributionPointFetcher.verifyCRL(
certImpl, point, crl, reasonsMask, signFlag,
prevKey, null, params.sigProvider(), anchors,
certStores, params.date(), params.variant()))
{
results.add(crl);
}
}
if (Arrays.equals(reasonsMask, ALL_REASONS))
break;
}
return results;
} catch (CertificateException | CRLException | IOException e) {
if (debug != null) {
debug.println("Exception while verifying CRL: "+e.getMessage());
e.printStackTrace();
}
return Collections.emptySet();
}
}
private void verifyWithSeparateSigningKey(X509Certificate cert,
PublicKey prevKey,
boolean signFlag,
Set<X509Certificate> stackedCerts)
throws CertPathValidatorException
{
String msg = "revocation status";
if (debug != null) {
debug.println(
"RevocationChecker.verifyWithSeparateSigningKey()" +
" ---checking " + msg + "...");
}
if ((stackedCerts != null) && stackedCerts.contains(cert)) {
if (debug != null) {
debug.println(
"RevocationChecker.verifyWithSeparateSigningKey()" +
" circular dependency");
}
throw new CertPathValidatorException
("Could not determine revocation status", null, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
if (!signFlag) {
buildToNewKey(cert, null, stackedCerts);
} else {
buildToNewKey(cert, prevKey, stackedCerts);
}
}
private static final boolean [] CRL_SIGN_USAGE =
{ false, false, false, false, false, false, true };
private void buildToNewKey(X509Certificate currCert,
PublicKey prevKey,
Set<X509Certificate> stackedCerts)
throws CertPathValidatorException
{
if (debug != null) {
debug.println("RevocationChecker.buildToNewKey()" +
" starting work");
}
Set<PublicKey> badKeys = new HashSet<>();
if (prevKey != null) {
badKeys.add(prevKey);
}
X509CertSelector certSel = new RejectKeySelector(badKeys);
certSel.setSubject(currCert.getIssuerX500Principal());
certSel.setKeyUsage(CRL_SIGN_USAGE);
Set<TrustAnchor> newAnchors = anchor == null ?
params.trustAnchors() :
Collections.singleton(anchor);
PKIXBuilderParameters builderParams;
try {
builderParams = new PKIXBuilderParameters(newAnchors, certSel);
} catch (InvalidAlgorithmParameterException iape) {
throw new RuntimeException(iape);
}
builderParams.setInitialPolicies(params.initialPolicies());
builderParams.setCertStores(certStores);
builderParams.setExplicitPolicyRequired
(params.explicitPolicyRequired());
builderParams.setPolicyMappingInhibited
(params.policyMappingInhibited());
builderParams.setAnyPolicyInhibited(params.anyPolicyInhibited());
builderParams.setDate(params.date());
builderParams.setCertPathCheckers(
params.getPKIXParameters().getCertPathCheckers());
builderParams.setSigProvider(params.sigProvider());
builderParams.setRevocationEnabled(false);
if (Builder.USE_AIA == true) {
X509CertImpl currCertImpl = null;
try {
currCertImpl = X509CertImpl.toImpl(currCert);
} catch (CertificateException ce) {
if (debug != null) {
debug.println("RevocationChecker.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("RevocationChecker.buildToNewKey()" +
" about to try build ...");
}
PKIXCertPathBuilderResult cpbr =
(PKIXCertPathBuilderResult)builder.build(builderParams);
if (debug != null) {
debug.println("RevocationChecker.buildToNewKey()" +
" about to check revocation ...");
}
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("RevocationChecker.buildToNewKey()"
+ " index " + i + " checking "
+ cert);
}
checkCRLs(cert, prevKey2, null, signFlag, true,
stackedCerts, newAnchors);
signFlag = certCanSignCrl(cert);
prevKey2 = cert.getPublicKey();
}
} catch (CertPathValidatorException cpve) {
badKeys.add(cpbr.getPublicKey());
continue;
}
if (debug != null) {
debug.println("RevocationChecker.buildToNewKey()" +
" got key " + cpbr.getPublicKey());
}
PublicKey newKey = cpbr.getPublicKey();
X509Certificate newCert = cpList.isEmpty() ?
null : (X509Certificate) cpList.get(0);
try {
checkCRLs(currCert, newKey, newCert,
true, false, null, params.trustAnchors());
return;
} catch (CertPathValidatorException cpve) {
if (cpve.getReason() == BasicReason.REVOKED) {
throw cpve;
}
}
badKeys.add(newKey);
} catch (InvalidAlgorithmParameterException iape) {
throw new CertPathValidatorException(iape);
} catch (CertPathBuilderException cpbe) {
throw new CertPathValidatorException
("Could not determine revocation status", null, null,
-1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
}
}
}
@Override
public RevocationChecker clone() {
RevocationChecker copy = (RevocationChecker)super.clone();
copy.softFailExceptions = new LinkedList<>(softFailExceptions);
return copy;
}
private static class RejectKeySelector extends X509CertSelector {
private final Set<PublicKey> badKeySet;
RejectKeySelector(Set<PublicKey> badPublicKeys) {
this.badKeySet = badPublicKeys;
}
@Override
public boolean match(Certificate cert) {
if (!super.match(cert))
return(false);
if (badKeySet.contains(cert.getPublicKey())) {
if (debug != null)
debug.println("RejectKeySelector.match: bad key");
return false;
}
if (debug != null)
debug.println("RejectKeySelector.match: returning true");
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("RejectKeySelector: [\n");
sb.append(super.toString());
sb.append(badKeySet);
sb.append("]");
return sb.toString();
}
}
}