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+
26+package sun.security.provider.certpath;
27+
28+import java.io.IOException;
29+import java.security.AccessController;
30+import java.security.GeneralSecurityException;
31+import java.security.InvalidAlgorithmParameterException;
32+import java.security.Principal;
33+import java.security.PublicKey;
34+import java.security.cert.*;
35+import java.security.cert.PKIXReason;
36+import java.security.interfaces.DSAPublicKey;
37+import java.util.ArrayList;
38+import java.util.Collection;
39+import java.util.Collections;
40+import java.util.Comparator;
41+import java.util.HashSet;
42+import java.util.Iterator;
43+import java.util.List;
44+import java.util.LinkedList;
45+import java.util.Set;
46+import javax.security.auth.x500.X500Principal;
47+
48+import sun.security.action.GetBooleanSecurityPropertyAction;
49+import sun.security.x509.X500Name;
50+import sun.security.x509.PKIXExtensions;
51+import 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+ */
74+public 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