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