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