--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/provider/certpath/PolicyChecker.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,921 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.provider.certpath;
+
+import java.util.*;
+import java.io.IOException;
+
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PolicyNode;
+import java.security.cert.PolicyQualifierInfo;
+
+import sun.security.util.Debug;
+import sun.security.x509.CertificatePoliciesExtension;
+import sun.security.x509.PolicyConstraintsExtension;
+import sun.security.x509.PolicyMappingsExtension;
+import sun.security.x509.CertificatePolicyMap;
+import sun.security.x509.PKIXExtensions;
+import sun.security.x509.PolicyInformation;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.InhibitAnyPolicyExtension;
+
+/**
+ * PolicyChecker is a <code>PKIXCertPathChecker</code> that checks policy
+ * information on a PKIX certificate, namely certificate policies, policy
+ * mappings, policy constraints and policy qualifiers.
+ *
+ * @since 1.4
+ * @author Yassir Elley
+ */
+class PolicyChecker extends PKIXCertPathChecker {
+
+ private final Set<String> initPolicies;
+ private final int certPathLen;
+ private final boolean expPolicyRequired;
+ private final boolean polMappingInhibited;
+ private final boolean anyPolicyInhibited;
+ private final boolean rejectPolicyQualifiers;
+ private PolicyNodeImpl rootNode;
+ private int explicitPolicy;
+ private int policyMapping;
+ private int inhibitAnyPolicy;
+ private int certIndex;
+
+ private static Set<String> supportedExts;
+
+ private static final Debug debug = Debug.getInstance("certpath");
+ static final String ANY_POLICY = "2.5.29.32.0";
+
+ /**
+ * Constructs a Policy Checker.
+ *
+ * @param initialPolicies Set of initial policies
+ * @param certPathLen length of the certification path to be checked
+ * @param expPolicyRequired true if explicit policy is required
+ * @param polMappingInhibited true if policy mapping is inhibited
+ * @param anyPolicyInhibited true if the ANY_POLICY OID should be inhibited
+ * @param rejectPolicyQualifiers true if pol qualifiers are to be rejected
+ * @param rootNode the initial root node of the valid policy tree
+ */
+ PolicyChecker(Set<String> initialPolicies, int certPathLen,
+ boolean expPolicyRequired, boolean polMappingInhibited,
+ boolean anyPolicyInhibited, boolean rejectPolicyQualifiers,
+ PolicyNodeImpl rootNode) throws CertPathValidatorException
+ {
+ if (initialPolicies.isEmpty()) {
+ // if no initialPolicies are specified by user, set
+ // initPolicies to be anyPolicy by default
+ this.initPolicies = new HashSet<String>(1);
+ this.initPolicies.add(ANY_POLICY);
+ } else {
+ this.initPolicies = new HashSet<String>(initialPolicies);
+ }
+ this.certPathLen = certPathLen;
+ this.expPolicyRequired = expPolicyRequired;
+ this.polMappingInhibited = polMappingInhibited;
+ this.anyPolicyInhibited = anyPolicyInhibited;
+ this.rejectPolicyQualifiers = rejectPolicyQualifiers;
+ this.rootNode = rootNode;
+ init(false);
+ }
+
+ /**
+ * Initializes the internal state of the checker from parameters
+ * specified in the constructor
+ *
+ * @param forward a boolean indicating whether this checker should
+ * be initialized capable of building in the forward direction
+ * @exception CertPathValidatorException Exception thrown if user
+ * wants to enable forward checking and forward checking is not supported.
+ */
+ public void init(boolean forward) throws CertPathValidatorException {
+ if (forward) {
+ throw new CertPathValidatorException
+ ("forward checking not supported");
+ }
+
+ certIndex = 1;
+ explicitPolicy = (expPolicyRequired ? 0 : certPathLen + 1);
+ policyMapping = (polMappingInhibited ? 0 : certPathLen + 1);
+ inhibitAnyPolicy = (anyPolicyInhibited ? 0 : certPathLen + 1);
+ }
+
+ /**
+ * Checks if forward checking is supported. Forward checking refers
+ * to the ability of the PKIXCertPathChecker to perform its checks
+ * when presented with certificates in the forward direction (from
+ * target to anchor).
+ *
+ * @return true if forward checking is supported, false otherwise
+ */
+ public boolean isForwardCheckingSupported() {
+ return false;
+ }
+
+ /**
+ * Gets an immutable Set of the OID strings for the extensions that
+ * the PKIXCertPathChecker supports (i.e. recognizes, is able to
+ * process), or null if no extensions are
+ * supported. All OID strings that a PKIXCertPathChecker might
+ * possibly be able to process should be included.
+ *
+ * @return the Set of extensions supported by this PKIXCertPathChecker,
+ * or null if no extensions are supported
+ */
+ public Set<String> getSupportedExtensions() {
+ if (supportedExts == null) {
+ supportedExts = new HashSet<String>();
+ supportedExts.add(PKIXExtensions.CertificatePolicies_Id.toString());
+ supportedExts.add(PKIXExtensions.PolicyMappings_Id.toString());
+ supportedExts.add(PKIXExtensions.PolicyConstraints_Id.toString());
+ supportedExts.add(PKIXExtensions.InhibitAnyPolicy_Id.toString());
+ supportedExts = Collections.unmodifiableSet(supportedExts);
+ }
+ return supportedExts;
+ }
+
+ /**
+ * Performs the policy processing checks on the certificate using its
+ * internal state.
+ *
+ * @param cert the Certificate to be processed
+ * @param unresCritExts the unresolved critical extensions
+ * @exception CertPathValidatorException Exception thrown if
+ * the certificate does not verify.
+ */
+ public void check(Certificate cert, Collection<String> unresCritExts)
+ throws CertPathValidatorException
+ {
+ // now do the policy checks
+ checkPolicy((X509Certificate) cert);
+
+ if (unresCritExts != null && !unresCritExts.isEmpty()) {
+ unresCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString());
+ unresCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString());
+ unresCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString());
+ unresCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString());
+ }
+ }
+
+ /**
+ * Internal method to run through all the checks.
+ *
+ * @param currCert the certificate to be processed
+ * @exception CertPathValidatorException Exception thrown if
+ * the certificate does not verify
+ */
+ private void checkPolicy(X509Certificate currCert)
+ throws CertPathValidatorException
+ {
+ String msg = "certificate policies";
+ if (debug != null) {
+ debug.println("PolicyChecker.checkPolicy() ---checking " + msg
+ + "...");
+ debug.println("PolicyChecker.checkPolicy() certIndex = "
+ + certIndex);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "explicitPolicy = " + explicitPolicy);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "policyMapping = " + policyMapping);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "inhibitAnyPolicy = " + inhibitAnyPolicy);
+ debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
+ + "policyTree = " + rootNode);
+ }
+
+ X509CertImpl currCertImpl = null;
+ try {
+ currCertImpl = X509CertImpl.toImpl(currCert);
+ } catch (CertificateException ce) {
+ throw new CertPathValidatorException(ce);
+ }
+
+ boolean finalCert = (certIndex == certPathLen);
+
+ rootNode = processPolicies(certIndex, initPolicies, explicitPolicy,
+ policyMapping, inhibitAnyPolicy, rejectPolicyQualifiers, rootNode,
+ currCertImpl, finalCert);
+
+ if (!finalCert) {
+ explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCertImpl,
+ finalCert);
+ policyMapping = mergePolicyMapping(policyMapping, currCertImpl);
+ inhibitAnyPolicy = mergeInhibitAnyPolicy(inhibitAnyPolicy,
+ currCertImpl);
+ }
+
+ certIndex++;
+
+ if (debug != null) {
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "explicitPolicy = " + explicitPolicy);
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "policyMapping = " + policyMapping);
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "inhibitAnyPolicy = " + inhibitAnyPolicy);
+ debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
+ + "policyTree = " + rootNode);
+ debug.println("PolicyChecker.checkPolicy() " + msg + " verified");
+ }
+ }
+
+ /**
+ * Merges the specified explicitPolicy value with the
+ * requireExplicitPolicy field of the <code>PolicyConstraints</code>
+ * extension obtained from the certificate. An explicitPolicy
+ * value of -1 implies no constraint.
+ *
+ * @param explicitPolicy an integer which indicates if a non-null
+ * valid policy tree is required
+ * @param currCert the Certificate to be processed
+ * @param finalCert a boolean indicating whether currCert is
+ * the final cert in the cert path
+ * @return returns the new explicitPolicy value
+ * @exception CertPathValidatorException Exception thrown if an error
+ * occurs
+ */
+ static int mergeExplicitPolicy(int explicitPolicy, X509CertImpl currCert,
+ boolean finalCert) throws CertPathValidatorException
+ {
+ if ((explicitPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {
+ explicitPolicy--;
+ }
+
+ try {
+ PolicyConstraintsExtension polConstExt
+ = currCert.getPolicyConstraintsExtension();
+ if (polConstExt == null)
+ return explicitPolicy;
+ int require = ((Integer)
+ polConstExt.get(PolicyConstraintsExtension.REQUIRE)).intValue();
+ if (debug != null) {
+ debug.println("PolicyChecker.mergeExplicitPolicy() "
+ + "require Index from cert = " + require);
+ }
+ if (!finalCert) {
+ if (require != -1) {
+ if ((explicitPolicy == -1) || (require < explicitPolicy)) {
+ explicitPolicy = require;
+ }
+ }
+ } else {
+ if (require == 0)
+ explicitPolicy = require;
+ }
+ } catch (Exception e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.mergeExplicitPolicy "
+ + "unexpected exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException(e);
+ }
+
+ return explicitPolicy;
+ }
+
+ /**
+ * Merges the specified policyMapping value with the
+ * inhibitPolicyMapping field of the <code>PolicyConstraints</code>
+ * extension obtained from the certificate. A policyMapping
+ * value of -1 implies no constraint.
+ *
+ * @param policyMapping an integer which indicates if policy mapping
+ * is inhibited
+ * @param currCert the Certificate to be processed
+ * @return returns the new policyMapping value
+ * @exception CertPathValidatorException Exception thrown if an error
+ * occurs
+ */
+ static int mergePolicyMapping(int policyMapping, X509CertImpl currCert)
+ throws CertPathValidatorException
+ {
+ if ((policyMapping > 0) && !X509CertImpl.isSelfIssued(currCert)) {
+ policyMapping--;
+ }
+
+ try {
+ PolicyConstraintsExtension polConstExt
+ = currCert.getPolicyConstraintsExtension();
+ if (polConstExt == null)
+ return policyMapping;
+
+ int inhibit = ((Integer)
+ polConstExt.get(PolicyConstraintsExtension.INHIBIT)).intValue();
+ if (debug != null)
+ debug.println("PolicyChecker.mergePolicyMapping() "
+ + "inhibit Index from cert = " + inhibit);
+
+ if (inhibit != -1) {
+ if ((policyMapping == -1) || (inhibit < policyMapping)) {
+ policyMapping = inhibit;
+ }
+ }
+ } catch (Exception e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.mergePolicyMapping "
+ + "unexpected exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException(e);
+ }
+
+ return policyMapping;
+ }
+
+ /**
+ * Merges the specified inhibitAnyPolicy value with the
+ * SkipCerts value of the InhibitAnyPolicy
+ * extension obtained from the certificate.
+ *
+ * @param inhibitAnyPolicy an integer which indicates whether
+ * "any-policy" is considered a match
+ * @param currCert the Certificate to be processed
+ * @return returns the new inhibitAnyPolicy value
+ * @exception CertPathValidatorException Exception thrown if an error
+ * occurs
+ */
+ static int mergeInhibitAnyPolicy(int inhibitAnyPolicy,
+ X509CertImpl currCert) throws CertPathValidatorException
+ {
+ if ((inhibitAnyPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {
+ inhibitAnyPolicy--;
+ }
+
+ try {
+ InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension)
+ currCert.getExtension(PKIXExtensions.InhibitAnyPolicy_Id);
+ if (inhAnyPolExt == null)
+ return inhibitAnyPolicy;
+
+ int skipCerts = ((Integer)
+ inhAnyPolExt.get(InhibitAnyPolicyExtension.SKIP_CERTS)).intValue();
+ if (debug != null)
+ debug.println("PolicyChecker.mergeInhibitAnyPolicy() "
+ + "skipCerts Index from cert = " + skipCerts);
+
+ if (skipCerts != -1) {
+ if (skipCerts < inhibitAnyPolicy) {
+ inhibitAnyPolicy = skipCerts;
+ }
+ }
+ } catch (Exception e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.mergeInhibitAnyPolicy "
+ + "unexpected exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException(e);
+ }
+
+ return inhibitAnyPolicy;
+ }
+
+ /**
+ * Processes certificate policies in the certificate.
+ *
+ * @param certIndex the index of the certificate
+ * @param initPolicies the initial policies required by the user
+ * @param explicitPolicy an integer which indicates if a non-null
+ * valid policy tree is required
+ * @param policyMapping an integer which indicates if policy
+ * mapping is inhibited
+ * @param inhibitAnyPolicy an integer which indicates whether
+ * "any-policy" is considered a match
+ * @param rejectPolicyQualifiers a boolean indicating whether the
+ * user wants to reject policies that have qualifiers
+ * @param origRootNode the root node of the valid policy tree
+ * @param currCert the Certificate to be processed
+ * @param finalCert a boolean indicating whether currCert is the final
+ * cert in the cert path
+ * @return the root node of the valid policy tree after modification
+ * @exception CertPathValidatorException Exception thrown if an
+ * error occurs while processing policies.
+ */
+ static PolicyNodeImpl processPolicies(int certIndex, Set<String> initPolicies,
+ int explicitPolicy, int policyMapping, int inhibitAnyPolicy,
+ boolean rejectPolicyQualifiers, PolicyNodeImpl origRootNode,
+ X509CertImpl currCert, boolean finalCert)
+ throws CertPathValidatorException
+ {
+ boolean policiesCritical = false;
+ List<PolicyInformation> policyInfo;
+ PolicyNodeImpl rootNode = null;
+ Set<PolicyQualifierInfo> anyQuals = new HashSet<PolicyQualifierInfo>();
+
+ if (origRootNode == null)
+ rootNode = null;
+ else
+ rootNode = origRootNode.copyTree();
+
+ // retrieve policyOIDs from currCert
+ CertificatePoliciesExtension currCertPolicies
+ = currCert.getCertificatePoliciesExtension();
+
+ // PKIX: Section 6.1.3: Step (d)
+ if ((currCertPolicies != null) && (rootNode != null)) {
+ policiesCritical = currCertPolicies.isCritical();
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "policiesCritical = " + policiesCritical);
+
+ try {
+ policyInfo = (List<PolicyInformation>)
+ currCertPolicies.get(CertificatePoliciesExtension.POLICIES);
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException("Exception while "
+ + "retrieving policyOIDs", ioe);
+ }
+
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "rejectPolicyQualifiers = " + rejectPolicyQualifiers);
+
+ boolean foundAnyPolicy = false;
+
+ // process each policy in cert
+ for (PolicyInformation curPolInfo : policyInfo) {
+ String curPolicy =
+ curPolInfo.getPolicyIdentifier().getIdentifier().toString();
+
+ if (curPolicy.equals(ANY_POLICY)) {
+ foundAnyPolicy = true;
+ anyQuals = curPolInfo.getPolicyQualifiers();
+ } else {
+ // PKIX: Section 6.1.3: Step (d)(1)
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "processing policy: " + curPolicy);
+
+ // retrieve policy qualifiers from cert
+ Set<PolicyQualifierInfo> pQuals =
+ curPolInfo.getPolicyQualifiers();
+
+ // reject cert if we find critical policy qualifiers and
+ // the policyQualifiersRejected flag is set in the params
+ if (!pQuals.isEmpty() && rejectPolicyQualifiers &&
+ policiesCritical) {
+ throw new CertPathValidatorException("critical " +
+ "policy qualifiers present in certificate");
+ }
+
+ // PKIX: Section 6.1.3: Step (d)(1)(i)
+ boolean foundMatch = processParents(certIndex,
+ policiesCritical, rejectPolicyQualifiers, rootNode,
+ curPolicy, pQuals, false);
+
+ if (!foundMatch) {
+ // PKIX: Section 6.1.3: Step (d)(1)(ii)
+ processParents(certIndex, policiesCritical,
+ rejectPolicyQualifiers, rootNode, curPolicy,
+ pQuals, true);
+ }
+ }
+ }
+
+ // PKIX: Section 6.1.3: Step (d)(2)
+ if (foundAnyPolicy) {
+ if ((inhibitAnyPolicy > 0) ||
+ (!finalCert && X509CertImpl.isSelfIssued(currCert))) {
+ if (debug != null) {
+ debug.println("PolicyChecker.processPolicies() "
+ + "processing policy: " + ANY_POLICY);
+ }
+ processParents(certIndex, policiesCritical,
+ rejectPolicyQualifiers, rootNode, ANY_POLICY, anyQuals,
+ true);
+ }
+ }
+
+ // PKIX: Section 6.1.3: Step (d)(3)
+ rootNode.prune(certIndex);
+ if (!rootNode.getChildren().hasNext()) {
+ rootNode = null;
+ }
+ } else if (currCertPolicies == null) {
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "no policies present in cert");
+ // PKIX: Section 6.1.3: Step (e)
+ rootNode = null;
+ }
+
+ // We delay PKIX: Section 6.1.3: Step (f) to the end
+ // because the code that follows may delete some nodes
+ // resulting in a null tree
+ if (rootNode != null) {
+ if (!finalCert) {
+ // PKIX: Section 6.1.4: Steps (a)-(b)
+ rootNode = processPolicyMappings(currCert, certIndex,
+ policyMapping, rootNode, policiesCritical, anyQuals);
+ }
+ }
+
+ // At this point, we optimize the PKIX algorithm by
+ // removing those nodes which would later have
+ // been removed by PKIX: Section 6.1.5: Step (g)(iii)
+
+ if ((rootNode != null) && (!initPolicies.contains(ANY_POLICY))
+ && (currCertPolicies != null)) {
+ rootNode = removeInvalidNodes(rootNode, certIndex,
+ initPolicies, currCertPolicies);
+
+ // PKIX: Section 6.1.5: Step (g)(iii)
+ if ((rootNode != null) && finalCert) {
+ // rewrite anyPolicy leaf nodes (see method comments)
+ rootNode = rewriteLeafNodes(certIndex, initPolicies, rootNode);
+ }
+ }
+
+
+ if (finalCert) {
+ // PKIX: Section 6.1.5: Steps (a) and (b)
+ explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCert,
+ finalCert);
+ }
+
+ // PKIX: Section 6.1.3: Step (f)
+ // verify that either explicit policy is greater than 0 or
+ // the valid_policy_tree is not equal to NULL
+
+ if ((explicitPolicy == 0) && (rootNode == null)) {
+ throw new CertPathValidatorException
+ ("non-null policy tree required and policy tree is null");
+ }
+
+ return rootNode;
+ }
+
+ /**
+ * Rewrite leaf nodes at the end of validation as described in RFC 3280
+ * section 6.1.5: Step (g)(iii). Leaf nodes with anyPolicy are replaced
+ * by nodes explicitly representing initial policies not already
+ * represented by leaf nodes.
+ *
+ * This method should only be called when processing the final cert
+ * and if the policy tree is not null and initial policies is not
+ * anyPolicy.
+ *
+ * @param certIndex the depth of the tree
+ * @param initPolicies Set of user specified initial policies
+ * @param rootNode the root of the policy tree
+ */
+ private static PolicyNodeImpl rewriteLeafNodes(int certIndex,
+ Set<String> initPolicies, PolicyNodeImpl rootNode) {
+ Set<PolicyNodeImpl> anyNodes =
+ rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);
+ if (anyNodes.isEmpty()) {
+ return rootNode;
+ }
+ PolicyNodeImpl anyNode = anyNodes.iterator().next();
+ PolicyNodeImpl parentNode = (PolicyNodeImpl)anyNode.getParent();
+ parentNode.deleteChild(anyNode);
+ // see if there are any initialPolicies not represented by leaf nodes
+ Set<String> initial = new HashSet<String>(initPolicies);
+ for (PolicyNodeImpl node : rootNode.getPolicyNodes(certIndex)) {
+ initial.remove(node.getValidPolicy());
+ }
+ if (initial.isEmpty()) {
+ // we deleted the anyPolicy node and have nothing to re-add,
+ // so we need to prune the tree
+ rootNode.prune(certIndex);
+ if (rootNode.getChildren().hasNext() == false) {
+ rootNode = null;
+ }
+ } else {
+ boolean anyCritical = anyNode.isCritical();
+ Set<PolicyQualifierInfo> anyQualifiers =
+ anyNode.getPolicyQualifiers();
+ for (String policy : initial) {
+ Set<String> expectedPolicies = Collections.singleton(policy);
+ PolicyNodeImpl node = new PolicyNodeImpl(parentNode, policy,
+ anyQualifiers, anyCritical, expectedPolicies, false);
+ }
+ }
+ return rootNode;
+ }
+
+ /**
+ * Finds the policy nodes of depth (certIndex-1) where curPolicy
+ * is in the expected policy set and creates a new child node
+ * appropriately. If matchAny is true, then a value of ANY_POLICY
+ * in the expected policy set will match any curPolicy. If matchAny
+ * is false, then the expected policy set must exactly contain the
+ * curPolicy to be considered a match. This method returns a boolean
+ * value indicating whether a match was found.
+ *
+ * @param certIndex the index of the certificate whose policy is
+ * being processed
+ * @param policiesCritical a boolean indicating whether the certificate
+ * policies extension is critical
+ * @param rejectPolicyQualifiers a boolean indicating whether the
+ * user wants to reject policies that have qualifiers
+ * @param rootNode the root node of the valid policy tree
+ * @param curPolicy a String representing the policy being processed
+ * @param pQuals the policy qualifiers of the policy being processed or an
+ * empty Set if there are no qualifiers
+ * @param matchAny a boolean indicating whether a value of ANY_POLICY
+ * in the expected policy set will be considered a match
+ * @return a boolean indicating whether a match was found
+ * @exception CertPathValidatorException Exception thrown if error occurs.
+ */
+ private static boolean processParents(int certIndex,
+ boolean policiesCritical, boolean rejectPolicyQualifiers,
+ PolicyNodeImpl rootNode, String curPolicy,
+ Set<PolicyQualifierInfo> pQuals,
+ boolean matchAny) throws CertPathValidatorException
+ {
+ boolean foundMatch = false;
+
+ if (debug != null)
+ debug.println("PolicyChecker.processParents(): matchAny = "
+ + matchAny);
+
+ // find matching parents
+ Set<PolicyNodeImpl> parentNodes =
+ rootNode.getPolicyNodesExpected(certIndex - 1,
+ curPolicy, matchAny);
+
+ // for each matching parent, extend policy tree
+ for (PolicyNodeImpl curParent : parentNodes) {
+ if (debug != null)
+ debug.println("PolicyChecker.processParents() "
+ + "found parent:\n" + curParent.asString());
+
+ foundMatch = true;
+ String curParPolicy = curParent.getValidPolicy();
+
+ PolicyNodeImpl curNode = null;
+ Set<String> curExpPols = null;
+
+ if (curPolicy.equals(ANY_POLICY)) {
+ // do step 2
+ Set<String> parExpPols = curParent.getExpectedPolicies();
+ parentExplicitPolicies:
+ for (String curParExpPol : parExpPols) {
+
+ Iterator<PolicyNodeImpl> childIter =
+ curParent.getChildren();
+ while (childIter.hasNext()) {
+ PolicyNodeImpl childNode = childIter.next();
+ String childPolicy = childNode.getValidPolicy();
+ if (curParExpPol.equals(childPolicy)) {
+ if (debug != null)
+ debug.println(childPolicy + " in parent's "
+ + "expected policy set already appears in "
+ + "child node");
+ continue parentExplicitPolicies;
+ }
+ }
+
+ Set<String> expPols = new HashSet<String>();
+ expPols.add(curParExpPol);
+
+ curNode = new PolicyNodeImpl
+ (curParent, curParExpPol, pQuals,
+ policiesCritical, expPols, false);
+ }
+ } else {
+ curExpPols = new HashSet<String>();
+ curExpPols.add(curPolicy);
+
+ curNode = new PolicyNodeImpl
+ (curParent, curPolicy, pQuals,
+ policiesCritical, curExpPols, false);
+ }
+ }
+
+ return foundMatch;
+ }
+
+ /**
+ * Processes policy mappings in the certificate.
+ *
+ * @param currCert the Certificate to be processed
+ * @param certIndex the index of the current certificate
+ * @param policyMapping an integer which indicates if policy
+ * mapping is inhibited
+ * @param rootNode the root node of the valid policy tree
+ * @param policiesCritical a boolean indicating if the certificate policies
+ * extension is critical
+ * @param anyQuals the qualifiers associated with ANY-POLICY, or an empty
+ * Set if there are no qualifiers associated with ANY-POLICY
+ * @return the root node of the valid policy tree after modification
+ * @exception CertPathValidatorException exception thrown if an error
+ * occurs while processing policy mappings
+ */
+ private static PolicyNodeImpl processPolicyMappings(X509CertImpl currCert,
+ int certIndex, int policyMapping, PolicyNodeImpl rootNode,
+ boolean policiesCritical, Set<PolicyQualifierInfo> anyQuals)
+ throws CertPathValidatorException
+ {
+ PolicyMappingsExtension polMappingsExt
+ = currCert.getPolicyMappingsExtension();
+
+ if (polMappingsExt == null)
+ return rootNode;
+
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "inside policyMapping check");
+
+ List<CertificatePolicyMap> maps = null;
+ try {
+ maps = (List<CertificatePolicyMap>)polMappingsExt.get
+ (PolicyMappingsExtension.MAP);
+ } catch (IOException e) {
+ if (debug != null) {
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "mapping exception");
+ e.printStackTrace();
+ }
+ throw new CertPathValidatorException("Exception while checking "
+ + "mapping", e);
+ }
+
+ boolean childDeleted = false;
+ for (int j = 0; j < maps.size(); j++) {
+ CertificatePolicyMap polMap = maps.get(j);
+ String issuerDomain
+ = polMap.getIssuerIdentifier().getIdentifier().toString();
+ String subjectDomain
+ = polMap.getSubjectIdentifier().getIdentifier().toString();
+ if (debug != null) {
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "issuerDomain = " + issuerDomain);
+ debug.println("PolicyChecker.processPolicyMappings() "
+ + "subjectDomain = " + subjectDomain);
+ }
+
+ if (issuerDomain.equals(ANY_POLICY)) {
+ throw new CertPathValidatorException
+ ("encountered an issuerDomainPolicy of ANY_POLICY");
+ }
+
+ if (subjectDomain.equals(ANY_POLICY)) {
+ throw new CertPathValidatorException
+ ("encountered a subjectDomainPolicy of ANY_POLICY");
+ }
+
+ Set<PolicyNodeImpl> validNodes =
+ rootNode.getPolicyNodesValid(certIndex, issuerDomain);
+ if (!validNodes.isEmpty()) {
+ for (PolicyNodeImpl curNode : validNodes) {
+ if ((policyMapping > 0) || (policyMapping == -1)) {
+ curNode.addExpectedPolicy(subjectDomain);
+ } else if (policyMapping == 0) {
+ PolicyNodeImpl parentNode =
+ (PolicyNodeImpl) curNode.getParent();
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicyMappings"
+ + "() before deleting: policy tree = "
+ + rootNode);
+ parentNode.deleteChild(curNode);
+ childDeleted = true;
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicyMappings"
+ + "() after deleting: policy tree = "
+ + rootNode);
+ }
+ }
+ } else { // no node of depth i has a valid policy
+ if ((policyMapping > 0) || (policyMapping == -1)) {
+ Set<PolicyNodeImpl> validAnyNodes =
+ rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);
+ for (PolicyNodeImpl curAnyNode : validAnyNodes) {
+ PolicyNodeImpl curAnyNodeParent =
+ (PolicyNodeImpl) curAnyNode.getParent();
+
+ Set<String> expPols = new HashSet<String>();
+ expPols.add(subjectDomain);
+
+ PolicyNodeImpl curNode = new PolicyNodeImpl
+ (curAnyNodeParent, issuerDomain, anyQuals,
+ policiesCritical, expPols, true);
+ }
+ }
+ }
+ }
+
+ if (childDeleted) {
+ rootNode.prune(certIndex);
+ if (!rootNode.getChildren().hasNext()) {
+ if (debug != null)
+ debug.println("setting rootNode to null");
+ rootNode = null;
+ }
+ }
+
+ return rootNode;
+ }
+
+ /**
+ * Removes those nodes which do not intersect with the initial policies
+ * specified by the user.
+ *
+ * @param rootNode the root node of the valid policy tree
+ * @param certIndex the index of the certificate being processed
+ * @param initPolicies the Set of policies required by the user
+ * @param currCertPolicies the CertificatePoliciesExtension of the
+ * certificate being processed
+ * @returns the root node of the valid policy tree after modification
+ * @exception CertPathValidatorException Exception thrown if error occurs.
+ */
+ private static PolicyNodeImpl removeInvalidNodes(PolicyNodeImpl rootNode,
+ int certIndex, Set<String> initPolicies,
+ CertificatePoliciesExtension currCertPolicies)
+ throws CertPathValidatorException
+ {
+ List<PolicyInformation> policyInfo = null;
+ try {
+ policyInfo = (List<PolicyInformation>)
+ currCertPolicies.get(CertificatePoliciesExtension.POLICIES);
+ } catch (IOException ioe) {
+ throw new CertPathValidatorException("Exception while "
+ + "retrieving policyOIDs", ioe);
+ }
+
+ boolean childDeleted = false;
+ for (PolicyInformation curPolInfo : policyInfo) {
+ String curPolicy =
+ curPolInfo.getPolicyIdentifier().getIdentifier().toString();
+
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "processing policy second time: " + curPolicy);
+
+ Set<PolicyNodeImpl> validNodes =
+ rootNode.getPolicyNodesValid(certIndex, curPolicy);
+ for (PolicyNodeImpl curNode : validNodes) {
+ PolicyNodeImpl parentNode = (PolicyNodeImpl)curNode.getParent();
+ if (parentNode.getValidPolicy().equals(ANY_POLICY)) {
+ if ((!initPolicies.contains(curPolicy)) &&
+ (!curPolicy.equals(ANY_POLICY))) {
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "before deleting: policy tree = " + rootNode);
+ parentNode.deleteChild(curNode);
+ childDeleted = true;
+ if (debug != null)
+ debug.println("PolicyChecker.processPolicies() "
+ + "after deleting: policy tree = " + rootNode);
+ }
+ }
+ }
+ }
+
+ if (childDeleted) {
+ rootNode.prune(certIndex);
+ if (!rootNode.getChildren().hasNext()) {
+ rootNode = null;
+ }
+ }
+
+ return rootNode;
+ }
+
+ /**
+ * Gets the root node of the valid policy tree, or null if the
+ * valid policy tree is null. Marks each node of the returned tree
+ * immutable and thread-safe.
+ *
+ * @returns the root node of the valid policy tree, or null if
+ * the valid policy tree is null
+ */
+ PolicyNode getPolicyTree() {
+ if (rootNode == null)
+ return null;
+ else {
+ PolicyNodeImpl policyTree = rootNode.copyTree();
+ policyTree.setImmutable();
+ return policyTree;
+ }
+ }
+}