Home | History | Annotate | Download | only in certpath
      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      */
     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
    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      */
    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      */
    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")
    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 
    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          */
    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
    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
    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
    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
    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
    927     void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
    928         certPathList.removeFirst();
    929     }
    930 }
    931