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
26package sun.security.provider.certpath;
27
28import java.math.BigInteger;
29import java.util.Arrays;
30import java.util.ArrayList;
31import java.util.Collection;
32import java.util.Collections;
33import java.util.Date;
34import java.util.List;
35import java.util.HashSet;
36import java.util.Set;
37import java.util.Iterator;
38import java.security.InvalidAlgorithmParameterException;
39import java.security.NoSuchAlgorithmException;
40import java.security.PublicKey;
41import java.security.cert.*;
42import java.security.cert.CertPathValidatorException.BasicReason;
43import java.security.interfaces.DSAPublicKey;
44import javax.security.auth.x500.X500Principal;
45import sun.security.util.Debug;
46import sun.security.x509.AccessDescription;
47import sun.security.x509.AuthorityInfoAccessExtension;
48import sun.security.x509.CRLDistributionPointsExtension;
49import sun.security.x509.DistributionPoint;
50import sun.security.x509.GeneralName;
51import sun.security.x509.GeneralNames;
52import sun.security.x509.PKIXExtensions;
53import sun.security.x509.X500Name;
54import sun.security.x509.X509CertImpl;
55import 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 */
67class 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}