Home | History | Annotate | Download | only in certpath
      1 /*
      2  * Copyright (c) 2002, 2015, 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.*;
     29 import java.net.URI;
     30 import java.security.*;
     31 import java.security.cert.*;
     32 import javax.security.auth.x500.X500Principal;
     33 import java.util.*;
     34 
     35 import sun.security.util.Debug;
     36 import static sun.security.x509.PKIXExtensions.*;
     37 import sun.security.x509.*;
     38 
     39 /**
     40  * Class to obtain CRLs via the CRLDistributionPoints extension.
     41  * Note that the functionality of this class must be explicitly enabled
     42  * via a system property, see the USE_CRLDP variable below.
     43  *
     44  * This class uses the URICertStore class to fetch CRLs. The URICertStore
     45  * class also implements CRL caching: see the class description for more
     46  * information.
     47  *
     48  * @author Andreas Sterbenz
     49  * @author Sean Mullan
     50  * @since 1.4.2
     51  */
     52 public class DistributionPointFetcher {
     53 
     54     private static final Debug debug = Debug.getInstance("certpath");
     55 
     56     private static final boolean[] ALL_REASONS =
     57         {true, true, true, true, true, true, true, true, true};
     58 
     59     /**
     60      * Private instantiation only.
     61      */
     62     private DistributionPointFetcher() {}
     63 
     64     /**
     65      * Return the X509CRLs matching this selector. The selector must be
     66      * an X509CRLSelector with certificateChecking set.
     67      */
     68     public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
     69                                               boolean signFlag,
     70                                               PublicKey prevKey,
     71                                               String provider,
     72                                               List<CertStore> certStores,
     73                                               boolean[] reasonsMask,
     74                                               Set<TrustAnchor> trustAnchors,
     75                                               Date validity)
     76         throws CertStoreException
     77     {
     78         return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
     79                        reasonsMask, trustAnchors, validity);
     80     }
     81 
     82     /**
     83      * Return the X509CRLs matching this selector. The selector must be
     84      * an X509CRLSelector with certificateChecking set.
     85      */
     86     public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
     87                                               boolean signFlag,
     88                                               PublicKey prevKey,
     89                                               X509Certificate prevCert,
     90                                               String provider,
     91                                               List<CertStore> certStores,
     92                                               boolean[] reasonsMask,
     93                                               Set<TrustAnchor> trustAnchors,
     94                                               Date validity)
     95         throws CertStoreException
     96     {
     97         X509Certificate cert = selector.getCertificateChecking();
     98         if (cert == null) {
     99             return Collections.emptySet();
    100         }
    101         try {
    102             X509CertImpl certImpl = X509CertImpl.toImpl(cert);
    103             if (debug != null) {
    104                 debug.println("DistributionPointFetcher.getCRLs: Checking "
    105                         + "CRLDPs for " + certImpl.getSubjectX500Principal());
    106             }
    107             CRLDistributionPointsExtension ext =
    108                 certImpl.getCRLDistributionPointsExtension();
    109             if (ext == null) {
    110                 if (debug != null) {
    111                     debug.println("No CRLDP ext");
    112                 }
    113                 return Collections.emptySet();
    114             }
    115             List<DistributionPoint> points =
    116                     ext.get(CRLDistributionPointsExtension.POINTS);
    117             Set<X509CRL> results = new HashSet<>();
    118             for (Iterator<DistributionPoint> t = points.iterator();
    119                  t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
    120                 DistributionPoint point = t.next();
    121                 Collection<X509CRL> crls = getCRLs(selector, certImpl,
    122                     point, reasonsMask, signFlag, prevKey, prevCert, provider,
    123                     certStores, trustAnchors, validity);
    124                 results.addAll(crls);
    125             }
    126             if (debug != null) {
    127                 debug.println("Returning " + results.size() + " CRLs");
    128             }
    129             return results;
    130         } catch (CertificateException | IOException e) {
    131             return Collections.emptySet();
    132         }
    133     }
    134 
    135     /**
    136      * Download CRLs from the given distribution point, verify and return them.
    137      * See the top of the class for current limitations.
    138      *
    139      * @throws CertStoreException if there is an error retrieving the CRLs
    140      *         from one of the GeneralNames and no other CRLs are retrieved from
    141      *         the other GeneralNames. If more than one GeneralName throws an
    142      *         exception then the one from the last GeneralName is thrown.
    143      */
    144     private static Collection<X509CRL> getCRLs(X509CRLSelector selector,
    145         X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
    146         boolean signFlag, PublicKey prevKey, X509Certificate prevCert,
    147         String provider, List<CertStore> certStores,
    148         Set<TrustAnchor> trustAnchors, Date validity)
    149             throws CertStoreException {
    150 
    151         // check for full name
    152         GeneralNames fullName = point.getFullName();
    153         if (fullName == null) {
    154             // check for relative name
    155             RDN relativeName = point.getRelativeName();
    156             if (relativeName == null) {
    157                 return Collections.emptySet();
    158             }
    159             try {
    160                 GeneralNames crlIssuers = point.getCRLIssuer();
    161                 if (crlIssuers == null) {
    162                     fullName = getFullNames
    163                         ((X500Name) certImpl.getIssuerDN(), relativeName);
    164                 } else {
    165                     // should only be one CRL Issuer
    166                     if (crlIssuers.size() != 1) {
    167                         return Collections.emptySet();
    168                     } else {
    169                         fullName = getFullNames
    170                             ((X500Name) crlIssuers.get(0).getName(), relativeName);
    171                     }
    172                 }
    173             } catch (IOException ioe) {
    174                 return Collections.emptySet();
    175             }
    176         }
    177         Collection<X509CRL> possibleCRLs = new ArrayList<>();
    178         CertStoreException savedCSE = null;
    179         for (Iterator<GeneralName> t = fullName.iterator(); t.hasNext(); ) {
    180             try {
    181                 GeneralName name = t.next();
    182                 if (name.getType() == GeneralNameInterface.NAME_DIRECTORY) {
    183                     X500Name x500Name = (X500Name) name.getName();
    184                     possibleCRLs.addAll(
    185                         getCRLs(x500Name, certImpl.getIssuerX500Principal(),
    186                                 certStores));
    187                 } else if (name.getType() == GeneralNameInterface.NAME_URI) {
    188                     URIName uriName = (URIName)name.getName();
    189                     X509CRL crl = getCRL(uriName);
    190                     if (crl != null) {
    191                         possibleCRLs.add(crl);
    192                     }
    193                 }
    194             } catch (CertStoreException cse) {
    195                 savedCSE = cse;
    196             }
    197         }
    198         // only throw CertStoreException if no CRLs are retrieved
    199         if (possibleCRLs.isEmpty() && savedCSE != null) {
    200             throw savedCSE;
    201         }
    202 
    203         Collection<X509CRL> crls = new ArrayList<>(2);
    204         for (X509CRL crl : possibleCRLs) {
    205             try {
    206                 // make sure issuer is not set
    207                 // we check the issuer in verifyCRLs method
    208                 selector.setIssuerNames(null);
    209                 if (selector.match(crl) && verifyCRL(certImpl, point, crl,
    210                         reasonsMask, signFlag, prevKey, prevCert, provider,
    211                         trustAnchors, certStores, validity)) {
    212                     crls.add(crl);
    213                 }
    214             } catch (IOException | CRLException e) {
    215                 // don't add the CRL
    216                 if (debug != null) {
    217                     debug.println("Exception verifying CRL: " + e.getMessage());
    218                     e.printStackTrace();
    219                 }
    220             }
    221         }
    222         return crls;
    223     }
    224 
    225     /**
    226      * Download CRL from given URI.
    227      */
    228     private static X509CRL getCRL(URIName name) throws CertStoreException {
    229         URI uri = name.getURI();
    230         if (debug != null) {
    231             debug.println("Trying to fetch CRL from DP " + uri);
    232         }
    233         CertStore ucs = null;
    234         try {
    235             ucs = URICertStore.getInstance
    236                 (new URICertStore.URICertStoreParameters(uri));
    237         } catch (InvalidAlgorithmParameterException |
    238                  NoSuchAlgorithmException e) {
    239             if (debug != null) {
    240                 debug.println("Can't create URICertStore: " + e.getMessage());
    241             }
    242             return null;
    243         }
    244 
    245         Collection<? extends CRL> crls = ucs.getCRLs(null);
    246         if (crls.isEmpty()) {
    247             return null;
    248         } else {
    249             return (X509CRL) crls.iterator().next();
    250         }
    251     }
    252 
    253     /**
    254      * Fetch CRLs from certStores.
    255      *
    256      * @throws CertStoreException if there is an error retrieving the CRLs from
    257      *         one of the CertStores and no other CRLs are retrieved from
    258      *         the other CertStores. If more than one CertStore throws an
    259      *         exception then the one from the last CertStore is thrown.
    260      */
    261     private static Collection<X509CRL> getCRLs(X500Name name,
    262                                                X500Principal certIssuer,
    263                                                List<CertStore> certStores)
    264         throws CertStoreException
    265     {
    266         if (debug != null) {
    267             debug.println("Trying to fetch CRL from DP " + name);
    268         }
    269         X509CRLSelector xcs = new X509CRLSelector();
    270         xcs.addIssuer(name.asX500Principal());
    271         xcs.addIssuer(certIssuer);
    272         Collection<X509CRL> crls = new ArrayList<>();
    273         CertStoreException savedCSE = null;
    274         for (CertStore store : certStores) {
    275             try {
    276                 for (CRL crl : store.getCRLs(xcs)) {
    277                     crls.add((X509CRL)crl);
    278                 }
    279             } catch (CertStoreException cse) {
    280                 if (debug != null) {
    281                     debug.println("Exception while retrieving " +
    282                         "CRLs: " + cse);
    283                     cse.printStackTrace();
    284                 }
    285                 savedCSE = new PKIX.CertStoreTypeException(store.getType(),cse);
    286             }
    287         }
    288         // only throw CertStoreException if no CRLs are retrieved
    289         if (crls.isEmpty() && savedCSE != null) {
    290             throw savedCSE;
    291         } else {
    292             return crls;
    293         }
    294     }
    295 
    296     /**
    297      * Verifies a CRL for the given certificate's Distribution Point to
    298      * ensure it is appropriate for checking the revocation status.
    299      *
    300      * @param certImpl the certificate whose revocation status is being checked
    301      * @param point one of the distribution points of the certificate
    302      * @param crl the CRL
    303      * @param reasonsMask the interim reasons mask
    304      * @param signFlag true if prevKey can be used to verify the CRL
    305      * @param prevKey the public key that verifies the certificate's signature
    306      * @param prevCert the certificate whose public key verifies
    307      *        {@code certImpl}'s signature
    308      * @param provider the Signature provider to use
    309      * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
    310      * @param certStores a {@code List} of {@code CertStore}s to be used in
    311      *        finding certificates and CRLs
    312      * @param validity the time for which the validity of the CRL issuer's
    313      *        certification path should be determined
    314      * @return true if ok, false if not
    315      */
    316     static boolean verifyCRL(X509CertImpl certImpl, DistributionPoint point,
    317         X509CRL crl, boolean[] reasonsMask, boolean signFlag,
    318         PublicKey prevKey, X509Certificate prevCert, String provider,
    319         Set<TrustAnchor> trustAnchors, List<CertStore> certStores,
    320         Date validity) throws CRLException, IOException {
    321 
    322         if (debug != null) {
    323             debug.println("DistributionPointFetcher.verifyCRL: " +
    324                 "checking revocation status for" +
    325                 "\n  SN: " + Debug.toHexString(certImpl.getSerialNumber()) +
    326                 "\n  Subject: " + certImpl.getSubjectX500Principal() +
    327                 "\n  Issuer: " + certImpl.getIssuerX500Principal());
    328         }
    329 
    330         boolean indirectCRL = false;
    331         X509CRLImpl crlImpl = X509CRLImpl.toImpl(crl);
    332         IssuingDistributionPointExtension idpExt =
    333             crlImpl.getIssuingDistributionPointExtension();
    334         X500Name certIssuer = (X500Name) certImpl.getIssuerDN();
    335         X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN();
    336 
    337         // if crlIssuer is set, verify that it matches the issuer of the
    338         // CRL and the CRL contains an IDP extension with the indirectCRL
    339         // boolean asserted. Otherwise, verify that the CRL issuer matches the
    340         // certificate issuer.
    341         GeneralNames pointCrlIssuers = point.getCRLIssuer();
    342         X500Name pointCrlIssuer = null;
    343         if (pointCrlIssuers != null) {
    344             if (idpExt == null ||
    345                 ((Boolean) idpExt.get
    346                     (IssuingDistributionPointExtension.INDIRECT_CRL)).equals
    347                         (Boolean.FALSE)) {
    348                 return false;
    349             }
    350             boolean match = false;
    351             for (Iterator<GeneralName> t = pointCrlIssuers.iterator();
    352                  !match && t.hasNext(); ) {
    353                 GeneralNameInterface name = t.next().getName();
    354                 if (crlIssuer.equals(name) == true) {
    355                     pointCrlIssuer = (X500Name) name;
    356                     match = true;
    357                 }
    358             }
    359             if (match == false) {
    360                 return false;
    361             }
    362 
    363             // we accept the case that a CRL issuer provide status
    364             // information for itself.
    365             if (issues(certImpl, crlImpl, provider)) {
    366                 // reset the public key used to verify the CRL's signature
    367                 prevKey = certImpl.getPublicKey();
    368             } else {
    369                 indirectCRL = true;
    370             }
    371         } else if (crlIssuer.equals(certIssuer) == false) {
    372             if (debug != null) {
    373                 debug.println("crl issuer does not equal cert issuer.\n" +
    374                               "crl issuer: " + crlIssuer + "\n" +
    375                               "cert issuer: " + certIssuer);
    376             }
    377             return false;
    378         } else {
    379             // in case of self-issued indirect CRL issuer.
    380             KeyIdentifier certAKID = certImpl.getAuthKeyId();
    381             KeyIdentifier crlAKID = crlImpl.getAuthKeyId();
    382 
    383             if (certAKID == null || crlAKID == null) {
    384                 // cannot recognize indirect CRL without AKID
    385 
    386                 // we accept the case that a CRL issuer provide status
    387                 // information for itself.
    388                 if (issues(certImpl, crlImpl, provider)) {
    389                     // reset the public key used to verify the CRL's signature
    390                     prevKey = certImpl.getPublicKey();
    391                 }
    392             } else if (!certAKID.equals(crlAKID)) {
    393                 // we accept the case that a CRL issuer provide status
    394                 // information for itself.
    395                 if (issues(certImpl, crlImpl, provider)) {
    396                     // reset the public key used to verify the CRL's signature
    397                     prevKey = certImpl.getPublicKey();
    398                 } else {
    399                     indirectCRL = true;
    400                 }
    401             }
    402         }
    403 
    404         if (!indirectCRL && !signFlag) {
    405             // cert's key cannot be used to verify the CRL
    406             return false;
    407         }
    408 
    409         if (idpExt != null) {
    410             DistributionPointName idpPoint = (DistributionPointName)
    411                 idpExt.get(IssuingDistributionPointExtension.POINT);
    412             if (idpPoint != null) {
    413                 GeneralNames idpNames = idpPoint.getFullName();
    414                 if (idpNames == null) {
    415                     RDN relativeName = idpPoint.getRelativeName();
    416                     if (relativeName == null) {
    417                         if (debug != null) {
    418                            debug.println("IDP must be relative or full DN");
    419                         }
    420                         return false;
    421                     }
    422                     if (debug != null) {
    423                         debug.println("IDP relativeName:" + relativeName);
    424                     }
    425                     idpNames = getFullNames(crlIssuer, relativeName);
    426                 }
    427                 // if the DP name is present in the IDP CRL extension and the
    428                 // DP field is present in the DP, then verify that one of the
    429                 // names in the IDP matches one of the names in the DP
    430                 if (point.getFullName() != null ||
    431                     point.getRelativeName() != null) {
    432                     GeneralNames pointNames = point.getFullName();
    433                     if (pointNames == null) {
    434                         RDN relativeName = point.getRelativeName();
    435                         if (relativeName == null) {
    436                             if (debug != null) {
    437                                 debug.println("DP must be relative or full DN");
    438                             }
    439                             return false;
    440                         }
    441                         if (debug != null) {
    442                             debug.println("DP relativeName:" + relativeName);
    443                         }
    444                         if (indirectCRL) {
    445                             if (pointCrlIssuers.size() != 1) {
    446                                 // RFC 3280: there must be only 1 CRL issuer
    447                                 // name when relativeName is present
    448                                 if (debug != null) {
    449                                     debug.println("must only be one CRL " +
    450                                         "issuer when relative name present");
    451                                 }
    452                                 return false;
    453                             }
    454                             pointNames = getFullNames
    455                                 (pointCrlIssuer, relativeName);
    456                         } else {
    457                             pointNames = getFullNames(certIssuer, relativeName);
    458                         }
    459                     }
    460                     boolean match = false;
    461                     for (Iterator<GeneralName> i = idpNames.iterator();
    462                          !match && i.hasNext(); ) {
    463                         GeneralNameInterface idpName = i.next().getName();
    464                         if (debug != null) {
    465                             debug.println("idpName: " + idpName);
    466                         }
    467                         for (Iterator<GeneralName> p = pointNames.iterator();
    468                              !match && p.hasNext(); ) {
    469                             GeneralNameInterface pointName = p.next().getName();
    470                             if (debug != null) {
    471                                 debug.println("pointName: " + pointName);
    472                             }
    473                             match = idpName.equals(pointName);
    474                         }
    475                     }
    476                     if (!match) {
    477                         if (debug != null) {
    478                             debug.println("IDP name does not match DP name");
    479                         }
    480                         return false;
    481                     }
    482                 // if the DP name is present in the IDP CRL extension and the
    483                 // DP field is absent from the DP, then verify that one of the
    484                 // names in the IDP matches one of the names in the crlIssuer
    485                 // field of the DP
    486                 } else {
    487                     // verify that one of the names in the IDP matches one of
    488                     // the names in the cRLIssuer of the cert's DP
    489                     boolean match = false;
    490                     for (Iterator<GeneralName> t = pointCrlIssuers.iterator();
    491                          !match && t.hasNext(); ) {
    492                         GeneralNameInterface crlIssuerName = t.next().getName();
    493                         for (Iterator<GeneralName> i = idpNames.iterator();
    494                              !match && i.hasNext(); ) {
    495                             GeneralNameInterface idpName = i.next().getName();
    496                             match = crlIssuerName.equals(idpName);
    497                         }
    498                     }
    499                     if (!match) {
    500                         return false;
    501                     }
    502                 }
    503             }
    504 
    505             // if the onlyContainsUserCerts boolean is asserted, verify that the
    506             // cert is not a CA cert
    507             Boolean b = (Boolean)
    508                 idpExt.get(IssuingDistributionPointExtension.ONLY_USER_CERTS);
    509             if (b.equals(Boolean.TRUE) && certImpl.getBasicConstraints() != -1) {
    510                 if (debug != null) {
    511                     debug.println("cert must be a EE cert");
    512                 }
    513                 return false;
    514             }
    515 
    516             // if the onlyContainsCACerts boolean is asserted, verify that the
    517             // cert is a CA cert
    518             b = (Boolean)
    519                 idpExt.get(IssuingDistributionPointExtension.ONLY_CA_CERTS);
    520             if (b.equals(Boolean.TRUE) && certImpl.getBasicConstraints() == -1) {
    521                 if (debug != null) {
    522                     debug.println("cert must be a CA cert");
    523                 }
    524                 return false;
    525             }
    526 
    527             // verify that the onlyContainsAttributeCerts boolean is not
    528             // asserted
    529             b = (Boolean) idpExt.get
    530                 (IssuingDistributionPointExtension.ONLY_ATTRIBUTE_CERTS);
    531             if (b.equals(Boolean.TRUE)) {
    532                 if (debug != null) {
    533                     debug.println("cert must not be an AA cert");
    534                 }
    535                 return false;
    536             }
    537         }
    538 
    539         // compute interim reasons mask
    540         boolean[] interimReasonsMask = new boolean[9];
    541         ReasonFlags reasons = null;
    542         if (idpExt != null) {
    543             reasons = (ReasonFlags)
    544                 idpExt.get(IssuingDistributionPointExtension.REASONS);
    545         }
    546 
    547         boolean[] pointReasonFlags = point.getReasonFlags();
    548         if (reasons != null) {
    549             if (pointReasonFlags != null) {
    550                 // set interim reasons mask to the intersection of
    551                 // reasons in the DP and onlySomeReasons in the IDP
    552                 boolean[] idpReasonFlags = reasons.getFlags();
    553                 for (int i = 0; i < interimReasonsMask.length; i++) {
    554                     interimReasonsMask[i] =
    555                         (i < idpReasonFlags.length && idpReasonFlags[i]) &&
    556                         (i < pointReasonFlags.length && pointReasonFlags[i]);
    557                 }
    558             } else {
    559                 // set interim reasons mask to the value of
    560                 // onlySomeReasons in the IDP (and clone it since we may
    561                 // modify it)
    562                 interimReasonsMask = reasons.getFlags().clone();
    563             }
    564         } else if (idpExt == null || reasons == null) {
    565             if (pointReasonFlags != null) {
    566                 // set interim reasons mask to the value of DP reasons
    567                 interimReasonsMask = pointReasonFlags.clone();
    568             } else {
    569                 // set interim reasons mask to the special value all-reasons
    570                 Arrays.fill(interimReasonsMask, true);
    571             }
    572         }
    573 
    574         // verify that interim reasons mask includes one or more reasons
    575         // not included in the reasons mask
    576         boolean oneOrMore = false;
    577         for (int i = 0; i < interimReasonsMask.length && !oneOrMore; i++) {
    578             if (interimReasonsMask[i] &&
    579                     !(i < reasonsMask.length && reasonsMask[i]))
    580             {
    581                 oneOrMore = true;
    582             }
    583         }
    584         if (!oneOrMore) {
    585             return false;
    586         }
    587 
    588         // Obtain and validate the certification path for the complete
    589         // CRL issuer (if indirect CRL). If a key usage extension is present
    590         // in the CRL issuer's certificate, verify that the cRLSign bit is set.
    591         if (indirectCRL) {
    592             X509CertSelector certSel = new X509CertSelector();
    593             certSel.setSubject(crlIssuer.asX500Principal());
    594             boolean[] crlSign = {false,false,false,false,false,false,true};
    595             certSel.setKeyUsage(crlSign);
    596 
    597             // Currently by default, forward builder does not enable
    598             // subject/authority key identifier identifying for target
    599             // certificate, instead, it only compares the CRL issuer and
    600             // the target certificate subject. If the certificate of the
    601             // delegated CRL issuer is a self-issued certificate, the
    602             // builder is unable to find the proper CRL issuer by issuer
    603             // name only, there is a potential dead loop on finding the
    604             // proper issuer. It is of great help to narrow the target
    605             // scope down to aware of authority key identifiers in the
    606             // selector, for the purposes of breaking the dead loop.
    607             AuthorityKeyIdentifierExtension akidext =
    608                                             crlImpl.getAuthKeyIdExtension();
    609             if (akidext != null) {
    610                 byte[] kid = akidext.getEncodedKeyIdentifier();
    611                 if (kid != null) {
    612                     certSel.setSubjectKeyIdentifier(kid);
    613                 }
    614 
    615                 SerialNumber asn = (SerialNumber)akidext.get(
    616                         AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
    617                 if (asn != null) {
    618                     certSel.setSerialNumber(asn.getNumber());
    619                 }
    620                 // the subject criterion will be set by builder automatically.
    621             }
    622 
    623             // By now, we have validated the previous certificate, so we can
    624             // trust it during the validation of the CRL issuer.
    625             // In addition to the performance improvement, another benefit is to
    626             // break the dead loop while looking for the issuer back and forth
    627             // between the delegated self-issued certificate and its issuer.
    628             Set<TrustAnchor> newTrustAnchors = new HashSet<>(trustAnchors);
    629 
    630             if (prevKey != null) {
    631                 // Add the previous certificate as a trust anchor.
    632                 // If prevCert is not null, we want to construct a TrustAnchor
    633                 // using the cert object because when the certpath for the CRL
    634                 // is built later, the CertSelector will make comparisons with
    635                 // the TrustAnchor's trustedCert member rather than its pubKey.
    636                 TrustAnchor temporary;
    637                 if (prevCert != null) {
    638                     temporary = new TrustAnchor(prevCert, null);
    639                 } else {
    640                     X500Principal principal = certImpl.getIssuerX500Principal();
    641                     temporary = new TrustAnchor(principal, prevKey, null);
    642                 }
    643                 newTrustAnchors.add(temporary);
    644             }
    645 
    646             PKIXBuilderParameters params = null;
    647             try {
    648                 params = new PKIXBuilderParameters(newTrustAnchors, certSel);
    649             } catch (InvalidAlgorithmParameterException iape) {
    650                 throw new CRLException(iape);
    651             }
    652             params.setCertStores(certStores);
    653             params.setSigProvider(provider);
    654             params.setDate(validity);
    655             try {
    656                 CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
    657                 PKIXCertPathBuilderResult result =
    658                     (PKIXCertPathBuilderResult) builder.build(params);
    659                 prevKey = result.getPublicKey();
    660             } catch (GeneralSecurityException e) {
    661                 throw new CRLException(e);
    662             }
    663         }
    664 
    665         // check the crl signature algorithm
    666         try {
    667             AlgorithmChecker.check(prevKey, crl);
    668         } catch (CertPathValidatorException cpve) {
    669             if (debug != null) {
    670                 debug.println("CRL signature algorithm check failed: " + cpve);
    671             }
    672             return false;
    673         }
    674 
    675         // validate the signature on the CRL
    676         try {
    677             crl.verify(prevKey, provider);
    678         } catch (GeneralSecurityException e) {
    679             if (debug != null) {
    680                 debug.println("CRL signature failed to verify");
    681             }
    682             return false;
    683         }
    684 
    685         // reject CRL if any unresolved critical extensions remain in the CRL.
    686         Set<String> unresCritExts = crl.getCriticalExtensionOIDs();
    687         // remove any that we have processed
    688         if (unresCritExts != null) {
    689             unresCritExts.remove(IssuingDistributionPoint_Id.toString());
    690             if (!unresCritExts.isEmpty()) {
    691                 if (debug != null) {
    692                     debug.println("Unrecognized critical extension(s) in CRL: "
    693                         + unresCritExts);
    694                     for (String ext : unresCritExts) {
    695                         debug.println(ext);
    696                     }
    697                 }
    698                 return false;
    699             }
    700         }
    701 
    702         // update reasonsMask
    703         for (int i = 0; i < reasonsMask.length; i++) {
    704             reasonsMask[i] = reasonsMask[i] ||
    705                     (i < interimReasonsMask.length && interimReasonsMask[i]);
    706         }
    707         return true;
    708     }
    709 
    710     /**
    711      * Append relative name to the issuer name and return a new
    712      * GeneralNames object.
    713      */
    714     private static GeneralNames getFullNames(X500Name issuer, RDN rdn)
    715         throws IOException
    716     {
    717         List<RDN> rdns = new ArrayList<>(issuer.rdns());
    718         rdns.add(rdn);
    719         X500Name fullName = new X500Name(rdns.toArray(new RDN[0]));
    720         GeneralNames fullNames = new GeneralNames();
    721         fullNames.add(new GeneralName(fullName));
    722         return fullNames;
    723     }
    724 
    725     /**
    726      * Verifies whether a CRL is issued by a certain certificate
    727      *
    728      * @param cert the certificate
    729      * @param crl the CRL to be verified
    730      * @param provider the name of the signature provider
    731      */
    732     private static boolean issues(X509CertImpl cert, X509CRLImpl crl,
    733                                   String provider) throws IOException
    734     {
    735         boolean matched = false;
    736 
    737         AdaptableX509CertSelector issuerSelector =
    738                                     new AdaptableX509CertSelector();
    739 
    740         // check certificate's key usage
    741         boolean[] usages = cert.getKeyUsage();
    742         if (usages != null) {
    743             usages[6] = true;       // cRLSign
    744             issuerSelector.setKeyUsage(usages);
    745         }
    746 
    747         // check certificate's subject
    748         X500Principal crlIssuer = crl.getIssuerX500Principal();
    749         issuerSelector.setSubject(crlIssuer);
    750 
    751         /*
    752          * Facilitate certification path construction with authority
    753          * key identifier and subject key identifier.
    754          *
    755          * In practice, conforming CAs MUST use the key identifier method,
    756          * and MUST include authority key identifier extension in all CRLs
    757          * issued. [section 5.2.1, RFC 2459]
    758          */
    759         AuthorityKeyIdentifierExtension crlAKID = crl.getAuthKeyIdExtension();
    760         issuerSelector.setSkiAndSerialNumber(crlAKID);
    761 
    762         matched = issuerSelector.match(cert);
    763 
    764         // if AKID is unreliable, verify the CRL signature with the cert
    765         if (matched && (crlAKID == null ||
    766                 cert.getAuthorityKeyIdentifierExtension() == null)) {
    767             try {
    768                 crl.verify(cert.getPublicKey(), provider);
    769                 matched = true;
    770             } catch (GeneralSecurityException e) {
    771                 matched = false;
    772             }
    773         }
    774 
    775         return matched;
    776     }
    777 }
    778