• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
DistributionPointFetcher()63     private DistributionPointFetcher() {}
64 
65     /**
66      * Return the X509CRLs matching this selector. The selector must be
67      * an X509CRLSelector with certificateChecking set.
68      */
getCRLs(X509CRLSelector selector, boolean signFlag, PublicKey prevKey, String provider, List<CertStore> certStores, boolean[] reasonsMask, Set<TrustAnchor> trustAnchors, Date validity)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      */
getCRLs(X509CRLSelector selector, boolean signFlag, PublicKey prevKey, X509Certificate prevCert, String provider, List<CertStore> certStores, boolean[] reasonsMask, Set<TrustAnchor> trustAnchors, Date validity)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      */
getCRLs(X509CRLSelector selector, X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask, boolean signFlag, PublicKey prevKey, X509Certificate prevCert, String provider, List<CertStore> certStores, Set<TrustAnchor> trustAnchors, Date validity)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      */
getCRL(URIName name)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      */
getCRLs(X500Name name, X500Principal certIssuer, List<CertStore> certStores)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      */
verifyCRL(X509CertImpl certImpl, DistributionPoint point, X509CRL crl, boolean[] reasonsMask, boolean signFlag, PublicKey prevKey, X509Certificate prevCert, String provider, Set<TrustAnchor> trustAnchors, List<CertStore> certStores, Date validity)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      */
getFullNames(X500Name issuer, RDN rdn)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      */
issues(X509CertImpl cert, X509CRLImpl crl, String provider)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