1 /* 2 * Copyright (c) 2000, 2012, 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.IOException; 29 import java.util.*; 30 31 import java.security.GeneralSecurityException; 32 import java.security.InvalidKeyException; 33 import java.security.cert.CertificateException; 34 import java.security.cert.CertPathValidatorException; 35 import java.security.cert.CertStore; 36 import java.security.cert.CertStoreException; 37 import java.security.cert.PKIXBuilderParameters; 38 import java.security.cert.PKIXCertPathChecker; 39 import java.security.cert.TrustAnchor; 40 import java.security.cert.X509Certificate; 41 import java.security.cert.X509CertSelector; 42 import javax.security.auth.x500.X500Principal; 43 44 import sun.security.util.Debug; 45 import sun.security.x509.AccessDescription; 46 import sun.security.x509.AuthorityInfoAccessExtension; 47 import sun.security.x509.PKIXExtensions; 48 import sun.security.x509.PolicyMappingsExtension; 49 import sun.security.x509.X500Name; 50 import sun.security.x509.X509CertImpl; 51 52 /** 53 * This class represents a forward builder, which is able to retrieve 54 * matching certificates from CertStores and verify a particular certificate 55 * against a ForwardState. 56 * 57 * @since 1.4 58 * @author Yassir Elley 59 * @author Sean Mullan 60 */ 61 class ForwardBuilder extends Builder { 62 63 private static final Debug debug = Debug.getInstance("certpath"); 64 private final Set<X509Certificate> trustedCerts; 65 private final Set<X500Principal> trustedSubjectDNs; 66 private final Set<TrustAnchor> trustAnchors; 67 private X509CertSelector eeSelector; 68 private X509CertSelector caSelector; 69 private X509CertSelector caTargetSelector; 70 TrustAnchor trustAnchor; 71 private Comparator<X509Certificate> comparator; 72 private boolean searchAllCertStores = true; 73 private boolean onlyEECert = false; 74 75 /** 76 * Initialize the builder with the input parameters. 77 * 78 * @param params the parameter set used to build a certification path 79 */ 80 ForwardBuilder(PKIXBuilderParameters buildParams, 81 X500Principal targetSubjectDN, boolean searchAllCertStores, 82 boolean onlyEECert) 83 { 84 super(buildParams, targetSubjectDN); 85 86 // populate sets of trusted certificates and subject DNs 87 trustAnchors = buildParams.getTrustAnchors(); 88 trustedCerts = new HashSet<X509Certificate>(trustAnchors.size()); 89 trustedSubjectDNs = new HashSet<X500Principal>(trustAnchors.size()); 90 for (TrustAnchor anchor : trustAnchors) { 91 X509Certificate trustedCert = anchor.getTrustedCert(); 92 if (trustedCert != null) { 93 trustedCerts.add(trustedCert); 94 trustedSubjectDNs.add(trustedCert.getSubjectX500Principal()); 95 } else { 96 trustedSubjectDNs.add(anchor.getCA()); 97 } 98 } 99 comparator = new PKIXCertComparator(trustedSubjectDNs); 100 this.searchAllCertStores = searchAllCertStores; 101 this.onlyEECert = onlyEECert; 102 } 103 104 /** 105 * Retrieves all certs from the specified CertStores that satisfy the 106 * requirements specified in the parameters and the current 107 * PKIX state (name constraints, policy constraints, etc). 108 * 109 * @param currentState the current state. 110 * Must be an instance of <code>ForwardState</code> 111 * @param certStores list of CertStores 112 */ 113 Collection<X509Certificate> getMatchingCerts 114 (State currentState, List<CertStore> certStores) 115 throws CertStoreException, CertificateException, IOException 116 { 117 if (debug != null) { 118 debug.println("ForwardBuilder.getMatchingCerts()..."); 119 } 120 121 ForwardState currState = (ForwardState) currentState; 122 123 /* 124 * We store certs in a Set because we don't want duplicates. 125 * As each cert is added, it is sorted based on the PKIXCertComparator 126 * algorithm. 127 */ 128 Set<X509Certificate> certs = new TreeSet<X509Certificate>(comparator); 129 130 /* 131 * Only look for EE certs if search has just started. 132 */ 133 if (currState.isInitial()) { 134 getMatchingEECerts(currState, certStores, certs); 135 } 136 getMatchingCACerts(currState, certStores, certs); 137 138 return certs; 139 } 140 141 /* 142 * Retrieves all end-entity certificates which satisfy constraints 143 * and requirements specified in the parameters and PKIX state. 144 */ 145 private void getMatchingEECerts(ForwardState currentState, 146 List<CertStore> certStores, Collection<X509Certificate> eeCerts) 147 throws IOException { 148 149 if (debug != null) { 150 debug.println("ForwardBuilder.getMatchingEECerts()..."); 151 } 152 /* 153 * Compose a certificate matching rule to filter out 154 * certs which don't satisfy constraints 155 * 156 * First, retrieve clone of current target cert constraints, 157 * and then add more selection criteria based on current validation 158 * state. Since selector never changes, cache local copy & reuse. 159 */ 160 if (eeSelector == null) { 161 eeSelector = (X509CertSelector) targetCertConstraints.clone(); 162 163 /* 164 * Match on certificate validity date 165 */ 166 eeSelector.setCertificateValid(date); 167 168 /* 169 * Policy processing optimizations 170 */ 171 if (buildParams.isExplicitPolicyRequired()) { 172 eeSelector.setPolicy(getMatchingPolicies()); 173 } 174 /* 175 * Require EE certs 176 */ 177 eeSelector.setBasicConstraints(-2); 178 } 179 180 /* Retrieve matching EE certs from CertStores */ 181 addMatchingCerts(eeSelector, certStores, eeCerts, searchAllCertStores); 182 } 183 184 /** 185 * Retrieves all CA certificates which satisfy constraints 186 * and requirements specified in the parameters and PKIX state. 187 */ 188 private void getMatchingCACerts(ForwardState currentState, 189 List<CertStore> certStores, Collection<X509Certificate> caCerts) 190 throws IOException { 191 192 if (debug != null) { 193 debug.println("ForwardBuilder.getMatchingCACerts()..."); 194 } 195 int initialSize = caCerts.size(); 196 197 /* 198 * Compose a CertSelector to filter out 199 * certs which do not satisfy requirements. 200 */ 201 X509CertSelector sel = null; 202 203 if (currentState.isInitial()) { 204 /* This means a CA is the target, so match on same stuff as 205 * getMatchingEECerts 206 */ 207 if (debug != null) { 208 debug.println("ForwardBuilder.getMatchingCACerts(): ca is target"); 209 } 210 211 if (caTargetSelector == null) { 212 caTargetSelector = (X509CertSelector) 213 targetCertConstraints.clone(); 214 215 /* 216 * Match on certificate validity date 217 */ 218 caTargetSelector.setCertificateValid(date); 219 220 /* 221 * Policy processing optimizations 222 */ 223 if (buildParams.isExplicitPolicyRequired()) 224 caTargetSelector.setPolicy(getMatchingPolicies()); 225 } 226 227 /* 228 * Require CA certs with a pathLenConstraint that allows 229 * at least as many CA certs that have already been traversed 230 */ 231 caTargetSelector.setBasicConstraints(currentState.traversedCACerts); 232 sel = caTargetSelector; 233 234 } else { 235 236 if (caSelector == null) { 237 caSelector = new X509CertSelector(); 238 239 /* 240 * Match on certificate validity date. 241 */ 242 caSelector.setCertificateValid(date); 243 244 /* 245 * Policy processing optimizations 246 */ 247 if (buildParams.isExplicitPolicyRequired()) 248 caSelector.setPolicy(getMatchingPolicies()); 249 } 250 251 /* 252 * Match on subject (issuer of previous cert) 253 */ 254 caSelector.setSubject(currentState.issuerDN); 255 256 /* 257 * Match on subjectNamesTraversed (both DNs and AltNames) 258 * (checks that current cert's name constraints permit it 259 * to certify all the DNs and AltNames that have been traversed) 260 */ 261 CertPathHelper.setPathToNames 262 (caSelector, currentState.subjectNamesTraversed); 263 264 /* 265 * Require CA certs with a pathLenConstraint that allows 266 * at least as many CA certs that have already been traversed 267 */ 268 caSelector.setBasicConstraints(currentState.traversedCACerts); 269 sel = caSelector; 270 } 271 272 /* 273 * Check if any of the trusted certs could be a match. 274 * Since we are not validating the trusted cert, we can't 275 * re-use the selector we've built up (sel) - we need 276 * to use a new selector (trustedSel) 277 */ 278 X509CertSelector trustedSel = null; 279 if (currentState.isInitial()) { 280 trustedSel = targetCertConstraints; 281 } else { 282 trustedSel = new X509CertSelector(); 283 trustedSel.setSubject(currentState.issuerDN); 284 } 285 286 boolean foundMatchingCert = false; 287 for (X509Certificate trustedCert : trustedCerts) { 288 if (trustedSel.match(trustedCert)) { 289 if (debug != null) { 290 debug.println("ForwardBuilder.getMatchingCACerts: " 291 + "found matching trust anchor"); 292 } 293 if (caCerts.add(trustedCert) && !searchAllCertStores) { 294 return; 295 } 296 } 297 } 298 299 300 /* 301 * If we have already traversed as many CA certs as the maxPathLength 302 * will allow us to, then we don't bother looking through these 303 * certificate pairs. If maxPathLength has a value of -1, this 304 * means it is unconstrained, so we always look through the 305 * certificate pairs. 306 */ 307 if (currentState.isInitial() || 308 (buildParams.getMaxPathLength() == -1) || 309 (buildParams.getMaxPathLength() > currentState.traversedCACerts)) 310 { 311 if (addMatchingCerts(sel, certStores, caCerts, searchAllCertStores) 312 && !searchAllCertStores) { 313 return; 314 } 315 } 316 317 if (!currentState.isInitial() && Builder.USE_AIA) { 318 // check for AuthorityInformationAccess extension 319 AuthorityInfoAccessExtension aiaExt = 320 currentState.cert.getAuthorityInfoAccessExtension(); 321 if (aiaExt != null) { 322 getCerts(aiaExt, caCerts); 323 } 324 } 325 326 if (debug != null) { 327 int numCerts = caCerts.size() - initialSize; 328 debug.println("ForwardBuilder.getMatchingCACerts: found " + 329 numCerts + " CA certs"); 330 } 331 } 332 333 /** 334 * Download Certificates from the given AIA and add them to the 335 * specified Collection. 336 */ 337 private boolean getCerts(AuthorityInfoAccessExtension aiaExt, 338 Collection<X509Certificate> certs) { 339 if (Builder.USE_AIA == false) { 340 return false; 341 } 342 List<AccessDescription> adList = aiaExt.getAccessDescriptions(); 343 if (adList == null || adList.isEmpty()) { 344 return false; 345 } 346 347 boolean add = false; 348 for (AccessDescription ad : adList) { 349 CertStore cs = URICertStore.getInstance(ad); 350 try { 351 if (certs.addAll((Collection<X509Certificate>) 352 cs.getCertificates(caSelector))) { 353 add = true; 354 if (!searchAllCertStores) { 355 return true; 356 } 357 } 358 } catch (CertStoreException cse) { 359 if (debug != null) { 360 debug.println("exception getting certs from CertStore:"); 361 cse.printStackTrace(); 362 } 363 continue; 364 } 365 } 366 return add; 367 } 368 369 /** 370 * This inner class compares 2 PKIX certificates according to which 371 * should be tried first when building a path from the target. 372 * The preference order is as follows: 373 * 374 * Given trusted certificate(s): 375 * Subject:ou=D,ou=C,o=B,c=A 376 * 377 * Preference order for current cert: 378 * 379 * 1) Issuer matches a trusted subject 380 * Issuer: ou=D,ou=C,o=B,c=A 381 * 382 * 2) Issuer is a descendant of a trusted subject (in order of 383 * number of links to the trusted subject) 384 * a) Issuer: ou=E,ou=D,ou=C,o=B,c=A [links=1] 385 * b) Issuer: ou=F,ou=E,ou=D,ou=C,ou=B,c=A [links=2] 386 * 387 * 3) Issuer is an ancestor of a trusted subject (in order of number of 388 * links to the trusted subject) 389 * a) Issuer: ou=C,o=B,c=A [links=1] 390 * b) Issuer: o=B,c=A [links=2] 391 * 392 * 4) Issuer is in the same namespace as a trusted subject (in order of 393 * number of links to the trusted subject) 394 * a) Issuer: ou=G,ou=C,o=B,c=A [links=2] 395 * b) Issuer: ou=H,o=B,c=A [links=3] 396 * 397 * 5) Issuer is an ancestor of certificate subject (in order of number 398 * of links to the certificate subject) 399 * a) Issuer: ou=K,o=J,c=A 400 * Subject: ou=L,ou=K,o=J,c=A 401 * b) Issuer: o=J,c=A 402 * Subject: ou=L,ou=K,0=J,c=A 403 * 404 * 6) Any other certificates 405 */ 406 static class PKIXCertComparator implements Comparator<X509Certificate> { 407 408 final static String METHOD_NME = "PKIXCertComparator.compare()"; 409 410 private final Set<X500Principal> trustedSubjectDNs; 411 412 PKIXCertComparator(Set<X500Principal> trustedSubjectDNs) { 413 this.trustedSubjectDNs = trustedSubjectDNs; 414 } 415 416 /** 417 * @param oCert1 First X509Certificate to be compared 418 * @param oCert2 Second X509Certificate to be compared 419 * @return -1 if oCert1 is preferable to oCert2, or 420 * if oCert1 and oCert2 are equally preferable (in this 421 * case it doesn't matter which is preferable, but we don't 422 * return 0 because the comparator would behave strangely 423 * when used in a SortedSet). 424 * 1 if oCert2 is preferable to oCert1 425 * 0 if oCert1.equals(oCert2). We only return 0 if the 426 * certs are equal so that this comparator behaves 427 * correctly when used in a SortedSet. 428 * @throws ClassCastException if either argument is not of type 429 * X509Certificate 430 */ 431 public int compare(X509Certificate oCert1, X509Certificate oCert2) { 432 433 // if certs are the same, return 0 434 if (oCert1.equals(oCert2)) return 0; 435 436 X500Principal cIssuer1 = oCert1.getIssuerX500Principal(); 437 X500Principal cIssuer2 = oCert2.getIssuerX500Principal(); 438 X500Name cIssuer1Name = X500Name.asX500Name(cIssuer1); 439 X500Name cIssuer2Name = X500Name.asX500Name(cIssuer2); 440 441 if (debug != null) { 442 debug.println(METHOD_NME + " o1 Issuer: " + cIssuer1); 443 debug.println(METHOD_NME + " o2 Issuer: " + cIssuer2); 444 } 445 446 /* If one cert's issuer matches a trusted subject, then it is 447 * preferable. 448 */ 449 if (debug != null) { 450 debug.println(METHOD_NME + " MATCH TRUSTED SUBJECT TEST..."); 451 } 452 453 boolean m1 = trustedSubjectDNs.contains(cIssuer1); 454 boolean m2 = trustedSubjectDNs.contains(cIssuer2); 455 if (debug != null) { 456 debug.println(METHOD_NME + " m1: " + m1); 457 debug.println(METHOD_NME + " m2: " + m2); 458 } 459 if (m1 && m2) { 460 return -1; 461 } else if (m1) { 462 return -1; 463 } else if (m2) { 464 return 1; 465 } 466 467 /* If one cert's issuer is a naming descendant of a trusted subject, 468 * then it is preferable, in order of increasing naming distance. 469 */ 470 if (debug != null) { 471 debug.println(METHOD_NME + " NAMING DESCENDANT TEST..."); 472 } 473 for (X500Principal tSubject : trustedSubjectDNs) { 474 X500Name tSubjectName = X500Name.asX500Name(tSubject); 475 int distanceTto1 = 476 Builder.distance(tSubjectName, cIssuer1Name, -1); 477 int distanceTto2 = 478 Builder.distance(tSubjectName, cIssuer2Name, -1); 479 if (debug != null) { 480 debug.println(METHOD_NME +" distanceTto1: " + distanceTto1); 481 debug.println(METHOD_NME +" distanceTto2: " + distanceTto2); 482 } 483 if (distanceTto1 > 0 || distanceTto2 > 0) { 484 if (distanceTto1 == distanceTto2) { 485 return -1; 486 } else if (distanceTto1 > 0 && distanceTto2 <= 0) { 487 return -1; 488 } else if (distanceTto1 <= 0 && distanceTto2 > 0) { 489 return 1; 490 } else if (distanceTto1 < distanceTto2) { 491 return -1; 492 } else { // distanceTto1 > distanceTto2 493 return 1; 494 } 495 } 496 } 497 498 /* If one cert's issuer is a naming ancestor of a trusted subject, 499 * then it is preferable, in order of increasing naming distance. 500 */ 501 if (debug != null) { 502 debug.println(METHOD_NME + " NAMING ANCESTOR TEST..."); 503 } 504 for (X500Principal tSubject : trustedSubjectDNs) { 505 X500Name tSubjectName = X500Name.asX500Name(tSubject); 506 507 int distanceTto1 = Builder.distance 508 (tSubjectName, cIssuer1Name, Integer.MAX_VALUE); 509 int distanceTto2 = Builder.distance 510 (tSubjectName, cIssuer2Name, Integer.MAX_VALUE); 511 if (debug != null) { 512 debug.println(METHOD_NME +" distanceTto1: " + distanceTto1); 513 debug.println(METHOD_NME +" distanceTto2: " + distanceTto2); 514 } 515 if (distanceTto1 < 0 || distanceTto2 < 0) { 516 if (distanceTto1 == distanceTto2) { 517 return -1; 518 } else if (distanceTto1 < 0 && distanceTto2 >= 0) { 519 return -1; 520 } else if (distanceTto1 >= 0 && distanceTto2 < 0) { 521 return 1; 522 } else if (distanceTto1 > distanceTto2) { 523 return -1; 524 } else { 525 return 1; 526 } 527 } 528 } 529 530 /* If one cert's issuer is in the same namespace as a trusted 531 * subject, then it is preferable, in order of increasing naming 532 * distance. 533 */ 534 if (debug != null) { 535 debug.println(METHOD_NME +" SAME NAMESPACE AS TRUSTED TEST..."); 536 } 537 for (X500Principal tSubject : trustedSubjectDNs) { 538 X500Name tSubjectName = X500Name.asX500Name(tSubject); 539 X500Name tAo1 = tSubjectName.commonAncestor(cIssuer1Name); 540 X500Name tAo2 = tSubjectName.commonAncestor(cIssuer2Name); 541 if (debug != null) { 542 debug.println(METHOD_NME +" tAo1: " + String.valueOf(tAo1)); 543 debug.println(METHOD_NME +" tAo2: " + String.valueOf(tAo2)); 544 } 545 if (tAo1 != null || tAo2 != null) { 546 if (tAo1 != null && tAo2 != null) { 547 int hopsTto1 = Builder.hops 548 (tSubjectName, cIssuer1Name, Integer.MAX_VALUE); 549 int hopsTto2 = Builder.hops 550 (tSubjectName, cIssuer2Name, Integer.MAX_VALUE); 551 if (debug != null) { 552 debug.println(METHOD_NME +" hopsTto1: " + hopsTto1); 553 debug.println(METHOD_NME +" hopsTto2: " + hopsTto2); 554 } 555 if (hopsTto1 == hopsTto2) { 556 } else if (hopsTto1 > hopsTto2) { 557 return 1; 558 } else { // hopsTto1 < hopsTto2 559 return -1; 560 } 561 } else if (tAo1 == null) { 562 return 1; 563 } else { 564 return -1; 565 } 566 } 567 } 568 569 570 /* If one cert's issuer is an ancestor of that cert's subject, 571 * then it is preferable, in order of increasing naming distance. 572 */ 573 if (debug != null) { 574 debug.println(METHOD_NME+" CERT ISSUER/SUBJECT COMPARISON TEST..."); 575 } 576 X500Principal cSubject1 = oCert1.getSubjectX500Principal(); 577 X500Principal cSubject2 = oCert2.getSubjectX500Principal(); 578 X500Name cSubject1Name = X500Name.asX500Name(cSubject1); 579 X500Name cSubject2Name = X500Name.asX500Name(cSubject2); 580 581 if (debug != null) { 582 debug.println(METHOD_NME + " o1 Subject: " + cSubject1); 583 debug.println(METHOD_NME + " o2 Subject: " + cSubject2); 584 } 585 int distanceStoI1 = Builder.distance 586 (cSubject1Name, cIssuer1Name, Integer.MAX_VALUE); 587 int distanceStoI2 = Builder.distance 588 (cSubject2Name, cIssuer2Name, Integer.MAX_VALUE); 589 if (debug != null) { 590 debug.println(METHOD_NME + " distanceStoI1: " + distanceStoI1); 591 debug.println(METHOD_NME + " distanceStoI2: " + distanceStoI2); 592 } 593 if (distanceStoI2 > distanceStoI1) { 594 return -1; 595 } else if (distanceStoI2 < distanceStoI1) { 596 return 1; 597 } 598 599 /* Otherwise, certs are equally preferable. 600 */ 601 if (debug != null) { 602 debug.println(METHOD_NME + " no tests matched; RETURN 0"); 603 } 604 return -1; 605 } 606 } 607 608 /** 609 * Verifies a matching certificate. 610 * 611 * This method executes the validation steps in the PKIX path 612 * validation algorithm <draft-ietf-pkix-new-part1-08.txt> which were 613 * not satisfied by the selection criteria used by getCertificates() 614 * to find the certs and only the steps that can be executed in a 615 * forward direction (target to trust anchor). Those steps that can 616 * only be executed in a reverse direction are deferred until the 617 * complete path has been built. 618 * 619 * Trust anchor certs are not validated, but are used to verify the 620 * signature and revocation status of the previous cert. 621 * 622 * If the last certificate is being verified (the one whose subject 623 * matches the target subject, then steps in 6.1.4 of the PKIX 624 * Certification Path Validation algorithm are NOT executed, 625 * regardless of whether or not the last cert is an end-entity 626 * cert or not. This allows callers to certify CA certs as 627 * well as EE certs. 628 * 629 * @param cert the certificate to be verified 630 * @param currentState the current state against which the cert is verified 631 * @param certPathList the certPathList generated thus far 632 */ 633 void verifyCert(X509Certificate cert, State currentState, 634 List<X509Certificate> certPathList) throws GeneralSecurityException 635 { 636 if (debug != null) { 637 debug.println("ForwardBuilder.verifyCert(SN: " 638 + Debug.toHexString(cert.getSerialNumber()) 639 + "\n Issuer: " + cert.getIssuerX500Principal() + ")" 640 + "\n Subject: " + cert.getSubjectX500Principal() + ")"); 641 } 642 643 ForwardState currState = (ForwardState)currentState; 644 645 // Don't bother to verify untrusted certificate. 646 currState.untrustedChecker.check(cert, Collections.<String>emptySet()); 647 648 /* 649 * check for looping - abort a loop if 650 * ((we encounter the same certificate twice) AND 651 * ((policyMappingInhibited = true) OR (no policy mapping 652 * extensions can be found between the occurences of the same 653 * certificate))) 654 */ 655 if (certPathList != null) { 656 boolean policyMappingFound = false; 657 for (X509Certificate cpListCert : certPathList) { 658 X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert); 659 PolicyMappingsExtension policyMappingsExt 660 = cpListCertImpl.getPolicyMappingsExtension(); 661 if (policyMappingsExt != null) { 662 policyMappingFound = true; 663 } 664 if (debug != null) { 665 debug.println("policyMappingFound = " + policyMappingFound); 666 } 667 if (cert.equals(cpListCert)) { 668 if ((buildParams.isPolicyMappingInhibited()) || 669 (!policyMappingFound)) { 670 if (debug != null) { 671 debug.println("loop detected!!"); 672 } 673 throw new CertPathValidatorException("loop detected"); 674 } 675 } 676 } 677 } 678 679 /* check if trusted cert */ 680 boolean isTrustedCert = trustedCerts.contains(cert); 681 682 /* we don't perform any validation of the trusted cert */ 683 if (!isTrustedCert) { 684 /* 685 * Check CRITICAL private extensions for user checkers that 686 * support forward checking (forwardCheckers) and remove 687 * ones we know how to check. 688 */ 689 Set<String> unresCritExts = cert.getCriticalExtensionOIDs(); 690 if (unresCritExts == null) { 691 unresCritExts = Collections.<String>emptySet(); 692 } 693 for (PKIXCertPathChecker checker : currState.forwardCheckers) { 694 checker.check(cert, unresCritExts); 695 } 696 697 /* 698 * Remove extensions from user checkers that don't support 699 * forward checking. After this step, we will have removed 700 * all extensions that all user checkers are capable of 701 * processing. 702 */ 703 for (PKIXCertPathChecker checker : buildParams.getCertPathCheckers()) { 704 if (!checker.isForwardCheckingSupported()) { 705 Set<String> supportedExts = checker.getSupportedExtensions(); 706 if (supportedExts != null) { 707 unresCritExts.removeAll(supportedExts); 708 } 709 } 710 } 711 712 /* 713 * Look at the remaining extensions and remove any ones we know how 714 * to check. If there are any left, throw an exception! 715 */ 716 if (!unresCritExts.isEmpty()) { 717 unresCritExts.remove( 718 PKIXExtensions.BasicConstraints_Id.toString()); 719 unresCritExts.remove( 720 PKIXExtensions.NameConstraints_Id.toString()); 721 unresCritExts.remove( 722 PKIXExtensions.CertificatePolicies_Id.toString()); 723 unresCritExts.remove( 724 PKIXExtensions.PolicyMappings_Id.toString()); 725 unresCritExts.remove( 726 PKIXExtensions.PolicyConstraints_Id.toString()); 727 unresCritExts.remove( 728 PKIXExtensions.InhibitAnyPolicy_Id.toString()); 729 unresCritExts.remove( 730 PKIXExtensions.SubjectAlternativeName_Id.toString()); 731 unresCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); 732 unresCritExts.remove( 733 PKIXExtensions.ExtendedKeyUsage_Id.toString()); 734 735 if (!unresCritExts.isEmpty()) 736 throw new CertificateException("Unrecognized critical " 737 + "extension(s)"); 738 } 739 } 740 741 /* 742 * if this is the target certificate (init=true), then we are 743 * not able to do any more verification, so just return 744 */ 745 if (currState.isInitial()) { 746 return; 747 } 748 749 /* we don't perform any validation of the trusted cert */ 750 if (!isTrustedCert) { 751 /* Make sure this is a CA cert */ 752 if (cert.getBasicConstraints() == -1) { 753 throw new CertificateException("cert is NOT a CA cert"); 754 } 755 756 /* 757 * Check keyUsage extension 758 */ 759 KeyChecker.verifyCAKeyUsage(cert); 760 } 761 762 /* 763 * the following checks are performed even when the cert 764 * is a trusted cert, since we are only extracting the 765 * subjectDN, and publicKey from the cert 766 * in order to verify a previous cert 767 */ 768 769 /* 770 * Check revocation for the previous cert 771 */ 772 if (buildParams.isRevocationEnabled()) { 773 774 // first off, see if this cert can authorize revocation... 775 if (CrlRevocationChecker.certCanSignCrl(cert)) { 776 // And then check to be sure no key requiring key parameters 777 // has been encountered 778 if (!currState.keyParamsNeeded()) 779 // If all that checks out, we can check the 780 // revocation status of the cert. Otherwise, 781 // we'll just wait until the end. 782 currState.crlChecker.check(currState.cert, 783 cert.getPublicKey(), 784 true); 785 } 786 } 787 788 /* 789 * Check signature only if no key requiring key parameters has been 790 * encountered. 791 */ 792 if (!currState.keyParamsNeeded()) { 793 (currState.cert).verify(cert.getPublicKey(), 794 buildParams.getSigProvider()); 795 } 796 } 797 798 /** 799 * Verifies whether the input certificate completes the path. 800 * Checks the cert against each trust anchor that was specified, in order, 801 * and returns true as soon as it finds a valid anchor. 802 * Returns true if the cert matches a trust anchor specified as a 803 * certificate or if the cert verifies with a trust anchor that 804 * was specified as a trusted {pubkey, caname} pair. Returns false if none 805 * of the trust anchors are valid for this cert. 806 * 807 * @param cert the certificate to test 808 * @return a boolean value indicating whether the cert completes the path. 809 */ 810 boolean isPathCompleted(X509Certificate cert) { 811 for (TrustAnchor anchor : trustAnchors) { 812 if (anchor.getTrustedCert() != null) { 813 if (cert.equals(anchor.getTrustedCert())) { 814 this.trustAnchor = anchor; 815 return true; 816 } else { 817 continue; 818 } 819 } 820 821 X500Principal trustedCAName = anchor.getCA(); 822 823 /* Check subject/issuer name chaining */ 824 if (!trustedCAName.equals(cert.getIssuerX500Principal())) { 825 continue; 826 } 827 828 /* Check revocation if it is enabled */ 829 if (buildParams.isRevocationEnabled()) { 830 try { 831 CrlRevocationChecker crlChecker = new CrlRevocationChecker 832 (anchor, buildParams, null, onlyEECert); 833 crlChecker.check(cert, anchor.getCAPublicKey(), true); 834 } catch (CertPathValidatorException cpve) { 835 if (debug != null) { 836 debug.println("ForwardBuilder.isPathCompleted() cpve"); 837 cpve.printStackTrace(); 838 } 839 continue; 840 } 841 } 842 843 /* 844 * Check signature 845 */ 846 try { 847 // NOTE: the DSA public key in the buildParams may lack 848 // parameters, yet there is no key to inherit the parameters 849 // from. This is probably such a rare case that it is not worth 850 // trying to detect the situation earlier. 851 cert.verify(anchor.getCAPublicKey(), 852 buildParams.getSigProvider()); 853 } catch (InvalidKeyException ike) { 854 if (debug != null) { 855 debug.println("ForwardBuilder.isPathCompleted() invalid " 856 + "DSA key found"); 857 } 858 continue; 859 } catch (Exception e){ 860 if (debug != null) { 861 debug.println("ForwardBuilder.isPathCompleted() " + 862 "unexpected exception"); 863 e.printStackTrace(); 864 } 865 continue; 866 } 867 868 this.trustAnchor = anchor; 869 return true; 870 } 871 872 return false; 873 } 874 875 /** Adds the certificate to the certPathList 876 * 877 * @param cert the certificate to be added 878 * @param certPathList the certification path list 879 */ 880 void addCertToPath(X509Certificate cert, 881 LinkedList<X509Certificate> certPathList) { 882 certPathList.addFirst(cert); 883 } 884 885 /** Removes final certificate from the certPathList 886 * 887 * @param certPathList the certification path list 888 */ 889 void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) { 890 certPathList.removeFirst(); 891 } 892 }