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