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