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