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