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