History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/provider/certpath/CrlRevocationChecker.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/provider/certpath/CrlRevocationChecker.java+787−0
@@ -0,0 +1,787 @@
1+/*
2+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.security.provider.certpath;
27+
28+import java.math.BigInteger;
29+import java.util.Arrays;
30+import java.util.ArrayList;
31+import java.util.Collection;
32+import java.util.Collections;
33+import java.util.Date;
34+import java.util.List;
35+import java.util.HashSet;
36+import java.util.Set;
37+import java.util.Iterator;
38+import java.security.InvalidAlgorithmParameterException;
39+import java.security.NoSuchAlgorithmException;
40+import java.security.PublicKey;
41+import java.security.cert.*;
42+import java.security.cert.CertPathValidatorException.BasicReason;
43+import java.security.interfaces.DSAPublicKey;
44+import javax.security.auth.x500.X500Principal;
45+import sun.security.util.Debug;
46+import sun.security.x509.AccessDescription;
47+import sun.security.x509.AuthorityInfoAccessExtension;
48+import sun.security.x509.CRLDistributionPointsExtension;
49+import sun.security.x509.DistributionPoint;
50+import sun.security.x509.GeneralName;
51+import sun.security.x509.GeneralNames;
52+import sun.security.x509.PKIXExtensions;
53+import sun.security.x509.X500Name;
54+import sun.security.x509.X509CertImpl;
55+import sun.security.x509.X509CRLEntryImpl;
56+
57+/**
58+ * CrlRevocationChecker is a <code>PKIXCertPathChecker</code> that checks
59+ * revocation status information on a PKIX certificate using CRLs obtained
60+ * from one or more <code>CertStores</code>. This is based on section 6.3
61+ * of RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt).
62+ *
63+ * @since 1.4
64+ * @author Seth Proctor
65+ * @author Steve Hanna
66+ */
67+class CrlRevocationChecker extends PKIXCertPathChecker {
68+
69+ private static final Debug debug = Debug.getInstance("certpath");
70+ private final TrustAnchor mAnchor;
71+ private final List<CertStore> mStores;
72+ private final String mSigProvider;
73+ private final Date mCurrentTime;
74+ private PublicKey mPrevPubKey;
75+ private boolean mCRLSignFlag;
76+ private HashSet<X509CRL> mPossibleCRLs;
77+ private HashSet<X509CRL> mApprovedCRLs;
78+ private final PKIXParameters mParams;
79+ private static final boolean [] mCrlSignUsage =
80+ { false, false, false, false, false, false, true };
81+ private static final boolean[] ALL_REASONS =
82+ {true, true, true, true, true, true, true, true, true};
83+ private boolean mOnlyEECert = false;
84+
85+ // Maximum clock skew in milliseconds (15 minutes) allowed when checking
86+ // validity of CRLs
87+ private static final long MAX_CLOCK_SKEW = 900000;
88+
89+ /**
90+ * Creates a <code>CrlRevocationChecker</code>.
91+ *
92+ * @param anchor anchor selected to validate the target certificate
93+ * @param params <code>PKIXParameters</code> to be used for
94+ * finding certificates and CRLs, etc.
95+ */
96+ CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params)
97+ throws CertPathValidatorException
98+ {
99+ this(anchor, params, null);
100+ }
101+
102+ /**
103+ * Creates a <code>CrlRevocationChecker</code>, allowing
104+ * extra certificates to be supplied beyond those contained
105+ * in the <code>PKIXParameters</code>.
106+ *
107+ * @param anchor anchor selected to validate the target certificate
108+ * @param params <code>PKIXParameters</code> to be used for
109+ * finding certificates and CRLs, etc.
110+ * @param certs a <code>Collection</code> of certificates
111+ * that may be useful, beyond those available
112+ * through <code>params</code> (<code>null</code>
113+ * if none)
114+ */
115+ CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
116+ Collection<X509Certificate> certs) throws CertPathValidatorException
117+ {
118+ this(anchor, params, certs, false);
119+ }
120+
121+ CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
122+ Collection<X509Certificate> certs, boolean onlyEECert)
123+ throws CertPathValidatorException {
124+ mAnchor = anchor;
125+ mParams = params;
126+ mStores = new ArrayList<CertStore>(params.getCertStores());
127+ mSigProvider = params.getSigProvider();
128+ if (certs != null) {
129+ try {
130+ mStores.add(CertStore.getInstance("Collection",
131+ new CollectionCertStoreParameters(certs)));
132+ } catch (Exception e) {
133+ // should never occur but not necessarily fatal, so log it,
134+ // ignore and continue
135+ if (debug != null) {
136+ debug.println("CrlRevocationChecker: " +
137+ "error creating Collection CertStore: " + e);
138+ }
139+ }
140+ }
141+ Date testDate = params.getDate();
142+ mCurrentTime = (testDate != null ? testDate : new Date());
143+ mOnlyEECert = onlyEECert;
144+ init(false);
145+ }
146+
147+ /**
148+ * Initializes the internal state of the checker from parameters
149+ * specified in the constructor
150+ */
151+ public void init(boolean forward) throws CertPathValidatorException
152+ {
153+ if (!forward) {
154+ if (mAnchor != null) {
155+ if (mAnchor.getCAPublicKey() != null) {
156+ mPrevPubKey = mAnchor.getCAPublicKey();
157+ } else {
158+ mPrevPubKey = mAnchor.getTrustedCert().getPublicKey();
159+ }
160+ } else {
161+ mPrevPubKey = null;
162+ }
163+ mCRLSignFlag = true;
164+ } else {
165+ throw new CertPathValidatorException("forward checking "
166+ + "not supported");
167+ }
168+ }
169+
170+ public boolean isForwardCheckingSupported() {
171+ return false;
172+ }
173+
174+ public Set<String> getSupportedExtensions() {
175+ return null;
176+ }
177+
178+ /**
179+ * Performs the revocation status check on the certificate using
180+ * its internal state.
181+ *
182+ * @param cert the Certificate
183+ * @param unresolvedCritExts a Collection of the unresolved critical
184+ * extensions
185+ * @exception CertPathValidatorException Exception thrown if
186+ * certificate does not verify
187+ */
188+ public void check(Certificate cert, Collection<String> unresolvedCritExts)
189+ throws CertPathValidatorException
190+ {
191+ X509Certificate currCert = (X509Certificate) cert;
192+ verifyRevocationStatus(currCert, mPrevPubKey, mCRLSignFlag, true);
193+
194+ // Make new public key if parameters are missing
195+ PublicKey cKey = currCert.getPublicKey();
196+ if (cKey instanceof DSAPublicKey &&
197+ ((DSAPublicKey)cKey).getParams() == null) {
198+ // cKey needs to inherit DSA parameters from prev key
199+ cKey = BasicChecker.makeInheritedParamsKey(cKey, mPrevPubKey);
200+ }
201+ mPrevPubKey = cKey;
202+ mCRLSignFlag = certCanSignCrl(currCert);
203+ }
204+
205+ /**
206+ * Performs the revocation status check on the certificate using
207+ * the provided state variables, as well as the constant internal
208+ * data.
209+ *
210+ * @param currCert the Certificate
211+ * @param prevKey the previous PublicKey in the chain
212+ * @param signFlag a boolean as returned from the last call, or true
213+ * if this is the first cert in the chain
214+ * @return a boolean specifying if the cert is allowed to vouch for the
215+ * validity of a CRL for the next iteration
216+ * @exception CertPathValidatorException Exception thrown if
217+ * certificate does not verify.
218+ */
219+ public boolean check(X509Certificate currCert, PublicKey prevKey,
220+ boolean signFlag) throws CertPathValidatorException
221+ {
222+ verifyRevocationStatus(currCert, prevKey, signFlag, true);
223+ return certCanSignCrl(currCert);
224+ }
225+
226+ /**
227+ * Checks that a cert can be used to verify a CRL.
228+ *
229+ * @param currCert an X509Certificate to check
230+ * @return a boolean specifying if the cert is allowed to vouch for the
231+ * validity of a CRL
232+ */
233+ static boolean certCanSignCrl(X509Certificate currCert) {
234+ // if the cert doesn't include the key usage ext, or
235+ // the key usage ext asserts cRLSigning, return true,
236+ // otherwise return false.
237+ boolean[] kbools = currCert.getKeyUsage();
238+ if (kbools != null) {
239+ return kbools[6];
240+ }
241+ return false;
242+ }
243+
244+ /**
245+ * Internal method to start the verification of a cert
246+ */
247+ private void verifyRevocationStatus(X509Certificate currCert,
248+ PublicKey prevKey, boolean signFlag, boolean allowSeparateKey)
249+ throws CertPathValidatorException
250+ {
251+ verifyRevocationStatus(currCert, prevKey, signFlag,
252+ allowSeparateKey, null, mParams.getTrustAnchors());
253+ }
254+
255+ /**
256+ * Internal method to start the verification of a cert
257+ * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
258+ * whose revocation status depends on the
259+ * non-revoked status of this cert. To avoid
260+ * circular dependencies, we assume they're
261+ * revoked while checking the revocation
262+ * status of this cert.
263+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
264+ */
265+ private void verifyRevocationStatus(X509Certificate currCert,
266+ PublicKey prevKey, boolean signFlag, boolean allowSeparateKey,
267+ Set<X509Certificate> stackedCerts,
268+ Set<TrustAnchor> trustAnchors) throws CertPathValidatorException {
269+
270+ String msg = "revocation status";
271+ if (debug != null) {
272+ debug.println("CrlRevocationChecker.verifyRevocationStatus()" +
273+ " ---checking " + msg + "...");
274+ }
275+
276+ if (mOnlyEECert && currCert.getBasicConstraints() != -1) {
277+ if (debug != null) {
278+ debug.println("Skipping revocation check, not end entity cert");
279+ }
280+ return;
281+ }
282+
283+ // reject circular dependencies - RFC 3280 is not explicit on how
284+ // to handle this, so we feel it is safest to reject them until
285+ // the issue is resolved in the PKIX WG.
286+ if ((stackedCerts != null) && stackedCerts.contains(currCert)) {
287+ if (debug != null) {
288+ debug.println("CrlRevocationChecker.verifyRevocationStatus()" +
289+ " circular dependency");
290+ }
291+ throw new CertPathValidatorException
292+ ("Could not determine revocation status", null, null, -1,
293+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
294+ }
295+
296+ // init the state for this run
297+ mPossibleCRLs = new HashSet<X509CRL>();
298+ mApprovedCRLs = new HashSet<X509CRL>();
299+ boolean[] reasonsMask = new boolean[9];
300+
301+ try {
302+ X509CRLSelector sel = new X509CRLSelector();
303+ sel.setCertificateChecking(currCert);
304+ CertPathHelper.setDateAndTime(sel, mCurrentTime, MAX_CLOCK_SKEW);
305+
306+ for (CertStore mStore : mStores) {
307+ for (java.security.cert.CRL crl : mStore.getCRLs(sel)) {
308+ mPossibleCRLs.add((X509CRL)crl);
309+ }
310+ }
311+ DistributionPointFetcher store =
312+ DistributionPointFetcher.getInstance();
313+ // all CRLs returned by the DP Fetcher have also been verified
314+ mApprovedCRLs.addAll(store.getCRLs(sel, signFlag, prevKey,
315+ mSigProvider, mStores, reasonsMask, trustAnchors,
316+ mParams.getDate()));
317+ } catch (Exception e) {
318+ if (debug != null) {
319+ debug.println("CrlRevocationChecker.verifyRevocationStatus() "
320+ + "unexpected exception: " + e.getMessage());
321+ }
322+ throw new CertPathValidatorException(e);
323+ }
324+
325+ if (debug != null) {
326+ debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
327+ "crls.size() = " + mPossibleCRLs.size());
328+ }
329+ if (!mPossibleCRLs.isEmpty()) {
330+ // Now that we have a list of possible CRLs, see which ones can
331+ // be approved
332+ mApprovedCRLs.addAll(verifyPossibleCRLs(mPossibleCRLs, currCert,
333+ signFlag, prevKey, reasonsMask, trustAnchors));
334+ }
335+ if (debug != null) {
336+ debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
337+ "approved crls.size() = " + mApprovedCRLs.size());
338+ }
339+
340+ // make sure that we have at least one CRL that _could_ cover
341+ // the certificate in question and all reasons are covered
342+ if (mApprovedCRLs.isEmpty() ||
343+ !Arrays.equals(reasonsMask, ALL_REASONS)) {
344+ if (allowSeparateKey) {
345+ verifyWithSeparateSigningKey(currCert, prevKey, signFlag,
346+ stackedCerts);
347+ return;
348+ } else {
349+ throw new CertPathValidatorException
350+ ("Could not determine revocation status", null, null, -1,
351+ BasicReason.UNDETERMINED_REVOCATION_STATUS);
352+ }
353+ }
354+
355+ // See if the cert is in the set of approved crls.
356+ if (debug != null) {
357+ BigInteger sn = currCert.getSerialNumber();
358+ debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
359+ "starting the final sweep...");
360+ debug.println("CrlRevocationChecker.verifyRevocationStatus" +
361+ " cert SN: " + sn.toString());
362+ }
363+
364+ CRLReason reasonCode = CRLReason.UNSPECIFIED;
365+ X509CRLEntryImpl entry = null;
366+ for (X509CRL crl : mApprovedCRLs) {
367+ X509CRLEntry e = crl.getRevokedCertificate(currCert);
368+ if (e != null) {
369+ try {
370+ entry = X509CRLEntryImpl.toImpl(e);
371+ } catch (CRLException ce) {
372+ throw new CertPathValidatorException(ce);
373+ }
374+ if (debug != null) {
375+ debug.println("CrlRevocationChecker.verifyRevocationStatus"
376+ + " CRL entry: " + entry.toString());
377+ }
378+
379+ /*
380+ * Abort CRL validation and throw exception if there are any
381+ * unrecognized critical CRL entry extensions (see section
382+ * 5.3 of RFC 3280).
383+ */
384+ Set<String> unresCritExts = entry.getCriticalExtensionOIDs();
385+ if (unresCritExts != null && !unresCritExts.isEmpty()) {
386+ /* remove any that we will process */
387+ unresCritExts.remove
388+ (PKIXExtensions.ReasonCode_Id.toString());
389+ unresCritExts.remove
390+ (PKIXExtensions.CertificateIssuer_Id.toString());
391+ if (!unresCritExts.isEmpty()) {
392+ if (debug != null) {
393+ debug.println("Unrecognized "
394+ + "critical extension(s) in revoked CRL entry: "
395+ + unresCritExts);
396+ }
397+ throw new CertPathValidatorException
398+ ("Could not determine revocation status", null, null,
399+ -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
400+ }
401+ }
402+
403+ reasonCode = entry.getRevocationReason();
404+ if (reasonCode == null) {
405+ reasonCode = CRLReason.UNSPECIFIED;
406+ }
407+ Throwable t = new CertificateRevokedException
408+ (entry.getRevocationDate(), reasonCode,
409+ crl.getIssuerX500Principal(), entry.getExtensions());
410+ throw new CertPathValidatorException(t.getMessage(), t,
411+ null, -1, BasicReason.REVOKED);
412+ }
413+ }
414+ }
415+
416+ /**
417+ * We have a cert whose revocation status couldn't be verified by
418+ * a CRL issued by the cert that issued the CRL. See if we can
419+ * find a valid CRL issued by a separate key that can verify the
420+ * revocation status of this certificate.
421+ * <p>
422+ * Note that this does not provide support for indirect CRLs,
423+ * only CRLs signed with a different key (but the same issuer
424+ * name) as the certificate being checked.
425+ *
426+ * @param currCert the <code>X509Certificate</code> to be checked
427+ * @param prevKey the <code>PublicKey</code> that failed
428+ * @param signFlag <code>true</code> if that key was trusted to sign CRLs
429+ * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
430+ * whose revocation status depends on the
431+ * non-revoked status of this cert. To avoid
432+ * circular dependencies, we assume they're
433+ * revoked while checking the revocation
434+ * status of this cert.
435+ * @throws CertPathValidatorException if the cert's revocation status
436+ * cannot be verified successfully with another key
437+ */
438+ private void verifyWithSeparateSigningKey(X509Certificate currCert,
439+ PublicKey prevKey, boolean signFlag, Set<X509Certificate> stackedCerts)
440+ throws CertPathValidatorException {
441+ String msg = "revocation status";
442+ if (debug != null) {
443+ debug.println(
444+ "CrlRevocationChecker.verifyWithSeparateSigningKey()" +
445+ " ---checking " + msg + "...");
446+ }
447+
448+ // reject circular dependencies - RFC 3280 is not explicit on how
449+ // to handle this, so we feel it is safest to reject them until
450+ // the issue is resolved in the PKIX WG.
451+ if ((stackedCerts != null) && stackedCerts.contains(currCert)) {
452+ if (debug != null) {
453+ debug.println(
454+ "CrlRevocationChecker.verifyWithSeparateSigningKey()" +
455+ " circular dependency");
456+ }
457+ throw new CertPathValidatorException
458+ ("Could not determine revocation status", null, null,
459+ -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
460+ }
461+
462+ // If prevKey wasn't trusted, maybe we just didn't have the right
463+ // path to it. Don't rule that key out.
464+ if (!signFlag) {
465+ prevKey = null;
466+ }
467+
468+ // Try to find another key that might be able to sign
469+ // CRLs vouching for this cert.
470+ buildToNewKey(currCert, prevKey, stackedCerts);
471+ }
472+
473+ /**
474+ * Tries to find a CertPath that establishes a key that can be
475+ * used to verify the revocation status of a given certificate.
476+ * Ignores keys that have previously been tried. Throws a
477+ * CertPathValidatorException if no such key could be found.
478+ *
479+ * @param currCert the <code>X509Certificate</code> to be checked
480+ * @param prevKey the <code>PublicKey</code> of the certificate whose key
481+ * cannot be used to vouch for the CRL and should be ignored
482+ * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
483+ * whose revocation status depends on the
484+ * establishment of this path.
485+ * @throws CertPathValidatorException on failure
486+ */
487+ private void buildToNewKey(X509Certificate currCert,
488+ PublicKey prevKey, Set<X509Certificate> stackedCerts)
489+ throws CertPathValidatorException {
490+
491+ if (debug != null) {
492+ debug.println("CrlRevocationChecker.buildToNewKey()" +
493+ " starting work");
494+ }
495+ Set<PublicKey> badKeys = new HashSet<PublicKey>();
496+ if (prevKey != null) {
497+ badKeys.add(prevKey);
498+ }
499+ X509CertSelector certSel = new RejectKeySelector(badKeys);
500+ certSel.setSubject(currCert.getIssuerX500Principal());
501+ certSel.setKeyUsage(mCrlSignUsage);
502+
503+ Set<TrustAnchor> newAnchors =
504+ (mAnchor == null ? mParams.getTrustAnchors() :
505+ Collections.singleton(mAnchor));
506+
507+ PKIXBuilderParameters builderParams;
508+ if (mParams instanceof PKIXBuilderParameters) {
509+ builderParams = (PKIXBuilderParameters) mParams.clone();
510+ builderParams.setTargetCertConstraints(certSel);
511+ // Policy qualifiers must be rejected, since we don't have
512+ // any way to convey them back to the application.
513+ builderParams.setPolicyQualifiersRejected(true);
514+ try {
515+ builderParams.setTrustAnchors(newAnchors);
516+ } catch (InvalidAlgorithmParameterException iape) {
517+ throw new RuntimeException(iape); // should never occur
518+ }
519+ } else {
520+ // It's unfortunate that there's no easy way to make a
521+ // PKIXBuilderParameters object from a PKIXParameters
522+ // object. This might miss some things if parameters
523+ // are added in the future or the validatorParams object
524+ // is a custom class derived from PKIXValidatorParameters.
525+ try {
526+ builderParams = new PKIXBuilderParameters(newAnchors, certSel);
527+ } catch (InvalidAlgorithmParameterException iape) {
528+ throw new RuntimeException(iape); // should never occur
529+ }
530+ builderParams.setInitialPolicies(mParams.getInitialPolicies());
531+ builderParams.setCertStores(mStores);
532+ builderParams.setExplicitPolicyRequired
533+ (mParams.isExplicitPolicyRequired());
534+ builderParams.setPolicyMappingInhibited
535+ (mParams.isPolicyMappingInhibited());
536+ builderParams.setAnyPolicyInhibited(mParams.isAnyPolicyInhibited());
537+ // Policy qualifiers must be rejected, since we don't have
538+ // any way to convey them back to the application.
539+ // That's the default, so no need to write code.
540+ builderParams.setDate(mParams.getDate());
541+ builderParams.setCertPathCheckers(mParams.getCertPathCheckers());
542+ builderParams.setSigProvider(mParams.getSigProvider());
543+ }
544+
545+ // Skip revocation during this build to detect circular
546+ // references. But check revocation afterwards, using the
547+ // key (or any other that works).
548+ builderParams.setRevocationEnabled(false);
549+
550+ // check for AuthorityInformationAccess extension
551+ if (Builder.USE_AIA == true) {
552+ X509CertImpl currCertImpl = null;
553+ try {
554+ currCertImpl = X509CertImpl.toImpl(currCert);
555+ } catch (CertificateException ce) {
556+ // ignore but log it
557+ if (debug != null) {
558+ debug.println("CrlRevocationChecker.buildToNewKey: " +
559+ "error decoding cert: " + ce);
560+ }
561+ }
562+ AuthorityInfoAccessExtension aiaExt = null;
563+ if (currCertImpl != null) {
564+ aiaExt = currCertImpl.getAuthorityInfoAccessExtension();
565+ }
566+ if (aiaExt != null) {
567+ List<AccessDescription> adList = aiaExt.getAccessDescriptions();
568+ if (adList != null) {
569+ for (AccessDescription ad : adList) {
570+ CertStore cs = URICertStore.getInstance(ad);
571+ if (cs != null) {
572+ if (debug != null) {
573+ debug.println("adding AIAext CertStore");
574+ }
575+ builderParams.addCertStore(cs);
576+ }
577+ }
578+ }
579+ }
580+ }
581+
582+ CertPathBuilder builder = null;
583+ try {
584+ builder = CertPathBuilder.getInstance("PKIX");
585+ } catch (NoSuchAlgorithmException nsae) {
586+ throw new CertPathValidatorException(nsae);
587+ }
588+ while (true) {
589+ try {
590+ if (debug != null) {
591+ debug.println("CrlRevocationChecker.buildToNewKey()" +
592+ " about to try build ...");
593+ }
594+ PKIXCertPathBuilderResult cpbr =
595+ (PKIXCertPathBuilderResult) builder.build(builderParams);
596+
597+ if (debug != null) {
598+ debug.println("CrlRevocationChecker.buildToNewKey()" +
599+ " about to check revocation ...");
600+ }
601+ // Now check revocation of all certs in path, assuming that
602+ // the stackedCerts are revoked.
603+ if (stackedCerts == null) {
604+ stackedCerts = new HashSet<X509Certificate>();
605+ }
606+ stackedCerts.add(currCert);
607+ TrustAnchor ta = cpbr.getTrustAnchor();
608+ PublicKey prevKey2 = ta.getCAPublicKey();
609+ if (prevKey2 == null) {
610+ prevKey2 = ta.getTrustedCert().getPublicKey();
611+ }
612+ boolean signFlag = true;
613+ List<? extends Certificate> cpList =
614+ cpbr.getCertPath().getCertificates();
615+ try {
616+ for (int i = cpList.size()-1; i >= 0; i-- ) {
617+ X509Certificate cert = (X509Certificate) cpList.get(i);
618+
619+ if (debug != null) {
620+ debug.println("CrlRevocationChecker.buildToNewKey()"
621+ + " index " + i + " checking " + cert);
622+ }
623+ verifyRevocationStatus(cert, prevKey2, signFlag, true,
624+ stackedCerts, newAnchors);
625+ signFlag = certCanSignCrl(cert);
626+ prevKey2 = cert.getPublicKey();
627+ }
628+ } catch (CertPathValidatorException cpve) {
629+ // ignore it and try to get another key
630+ badKeys.add(cpbr.getPublicKey());
631+ continue;
632+ }
633+
634+ if (debug != null) {
635+ debug.println("CrlRevocationChecker.buildToNewKey()" +
636+ " got key " + cpbr.getPublicKey());
637+ }
638+ // Now check revocation on the current cert using that key.
639+ // If it doesn't check out, try to find a different key.
640+ // And if we can't find a key, then return false.
641+ PublicKey newKey = cpbr.getPublicKey();
642+ try {
643+ verifyRevocationStatus(currCert, newKey, true, false);
644+ // If that passed, the cert is OK!
645+ return;
646+ } catch (CertPathValidatorException cpve) {
647+ // If it is revoked, rethrow exception
648+ if (cpve.getReason() == BasicReason.REVOKED) {
649+ throw cpve;
650+ }
651+ // Otherwise, ignore the exception and
652+ // try to get another key.
653+ }
654+ badKeys.add(newKey);
655+ } catch (InvalidAlgorithmParameterException iape) {
656+ throw new CertPathValidatorException(iape);
657+ } catch (CertPathBuilderException cpbe) {
658+ throw new CertPathValidatorException
659+ ("Could not determine revocation status", null, null,
660+ -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
661+ }
662+ }
663+ }
664+
665+ /*
666+ * This inner class extends the X509CertSelector to add an additional
667+ * check to make sure the subject public key isn't on a particular list.
668+ * This class is used by buildToNewKey() to make sure the builder doesn't
669+ * end up with a CertPath to a public key that has already been rejected.
670+ */
671+ private static class RejectKeySelector extends X509CertSelector {
672+ private final Set<PublicKey> badKeySet;
673+
674+ /**
675+ * Creates a new <code>RejectKeySelector</code>.
676+ *
677+ * @param badPublicKeys a <code>Set</code> of
678+ * <code>PublicKey</code>s that
679+ * should be rejected (or <code>null</code>
680+ * if no such check should be done)
681+ */
682+ RejectKeySelector(Set<PublicKey> badPublicKeys) {
683+ this.badKeySet = badPublicKeys;
684+ }
685+
686+ /**
687+ * Decides whether a <code>Certificate</code> should be selected.
688+ *
689+ * @param cert the <code>Certificate</code> to be checked
690+ * @return <code>true</code> if the <code>Certificate</code> should be
691+ * selected, <code>false</code> otherwise
692+ */
693+ public boolean match(Certificate cert) {
694+ if (!super.match(cert))
695+ return(false);
696+
697+ if (badKeySet.contains(cert.getPublicKey())) {
698+ if (debug != null)
699+ debug.println("RejectCertSelector.match: bad key");
700+ return false;
701+ }
702+
703+ if (debug != null)
704+ debug.println("RejectCertSelector.match: returning true");
705+ return true;
706+ }
707+
708+ /**
709+ * Return a printable representation of the <code>CertSelector</code>.
710+ *
711+ * @return a <code>String</code> describing the contents of the
712+ * <code>CertSelector</code>
713+ */
714+ public String toString() {
715+ StringBuilder sb = new StringBuilder();
716+ sb.append("RejectCertSelector: [\n");
717+ sb.append(super.toString());
718+ sb.append(badKeySet);
719+ sb.append("]");
720+ return sb.toString();
721+ }
722+ }
723+
724+ /**
725+ * Internal method that verifies a set of possible_crls,
726+ * and sees if each is approved, based on the cert.
727+ *
728+ * @param crls a set of possible CRLs to test for acceptability
729+ * @param cert the certificate whose revocation status is being checked
730+ * @param signFlag <code>true</code> if prevKey was trusted to sign CRLs
731+ * @param prevKey the public key of the issuer of cert
732+ * @param reasonsMask the reason code mask
733+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s>
734+ * @return a collection of approved crls (or an empty collection)
735+ */
736+ private Collection<X509CRL> verifyPossibleCRLs(Set<X509CRL> crls,
737+ X509Certificate cert, boolean signFlag, PublicKey prevKey,
738+ boolean[] reasonsMask,
739+ Set<TrustAnchor> trustAnchors) throws CertPathValidatorException {
740+
741+ try {
742+ X509CertImpl certImpl = X509CertImpl.toImpl(cert);
743+ if (debug != null) {
744+ debug.println("CRLRevocationChecker.verifyPossibleCRLs: " +
745+ "Checking CRLDPs for "
746+ + certImpl.getSubjectX500Principal());
747+ }
748+ CRLDistributionPointsExtension ext =
749+ certImpl.getCRLDistributionPointsExtension();
750+ List<DistributionPoint> points = null;
751+ if (ext == null) {
752+ // assume a DP with reasons and CRLIssuer fields omitted
753+ // and a DP name of the cert issuer.
754+ // TODO add issuerAltName too
755+ X500Name certIssuer = (X500Name)certImpl.getIssuerDN();
756+ DistributionPoint point = new DistributionPoint
757+ (new GeneralNames().add(new GeneralName(certIssuer)),
758+ null, null);
759+ points = Collections.singletonList(point);
760+ } else {
761+ points = (List<DistributionPoint>)ext.get(
762+ CRLDistributionPointsExtension.POINTS);
763+ }
764+ Set<X509CRL> results = new HashSet<X509CRL>();
765+ DistributionPointFetcher dpf =
766+ DistributionPointFetcher.getInstance();
767+ for (Iterator<DistributionPoint> t = points.iterator();
768+ t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
769+ DistributionPoint point = t.next();
770+ for (X509CRL crl : crls) {
771+ if (dpf.verifyCRL(certImpl, point, crl, reasonsMask,
772+ signFlag, prevKey, mSigProvider,
773+ trustAnchors, mStores, mParams.getDate())) {
774+ results.add(crl);
775+ }
776+ }
777+ }
778+ return results;
779+ } catch (Exception e) {
780+ if (debug != null) {
781+ debug.println("Exception while verifying CRL: "+e.getMessage());
782+ e.printStackTrace();
783+ }
784+ return Collections.emptySet();
785+ }
786+ }
787+}