| /* |
| * Copyright (c) 2000, 2012, Oracle and/or its affiliates. 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. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.security.provider.certpath; |
| |
| import java.io.IOException; |
| import java.security.GeneralSecurityException; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateException; |
| import java.security.cert.CertPathValidatorException; |
| import java.security.cert.PKIXCertPathChecker; |
| import java.security.cert.PKIXReason; |
| import java.security.cert.PolicyNode; |
| import java.security.cert.PolicyQualifierInfo; |
| import java.security.cert.X509Certificate; |
| import java.util.*; |
| |
| 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 static 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 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) |
| { |
| 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; |
| } |
| |
| /** |
| * 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 |
| * @throws CertPathValidatorException if user wants to enable forward |
| * checking and forward checking is not supported. |
| */ |
| @Override |
| 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 |
| */ |
| @Override |
| 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 |
| */ |
| @Override |
| public Set<String> getSupportedExtensions() { |
| if (supportedExts == null) { |
| supportedExts = new HashSet<String>(4); |
| supportedExts.add(CertificatePolicies_Id.toString()); |
| supportedExts.add(PolicyMappings_Id.toString()); |
| supportedExts.add(PolicyConstraints_Id.toString()); |
| supportedExts.add(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 |
| * @throws CertPathValidatorException if the certificate does not verify |
| */ |
| @Override |
| 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(CertificatePolicies_Id.toString()); |
| unresCritExts.remove(PolicyMappings_Id.toString()); |
| unresCritExts.remove(PolicyConstraints_Id.toString()); |
| unresCritExts.remove(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 = |
| 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 (IOException 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 = |
| 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 (IOException 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(InhibitAnyPolicy_Id); |
| if (inhAnyPolExt == null) |
| return inhibitAnyPolicy; |
| |
| int skipCerts = |
| 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 (IOException 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<>(); |
| |
| 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 = 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", |
| null, null, -1, PKIXReason.INVALID_POLICY); |
| } |
| |
| // 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", |
| null, null, -1, PKIXReason.INVALID_POLICY); |
| } |
| |
| 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<>(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<>(); |
| 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 = 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 (CertificatePolicyMap polMap : maps) { |
| 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", |
| null, null, -1, PKIXReason.INVALID_POLICY); |
| } |
| |
| if (subjectDomain.equals(ANY_POLICY)) { |
| throw new CertPathValidatorException |
| ("encountered a subjectDomainPolicy of ANY_POLICY", |
| null, null, -1, PKIXReason.INVALID_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<>(); |
| 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 = 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; |
| } |
| } |
| } |