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.security.GeneralSecurityException; 30 import java.security.cert.Certificate; 31 import java.security.cert.CertificateException; 32 import java.security.cert.CertPathValidatorException; 33 import java.security.cert.PKIXCertPathChecker; 34 import java.security.cert.PKIXReason; 35 import java.security.cert.PolicyNode; 36 import java.security.cert.PolicyQualifierInfo; 37 import java.security.cert.X509Certificate; 38 import java.util.*; 39 40 import sun.security.util.Debug; 41 import sun.security.x509.CertificatePoliciesExtension; 42 import sun.security.x509.PolicyConstraintsExtension; 43 import sun.security.x509.PolicyMappingsExtension; 44 import sun.security.x509.CertificatePolicyMap; 45 import static sun.security.x509.PKIXExtensions.*; 46 import sun.security.x509.PolicyInformation; 47 import sun.security.x509.X509CertImpl; 48 import sun.security.x509.InhibitAnyPolicyExtension; 49 50 /** 51 * PolicyChecker is a <code>PKIXCertPathChecker</code> that checks policy 52 * information on a PKIX certificate, namely certificate policies, policy 53 * mappings, policy constraints and policy qualifiers. 54 * 55 * @since 1.4 56 * @author Yassir Elley 57 */ 58 class PolicyChecker extends PKIXCertPathChecker { 59 60 private final Set<String> initPolicies; 61 private final int certPathLen; 62 private final boolean expPolicyRequired; 63 private final boolean polMappingInhibited; 64 private final boolean anyPolicyInhibited; 65 private final boolean rejectPolicyQualifiers; 66 private PolicyNodeImpl rootNode; 67 private int explicitPolicy; 68 private int policyMapping; 69 private int inhibitAnyPolicy; 70 private int certIndex; 71 72 private Set<String> supportedExts; 73 74 private static final Debug debug = Debug.getInstance("certpath"); 75 static final String ANY_POLICY = "2.5.29.32.0"; 76 77 /** 78 * Constructs a Policy Checker. 79 * 80 * @param initialPolicies Set of initial policies 81 * @param certPathLen length of the certification path to be checked 82 * @param expPolicyRequired true if explicit policy is required 83 * @param polMappingInhibited true if policy mapping is inhibited 84 * @param anyPolicyInhibited true if the ANY_POLICY OID should be inhibited 85 * @param rejectPolicyQualifiers true if pol qualifiers are to be rejected 86 * @param rootNode the initial root node of the valid policy tree 87 */ PolicyChecker(Set<String> initialPolicies, int certPathLen, boolean expPolicyRequired, boolean polMappingInhibited, boolean anyPolicyInhibited, boolean rejectPolicyQualifiers, PolicyNodeImpl rootNode)88 PolicyChecker(Set<String> initialPolicies, int certPathLen, 89 boolean expPolicyRequired, boolean polMappingInhibited, 90 boolean anyPolicyInhibited, boolean rejectPolicyQualifiers, 91 PolicyNodeImpl rootNode) 92 { 93 if (initialPolicies.isEmpty()) { 94 // if no initialPolicies are specified by user, set 95 // initPolicies to be anyPolicy by default 96 this.initPolicies = new HashSet<String>(1); 97 this.initPolicies.add(ANY_POLICY); 98 } else { 99 this.initPolicies = new HashSet<String>(initialPolicies); 100 } 101 this.certPathLen = certPathLen; 102 this.expPolicyRequired = expPolicyRequired; 103 this.polMappingInhibited = polMappingInhibited; 104 this.anyPolicyInhibited = anyPolicyInhibited; 105 this.rejectPolicyQualifiers = rejectPolicyQualifiers; 106 this.rootNode = rootNode; 107 } 108 109 /** 110 * Initializes the internal state of the checker from parameters 111 * specified in the constructor 112 * 113 * @param forward a boolean indicating whether this checker should be 114 * initialized capable of building in the forward direction 115 * @throws CertPathValidatorException if user wants to enable forward 116 * checking and forward checking is not supported. 117 */ 118 @Override init(boolean forward)119 public void init(boolean forward) throws CertPathValidatorException { 120 if (forward) { 121 throw new CertPathValidatorException 122 ("forward checking not supported"); 123 } 124 125 certIndex = 1; 126 explicitPolicy = (expPolicyRequired ? 0 : certPathLen + 1); 127 policyMapping = (polMappingInhibited ? 0 : certPathLen + 1); 128 inhibitAnyPolicy = (anyPolicyInhibited ? 0 : certPathLen + 1); 129 } 130 131 /** 132 * Checks if forward checking is supported. Forward checking refers 133 * to the ability of the PKIXCertPathChecker to perform its checks 134 * when presented with certificates in the forward direction (from 135 * target to anchor). 136 * 137 * @return true if forward checking is supported, false otherwise 138 */ 139 @Override isForwardCheckingSupported()140 public boolean isForwardCheckingSupported() { 141 return false; 142 } 143 144 /** 145 * Gets an immutable Set of the OID strings for the extensions that 146 * the PKIXCertPathChecker supports (i.e. recognizes, is able to 147 * process), or null if no extensions are 148 * supported. All OID strings that a PKIXCertPathChecker might 149 * possibly be able to process should be included. 150 * 151 * @return the Set of extensions supported by this PKIXCertPathChecker, 152 * or null if no extensions are supported 153 */ 154 @Override getSupportedExtensions()155 public Set<String> getSupportedExtensions() { 156 if (supportedExts == null) { 157 supportedExts = new HashSet<String>(4); 158 supportedExts.add(CertificatePolicies_Id.toString()); 159 supportedExts.add(PolicyMappings_Id.toString()); 160 supportedExts.add(PolicyConstraints_Id.toString()); 161 supportedExts.add(InhibitAnyPolicy_Id.toString()); 162 supportedExts = Collections.unmodifiableSet(supportedExts); 163 } 164 return supportedExts; 165 } 166 167 /** 168 * Performs the policy processing checks on the certificate using its 169 * internal state. 170 * 171 * @param cert the Certificate to be processed 172 * @param unresCritExts the unresolved critical extensions 173 * @throws CertPathValidatorException if the certificate does not verify 174 */ 175 @Override check(Certificate cert, Collection<String> unresCritExts)176 public void check(Certificate cert, Collection<String> unresCritExts) 177 throws CertPathValidatorException 178 { 179 // now do the policy checks 180 checkPolicy((X509Certificate) cert); 181 182 if (unresCritExts != null && !unresCritExts.isEmpty()) { 183 unresCritExts.remove(CertificatePolicies_Id.toString()); 184 unresCritExts.remove(PolicyMappings_Id.toString()); 185 unresCritExts.remove(PolicyConstraints_Id.toString()); 186 unresCritExts.remove(InhibitAnyPolicy_Id.toString()); 187 } 188 } 189 190 /** 191 * Internal method to run through all the checks. 192 * 193 * @param currCert the certificate to be processed 194 * @exception CertPathValidatorException Exception thrown if 195 * the certificate does not verify 196 */ checkPolicy(X509Certificate currCert)197 private void checkPolicy(X509Certificate currCert) 198 throws CertPathValidatorException 199 { 200 String msg = "certificate policies"; 201 if (debug != null) { 202 debug.println("PolicyChecker.checkPolicy() ---checking " + msg 203 + "..."); 204 debug.println("PolicyChecker.checkPolicy() certIndex = " 205 + certIndex); 206 debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: " 207 + "explicitPolicy = " + explicitPolicy); 208 debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: " 209 + "policyMapping = " + policyMapping); 210 debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: " 211 + "inhibitAnyPolicy = " + inhibitAnyPolicy); 212 debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: " 213 + "policyTree = " + rootNode); 214 } 215 216 X509CertImpl currCertImpl = null; 217 try { 218 currCertImpl = X509CertImpl.toImpl(currCert); 219 } catch (CertificateException ce) { 220 throw new CertPathValidatorException(ce); 221 } 222 223 boolean finalCert = (certIndex == certPathLen); 224 225 rootNode = processPolicies(certIndex, initPolicies, explicitPolicy, 226 policyMapping, inhibitAnyPolicy, rejectPolicyQualifiers, rootNode, 227 currCertImpl, finalCert); 228 229 if (!finalCert) { 230 explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCertImpl, 231 finalCert); 232 policyMapping = mergePolicyMapping(policyMapping, currCertImpl); 233 inhibitAnyPolicy = mergeInhibitAnyPolicy(inhibitAnyPolicy, 234 currCertImpl); 235 } 236 237 certIndex++; 238 239 if (debug != null) { 240 debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: " 241 + "explicitPolicy = " + explicitPolicy); 242 debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: " 243 + "policyMapping = " + policyMapping); 244 debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: " 245 + "inhibitAnyPolicy = " + inhibitAnyPolicy); 246 debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: " 247 + "policyTree = " + rootNode); 248 debug.println("PolicyChecker.checkPolicy() " + msg + " verified"); 249 } 250 } 251 252 /** 253 * Merges the specified explicitPolicy value with the 254 * requireExplicitPolicy field of the <code>PolicyConstraints</code> 255 * extension obtained from the certificate. An explicitPolicy 256 * value of -1 implies no constraint. 257 * 258 * @param explicitPolicy an integer which indicates if a non-null 259 * valid policy tree is required 260 * @param currCert the Certificate to be processed 261 * @param finalCert a boolean indicating whether currCert is 262 * the final cert in the cert path 263 * @return returns the new explicitPolicy value 264 * @exception CertPathValidatorException Exception thrown if an error 265 * occurs 266 */ mergeExplicitPolicy(int explicitPolicy, X509CertImpl currCert, boolean finalCert)267 static int mergeExplicitPolicy(int explicitPolicy, X509CertImpl currCert, 268 boolean finalCert) throws CertPathValidatorException 269 { 270 if ((explicitPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) { 271 explicitPolicy--; 272 } 273 274 try { 275 PolicyConstraintsExtension polConstExt 276 = currCert.getPolicyConstraintsExtension(); 277 if (polConstExt == null) 278 return explicitPolicy; 279 int require = 280 polConstExt.get(PolicyConstraintsExtension.REQUIRE).intValue(); 281 if (debug != null) { 282 debug.println("PolicyChecker.mergeExplicitPolicy() " 283 + "require Index from cert = " + require); 284 } 285 if (!finalCert) { 286 if (require != -1) { 287 if ((explicitPolicy == -1) || (require < explicitPolicy)) { 288 explicitPolicy = require; 289 } 290 } 291 } else { 292 if (require == 0) 293 explicitPolicy = require; 294 } 295 } catch (IOException e) { 296 if (debug != null) { 297 debug.println("PolicyChecker.mergeExplicitPolicy " 298 + "unexpected exception"); 299 e.printStackTrace(); 300 } 301 throw new CertPathValidatorException(e); 302 } 303 304 return explicitPolicy; 305 } 306 307 /** 308 * Merges the specified policyMapping value with the 309 * inhibitPolicyMapping field of the <code>PolicyConstraints</code> 310 * extension obtained from the certificate. A policyMapping 311 * value of -1 implies no constraint. 312 * 313 * @param policyMapping an integer which indicates if policy mapping 314 * is inhibited 315 * @param currCert the Certificate to be processed 316 * @return returns the new policyMapping value 317 * @exception CertPathValidatorException Exception thrown if an error 318 * occurs 319 */ mergePolicyMapping(int policyMapping, X509CertImpl currCert)320 static int mergePolicyMapping(int policyMapping, X509CertImpl currCert) 321 throws CertPathValidatorException 322 { 323 if ((policyMapping > 0) && !X509CertImpl.isSelfIssued(currCert)) { 324 policyMapping--; 325 } 326 327 try { 328 PolicyConstraintsExtension polConstExt 329 = currCert.getPolicyConstraintsExtension(); 330 if (polConstExt == null) 331 return policyMapping; 332 333 int inhibit = 334 polConstExt.get(PolicyConstraintsExtension.INHIBIT).intValue(); 335 if (debug != null) 336 debug.println("PolicyChecker.mergePolicyMapping() " 337 + "inhibit Index from cert = " + inhibit); 338 339 if (inhibit != -1) { 340 if ((policyMapping == -1) || (inhibit < policyMapping)) { 341 policyMapping = inhibit; 342 } 343 } 344 } catch (IOException e) { 345 if (debug != null) { 346 debug.println("PolicyChecker.mergePolicyMapping " 347 + "unexpected exception"); 348 e.printStackTrace(); 349 } 350 throw new CertPathValidatorException(e); 351 } 352 353 return policyMapping; 354 } 355 356 /** 357 * Merges the specified inhibitAnyPolicy value with the 358 * SkipCerts value of the InhibitAnyPolicy 359 * extension obtained from the certificate. 360 * 361 * @param inhibitAnyPolicy an integer which indicates whether 362 * "any-policy" is considered a match 363 * @param currCert the Certificate to be processed 364 * @return returns the new inhibitAnyPolicy value 365 * @exception CertPathValidatorException Exception thrown if an error 366 * occurs 367 */ mergeInhibitAnyPolicy(int inhibitAnyPolicy, X509CertImpl currCert)368 static int mergeInhibitAnyPolicy(int inhibitAnyPolicy, 369 X509CertImpl currCert) throws CertPathValidatorException 370 { 371 if ((inhibitAnyPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) { 372 inhibitAnyPolicy--; 373 } 374 375 try { 376 InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension) 377 currCert.getExtension(InhibitAnyPolicy_Id); 378 if (inhAnyPolExt == null) 379 return inhibitAnyPolicy; 380 381 int skipCerts = 382 inhAnyPolExt.get(InhibitAnyPolicyExtension.SKIP_CERTS).intValue(); 383 if (debug != null) 384 debug.println("PolicyChecker.mergeInhibitAnyPolicy() " 385 + "skipCerts Index from cert = " + skipCerts); 386 387 if (skipCerts != -1) { 388 if (skipCerts < inhibitAnyPolicy) { 389 inhibitAnyPolicy = skipCerts; 390 } 391 } 392 } catch (IOException e) { 393 if (debug != null) { 394 debug.println("PolicyChecker.mergeInhibitAnyPolicy " 395 + "unexpected exception"); 396 e.printStackTrace(); 397 } 398 throw new CertPathValidatorException(e); 399 } 400 401 return inhibitAnyPolicy; 402 } 403 404 /** 405 * Processes certificate policies in the certificate. 406 * 407 * @param certIndex the index of the certificate 408 * @param initPolicies the initial policies required by the user 409 * @param explicitPolicy an integer which indicates if a non-null 410 * valid policy tree is required 411 * @param policyMapping an integer which indicates if policy 412 * mapping is inhibited 413 * @param inhibitAnyPolicy an integer which indicates whether 414 * "any-policy" is considered a match 415 * @param rejectPolicyQualifiers a boolean indicating whether the 416 * user wants to reject policies that have qualifiers 417 * @param origRootNode the root node of the valid policy tree 418 * @param currCert the Certificate to be processed 419 * @param finalCert a boolean indicating whether currCert is the final 420 * cert in the cert path 421 * @return the root node of the valid policy tree after modification 422 * @exception CertPathValidatorException Exception thrown if an 423 * error occurs while processing policies. 424 */ processPolicies(int certIndex, Set<String> initPolicies, int explicitPolicy, int policyMapping, int inhibitAnyPolicy, boolean rejectPolicyQualifiers, PolicyNodeImpl origRootNode, X509CertImpl currCert, boolean finalCert)425 static PolicyNodeImpl processPolicies(int certIndex, Set<String> initPolicies, 426 int explicitPolicy, int policyMapping, int inhibitAnyPolicy, 427 boolean rejectPolicyQualifiers, PolicyNodeImpl origRootNode, 428 X509CertImpl currCert, boolean finalCert) 429 throws CertPathValidatorException 430 { 431 boolean policiesCritical = false; 432 List<PolicyInformation> policyInfo; 433 PolicyNodeImpl rootNode = null; 434 Set<PolicyQualifierInfo> anyQuals = new HashSet<>(); 435 436 if (origRootNode == null) 437 rootNode = null; 438 else 439 rootNode = origRootNode.copyTree(); 440 441 // retrieve policyOIDs from currCert 442 CertificatePoliciesExtension currCertPolicies 443 = currCert.getCertificatePoliciesExtension(); 444 445 // PKIX: Section 6.1.3: Step (d) 446 if ((currCertPolicies != null) && (rootNode != null)) { 447 policiesCritical = currCertPolicies.isCritical(); 448 if (debug != null) 449 debug.println("PolicyChecker.processPolicies() " 450 + "policiesCritical = " + policiesCritical); 451 452 try { 453 policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES); 454 } catch (IOException ioe) { 455 throw new CertPathValidatorException("Exception while " 456 + "retrieving policyOIDs", ioe); 457 } 458 459 if (debug != null) 460 debug.println("PolicyChecker.processPolicies() " 461 + "rejectPolicyQualifiers = " + rejectPolicyQualifiers); 462 463 boolean foundAnyPolicy = false; 464 465 // process each policy in cert 466 for (PolicyInformation curPolInfo : policyInfo) { 467 String curPolicy = 468 curPolInfo.getPolicyIdentifier().getIdentifier().toString(); 469 470 if (curPolicy.equals(ANY_POLICY)) { 471 foundAnyPolicy = true; 472 anyQuals = curPolInfo.getPolicyQualifiers(); 473 } else { 474 // PKIX: Section 6.1.3: Step (d)(1) 475 if (debug != null) 476 debug.println("PolicyChecker.processPolicies() " 477 + "processing policy: " + curPolicy); 478 479 // retrieve policy qualifiers from cert 480 Set<PolicyQualifierInfo> pQuals = 481 curPolInfo.getPolicyQualifiers(); 482 483 // reject cert if we find critical policy qualifiers and 484 // the policyQualifiersRejected flag is set in the params 485 if (!pQuals.isEmpty() && rejectPolicyQualifiers && 486 policiesCritical) { 487 throw new CertPathValidatorException( 488 "critical policy qualifiers present in certificate", 489 null, null, -1, PKIXReason.INVALID_POLICY); 490 } 491 492 // PKIX: Section 6.1.3: Step (d)(1)(i) 493 boolean foundMatch = processParents(certIndex, 494 policiesCritical, rejectPolicyQualifiers, rootNode, 495 curPolicy, pQuals, false); 496 497 if (!foundMatch) { 498 // PKIX: Section 6.1.3: Step (d)(1)(ii) 499 processParents(certIndex, policiesCritical, 500 rejectPolicyQualifiers, rootNode, curPolicy, 501 pQuals, true); 502 } 503 } 504 } 505 506 // PKIX: Section 6.1.3: Step (d)(2) 507 if (foundAnyPolicy) { 508 if ((inhibitAnyPolicy > 0) || 509 (!finalCert && X509CertImpl.isSelfIssued(currCert))) { 510 if (debug != null) { 511 debug.println("PolicyChecker.processPolicies() " 512 + "processing policy: " + ANY_POLICY); 513 } 514 processParents(certIndex, policiesCritical, 515 rejectPolicyQualifiers, rootNode, ANY_POLICY, anyQuals, 516 true); 517 } 518 } 519 520 // PKIX: Section 6.1.3: Step (d)(3) 521 rootNode.prune(certIndex); 522 if (!rootNode.getChildren().hasNext()) { 523 rootNode = null; 524 } 525 } else if (currCertPolicies == null) { 526 if (debug != null) 527 debug.println("PolicyChecker.processPolicies() " 528 + "no policies present in cert"); 529 // PKIX: Section 6.1.3: Step (e) 530 rootNode = null; 531 } 532 533 // We delay PKIX: Section 6.1.3: Step (f) to the end 534 // because the code that follows may delete some nodes 535 // resulting in a null tree 536 if (rootNode != null) { 537 if (!finalCert) { 538 // PKIX: Section 6.1.4: Steps (a)-(b) 539 rootNode = processPolicyMappings(currCert, certIndex, 540 policyMapping, rootNode, policiesCritical, anyQuals); 541 } 542 } 543 544 // At this point, we optimize the PKIX algorithm by 545 // removing those nodes which would later have 546 // been removed by PKIX: Section 6.1.5: Step (g)(iii) 547 548 if ((rootNode != null) && (!initPolicies.contains(ANY_POLICY)) 549 && (currCertPolicies != null)) { 550 rootNode = removeInvalidNodes(rootNode, certIndex, 551 initPolicies, currCertPolicies); 552 553 // PKIX: Section 6.1.5: Step (g)(iii) 554 if ((rootNode != null) && finalCert) { 555 // rewrite anyPolicy leaf nodes (see method comments) 556 rootNode = rewriteLeafNodes(certIndex, initPolicies, rootNode); 557 } 558 } 559 560 561 if (finalCert) { 562 // PKIX: Section 6.1.5: Steps (a) and (b) 563 explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCert, 564 finalCert); 565 } 566 567 // PKIX: Section 6.1.3: Step (f) 568 // verify that either explicit policy is greater than 0 or 569 // the valid_policy_tree is not equal to NULL 570 571 if ((explicitPolicy == 0) && (rootNode == null)) { 572 throw new CertPathValidatorException 573 ("non-null policy tree required and policy tree is null", 574 null, null, -1, PKIXReason.INVALID_POLICY); 575 } 576 577 return rootNode; 578 } 579 580 /** 581 * Rewrite leaf nodes at the end of validation as described in RFC 3280 582 * section 6.1.5: Step (g)(iii). Leaf nodes with anyPolicy are replaced 583 * by nodes explicitly representing initial policies not already 584 * represented by leaf nodes. 585 * 586 * This method should only be called when processing the final cert 587 * and if the policy tree is not null and initial policies is not 588 * anyPolicy. 589 * 590 * @param certIndex the depth of the tree 591 * @param initPolicies Set of user specified initial policies 592 * @param rootNode the root of the policy tree 593 */ rewriteLeafNodes(int certIndex, Set<String> initPolicies, PolicyNodeImpl rootNode)594 private static PolicyNodeImpl rewriteLeafNodes(int certIndex, 595 Set<String> initPolicies, PolicyNodeImpl rootNode) { 596 Set<PolicyNodeImpl> anyNodes = 597 rootNode.getPolicyNodesValid(certIndex, ANY_POLICY); 598 if (anyNodes.isEmpty()) { 599 return rootNode; 600 } 601 PolicyNodeImpl anyNode = anyNodes.iterator().next(); 602 PolicyNodeImpl parentNode = (PolicyNodeImpl)anyNode.getParent(); 603 parentNode.deleteChild(anyNode); 604 // see if there are any initialPolicies not represented by leaf nodes 605 Set<String> initial = new HashSet<>(initPolicies); 606 for (PolicyNodeImpl node : rootNode.getPolicyNodes(certIndex)) { 607 initial.remove(node.getValidPolicy()); 608 } 609 if (initial.isEmpty()) { 610 // we deleted the anyPolicy node and have nothing to re-add, 611 // so we need to prune the tree 612 rootNode.prune(certIndex); 613 if (rootNode.getChildren().hasNext() == false) { 614 rootNode = null; 615 } 616 } else { 617 boolean anyCritical = anyNode.isCritical(); 618 Set<PolicyQualifierInfo> anyQualifiers = 619 anyNode.getPolicyQualifiers(); 620 for (String policy : initial) { 621 Set<String> expectedPolicies = Collections.singleton(policy); 622 PolicyNodeImpl node = new PolicyNodeImpl(parentNode, policy, 623 anyQualifiers, anyCritical, expectedPolicies, false); 624 } 625 } 626 return rootNode; 627 } 628 629 /** 630 * Finds the policy nodes of depth (certIndex-1) where curPolicy 631 * is in the expected policy set and creates a new child node 632 * appropriately. If matchAny is true, then a value of ANY_POLICY 633 * in the expected policy set will match any curPolicy. If matchAny 634 * is false, then the expected policy set must exactly contain the 635 * curPolicy to be considered a match. This method returns a boolean 636 * value indicating whether a match was found. 637 * 638 * @param certIndex the index of the certificate whose policy is 639 * being processed 640 * @param policiesCritical a boolean indicating whether the certificate 641 * policies extension is critical 642 * @param rejectPolicyQualifiers a boolean indicating whether the 643 * user wants to reject policies that have qualifiers 644 * @param rootNode the root node of the valid policy tree 645 * @param curPolicy a String representing the policy being processed 646 * @param pQuals the policy qualifiers of the policy being processed or an 647 * empty Set if there are no qualifiers 648 * @param matchAny a boolean indicating whether a value of ANY_POLICY 649 * in the expected policy set will be considered a match 650 * @return a boolean indicating whether a match was found 651 * @exception CertPathValidatorException Exception thrown if error occurs. 652 */ processParents(int certIndex, boolean policiesCritical, boolean rejectPolicyQualifiers, PolicyNodeImpl rootNode, String curPolicy, Set<PolicyQualifierInfo> pQuals, boolean matchAny)653 private static boolean processParents(int certIndex, 654 boolean policiesCritical, boolean rejectPolicyQualifiers, 655 PolicyNodeImpl rootNode, String curPolicy, 656 Set<PolicyQualifierInfo> pQuals, 657 boolean matchAny) throws CertPathValidatorException 658 { 659 boolean foundMatch = false; 660 661 if (debug != null) 662 debug.println("PolicyChecker.processParents(): matchAny = " 663 + matchAny); 664 665 // find matching parents 666 Set<PolicyNodeImpl> parentNodes = 667 rootNode.getPolicyNodesExpected(certIndex - 1, 668 curPolicy, matchAny); 669 670 // for each matching parent, extend policy tree 671 for (PolicyNodeImpl curParent : parentNodes) { 672 if (debug != null) 673 debug.println("PolicyChecker.processParents() " 674 + "found parent:\n" + curParent.asString()); 675 676 foundMatch = true; 677 String curParPolicy = curParent.getValidPolicy(); 678 679 PolicyNodeImpl curNode = null; 680 Set<String> curExpPols = null; 681 682 if (curPolicy.equals(ANY_POLICY)) { 683 // do step 2 684 Set<String> parExpPols = curParent.getExpectedPolicies(); 685 parentExplicitPolicies: 686 for (String curParExpPol : parExpPols) { 687 688 Iterator<PolicyNodeImpl> childIter = 689 curParent.getChildren(); 690 while (childIter.hasNext()) { 691 PolicyNodeImpl childNode = childIter.next(); 692 String childPolicy = childNode.getValidPolicy(); 693 if (curParExpPol.equals(childPolicy)) { 694 if (debug != null) 695 debug.println(childPolicy + " in parent's " 696 + "expected policy set already appears in " 697 + "child node"); 698 continue parentExplicitPolicies; 699 } 700 } 701 702 Set<String> expPols = new HashSet<>(); 703 expPols.add(curParExpPol); 704 705 curNode = new PolicyNodeImpl 706 (curParent, curParExpPol, pQuals, 707 policiesCritical, expPols, false); 708 } 709 } else { 710 curExpPols = new HashSet<String>(); 711 curExpPols.add(curPolicy); 712 713 curNode = new PolicyNodeImpl 714 (curParent, curPolicy, pQuals, 715 policiesCritical, curExpPols, false); 716 } 717 } 718 719 return foundMatch; 720 } 721 722 /** 723 * Processes policy mappings in the certificate. 724 * 725 * @param currCert the Certificate to be processed 726 * @param certIndex the index of the current certificate 727 * @param policyMapping an integer which indicates if policy 728 * mapping is inhibited 729 * @param rootNode the root node of the valid policy tree 730 * @param policiesCritical a boolean indicating if the certificate policies 731 * extension is critical 732 * @param anyQuals the qualifiers associated with ANY-POLICY, or an empty 733 * Set if there are no qualifiers associated with ANY-POLICY 734 * @return the root node of the valid policy tree after modification 735 * @exception CertPathValidatorException exception thrown if an error 736 * occurs while processing policy mappings 737 */ processPolicyMappings(X509CertImpl currCert, int certIndex, int policyMapping, PolicyNodeImpl rootNode, boolean policiesCritical, Set<PolicyQualifierInfo> anyQuals)738 private static PolicyNodeImpl processPolicyMappings(X509CertImpl currCert, 739 int certIndex, int policyMapping, PolicyNodeImpl rootNode, 740 boolean policiesCritical, Set<PolicyQualifierInfo> anyQuals) 741 throws CertPathValidatorException 742 { 743 PolicyMappingsExtension polMappingsExt 744 = currCert.getPolicyMappingsExtension(); 745 746 if (polMappingsExt == null) 747 return rootNode; 748 749 if (debug != null) 750 debug.println("PolicyChecker.processPolicyMappings() " 751 + "inside policyMapping check"); 752 753 List<CertificatePolicyMap> maps = null; 754 try { 755 maps = polMappingsExt.get(PolicyMappingsExtension.MAP); 756 } catch (IOException e) { 757 if (debug != null) { 758 debug.println("PolicyChecker.processPolicyMappings() " 759 + "mapping exception"); 760 e.printStackTrace(); 761 } 762 throw new CertPathValidatorException("Exception while checking " 763 + "mapping", e); 764 } 765 766 boolean childDeleted = false; 767 for (CertificatePolicyMap polMap : maps) { 768 String issuerDomain 769 = polMap.getIssuerIdentifier().getIdentifier().toString(); 770 String subjectDomain 771 = polMap.getSubjectIdentifier().getIdentifier().toString(); 772 if (debug != null) { 773 debug.println("PolicyChecker.processPolicyMappings() " 774 + "issuerDomain = " + issuerDomain); 775 debug.println("PolicyChecker.processPolicyMappings() " 776 + "subjectDomain = " + subjectDomain); 777 } 778 779 if (issuerDomain.equals(ANY_POLICY)) { 780 throw new CertPathValidatorException 781 ("encountered an issuerDomainPolicy of ANY_POLICY", 782 null, null, -1, PKIXReason.INVALID_POLICY); 783 } 784 785 if (subjectDomain.equals(ANY_POLICY)) { 786 throw new CertPathValidatorException 787 ("encountered a subjectDomainPolicy of ANY_POLICY", 788 null, null, -1, PKIXReason.INVALID_POLICY); 789 } 790 791 Set<PolicyNodeImpl> validNodes = 792 rootNode.getPolicyNodesValid(certIndex, issuerDomain); 793 if (!validNodes.isEmpty()) { 794 for (PolicyNodeImpl curNode : validNodes) { 795 if ((policyMapping > 0) || (policyMapping == -1)) { 796 curNode.addExpectedPolicy(subjectDomain); 797 } else if (policyMapping == 0) { 798 PolicyNodeImpl parentNode = 799 (PolicyNodeImpl) curNode.getParent(); 800 if (debug != null) 801 debug.println("PolicyChecker.processPolicyMappings" 802 + "() before deleting: policy tree = " 803 + rootNode); 804 parentNode.deleteChild(curNode); 805 childDeleted = true; 806 if (debug != null) 807 debug.println("PolicyChecker.processPolicyMappings" 808 + "() after deleting: policy tree = " 809 + rootNode); 810 } 811 } 812 } else { // no node of depth i has a valid policy 813 if ((policyMapping > 0) || (policyMapping == -1)) { 814 Set<PolicyNodeImpl> validAnyNodes = 815 rootNode.getPolicyNodesValid(certIndex, ANY_POLICY); 816 for (PolicyNodeImpl curAnyNode : validAnyNodes) { 817 PolicyNodeImpl curAnyNodeParent = 818 (PolicyNodeImpl) curAnyNode.getParent(); 819 820 Set<String> expPols = new HashSet<>(); 821 expPols.add(subjectDomain); 822 823 PolicyNodeImpl curNode = new PolicyNodeImpl 824 (curAnyNodeParent, issuerDomain, anyQuals, 825 policiesCritical, expPols, true); 826 } 827 } 828 } 829 } 830 831 if (childDeleted) { 832 rootNode.prune(certIndex); 833 if (!rootNode.getChildren().hasNext()) { 834 if (debug != null) 835 debug.println("setting rootNode to null"); 836 rootNode = null; 837 } 838 } 839 840 return rootNode; 841 } 842 843 /** 844 * Removes those nodes which do not intersect with the initial policies 845 * specified by the user. 846 * 847 * @param rootNode the root node of the valid policy tree 848 * @param certIndex the index of the certificate being processed 849 * @param initPolicies the Set of policies required by the user 850 * @param currCertPolicies the CertificatePoliciesExtension of the 851 * certificate being processed 852 * @returns the root node of the valid policy tree after modification 853 * @exception CertPathValidatorException Exception thrown if error occurs. 854 */ removeInvalidNodes(PolicyNodeImpl rootNode, int certIndex, Set<String> initPolicies, CertificatePoliciesExtension currCertPolicies)855 private static PolicyNodeImpl removeInvalidNodes(PolicyNodeImpl rootNode, 856 int certIndex, Set<String> initPolicies, 857 CertificatePoliciesExtension currCertPolicies) 858 throws CertPathValidatorException 859 { 860 List<PolicyInformation> policyInfo = null; 861 try { 862 policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES); 863 } catch (IOException ioe) { 864 throw new CertPathValidatorException("Exception while " 865 + "retrieving policyOIDs", ioe); 866 } 867 868 boolean childDeleted = false; 869 for (PolicyInformation curPolInfo : policyInfo) { 870 String curPolicy = 871 curPolInfo.getPolicyIdentifier().getIdentifier().toString(); 872 873 if (debug != null) 874 debug.println("PolicyChecker.processPolicies() " 875 + "processing policy second time: " + curPolicy); 876 877 Set<PolicyNodeImpl> validNodes = 878 rootNode.getPolicyNodesValid(certIndex, curPolicy); 879 for (PolicyNodeImpl curNode : validNodes) { 880 PolicyNodeImpl parentNode = (PolicyNodeImpl)curNode.getParent(); 881 if (parentNode.getValidPolicy().equals(ANY_POLICY)) { 882 if ((!initPolicies.contains(curPolicy)) && 883 (!curPolicy.equals(ANY_POLICY))) { 884 if (debug != null) 885 debug.println("PolicyChecker.processPolicies() " 886 + "before deleting: policy tree = " + rootNode); 887 parentNode.deleteChild(curNode); 888 childDeleted = true; 889 if (debug != null) 890 debug.println("PolicyChecker.processPolicies() " 891 + "after deleting: policy tree = " + rootNode); 892 } 893 } 894 } 895 } 896 897 if (childDeleted) { 898 rootNode.prune(certIndex); 899 if (!rootNode.getChildren().hasNext()) { 900 rootNode = null; 901 } 902 } 903 904 return rootNode; 905 } 906 907 /** 908 * Gets the root node of the valid policy tree, or null if the 909 * valid policy tree is null. Marks each node of the returned tree 910 * immutable and thread-safe. 911 * 912 * @returns the root node of the valid policy tree, or null if 913 * the valid policy tree is null 914 */ getPolicyTree()915 PolicyNode getPolicyTree() { 916 if (rootNode == null) 917 return null; 918 else { 919 PolicyNodeImpl policyTree = rootNode.copyTree(); 920 policyTree.setImmutable(); 921 return policyTree; 922 } 923 } 924 } 925