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/SunCertPathBuilder.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/provider/certpath/SunCertPathBuilder.java+880−0
@@ -0,0 +1,880 @@
1/*
2 * Copyright (c) 2000, 2010, 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.io.IOException;
29import java.security.AccessController;
30import java.security.GeneralSecurityException;
31import java.security.InvalidAlgorithmParameterException;
32import java.security.Principal;
33import java.security.PublicKey;
34import java.security.cert.*;
35import java.security.cert.PKIXReason;
36import java.security.interfaces.DSAPublicKey;
37import java.util.ArrayList;
38import java.util.Collection;
39import java.util.Collections;
40import java.util.Comparator;
41import java.util.HashSet;
42import java.util.Iterator;
43import java.util.List;
44import java.util.LinkedList;
45import java.util.Set;
46import javax.security.auth.x500.X500Principal;
47
48import sun.security.action.GetBooleanSecurityPropertyAction;
49import sun.security.x509.X500Name;
50import sun.security.x509.PKIXExtensions;
51import sun.security.util.Debug;
52
53/**
54 * This class is able to build certification paths in either the forward
55 * or reverse directions.
56 *
57 * <p> If successful, it returns a certification path which has succesfully
58 * satisfied all the constraints and requirements specified in the
59 * PKIXBuilderParameters object and has been validated according to the PKIX
60 * path validation algorithm defined in RFC 3280.
61 *
62 * <p> This implementation uses a depth-first search approach to finding
63 * certification paths. If it comes to a point in which it cannot find
64 * any more certificates leading to the target OR the path length is too long
65 * it backtracks to previous paths until the target has been found or
66 * all possible paths have been exhausted.
67 *
68 * <p> This implementation is not thread-safe.
69 *
70 * @since 1.4
71 * @author Sean Mullan
72 * @author Yassir Elley
73 */
74public final class SunCertPathBuilder extends CertPathBuilderSpi {
75
76 private static final Debug debug = Debug.getInstance("certpath");
77
78 /*
79 * private objects shared by methods
80 */
81 private PKIXBuilderParameters buildParams;
82 private CertificateFactory cf;
83 private boolean pathCompleted = false;
84 private X500Principal targetSubjectDN;
85 private PolicyNode policyTreeResult;
86 private TrustAnchor trustAnchor;
87 private PublicKey finalPublicKey;
88 private X509CertSelector targetSel;
89 private List<CertStore> orderedCertStores;
90 private boolean onlyEECert = false;
91
92 /**
93 * Create an instance of <code>SunCertPathBuilder</code>.
94 *
95 * @throws CertPathBuilderException if an error occurs
96 */
97 public SunCertPathBuilder() throws CertPathBuilderException {
98 try {
99 cf = CertificateFactory.getInstance("X.509");
100 } catch (CertificateException e) {
101 throw new CertPathBuilderException(e);
102 }
103 onlyEECert = AccessController.doPrivileged(
104 new GetBooleanSecurityPropertyAction
105 ("com.sun.security.onlyCheckRevocationOfEECert"));
106 }
107
108 /**
109 * Attempts to build a certification path using the Sun build
110 * algorithm from a trusted anchor(s) to a target subject, which must both
111 * be specified in the input parameter set. By default, this method will
112 * attempt to build in the forward direction. In order to build in the
113 * reverse direction, the caller needs to pass in an instance of
114 * SunCertPathBuilderParameters with the buildForward flag set to false.
115 *
116 * <p>The certification path that is constructed is validated
117 * according to the PKIX specification.
118 *
119 * @param params the parameter set for building a path. Must be an instance
120 * of <code>PKIXBuilderParameters</code>.
121 * @return a certification path builder result.
122 * @exception CertPathBuilderException Exception thrown if builder is
123 * unable to build a complete certification path from the trusted anchor(s)
124 * to the target subject.
125 * @throws InvalidAlgorithmParameterException if the given parameters are
126 * inappropriate for this certification path builder.
127 */
128 public CertPathBuilderResult engineBuild(CertPathParameters params)
129 throws CertPathBuilderException, InvalidAlgorithmParameterException {
130
131 if (debug != null) {
132 debug.println("SunCertPathBuilder.engineBuild(" + params + ")");
133 }
134
135 if (!(params instanceof PKIXBuilderParameters)) {
136 throw new InvalidAlgorithmParameterException("inappropriate " +
137 "parameter type, must be an instance of PKIXBuilderParameters");
138 }
139
140 boolean buildForward = true;
141 if (params instanceof SunCertPathBuilderParameters) {
142 buildForward =
143 ((SunCertPathBuilderParameters)params).getBuildForward();
144 }
145
146 buildParams = (PKIXBuilderParameters)params;
147
148 /* Check mandatory parameters */
149
150 // Make sure that none of the trust anchors include name constraints
151 // (not supported).
152 for (TrustAnchor anchor : buildParams.getTrustAnchors()) {
153 if (anchor.getNameConstraints() != null) {
154 throw new InvalidAlgorithmParameterException
155 ("name constraints in trust anchor not supported");
156 }
157 }
158
159 CertSelector sel = buildParams.getTargetCertConstraints();
160 if (!(sel instanceof X509CertSelector)) {
161 throw new InvalidAlgorithmParameterException("the "
162 + "targetCertConstraints parameter must be an "
163 + "X509CertSelector");
164 }
165 targetSel = (X509CertSelector)sel;
166 targetSubjectDN = targetSel.getSubject();
167 if (targetSubjectDN == null) {
168 X509Certificate targetCert = targetSel.getCertificate();
169 if (targetCert != null) {
170 targetSubjectDN = targetCert.getSubjectX500Principal();
171 }
172 }
173 // reorder CertStores so that local CertStores are tried first
174 orderedCertStores =
175 new ArrayList<CertStore>(buildParams.getCertStores());
176 Collections.sort(orderedCertStores, new CertStoreComparator());
177 if (targetSubjectDN == null) {
178 targetSubjectDN = getTargetSubjectDN(orderedCertStores, targetSel);
179 }
180 if (targetSubjectDN == null) {
181 throw new InvalidAlgorithmParameterException
182 ("Could not determine unique target subject");
183 }
184
185 List<List<Vertex>> adjList = new ArrayList<List<Vertex>>();
186 CertPathBuilderResult result =
187 buildCertPath(buildForward, false, adjList);
188 if (result == null) {
189 if (debug != null) {
190 debug.println("SunCertPathBuilder.engineBuild: 2nd pass");
191 }
192 // try again
193 adjList.clear();
194 result = buildCertPath(buildForward, true, adjList);
195 if (result == null) {
196 throw new SunCertPathBuilderException("unable to find valid "
197 + "certification path to requested target",
198 new AdjacencyList(adjList));
199 }
200 }
201 return result;
202 }
203
204 private CertPathBuilderResult buildCertPath(boolean buildForward,
205 boolean searchAllCertStores, List<List<Vertex>> adjList)
206 throws CertPathBuilderException {
207
208 // Init shared variables and build certification path
209 pathCompleted = false;
210 trustAnchor = null;
211 finalPublicKey = null;
212 policyTreeResult = null;
213 LinkedList<X509Certificate> certPathList =
214 new LinkedList<X509Certificate>();
215 try {
216 if (buildForward) {
217 buildForward(adjList, certPathList, searchAllCertStores);
218 } else {
219 buildReverse(adjList, certPathList);
220 }
221 } catch (Exception e) {
222 if (debug != null) {
223 debug.println("SunCertPathBuilder.engineBuild() exception in "
224 + "build");
225 e.printStackTrace();
226 }
227 throw new SunCertPathBuilderException("unable to find valid "
228 + "certification path to requested target", e,
229 new AdjacencyList(adjList));
230 }
231
232 // construct SunCertPathBuilderResult
233 try {
234 if (pathCompleted) {
235 if (debug != null)
236 debug.println("SunCertPathBuilder.engineBuild() "
237 + "pathCompleted");
238
239 // we must return a certpath which has the target
240 // as the first cert in the certpath - i.e. reverse
241 // the certPathList
242 Collections.reverse(certPathList);
243
244 return new SunCertPathBuilderResult(
245 cf.generateCertPath(certPathList), this.trustAnchor,
246 policyTreeResult, finalPublicKey,
247 new AdjacencyList(adjList));
248 }
249 } catch (Exception e) {
250 if (debug != null) {
251 debug.println("SunCertPathBuilder.engineBuild() exception "
252 + "in wrap-up");
253 e.printStackTrace();
254 }
255 throw new SunCertPathBuilderException("unable to find valid "
256 + "certification path to requested target", e,
257 new AdjacencyList(adjList));
258 }
259
260 return null;
261 }
262
263 /*
264 * Private build reverse method.
265 */
266 private void buildReverse(List<List<Vertex>> adjacencyList,
267 LinkedList<X509Certificate> certPathList) throws Exception
268 {
269 if (debug != null) {
270 debug.println("SunCertPathBuilder.buildReverse()...");
271 debug.println("SunCertPathBuilder.buildReverse() InitialPolicies: "
272 + buildParams.getInitialPolicies());
273 }
274
275 ReverseState currentState = new ReverseState();
276 /* Initialize adjacency list */
277 adjacencyList.clear();
278 adjacencyList.add(new LinkedList<Vertex>());
279
280 /*
281 * Perform a search using each trust anchor, until a valid
282 * path is found
283 */
284 Iterator<TrustAnchor> iter = buildParams.getTrustAnchors().iterator();
285 while (iter.hasNext()) {
286 TrustAnchor anchor = iter.next();
287 /* check if anchor satisfies target constraints */
288 if (anchorIsTarget(anchor, targetSel)) {
289 this.trustAnchor = anchor;
290 this.pathCompleted = true;
291 this.finalPublicKey = anchor.getTrustedCert().getPublicKey();
292 break;
293 }
294
295 /* Initialize current state */
296 currentState.initState(buildParams.getMaxPathLength(),
297 buildParams.isExplicitPolicyRequired(),
298 buildParams.isPolicyMappingInhibited(),
299 buildParams.isAnyPolicyInhibited(),
300 buildParams.getCertPathCheckers());
301 currentState.updateState(anchor);
302 // init the crl checker
303 currentState.crlChecker =
304 new CrlRevocationChecker(null, buildParams, null, onlyEECert);
305 currentState.algorithmChecker = new AlgorithmChecker(anchor);
306 try {
307 depthFirstSearchReverse(null, currentState,
308 new ReverseBuilder(buildParams, targetSubjectDN), adjacencyList,
309 certPathList);
310 } catch (Exception e) {
311 // continue on error if more anchors to try
312 if (iter.hasNext())
313 continue;
314 else
315 throw e;
316 }
317
318 // break out of loop if search is successful
319 break;
320 }
321
322 if (debug != null) {
323 debug.println("SunCertPathBuilder.buildReverse() returned from "
324 + "depthFirstSearchReverse()");
325 debug.println("SunCertPathBuilder.buildReverse() "
326 + "certPathList.size: " + certPathList.size());
327 }
328 }
329
330 /*
331 * Private build forward method.
332 */
333 private void buildForward(List<List<Vertex>> adjacencyList,
334 LinkedList<X509Certificate> certPathList, boolean searchAllCertStores)
335 throws GeneralSecurityException, IOException
336 {
337 if (debug != null) {
338 debug.println("SunCertPathBuilder.buildForward()...");
339 }
340
341 /* Initialize current state */
342 ForwardState currentState = new ForwardState();
343 currentState.initState(buildParams.getCertPathCheckers());
344
345 /* Initialize adjacency list */
346 adjacencyList.clear();
347 adjacencyList.add(new LinkedList<Vertex>());
348
349 // init the crl checker
350 currentState.crlChecker
351 = new CrlRevocationChecker(null, buildParams, null, onlyEECert);
352
353 depthFirstSearchForward(targetSubjectDN, currentState,
354 new ForwardBuilder
355 (buildParams, targetSubjectDN, searchAllCertStores, onlyEECert),
356 adjacencyList, certPathList);
357 }
358
359 /*
360 * This method performs a depth first search for a certification
361 * path while building forward which meets the requirements set in
362 * the parameters object.
363 * It uses an adjacency list to store all certificates which were
364 * tried (i.e. at one time added to the path - they may not end up in
365 * the final path if backtracking occurs). This information can
366 * be used later to debug or demo the build.
367 *
368 * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
369 * for an explanation of the DFS algorithm.
370 *
371 * @param dN the distinguished name being currently searched for certs
372 * @param currentState the current PKIX validation state
373 */
374 void depthFirstSearchForward(X500Principal dN, ForwardState currentState,
375 ForwardBuilder builder, List<List<Vertex>> adjList,
376 LinkedList<X509Certificate> certPathList)
377 throws GeneralSecurityException, IOException
378 {
379 //XXX This method should probably catch & handle exceptions
380
381 if (debug != null) {
382 debug.println("SunCertPathBuilder.depthFirstSearchForward(" + dN
383 + ", " + currentState.toString() + ")");
384 }
385
386 /*
387 * Find all the certificates issued to dN which
388 * satisfy the PKIX certification path constraints.
389 */
390 List<Vertex> vertices = addVertices
391 (builder.getMatchingCerts(currentState, orderedCertStores), adjList);
392 if (debug != null) {
393 debug.println("SunCertPathBuilder.depthFirstSearchForward(): "
394 + "certs.size=" + vertices.size());
395 }
396
397 /*
398 * For each cert in the collection, verify anything
399 * that hasn't been checked yet (signature, revocation, etc)
400 * and check for loops. Call depthFirstSearchForward()
401 * recursively for each good cert.
402 */
403
404 vertices:
405 for (Vertex vertex : vertices) {
406 /**
407 * Restore state to currentState each time through the loop.
408 * This is important because some of the user-defined
409 * checkers modify the state, which MUST be restored if
410 * the cert eventually fails to lead to the target and
411 * the next matching cert is tried.
412 */
413 ForwardState nextState = (ForwardState) currentState.clone();
414 X509Certificate cert = (X509Certificate) vertex.getCertificate();
415
416 try {
417 builder.verifyCert(cert, nextState, certPathList);
418 } catch (GeneralSecurityException gse) {
419 if (debug != null) {
420 debug.println("SunCertPathBuilder.depthFirstSearchForward()"
421 + ": validation failed: " + gse);
422 gse.printStackTrace();
423 }
424 vertex.setThrowable(gse);
425 continue;
426 }
427
428 /*
429 * Certificate is good.
430 * If cert completes the path,
431 * process userCheckers that don't support forward checking
432 * and process policies over whole path
433 * and backtrack appropriately if there is a failure
434 * else if cert does not complete the path,
435 * add it to the path
436 */
437 if (builder.isPathCompleted(cert)) {
438
439 BasicChecker basicChecker = null;
440 if (debug != null)
441 debug.println("SunCertPathBuilder.depthFirstSearchForward()"
442 + ": commencing final verification");
443
444 ArrayList<X509Certificate> appendedCerts =
445 new ArrayList<X509Certificate>(certPathList);
446
447 /*
448 * if the trust anchor selected is specified as a trusted
449 * public key rather than a trusted cert, then verify this
450 * cert (which is signed by the trusted public key), but
451 * don't add it yet to the certPathList
452 */
453 if (builder.trustAnchor.getTrustedCert() == null) {
454 appendedCerts.add(0, cert);
455 }
456
457 HashSet<String> initExpPolSet = new HashSet<String>(1);
458 initExpPolSet.add(PolicyChecker.ANY_POLICY);
459
460 PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
461 PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
462
463 PolicyChecker policyChecker
464 = new PolicyChecker(buildParams.getInitialPolicies(),
465 appendedCerts.size(),
466 buildParams.isExplicitPolicyRequired(),
467 buildParams.isPolicyMappingInhibited(),
468 buildParams.isAnyPolicyInhibited(),
469 buildParams.getPolicyQualifiersRejected(),
470 rootNode);
471
472 List<PKIXCertPathChecker> userCheckers = new
473 ArrayList<PKIXCertPathChecker>
474 (buildParams.getCertPathCheckers());
475 int mustCheck = 0;
476 userCheckers.add(mustCheck, policyChecker);
477 mustCheck++;
478
479 // add the algorithm checker
480 userCheckers.add(mustCheck,
481 new AlgorithmChecker(builder.trustAnchor));
482 mustCheck++;
483
484 if (nextState.keyParamsNeeded()) {
485 PublicKey rootKey = cert.getPublicKey();
486 if (builder.trustAnchor.getTrustedCert() == null) {
487 rootKey = builder.trustAnchor.getCAPublicKey();
488 if (debug != null)
489 debug.println(
490 "SunCertPathBuilder.depthFirstSearchForward " +
491 "using buildParams public key: " +
492 rootKey.toString());
493 }
494 TrustAnchor anchor = new TrustAnchor
495 (cert.getSubjectX500Principal(), rootKey, null);
496
497 // add the basic checker
498 basicChecker = new BasicChecker(anchor,
499 builder.date,
500 buildParams.getSigProvider(),
501 true);
502 userCheckers.add(mustCheck, basicChecker);
503 mustCheck++;
504
505 // add the crl revocation checker
506 if (buildParams.isRevocationEnabled()) {
507 userCheckers.add(mustCheck, new CrlRevocationChecker
508 (anchor, buildParams, null, onlyEECert));
509 mustCheck++;
510 }
511 }
512 // Why we don't need BasicChecker and CrlRevocationChecker
513 // if nextState.keyParamsNeeded() is false?
514
515 for (int i=0; i<appendedCerts.size(); i++) {
516 X509Certificate currCert = appendedCerts.get(i);
517 if (debug != null)
518 debug.println("current subject = "
519 + currCert.getSubjectX500Principal());
520 Set<String> unresCritExts =
521 currCert.getCriticalExtensionOIDs();
522 if (unresCritExts == null) {
523 unresCritExts = Collections.<String>emptySet();
524 }
525
526 for (int j=0; j<userCheckers.size(); j++) {
527 PKIXCertPathChecker currChecker = userCheckers.get(j);
528 if (j < mustCheck ||
529 !currChecker.isForwardCheckingSupported()) {
530 if (i == 0) {
531 currChecker.init(false);
532
533 // The user specified
534 // AlgorithmChecker may not be
535 // able to set the trust anchor until now.
536 if (j >= mustCheck &&
537 currChecker instanceof AlgorithmChecker) {
538 ((AlgorithmChecker)currChecker).
539 trySetTrustAnchor(builder.trustAnchor);
540 }
541 }
542
543 try {
544 currChecker.check(currCert, unresCritExts);
545 } catch (CertPathValidatorException cpve) {
546 if (debug != null)
547 debug.println
548 ("SunCertPathBuilder.depthFirstSearchForward(): " +
549 "final verification failed: " + cpve);
550 vertex.setThrowable(cpve);
551 continue vertices;
552 }
553 }
554 }
555
556 /*
557 * Remove extensions from user checkers that support
558 * forward checking. After this step, we will have
559 * removed all extensions that all user checkers
560 * are capable of processing.
561 */
562 for (PKIXCertPathChecker checker :
563 buildParams.getCertPathCheckers())
564 {
565 if (checker.isForwardCheckingSupported()) {
566 Set<String> suppExts =
567 checker.getSupportedExtensions();
568 if (suppExts != null) {
569 unresCritExts.removeAll(suppExts);
570 }
571 }
572 }
573
574 if (!unresCritExts.isEmpty()) {
575 unresCritExts.remove
576 (PKIXExtensions.BasicConstraints_Id.toString());
577 unresCritExts.remove
578 (PKIXExtensions.NameConstraints_Id.toString());
579 unresCritExts.remove
580 (PKIXExtensions.CertificatePolicies_Id.toString());
581 unresCritExts.remove
582 (PKIXExtensions.PolicyMappings_Id.toString());
583 unresCritExts.remove
584 (PKIXExtensions.PolicyConstraints_Id.toString());
585 unresCritExts.remove
586 (PKIXExtensions.InhibitAnyPolicy_Id.toString());
587 unresCritExts.remove(PKIXExtensions.
588 SubjectAlternativeName_Id.toString());
589 unresCritExts.remove
590 (PKIXExtensions.KeyUsage_Id.toString());
591 unresCritExts.remove
592 (PKIXExtensions.ExtendedKeyUsage_Id.toString());
593
594 if (!unresCritExts.isEmpty()) {
595 throw new CertPathValidatorException
596 ("unrecognized critical extension(s)", null,
597 null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT);
598 }
599 }
600 }
601 if (debug != null)
602 debug.println("SunCertPathBuilder.depthFirstSearchForward()"
603 + ": final verification succeeded - path completed!");
604 pathCompleted = true;
605
606 /*
607 * if the user specified a trusted public key rather than
608 * trusted certs, then add this cert (which is signed by
609 * the trusted public key) to the certPathList
610 */
611 if (builder.trustAnchor.getTrustedCert() == null)
612 builder.addCertToPath(cert, certPathList);
613 // Save the trust anchor
614 this.trustAnchor = builder.trustAnchor;
615
616 /*
617 * Extract and save the final target public key
618 */
619 if (basicChecker != null) {
620 finalPublicKey = basicChecker.getPublicKey();
621 } else {
622 Certificate finalCert;
623 if (certPathList.size() == 0) {
624 finalCert = builder.trustAnchor.getTrustedCert();
625 } else {
626 finalCert = certPathList.get(certPathList.size()-1);
627 }
628 finalPublicKey = finalCert.getPublicKey();
629 }
630
631 policyTreeResult = policyChecker.getPolicyTree();
632 return;
633 } else {
634 builder.addCertToPath(cert, certPathList);
635 }
636
637 /* Update the PKIX state */
638 nextState.updateState(cert);
639
640 /*
641 * Append an entry for cert in adjacency list and
642 * set index for current vertex.
643 */
644 adjList.add(new LinkedList<Vertex>());
645 vertex.setIndex(adjList.size() - 1);
646
647 /* recursively search for matching certs at next dN */
648 depthFirstSearchForward(cert.getIssuerX500Principal(), nextState, builder,
649 adjList, certPathList);
650
651 /*
652 * If path has been completed, return ASAP!
653 */
654 if (pathCompleted) {
655 return;
656 } else {
657 /*
658 * If we get here, it means we have searched all possible
659 * certs issued by the dN w/o finding any matching certs.
660 * This means we have to backtrack to the previous cert in
661 * the path and try some other paths.
662 */
663 if (debug != null)
664 debug.println("SunCertPathBuilder.depthFirstSearchForward()"
665 + ": backtracking");
666 builder.removeFinalCertFromPath(certPathList);
667 }
668 }
669 }
670
671 /*
672 * This method performs a depth first search for a certification
673 * path while building reverse which meets the requirements set in
674 * the parameters object.
675 * It uses an adjacency list to store all certificates which were
676 * tried (i.e. at one time added to the path - they may not end up in
677 * the final path if backtracking occurs). This information can
678 * be used later to debug or demo the build.
679 *
680 * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
681 * for an explanation of the DFS algorithm.
682 *
683 * @param dN the distinguished name being currently searched for certs
684 * @param currentState the current PKIX validation state
685 */
686 void depthFirstSearchReverse(X500Principal dN, ReverseState currentState,
687 ReverseBuilder builder, List<List<Vertex>> adjList,
688 LinkedList<X509Certificate> certPathList)
689 throws GeneralSecurityException, IOException
690 {
691 if (debug != null)
692 debug.println("SunCertPathBuilder.depthFirstSearchReverse(" + dN
693 + ", " + currentState.toString() + ")");
694
695 /*
696 * Find all the certificates issued by dN which
697 * satisfy the PKIX certification path constraints.
698 */
699 List<Vertex> vertices = addVertices
700 (builder.getMatchingCerts(currentState, orderedCertStores), adjList);
701 if (debug != null)
702 debug.println("SunCertPathBuilder.depthFirstSearchReverse(): "
703 + "certs.size=" + vertices.size());
704
705 /*
706 * For each cert in the collection, verify anything
707 * that hasn't been checked yet (signature, revocation, etc)
708 * and check for loops. Call depthFirstSearchReverse()
709 * recursively for each good cert.
710 */
711 for (Vertex vertex : vertices) {
712 /**
713 * Restore state to currentState each time through the loop.
714 * This is important because some of the user-defined
715 * checkers modify the state, which MUST be restored if
716 * the cert eventually fails to lead to the target and
717 * the next matching cert is tried.
718 */
719 ReverseState nextState = (ReverseState) currentState.clone();
720 X509Certificate cert = (X509Certificate) vertex.getCertificate();
721 try {
722 builder.verifyCert(cert, nextState, certPathList);
723 } catch (GeneralSecurityException gse) {
724 if (debug != null)
725 debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
726 + ": validation failed: " + gse);
727 vertex.setThrowable(gse);
728 continue;
729 }
730
731 /*
732 * Certificate is good, add it to the path (if it isn't a
733 * self-signed cert) and update state
734 */
735 if (!currentState.isInitial())
736 builder.addCertToPath(cert, certPathList);
737 // save trust anchor
738 this.trustAnchor = currentState.trustAnchor;
739
740 /*
741 * Check if path is completed, return ASAP if so.
742 */
743 if (builder.isPathCompleted(cert)) {
744 if (debug != null)
745 debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
746 + ": path completed!");
747 pathCompleted = true;
748
749 PolicyNodeImpl rootNode = nextState.rootNode;
750
751 if (rootNode == null)
752 policyTreeResult = null;
753 else {
754 policyTreeResult = rootNode.copyTree();
755 ((PolicyNodeImpl)policyTreeResult).setImmutable();
756 }
757
758 /*
759 * Extract and save the final target public key
760 */
761 finalPublicKey = cert.getPublicKey();
762 if (finalPublicKey instanceof DSAPublicKey &&
763 ((DSAPublicKey)finalPublicKey).getParams() == null)
764 {
765 finalPublicKey =
766 BasicChecker.makeInheritedParamsKey
767 (finalPublicKey, currentState.pubKey);
768 }
769
770 return;
771 }
772
773 /* Update the PKIX state */
774 nextState.updateState(cert);
775
776 /*
777 * Append an entry for cert in adjacency list and
778 * set index for current vertex.
779 */
780 adjList.add(new LinkedList<Vertex>());
781 vertex.setIndex(adjList.size() - 1);
782
783 /* recursively search for matching certs at next dN */
784 depthFirstSearchReverse(cert.getSubjectX500Principal(), nextState,
785 builder, adjList, certPathList);
786
787 /*
788 * If path has been completed, return ASAP!
789 */
790 if (pathCompleted) {
791 return;
792 } else {
793 /*
794 * If we get here, it means we have searched all possible
795 * certs issued by the dN w/o finding any matching certs. This
796 * means we have to backtrack to the previous cert in the path
797 * and try some other paths.
798 */
799 if (debug != null)
800 debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
801 + ": backtracking");
802 if (!currentState.isInitial())
803 builder.removeFinalCertFromPath(certPathList);
804 }
805 }
806 if (debug != null)
807 debug.println("SunCertPathBuilder.depthFirstSearchReverse() all "
808 + "certs in this adjacency list checked");
809 }
810
811 /*
812 * Adds a collection of matching certificates to the
813 * adjacency list.
814 */
815 private List<Vertex> addVertices(Collection<X509Certificate> certs,
816 List<List<Vertex>> adjList) {
817 List<Vertex> l = adjList.get(adjList.size() - 1);
818
819 for (X509Certificate cert : certs) {
820 Vertex v = new Vertex(cert);
821 l.add(v);
822 }
823
824 return l;
825 }
826
827 /**
828 * Returns true if trust anchor certificate matches specified
829 * certificate constraints.
830 */
831 private boolean anchorIsTarget(TrustAnchor anchor, X509CertSelector sel) {
832 X509Certificate anchorCert = anchor.getTrustedCert();
833 if (anchorCert != null) {
834 return sel.match(anchorCert);
835 }
836 return false;
837 }
838
839 /**
840 * Comparator that orders CertStores so that local CertStores come before
841 * remote CertStores.
842 */
843 private static class CertStoreComparator implements Comparator<CertStore> {
844 public int compare(CertStore store1, CertStore store2) {
845 if (Builder.isLocalCertStore(store1)) {
846 return -1;
847 } else {
848 return 1;
849 }
850 }
851 }
852
853 /**
854 * Returns the target subject DN from the first X509Certificate that
855 * is fetched that matches the specified X509CertSelector.
856 */
857 private X500Principal getTargetSubjectDN(List<CertStore> stores,
858 X509CertSelector targetSel) {
859 for (CertStore store : stores) {
860 try {
861 Collection<? extends Certificate> targetCerts =
862 (Collection<? extends Certificate>)
863 store.getCertificates(targetSel);
864 if (!targetCerts.isEmpty()) {
865 X509Certificate targetCert =
866 (X509Certificate)targetCerts.iterator().next();
867 return targetCert.getSubjectX500Principal();
868 }
869 } catch (CertStoreException e) {
870 // ignore but log it
871 if (debug != null) {
872 debug.println("SunCertPathBuilder.getTargetSubjectDN: " +
873 "non-fatal exception retrieving certs: " + e);
874 e.printStackTrace();
875 }
876 }
877 }
878 return null;
879 }
880}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t