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

Unified · Split

java/pkg/sun/security/provider/certpath/ForwardBuilder.java+930−0
@@ -0,0 +1,930 @@
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.io.IOException;
29+import java.util.*;
30+
31+import java.security.GeneralSecurityException;
32+import java.security.InvalidKeyException;
33+import java.security.cert.Certificate;
34+import java.security.cert.CertificateException;
35+import java.security.cert.CertPathValidatorException;
36+import java.security.cert.PKIXReason;
37+import java.security.cert.CertStore;
38+import java.security.cert.CertStoreException;
39+import java.security.cert.PKIXBuilderParameters;
40+import java.security.cert.PKIXCertPathChecker;
41+import java.security.cert.TrustAnchor;
42+import java.security.cert.X509Certificate;
43+import java.security.cert.X509CertSelector;
44+import javax.security.auth.x500.X500Principal;
45+
46+import sun.security.util.Debug;
47+import sun.security.util.DerOutputStream;
48+import sun.security.x509.AccessDescription;
49+import sun.security.x509.AuthorityInfoAccessExtension;
50+import sun.security.x509.PKIXExtensions;
51+import sun.security.x509.PolicyMappingsExtension;
52+import sun.security.x509.X500Name;
53+import sun.security.x509.X509CertImpl;
54+import sun.security.x509.X509CRLImpl;
55+import sun.security.x509.AuthorityKeyIdentifierExtension;
56+import sun.security.x509.KeyIdentifier;
57+import sun.security.x509.SubjectKeyIdentifierExtension;
58+import sun.security.x509.SerialNumber;
59+import sun.security.x509.GeneralNames;
60+import sun.security.x509.GeneralName;
61+import sun.security.x509.GeneralNameInterface;
62+import java.math.BigInteger;
63+
64+/**
65+ * This class represents a forward builder, which is able to retrieve
66+ * matching certificates from CertStores and verify a particular certificate
67+ * against a ForwardState.
68+ *
69+ * @since 1.4
70+ * @author Yassir Elley
71+ * @author Sean Mullan
72+ */
73+class ForwardBuilder extends Builder {
74+
75+ private static final Debug debug = Debug.getInstance("certpath");
76+ private final Set<X509Certificate> trustedCerts;
77+ private final Set<X500Principal> trustedSubjectDNs;
78+ private final Set<TrustAnchor> trustAnchors;
79+ private X509CertSelector eeSelector;
80+ private AdaptableX509CertSelector caSelector;
81+ private X509CertSelector caTargetSelector;
82+ TrustAnchor trustAnchor;
83+ private Comparator<X509Certificate> comparator;
84+ private boolean searchAllCertStores = true;
85+ private boolean onlyEECert = false;
86+
87+ /**
88+ * Initialize the builder with the input parameters.
89+ *
90+ * @param params the parameter set used to build a certification path
91+ */
92+ ForwardBuilder(PKIXBuilderParameters buildParams,
93+ X500Principal targetSubjectDN, boolean searchAllCertStores,
94+ boolean onlyEECert)
95+ {
96+ super(buildParams, targetSubjectDN);
97+
98+ // populate sets of trusted certificates and subject DNs
99+ trustAnchors = buildParams.getTrustAnchors();
100+ trustedCerts = new HashSet<X509Certificate>(trustAnchors.size());
101+ trustedSubjectDNs = new HashSet<X500Principal>(trustAnchors.size());
102+ for (TrustAnchor anchor : trustAnchors) {
103+ X509Certificate trustedCert = anchor.getTrustedCert();
104+ if (trustedCert != null) {
105+ trustedCerts.add(trustedCert);
106+ trustedSubjectDNs.add(trustedCert.getSubjectX500Principal());
107+ } else {
108+ trustedSubjectDNs.add(anchor.getCA());
109+ }
110+ }
111+ comparator = new PKIXCertComparator(trustedSubjectDNs);
112+ this.searchAllCertStores = searchAllCertStores;
113+ this.onlyEECert = onlyEECert;
114+ }
115+
116+ /**
117+ * Retrieves all certs from the specified CertStores that satisfy the
118+ * requirements specified in the parameters and the current
119+ * PKIX state (name constraints, policy constraints, etc).
120+ *
121+ * @param currentState the current state.
122+ * Must be an instance of <code>ForwardState</code>
123+ * @param certStores list of CertStores
124+ */
125+ Collection<X509Certificate> getMatchingCerts
126+ (State currentState, List<CertStore> certStores)
127+ throws CertStoreException, CertificateException, IOException
128+ {
129+ if (debug != null) {
130+ debug.println("ForwardBuilder.getMatchingCerts()...");
131+ }
132+
133+ ForwardState currState = (ForwardState) currentState;
134+
135+ /*
136+ * We store certs in a Set because we don't want duplicates.
137+ * As each cert is added, it is sorted based on the PKIXCertComparator
138+ * algorithm.
139+ */
140+ Set<X509Certificate> certs = new TreeSet<X509Certificate>(comparator);
141+
142+ /*
143+ * Only look for EE certs if search has just started.
144+ */
145+ if (currState.isInitial()) {
146+ getMatchingEECerts(currState, certStores, certs);
147+ }
148+ getMatchingCACerts(currState, certStores, certs);
149+
150+ return certs;
151+ }
152+
153+ /*
154+ * Retrieves all end-entity certificates which satisfy constraints
155+ * and requirements specified in the parameters and PKIX state.
156+ */
157+ private void getMatchingEECerts(ForwardState currentState,
158+ List<CertStore> certStores, Collection<X509Certificate> eeCerts)
159+ throws IOException {
160+
161+ if (debug != null) {
162+ debug.println("ForwardBuilder.getMatchingEECerts()...");
163+ }
164+ /*
165+ * Compose a certificate matching rule to filter out
166+ * certs which don't satisfy constraints
167+ *
168+ * First, retrieve clone of current target cert constraints,
169+ * and then add more selection criteria based on current validation
170+ * state. Since selector never changes, cache local copy & reuse.
171+ */
172+ if (eeSelector == null) {
173+ eeSelector = (X509CertSelector) targetCertConstraints.clone();
174+
175+ /*
176+ * Match on certificate validity date
177+ */
178+ eeSelector.setCertificateValid(date);
179+
180+ /*
181+ * Policy processing optimizations
182+ */
183+ if (buildParams.isExplicitPolicyRequired()) {
184+ eeSelector.setPolicy(getMatchingPolicies());
185+ }
186+ /*
187+ * Require EE certs
188+ */
189+ eeSelector.setBasicConstraints(-2);
190+ }
191+
192+ /* Retrieve matching EE certs from CertStores */
193+ addMatchingCerts(eeSelector, certStores, eeCerts, searchAllCertStores);
194+ }
195+
196+ /**
197+ * Retrieves all CA certificates which satisfy constraints
198+ * and requirements specified in the parameters and PKIX state.
199+ */
200+ private void getMatchingCACerts(ForwardState currentState,
201+ List<CertStore> certStores, Collection<X509Certificate> caCerts)
202+ throws IOException {
203+
204+ if (debug != null) {
205+ debug.println("ForwardBuilder.getMatchingCACerts()...");
206+ }
207+ int initialSize = caCerts.size();
208+
209+ /*
210+ * Compose a CertSelector to filter out
211+ * certs which do not satisfy requirements.
212+ */
213+ X509CertSelector sel = null;
214+
215+ if (currentState.isInitial()) {
216+ if (targetCertConstraints.getBasicConstraints() == -2) {
217+ // no need to continue: this means we never can match a CA cert
218+ return;
219+ }
220+
221+ /* This means a CA is the target, so match on same stuff as
222+ * getMatchingEECerts
223+ */
224+ if (debug != null) {
225+ debug.println("ForwardBuilder.getMatchingCACerts(): ca is target");
226+ }
227+
228+ if (caTargetSelector == null) {
229+ caTargetSelector = (X509CertSelector)
230+ targetCertConstraints.clone();
231+
232+ /*
233+ * Since we don't check the validity period of trusted
234+ * certificates, please don't set the certificate valid
235+ * criterion unless the trusted certificate matching is
236+ * completed.
237+ */
238+
239+ /*
240+ * Policy processing optimizations
241+ */
242+ if (buildParams.isExplicitPolicyRequired())
243+ caTargetSelector.setPolicy(getMatchingPolicies());
244+ }
245+
246+ sel = caTargetSelector;
247+ } else {
248+
249+ if (caSelector == null) {
250+ caSelector = new AdaptableX509CertSelector();
251+
252+ /*
253+ * Since we don't check the validity period of trusted
254+ * certificates, please don't set the certificate valid
255+ * criterion unless the trusted certificate matching is
256+ * completed.
257+ */
258+
259+ /*
260+ * Policy processing optimizations
261+ */
262+ if (buildParams.isExplicitPolicyRequired())
263+ caSelector.setPolicy(getMatchingPolicies());
264+ }
265+
266+ /*
267+ * Match on subject (issuer of previous cert)
268+ */
269+ caSelector.setSubject(currentState.issuerDN);
270+
271+ /*
272+ * Match on subjectNamesTraversed (both DNs and AltNames)
273+ * (checks that current cert's name constraints permit it
274+ * to certify all the DNs and AltNames that have been traversed)
275+ */
276+ CertPathHelper.setPathToNames
277+ (caSelector, currentState.subjectNamesTraversed);
278+
279+ /*
280+ * Facilitate certification path construction with authority
281+ * key identifier and subject key identifier.
282+ */
283+ AuthorityKeyIdentifierExtension akidext =
284+ currentState.cert.getAuthorityKeyIdentifierExtension();
285+ caSelector.parseAuthorityKeyIdentifierExtension(akidext);
286+
287+ /*
288+ * check the validity period
289+ */
290+ caSelector.setValidityPeriod(currentState.cert.getNotBefore(),
291+ currentState.cert.getNotAfter());
292+
293+ sel = caSelector;
294+ }
295+
296+ /*
297+ * For compatibility, conservatively, we don't check the path
298+ * length constraint of trusted anchors. Please don't set the
299+ * basic constraints criterion unless the trusted certificate
300+ * matching is completed.
301+ */
302+ sel.setBasicConstraints(-1);
303+
304+ for (X509Certificate trustedCert : trustedCerts) {
305+ if (sel.match(trustedCert)) {
306+ if (debug != null) {
307+ debug.println("ForwardBuilder.getMatchingCACerts: "
308+ + "found matching trust anchor");
309+ }
310+ if (caCerts.add(trustedCert) && !searchAllCertStores) {
311+ return;
312+ }
313+ }
314+ }
315+
316+ /*
317+ * The trusted certificate matching is completed. We need to match
318+ * on certificate validity date.
319+ */
320+ sel.setCertificateValid(date);
321+
322+ /*
323+ * Require CA certs with a pathLenConstraint that allows
324+ * at least as many CA certs that have already been traversed
325+ */
326+ sel.setBasicConstraints(currentState.traversedCACerts);
327+
328+ /*
329+ * If we have already traversed as many CA certs as the maxPathLength
330+ * will allow us to, then we don't bother looking through these
331+ * certificate pairs. If maxPathLength has a value of -1, this
332+ * means it is unconstrained, so we always look through the
333+ * certificate pairs.
334+ */
335+ if (currentState.isInitial() ||
336+ (buildParams.getMaxPathLength() == -1) ||
337+ (buildParams.getMaxPathLength() > currentState.traversedCACerts))
338+ {
339+ if (addMatchingCerts(sel, certStores,
340+ caCerts, searchAllCertStores) && !searchAllCertStores) {
341+ return;
342+ }
343+ }
344+
345+ if (!currentState.isInitial() && Builder.USE_AIA) {
346+ // check for AuthorityInformationAccess extension
347+ AuthorityInfoAccessExtension aiaExt =
348+ currentState.cert.getAuthorityInfoAccessExtension();
349+ if (aiaExt != null) {
350+ getCerts(aiaExt, caCerts);
351+ }
352+ }
353+
354+ if (debug != null) {
355+ int numCerts = caCerts.size() - initialSize;
356+ debug.println("ForwardBuilder.getMatchingCACerts: found " +
357+ numCerts + " CA certs");
358+ }
359+ }
360+
361+ /**
362+ * Download Certificates from the given AIA and add them to the
363+ * specified Collection.
364+ */
365+ private boolean getCerts(AuthorityInfoAccessExtension aiaExt,
366+ Collection<X509Certificate> certs) {
367+ if (Builder.USE_AIA == false) {
368+ return false;
369+ }
370+ List<AccessDescription> adList = aiaExt.getAccessDescriptions();
371+ if (adList == null || adList.isEmpty()) {
372+ return false;
373+ }
374+
375+ boolean add = false;
376+ for (AccessDescription ad : adList) {
377+ CertStore cs = URICertStore.getInstance(ad);
378+ try {
379+ if (certs.addAll((Collection<X509Certificate>)
380+ cs.getCertificates(caSelector))) {
381+ add = true;
382+ if (!searchAllCertStores) {
383+ return true;
384+ }
385+ }
386+ } catch (CertStoreException cse) {
387+ if (debug != null) {
388+ debug.println("exception getting certs from CertStore:");
389+ cse.printStackTrace();
390+ }
391+ continue;
392+ }
393+ }
394+ return add;
395+ }
396+
397+ /**
398+ * This inner class compares 2 PKIX certificates according to which
399+ * should be tried first when building a path from the target.
400+ * The preference order is as follows:
401+ *
402+ * Given trusted certificate(s):
403+ * Subject:ou=D,ou=C,o=B,c=A
404+ *
405+ * Preference order for current cert:
406+ *
407+ * 1) Issuer matches a trusted subject
408+ * Issuer: ou=D,ou=C,o=B,c=A
409+ *
410+ * 2) Issuer is a descendant of a trusted subject (in order of
411+ * number of links to the trusted subject)
412+ * a) Issuer: ou=E,ou=D,ou=C,o=B,c=A [links=1]
413+ * b) Issuer: ou=F,ou=E,ou=D,ou=C,ou=B,c=A [links=2]
414+ *
415+ * 3) Issuer is an ancestor of a trusted subject (in order of number of
416+ * links to the trusted subject)
417+ * a) Issuer: ou=C,o=B,c=A [links=1]
418+ * b) Issuer: o=B,c=A [links=2]
419+ *
420+ * 4) Issuer is in the same namespace as a trusted subject (in order of
421+ * number of links to the trusted subject)
422+ * a) Issuer: ou=G,ou=C,o=B,c=A [links=2]
423+ * b) Issuer: ou=H,o=B,c=A [links=3]
424+ *
425+ * 5) Issuer is an ancestor of certificate subject (in order of number
426+ * of links to the certificate subject)
427+ * a) Issuer: ou=K,o=J,c=A
428+ * Subject: ou=L,ou=K,o=J,c=A
429+ * b) Issuer: o=J,c=A
430+ * Subject: ou=L,ou=K,0=J,c=A
431+ *
432+ * 6) Any other certificates
433+ */
434+ static class PKIXCertComparator implements Comparator<X509Certificate> {
435+
436+ final static String METHOD_NME = "PKIXCertComparator.compare()";
437+
438+ private final Set<X500Principal> trustedSubjectDNs;
439+
440+ PKIXCertComparator(Set<X500Principal> trustedSubjectDNs) {
441+ this.trustedSubjectDNs = trustedSubjectDNs;
442+ }
443+
444+ /**
445+ * @param oCert1 First X509Certificate to be compared
446+ * @param oCert2 Second X509Certificate to be compared
447+ * @return -1 if oCert1 is preferable to oCert2, or
448+ * if oCert1 and oCert2 are equally preferable (in this
449+ * case it doesn't matter which is preferable, but we don't
450+ * return 0 because the comparator would behave strangely
451+ * when used in a SortedSet).
452+ * 1 if oCert2 is preferable to oCert1
453+ * 0 if oCert1.equals(oCert2). We only return 0 if the
454+ * certs are equal so that this comparator behaves
455+ * correctly when used in a SortedSet.
456+ * @throws ClassCastException if either argument is not of type
457+ * X509Certificate
458+ */
459+ public int compare(X509Certificate oCert1, X509Certificate oCert2) {
460+
461+ // if certs are the same, return 0
462+ if (oCert1.equals(oCert2)) return 0;
463+
464+ X500Principal cIssuer1 = oCert1.getIssuerX500Principal();
465+ X500Principal cIssuer2 = oCert2.getIssuerX500Principal();
466+ X500Name cIssuer1Name = X500Name.asX500Name(cIssuer1);
467+ X500Name cIssuer2Name = X500Name.asX500Name(cIssuer2);
468+
469+ if (debug != null) {
470+ debug.println(METHOD_NME + " o1 Issuer: " + cIssuer1);
471+ debug.println(METHOD_NME + " o2 Issuer: " + cIssuer2);
472+ }
473+
474+ /* If one cert's issuer matches a trusted subject, then it is
475+ * preferable.
476+ */
477+ if (debug != null) {
478+ debug.println(METHOD_NME + " MATCH TRUSTED SUBJECT TEST...");
479+ }
480+
481+ boolean m1 = trustedSubjectDNs.contains(cIssuer1);
482+ boolean m2 = trustedSubjectDNs.contains(cIssuer2);
483+ if (debug != null) {
484+ debug.println(METHOD_NME + " m1: " + m1);
485+ debug.println(METHOD_NME + " m2: " + m2);
486+ }
487+ if (m1 && m2) {
488+ return -1;
489+ } else if (m1) {
490+ return -1;
491+ } else if (m2) {
492+ return 1;
493+ }
494+
495+ /* If one cert's issuer is a naming descendant of a trusted subject,
496+ * then it is preferable, in order of increasing naming distance.
497+ */
498+ if (debug != null) {
499+ debug.println(METHOD_NME + " NAMING DESCENDANT TEST...");
500+ }
501+ for (X500Principal tSubject : trustedSubjectDNs) {
502+ X500Name tSubjectName = X500Name.asX500Name(tSubject);
503+ int distanceTto1 =
504+ Builder.distance(tSubjectName, cIssuer1Name, -1);
505+ int distanceTto2 =
506+ Builder.distance(tSubjectName, cIssuer2Name, -1);
507+ if (debug != null) {
508+ debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
509+ debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
510+ }
511+ if (distanceTto1 > 0 || distanceTto2 > 0) {
512+ if (distanceTto1 == distanceTto2) {
513+ return -1;
514+ } else if (distanceTto1 > 0 && distanceTto2 <= 0) {
515+ return -1;
516+ } else if (distanceTto1 <= 0 && distanceTto2 > 0) {
517+ return 1;
518+ } else if (distanceTto1 < distanceTto2) {
519+ return -1;
520+ } else { // distanceTto1 > distanceTto2
521+ return 1;
522+ }
523+ }
524+ }
525+
526+ /* If one cert's issuer is a naming ancestor of a trusted subject,
527+ * then it is preferable, in order of increasing naming distance.
528+ */
529+ if (debug != null) {
530+ debug.println(METHOD_NME + " NAMING ANCESTOR TEST...");
531+ }
532+ for (X500Principal tSubject : trustedSubjectDNs) {
533+ X500Name tSubjectName = X500Name.asX500Name(tSubject);
534+
535+ int distanceTto1 = Builder.distance
536+ (tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
537+ int distanceTto2 = Builder.distance
538+ (tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
539+ if (debug != null) {
540+ debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
541+ debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
542+ }
543+ if (distanceTto1 < 0 || distanceTto2 < 0) {
544+ if (distanceTto1 == distanceTto2) {
545+ return -1;
546+ } else if (distanceTto1 < 0 && distanceTto2 >= 0) {
547+ return -1;
548+ } else if (distanceTto1 >= 0 && distanceTto2 < 0) {
549+ return 1;
550+ } else if (distanceTto1 > distanceTto2) {
551+ return -1;
552+ } else {
553+ return 1;
554+ }
555+ }
556+ }
557+
558+ /* If one cert's issuer is in the same namespace as a trusted
559+ * subject, then it is preferable, in order of increasing naming
560+ * distance.
561+ */
562+ if (debug != null) {
563+ debug.println(METHOD_NME +" SAME NAMESPACE AS TRUSTED TEST...");
564+ }
565+ for (X500Principal tSubject : trustedSubjectDNs) {
566+ X500Name tSubjectName = X500Name.asX500Name(tSubject);
567+ X500Name tAo1 = tSubjectName.commonAncestor(cIssuer1Name);
568+ X500Name tAo2 = tSubjectName.commonAncestor(cIssuer2Name);
569+ if (debug != null) {
570+ debug.println(METHOD_NME +" tAo1: " + String.valueOf(tAo1));
571+ debug.println(METHOD_NME +" tAo2: " + String.valueOf(tAo2));
572+ }
573+ if (tAo1 != null || tAo2 != null) {
574+ if (tAo1 != null && tAo2 != null) {
575+ int hopsTto1 = Builder.hops
576+ (tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
577+ int hopsTto2 = Builder.hops
578+ (tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
579+ if (debug != null) {
580+ debug.println(METHOD_NME +" hopsTto1: " + hopsTto1);
581+ debug.println(METHOD_NME +" hopsTto2: " + hopsTto2);
582+ }
583+ if (hopsTto1 == hopsTto2) {
584+ } else if (hopsTto1 > hopsTto2) {
585+ return 1;
586+ } else { // hopsTto1 < hopsTto2
587+ return -1;
588+ }
589+ } else if (tAo1 == null) {
590+ return 1;
591+ } else {
592+ return -1;
593+ }
594+ }
595+ }
596+
597+
598+ /* If one cert's issuer is an ancestor of that cert's subject,
599+ * then it is preferable, in order of increasing naming distance.
600+ */
601+ if (debug != null) {
602+ debug.println(METHOD_NME+" CERT ISSUER/SUBJECT COMPARISON TEST...");
603+ }
604+ X500Principal cSubject1 = oCert1.getSubjectX500Principal();
605+ X500Principal cSubject2 = oCert2.getSubjectX500Principal();
606+ X500Name cSubject1Name = X500Name.asX500Name(cSubject1);
607+ X500Name cSubject2Name = X500Name.asX500Name(cSubject2);
608+
609+ if (debug != null) {
610+ debug.println(METHOD_NME + " o1 Subject: " + cSubject1);
611+ debug.println(METHOD_NME + " o2 Subject: " + cSubject2);
612+ }
613+ int distanceStoI1 = Builder.distance
614+ (cSubject1Name, cIssuer1Name, Integer.MAX_VALUE);
615+ int distanceStoI2 = Builder.distance
616+ (cSubject2Name, cIssuer2Name, Integer.MAX_VALUE);
617+ if (debug != null) {
618+ debug.println(METHOD_NME + " distanceStoI1: " + distanceStoI1);
619+ debug.println(METHOD_NME + " distanceStoI2: " + distanceStoI2);
620+ }
621+ if (distanceStoI2 > distanceStoI1) {
622+ return -1;
623+ } else if (distanceStoI2 < distanceStoI1) {
624+ return 1;
625+ }
626+
627+ /* Otherwise, certs are equally preferable.
628+ */
629+ if (debug != null) {
630+ debug.println(METHOD_NME + " no tests matched; RETURN 0");
631+ }
632+ return -1;
633+ }
634+ }
635+
636+ /**
637+ * Verifies a matching certificate.
638+ *
639+ * This method executes the validation steps in the PKIX path
640+ * validation algorithm <draft-ietf-pkix-new-part1-08.txt> which were
641+ * not satisfied by the selection criteria used by getCertificates()
642+ * to find the certs and only the steps that can be executed in a
643+ * forward direction (target to trust anchor). Those steps that can
644+ * only be executed in a reverse direction are deferred until the
645+ * complete path has been built.
646+ *
647+ * Trust anchor certs are not validated, but are used to verify the
648+ * signature and revocation status of the previous cert.
649+ *
650+ * If the last certificate is being verified (the one whose subject
651+ * matches the target subject, then steps in 6.1.4 of the PKIX
652+ * Certification Path Validation algorithm are NOT executed,
653+ * regardless of whether or not the last cert is an end-entity
654+ * cert or not. This allows callers to certify CA certs as
655+ * well as EE certs.
656+ *
657+ * @param cert the certificate to be verified
658+ * @param currentState the current state against which the cert is verified
659+ * @param certPathList the certPathList generated thus far
660+ */
661+ void verifyCert(X509Certificate cert, State currentState,
662+ List<X509Certificate> certPathList) throws GeneralSecurityException
663+ {
664+ if (debug != null) {
665+ debug.println("ForwardBuilder.verifyCert(SN: "
666+ + Debug.toHexString(cert.getSerialNumber())
667+ + "\n Issuer: " + cert.getIssuerX500Principal() + ")"
668+ + "\n Subject: " + cert.getSubjectX500Principal() + ")");
669+ }
670+
671+ ForwardState currState = (ForwardState) currentState;
672+
673+ /*
674+ * check for looping - abort a loop if
675+ * ((we encounter the same certificate twice) AND
676+ * ((policyMappingInhibited = true) OR (no policy mapping
677+ * extensions can be found between the occurences of the same
678+ * certificate)))
679+ */
680+ if (certPathList != null) {
681+ boolean policyMappingFound = false;
682+ for (X509Certificate cpListCert : certPathList) {
683+ X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert);
684+ PolicyMappingsExtension policyMappingsExt
685+ = cpListCertImpl.getPolicyMappingsExtension();
686+ if (policyMappingsExt != null) {
687+ policyMappingFound = true;
688+ }
689+ if (debug != null) {
690+ debug.println("policyMappingFound = " + policyMappingFound);
691+ }
692+ if (cert.equals(cpListCert)) {
693+ if ((buildParams.isPolicyMappingInhibited()) ||
694+ (!policyMappingFound)) {
695+ if (debug != null) {
696+ debug.println("loop detected!!");
697+ }
698+ throw new CertPathValidatorException("loop detected");
699+ }
700+ }
701+ }
702+ }
703+
704+ /* check if trusted cert */
705+ boolean isTrustedCert = trustedCerts.contains(cert);
706+
707+ /* we don't perform any validation of the trusted cert */
708+ if (!isTrustedCert) {
709+ /*
710+ * Check CRITICAL private extensions for user checkers that
711+ * support forward checking (forwardCheckers) and remove
712+ * ones we know how to check.
713+ */
714+ Set<String> unresCritExts = cert.getCriticalExtensionOIDs();
715+ if (unresCritExts == null) {
716+ unresCritExts = Collections.<String>emptySet();
717+ }
718+ for (PKIXCertPathChecker checker : currState.forwardCheckers) {
719+ checker.check(cert, unresCritExts);
720+ }
721+
722+ /*
723+ * Remove extensions from user checkers that don't support
724+ * forward checking. After this step, we will have removed
725+ * all extensions that all user checkers are capable of
726+ * processing.
727+ */
728+ for (PKIXCertPathChecker checker : buildParams.getCertPathCheckers()) {
729+ if (!checker.isForwardCheckingSupported()) {
730+ Set<String> supportedExts = checker.getSupportedExtensions();
731+ if (supportedExts != null) {
732+ unresCritExts.removeAll(supportedExts);
733+ }
734+ }
735+ }
736+
737+ /*
738+ * Look at the remaining extensions and remove any ones we know how
739+ * to check. If there are any left, throw an exception!
740+ */
741+ if (!unresCritExts.isEmpty()) {
742+ unresCritExts.remove(
743+ PKIXExtensions.BasicConstraints_Id.toString());
744+ unresCritExts.remove(
745+ PKIXExtensions.NameConstraints_Id.toString());
746+ unresCritExts.remove(
747+ PKIXExtensions.CertificatePolicies_Id.toString());
748+ unresCritExts.remove(
749+ PKIXExtensions.PolicyMappings_Id.toString());
750+ unresCritExts.remove(
751+ PKIXExtensions.PolicyConstraints_Id.toString());
752+ unresCritExts.remove(
753+ PKIXExtensions.InhibitAnyPolicy_Id.toString());
754+ unresCritExts.remove(
755+ PKIXExtensions.SubjectAlternativeName_Id.toString());
756+ unresCritExts.remove(PKIXExtensions.KeyUsage_Id.toString());
757+ unresCritExts.remove(
758+ PKIXExtensions.ExtendedKeyUsage_Id.toString());
759+
760+ if (!unresCritExts.isEmpty())
761+ throw new CertPathValidatorException
762+ ("Unrecognized critical extension(s)", null, null, -1,
763+ PKIXReason.UNRECOGNIZED_CRIT_EXT);
764+ }
765+ }
766+
767+ /*
768+ * if this is the target certificate (init=true), then we are
769+ * not able to do any more verification, so just return
770+ */
771+ if (currState.isInitial()) {
772+ return;
773+ }
774+
775+ /* we don't perform any validation of the trusted cert */
776+ if (!isTrustedCert) {
777+ /* Make sure this is a CA cert */
778+ if (cert.getBasicConstraints() == -1) {
779+ throw new CertificateException("cert is NOT a CA cert");
780+ }
781+
782+ /*
783+ * Check keyUsage extension
784+ */
785+ KeyChecker.verifyCAKeyUsage(cert);
786+ }
787+
788+ /*
789+ * the following checks are performed even when the cert
790+ * is a trusted cert, since we are only extracting the
791+ * subjectDN, and publicKey from the cert
792+ * in order to verify a previous cert
793+ */
794+
795+ /*
796+ * Check revocation for the previous cert
797+ */
798+ if (buildParams.isRevocationEnabled()) {
799+
800+ // first off, see if this cert can authorize revocation...
801+ if (CrlRevocationChecker.certCanSignCrl(cert)) {
802+ // And then check to be sure no key requiring key parameters
803+ // has been encountered
804+ if (!currState.keyParamsNeeded())
805+ // If all that checks out, we can check the
806+ // revocation status of the cert. Otherwise,
807+ // we'll just wait until the end.
808+ currState.crlChecker.check(currState.cert,
809+ cert.getPublicKey(),
810+ true);
811+ }
812+ }
813+
814+ /*
815+ * Check signature only if no key requiring key parameters has been
816+ * encountered.
817+ */
818+ if (!currState.keyParamsNeeded()) {
819+ (currState.cert).verify(cert.getPublicKey(),
820+ buildParams.getSigProvider());
821+ }
822+ }
823+
824+ /**
825+ * Verifies whether the input certificate completes the path.
826+ * Checks the cert against each trust anchor that was specified, in order,
827+ * and returns true as soon as it finds a valid anchor.
828+ * Returns true if the cert matches a trust anchor specified as a
829+ * certificate or if the cert verifies with a trust anchor that
830+ * was specified as a trusted {pubkey, caname} pair. Returns false if none
831+ * of the trust anchors are valid for this cert.
832+ *
833+ * @param cert the certificate to test
834+ * @return a boolean value indicating whether the cert completes the path.
835+ */
836+ boolean isPathCompleted(X509Certificate cert) {
837+ for (TrustAnchor anchor : trustAnchors) {
838+ if (anchor.getTrustedCert() != null) {
839+ if (cert.equals(anchor.getTrustedCert())) {
840+ this.trustAnchor = anchor;
841+ return true;
842+ } else {
843+ continue;
844+ }
845+ } else {
846+ X500Principal principal = anchor.getCA();
847+ java.security.PublicKey publicKey = anchor.getCAPublicKey();
848+
849+ if (principal != null && publicKey != null &&
850+ principal.equals(cert.getSubjectX500Principal())) {
851+ if (publicKey.equals(cert.getPublicKey())) {
852+ // the cert itself is a trust anchor
853+ this.trustAnchor = anchor;
854+ return true;
855+ }
856+ // else, it is a self-issued certificate of the anchor
857+ }
858+
859+ // Check subject/issuer name chaining
860+ if (principal == null ||
861+ !principal.equals(cert.getIssuerX500Principal())) {
862+ continue;
863+ }
864+ }
865+
866+ /* Check revocation if it is enabled */
867+ if (buildParams.isRevocationEnabled()) {
868+ try {
869+ CrlRevocationChecker crlChecker = new CrlRevocationChecker
870+ (anchor, buildParams, null, onlyEECert);
871+ crlChecker.check(cert, anchor.getCAPublicKey(), true);
872+ } catch (CertPathValidatorException cpve) {
873+ if (debug != null) {
874+ debug.println("ForwardBuilder.isPathCompleted() cpve");
875+ cpve.printStackTrace();
876+ }
877+ continue;
878+ }
879+ }
880+
881+ /*
882+ * Check signature
883+ */
884+ try {
885+ // NOTE: the DSA public key in the buildParams may lack
886+ // parameters, yet there is no key to inherit the parameters
887+ // from. This is probably such a rare case that it is not worth
888+ // trying to detect the situation earlier.
889+ cert.verify(anchor.getCAPublicKey(),
890+ buildParams.getSigProvider());
891+ } catch (InvalidKeyException ike) {
892+ if (debug != null) {
893+ debug.println("ForwardBuilder.isPathCompleted() invalid "
894+ + "DSA key found");
895+ }
896+ continue;
897+ } catch (Exception e){
898+ if (debug != null) {
899+ debug.println("ForwardBuilder.isPathCompleted() " +
900+ "unexpected exception");
901+ e.printStackTrace();
902+ }
903+ continue;
904+ }
905+
906+ this.trustAnchor = anchor;
907+ return true;
908+ }
909+
910+ return false;
911+ }
912+
913+ /** Adds the certificate to the certPathList
914+ *
915+ * @param cert the certificate to be added
916+ * @param certPathList the certification path list
917+ */
918+ void addCertToPath(X509Certificate cert,
919+ LinkedList<X509Certificate> certPathList) {
920+ certPathList.addFirst(cert);
921+ }
922+
923+ /** Removes final certificate from the certPathList
924+ *
925+ * @param certPathList the certification path list
926+ */
927+ void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
928+ certPathList.removeFirst();
929+ }
930+}