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