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