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