Path: blob/master/src/java.base/share/classes/sun/security/provider/certpath/PolicyChecker.java
41161 views
/*1* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider.certpath;2627import java.io.IOException;28import java.security.cert.Certificate;29import java.security.cert.CertificateException;30import java.security.cert.CertPathValidatorException;31import java.security.cert.PKIXCertPathChecker;32import java.security.cert.PKIXReason;33import java.security.cert.PolicyNode;34import java.security.cert.PolicyQualifierInfo;35import java.security.cert.X509Certificate;36import java.util.*;3738import sun.security.util.Debug;39import sun.security.util.KnownOIDs;40import sun.security.x509.CertificatePoliciesExtension;41import sun.security.x509.PolicyConstraintsExtension;42import sun.security.x509.PolicyMappingsExtension;43import sun.security.x509.CertificatePolicyMap;44import static sun.security.x509.PKIXExtensions.*;45import sun.security.x509.PolicyInformation;46import sun.security.x509.X509CertImpl;47import sun.security.x509.InhibitAnyPolicyExtension;4849/**50* PolicyChecker is a <code>PKIXCertPathChecker</code> that checks policy51* information on a PKIX certificate, namely certificate policies, policy52* mappings, policy constraints and policy qualifiers.53*54* @since 1.455* @author Yassir Elley56*/57class PolicyChecker extends PKIXCertPathChecker {5859private final Set<String> initPolicies;60private final int certPathLen;61private final boolean expPolicyRequired;62private final boolean polMappingInhibited;63private final boolean anyPolicyInhibited;64private final boolean rejectPolicyQualifiers;65private PolicyNodeImpl rootNode;66private int explicitPolicy;67private int policyMapping;68private int inhibitAnyPolicy;69private int certIndex;7071private Set<String> supportedExts;7273private static final Debug debug = Debug.getInstance("certpath");74static final String ANY_POLICY = KnownOIDs.CE_CERT_POLICIES_ANY.value();7576/**77* Constructs a Policy Checker.78*79* @param initialPolicies Set of initial policies80* @param certPathLen length of the certification path to be checked81* @param expPolicyRequired true if explicit policy is required82* @param polMappingInhibited true if policy mapping is inhibited83* @param anyPolicyInhibited true if the ANY_POLICY OID should be inhibited84* @param rejectPolicyQualifiers true if pol qualifiers are to be rejected85* @param rootNode the initial root node of the valid policy tree86*/87PolicyChecker(Set<String> initialPolicies, int certPathLen,88boolean expPolicyRequired, boolean polMappingInhibited,89boolean anyPolicyInhibited, boolean rejectPolicyQualifiers,90PolicyNodeImpl rootNode)91{92if (initialPolicies.isEmpty()) {93// if no initialPolicies are specified by user, set94// initPolicies to be anyPolicy by default95this.initPolicies = new HashSet<String>(1);96this.initPolicies.add(ANY_POLICY);97} else {98this.initPolicies = new HashSet<String>(initialPolicies);99}100this.certPathLen = certPathLen;101this.expPolicyRequired = expPolicyRequired;102this.polMappingInhibited = polMappingInhibited;103this.anyPolicyInhibited = anyPolicyInhibited;104this.rejectPolicyQualifiers = rejectPolicyQualifiers;105this.rootNode = rootNode;106}107108/**109* Initializes the internal state of the checker from parameters110* specified in the constructor111*112* @param forward a boolean indicating whether this checker should be113* initialized capable of building in the forward direction114* @throws CertPathValidatorException if user wants to enable forward115* checking and forward checking is not supported.116*/117@Override118public void init(boolean forward) throws CertPathValidatorException {119if (forward) {120throw new CertPathValidatorException121("forward checking not supported");122}123124certIndex = 1;125explicitPolicy = (expPolicyRequired ? 0 : certPathLen + 1);126policyMapping = (polMappingInhibited ? 0 : certPathLen + 1);127inhibitAnyPolicy = (anyPolicyInhibited ? 0 : certPathLen + 1);128}129130/**131* Checks if forward checking is supported. Forward checking refers132* to the ability of the PKIXCertPathChecker to perform its checks133* when presented with certificates in the forward direction (from134* target to anchor).135*136* @return true if forward checking is supported, false otherwise137*/138@Override139public boolean isForwardCheckingSupported() {140return false;141}142143/**144* Gets an immutable Set of the OID strings for the extensions that145* the PKIXCertPathChecker supports (i.e. recognizes, is able to146* process), or null if no extensions are147* supported. All OID strings that a PKIXCertPathChecker might148* possibly be able to process should be included.149*150* @return the Set of extensions supported by this PKIXCertPathChecker,151* or null if no extensions are supported152*/153@Override154public Set<String> getSupportedExtensions() {155if (supportedExts == null) {156supportedExts = new HashSet<String>(4);157supportedExts.add(CertificatePolicies_Id.toString());158supportedExts.add(PolicyMappings_Id.toString());159supportedExts.add(PolicyConstraints_Id.toString());160supportedExts.add(InhibitAnyPolicy_Id.toString());161supportedExts = Collections.unmodifiableSet(supportedExts);162}163return supportedExts;164}165166/**167* Performs the policy processing checks on the certificate using its168* internal state.169*170* @param cert the Certificate to be processed171* @param unresCritExts the unresolved critical extensions172* @throws CertPathValidatorException if the certificate does not verify173*/174@Override175public void check(Certificate cert, Collection<String> unresCritExts)176throws CertPathValidatorException177{178// now do the policy checks179checkPolicy((X509Certificate) cert);180181if (unresCritExts != null && !unresCritExts.isEmpty()) {182unresCritExts.remove(CertificatePolicies_Id.toString());183unresCritExts.remove(PolicyMappings_Id.toString());184unresCritExts.remove(PolicyConstraints_Id.toString());185unresCritExts.remove(InhibitAnyPolicy_Id.toString());186}187}188189/**190* Internal method to run through all the checks.191*192* @param currCert the certificate to be processed193* @exception CertPathValidatorException Exception thrown if194* the certificate does not verify195*/196private void checkPolicy(X509Certificate currCert)197throws CertPathValidatorException198{199String msg = "certificate policies";200if (debug != null) {201debug.println("PolicyChecker.checkPolicy() ---checking " + msg202+ "...");203debug.println("PolicyChecker.checkPolicy() certIndex = "204+ certIndex);205debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "206+ "explicitPolicy = " + explicitPolicy);207debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "208+ "policyMapping = " + policyMapping);209debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "210+ "inhibitAnyPolicy = " + inhibitAnyPolicy);211debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "212+ "policyTree = " + rootNode);213}214215X509CertImpl currCertImpl = null;216try {217currCertImpl = X509CertImpl.toImpl(currCert);218} catch (CertificateException ce) {219throw new CertPathValidatorException(ce);220}221222boolean finalCert = (certIndex == certPathLen);223224rootNode = processPolicies(certIndex, initPolicies, explicitPolicy,225policyMapping, inhibitAnyPolicy, rejectPolicyQualifiers, rootNode,226currCertImpl, finalCert);227228if (!finalCert) {229explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCertImpl,230finalCert);231policyMapping = mergePolicyMapping(policyMapping, currCertImpl);232inhibitAnyPolicy = mergeInhibitAnyPolicy(inhibitAnyPolicy,233currCertImpl);234}235236certIndex++;237238if (debug != null) {239debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "240+ "explicitPolicy = " + explicitPolicy);241debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "242+ "policyMapping = " + policyMapping);243debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "244+ "inhibitAnyPolicy = " + inhibitAnyPolicy);245debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "246+ "policyTree = " + rootNode);247debug.println("PolicyChecker.checkPolicy() " + msg + " verified");248}249}250251/**252* Merges the specified explicitPolicy value with the253* requireExplicitPolicy field of the <code>PolicyConstraints</code>254* extension obtained from the certificate. An explicitPolicy255* value of -1 implies no constraint.256*257* @param explicitPolicy an integer which indicates if a non-null258* valid policy tree is required259* @param currCert the Certificate to be processed260* @param finalCert a boolean indicating whether currCert is261* the final cert in the cert path262* @return returns the new explicitPolicy value263* @exception CertPathValidatorException Exception thrown if an error264* occurs265*/266static int mergeExplicitPolicy(int explicitPolicy, X509CertImpl currCert,267boolean finalCert) throws CertPathValidatorException268{269if ((explicitPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {270explicitPolicy--;271}272273try {274PolicyConstraintsExtension polConstExt275= currCert.getPolicyConstraintsExtension();276if (polConstExt == null)277return explicitPolicy;278int require =279polConstExt.get(PolicyConstraintsExtension.REQUIRE).intValue();280if (debug != null) {281debug.println("PolicyChecker.mergeExplicitPolicy() "282+ "require Index from cert = " + require);283}284if (!finalCert) {285if (require != -1) {286if ((explicitPolicy == -1) || (require < explicitPolicy)) {287explicitPolicy = require;288}289}290} else {291if (require == 0)292explicitPolicy = require;293}294} catch (IOException e) {295if (debug != null) {296debug.println("PolicyChecker.mergeExplicitPolicy "297+ "unexpected exception");298e.printStackTrace();299}300throw new CertPathValidatorException(e);301}302303return explicitPolicy;304}305306/**307* Merges the specified policyMapping value with the308* inhibitPolicyMapping field of the <code>PolicyConstraints</code>309* extension obtained from the certificate. A policyMapping310* value of -1 implies no constraint.311*312* @param policyMapping an integer which indicates if policy mapping313* is inhibited314* @param currCert the Certificate to be processed315* @return returns the new policyMapping value316* @exception CertPathValidatorException Exception thrown if an error317* occurs318*/319static int mergePolicyMapping(int policyMapping, X509CertImpl currCert)320throws CertPathValidatorException321{322if ((policyMapping > 0) && !X509CertImpl.isSelfIssued(currCert)) {323policyMapping--;324}325326try {327PolicyConstraintsExtension polConstExt328= currCert.getPolicyConstraintsExtension();329if (polConstExt == null)330return policyMapping;331332int inhibit =333polConstExt.get(PolicyConstraintsExtension.INHIBIT).intValue();334if (debug != null)335debug.println("PolicyChecker.mergePolicyMapping() "336+ "inhibit Index from cert = " + inhibit);337338if (inhibit != -1) {339if ((policyMapping == -1) || (inhibit < policyMapping)) {340policyMapping = inhibit;341}342}343} catch (IOException e) {344if (debug != null) {345debug.println("PolicyChecker.mergePolicyMapping "346+ "unexpected exception");347e.printStackTrace();348}349throw new CertPathValidatorException(e);350}351352return policyMapping;353}354355/**356* Merges the specified inhibitAnyPolicy value with the357* SkipCerts value of the InhibitAnyPolicy358* extension obtained from the certificate.359*360* @param inhibitAnyPolicy an integer which indicates whether361* "any-policy" is considered a match362* @param currCert the Certificate to be processed363* @return returns the new inhibitAnyPolicy value364* @exception CertPathValidatorException Exception thrown if an error365* occurs366*/367static int mergeInhibitAnyPolicy(int inhibitAnyPolicy,368X509CertImpl currCert) throws CertPathValidatorException369{370if ((inhibitAnyPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {371inhibitAnyPolicy--;372}373374try {375InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension)376currCert.getExtension(InhibitAnyPolicy_Id);377if (inhAnyPolExt == null)378return inhibitAnyPolicy;379380int skipCerts =381inhAnyPolExt.get(InhibitAnyPolicyExtension.SKIP_CERTS).intValue();382if (debug != null)383debug.println("PolicyChecker.mergeInhibitAnyPolicy() "384+ "skipCerts Index from cert = " + skipCerts);385386if (skipCerts != -1) {387if (skipCerts < inhibitAnyPolicy) {388inhibitAnyPolicy = skipCerts;389}390}391} catch (IOException e) {392if (debug != null) {393debug.println("PolicyChecker.mergeInhibitAnyPolicy "394+ "unexpected exception");395e.printStackTrace();396}397throw new CertPathValidatorException(e);398}399400return inhibitAnyPolicy;401}402403/**404* Processes certificate policies in the certificate.405*406* @param certIndex the index of the certificate407* @param initPolicies the initial policies required by the user408* @param explicitPolicy an integer which indicates if a non-null409* valid policy tree is required410* @param policyMapping an integer which indicates if policy411* mapping is inhibited412* @param inhibitAnyPolicy an integer which indicates whether413* "any-policy" is considered a match414* @param rejectPolicyQualifiers a boolean indicating whether the415* user wants to reject policies that have qualifiers416* @param origRootNode the root node of the valid policy tree417* @param currCert the Certificate to be processed418* @param finalCert a boolean indicating whether currCert is the final419* cert in the cert path420* @return the root node of the valid policy tree after modification421* @exception CertPathValidatorException Exception thrown if an422* error occurs while processing policies.423*/424static PolicyNodeImpl processPolicies(int certIndex, Set<String> initPolicies,425int explicitPolicy, int policyMapping, int inhibitAnyPolicy,426boolean rejectPolicyQualifiers, PolicyNodeImpl origRootNode,427X509CertImpl currCert, boolean finalCert)428throws CertPathValidatorException429{430boolean policiesCritical = false;431List<PolicyInformation> policyInfo;432PolicyNodeImpl rootNode = null;433Set<PolicyQualifierInfo> anyQuals = new HashSet<>();434435if (origRootNode == null)436rootNode = null;437else438rootNode = origRootNode.copyTree();439440// retrieve policyOIDs from currCert441CertificatePoliciesExtension currCertPolicies442= currCert.getCertificatePoliciesExtension();443444// PKIX: Section 6.1.3: Step (d)445if ((currCertPolicies != null) && (rootNode != null)) {446policiesCritical = currCertPolicies.isCritical();447if (debug != null)448debug.println("PolicyChecker.processPolicies() "449+ "policiesCritical = " + policiesCritical);450451try {452policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES);453} catch (IOException ioe) {454throw new CertPathValidatorException("Exception while "455+ "retrieving policyOIDs", ioe);456}457458if (debug != null)459debug.println("PolicyChecker.processPolicies() "460+ "rejectPolicyQualifiers = " + rejectPolicyQualifiers);461462boolean foundAnyPolicy = false;463464// process each policy in cert465for (PolicyInformation curPolInfo : policyInfo) {466String curPolicy =467curPolInfo.getPolicyIdentifier().getIdentifier().toString();468469if (curPolicy.equals(ANY_POLICY)) {470foundAnyPolicy = true;471anyQuals = curPolInfo.getPolicyQualifiers();472} else {473// PKIX: Section 6.1.3: Step (d)(1)474if (debug != null)475debug.println("PolicyChecker.processPolicies() "476+ "processing policy: " + curPolicy);477478// retrieve policy qualifiers from cert479Set<PolicyQualifierInfo> pQuals =480curPolInfo.getPolicyQualifiers();481482// reject cert if we find critical policy qualifiers and483// the policyQualifiersRejected flag is set in the params484if (!pQuals.isEmpty() && rejectPolicyQualifiers &&485policiesCritical) {486throw new CertPathValidatorException(487"critical policy qualifiers present in certificate",488null, null, -1, PKIXReason.INVALID_POLICY);489}490491// PKIX: Section 6.1.3: Step (d)(1)(i)492boolean foundMatch = processParents(certIndex,493policiesCritical, rejectPolicyQualifiers, rootNode,494curPolicy, pQuals, false);495496if (!foundMatch) {497// PKIX: Section 6.1.3: Step (d)(1)(ii)498processParents(certIndex, policiesCritical,499rejectPolicyQualifiers, rootNode, curPolicy,500pQuals, true);501}502}503}504505// PKIX: Section 6.1.3: Step (d)(2)506if (foundAnyPolicy) {507if ((inhibitAnyPolicy > 0) ||508(!finalCert && X509CertImpl.isSelfIssued(currCert))) {509if (debug != null) {510debug.println("PolicyChecker.processPolicies() "511+ "processing policy: " + ANY_POLICY);512}513processParents(certIndex, policiesCritical,514rejectPolicyQualifiers, rootNode, ANY_POLICY, anyQuals,515true);516}517}518519// PKIX: Section 6.1.3: Step (d)(3)520rootNode.prune(certIndex);521if (!rootNode.getChildren().hasNext()) {522rootNode = null;523}524} else if (currCertPolicies == null) {525if (debug != null)526debug.println("PolicyChecker.processPolicies() "527+ "no policies present in cert");528// PKIX: Section 6.1.3: Step (e)529rootNode = null;530}531532// We delay PKIX: Section 6.1.3: Step (f) to the end533// because the code that follows may delete some nodes534// resulting in a null tree535if (rootNode != null) {536if (!finalCert) {537// PKIX: Section 6.1.4: Steps (a)-(b)538rootNode = processPolicyMappings(currCert, certIndex,539policyMapping, rootNode, policiesCritical, anyQuals);540}541}542543// At this point, we optimize the PKIX algorithm by544// removing those nodes which would later have545// been removed by PKIX: Section 6.1.5: Step (g)(iii)546547if ((rootNode != null) && (!initPolicies.contains(ANY_POLICY))548&& (currCertPolicies != null)) {549rootNode = removeInvalidNodes(rootNode, certIndex,550initPolicies, currCertPolicies);551552// PKIX: Section 6.1.5: Step (g)(iii)553if ((rootNode != null) && finalCert) {554// rewrite anyPolicy leaf nodes (see method comments)555rootNode = rewriteLeafNodes(certIndex, initPolicies, rootNode);556}557}558559560if (finalCert) {561// PKIX: Section 6.1.5: Steps (a) and (b)562explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCert,563finalCert);564}565566// PKIX: Section 6.1.3: Step (f)567// verify that either explicit policy is greater than 0 or568// the valid_policy_tree is not equal to NULL569570if ((explicitPolicy == 0) && (rootNode == null)) {571throw new CertPathValidatorException572("non-null policy tree required and policy tree is null",573null, null, -1, PKIXReason.INVALID_POLICY);574}575576return rootNode;577}578579/**580* Rewrite leaf nodes at the end of validation as described in RFC 5280581* section 6.1.5: Step (g)(iii). Leaf nodes with anyPolicy are replaced582* by nodes explicitly representing initial policies not already583* represented by leaf nodes.584*585* This method should only be called when processing the final cert586* and if the policy tree is not null and initial policies is not587* anyPolicy.588*589* @param certIndex the depth of the tree590* @param initPolicies Set of user specified initial policies591* @param rootNode the root of the policy tree592*/593private static PolicyNodeImpl rewriteLeafNodes(int certIndex,594Set<String> initPolicies, PolicyNodeImpl rootNode) {595Set<PolicyNodeImpl> anyNodes =596rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);597if (anyNodes.isEmpty()) {598return rootNode;599}600PolicyNodeImpl anyNode = anyNodes.iterator().next();601PolicyNodeImpl parentNode = (PolicyNodeImpl)anyNode.getParent();602parentNode.deleteChild(anyNode);603// see if there are any initialPolicies not represented by leaf nodes604Set<String> initial = new HashSet<>(initPolicies);605for (PolicyNodeImpl node : rootNode.getPolicyNodes(certIndex)) {606initial.remove(node.getValidPolicy());607}608if (initial.isEmpty()) {609// we deleted the anyPolicy node and have nothing to re-add,610// so we need to prune the tree611rootNode.prune(certIndex);612if (rootNode.getChildren().hasNext() == false) {613rootNode = null;614}615} else {616boolean anyCritical = anyNode.isCritical();617Set<PolicyQualifierInfo> anyQualifiers =618anyNode.getPolicyQualifiers();619for (String policy : initial) {620Set<String> expectedPolicies = Collections.singleton(policy);621PolicyNodeImpl node = new PolicyNodeImpl(parentNode, policy,622anyQualifiers, anyCritical, expectedPolicies, false);623}624}625return rootNode;626}627628/**629* Finds the policy nodes of depth (certIndex-1) where curPolicy630* is in the expected policy set and creates a new child node631* appropriately. If matchAny is true, then a value of ANY_POLICY632* in the expected policy set will match any curPolicy. If matchAny633* is false, then the expected policy set must exactly contain the634* curPolicy to be considered a match. This method returns a boolean635* value indicating whether a match was found.636*637* @param certIndex the index of the certificate whose policy is638* being processed639* @param policiesCritical a boolean indicating whether the certificate640* policies extension is critical641* @param rejectPolicyQualifiers a boolean indicating whether the642* user wants to reject policies that have qualifiers643* @param rootNode the root node of the valid policy tree644* @param curPolicy a String representing the policy being processed645* @param pQuals the policy qualifiers of the policy being processed or an646* empty Set if there are no qualifiers647* @param matchAny a boolean indicating whether a value of ANY_POLICY648* in the expected policy set will be considered a match649* @return a boolean indicating whether a match was found650* @exception CertPathValidatorException Exception thrown if error occurs.651*/652private static boolean processParents(int certIndex,653boolean policiesCritical, boolean rejectPolicyQualifiers,654PolicyNodeImpl rootNode, String curPolicy,655Set<PolicyQualifierInfo> pQuals,656boolean matchAny) throws CertPathValidatorException657{658boolean foundMatch = false;659660if (debug != null)661debug.println("PolicyChecker.processParents(): matchAny = "662+ matchAny);663664// find matching parents665Set<PolicyNodeImpl> parentNodes =666rootNode.getPolicyNodesExpected(certIndex - 1,667curPolicy, matchAny);668669// for each matching parent, extend policy tree670for (PolicyNodeImpl curParent : parentNodes) {671if (debug != null)672debug.println("PolicyChecker.processParents() "673+ "found parent:\n" + curParent.asString());674675foundMatch = true;676String curParPolicy = curParent.getValidPolicy();677678PolicyNodeImpl curNode = null;679Set<String> curExpPols = null;680681if (curPolicy.equals(ANY_POLICY)) {682// do step 2683Set<String> parExpPols = curParent.getExpectedPolicies();684parentExplicitPolicies:685for (String curParExpPol : parExpPols) {686687Iterator<PolicyNodeImpl> childIter =688curParent.getChildren();689while (childIter.hasNext()) {690PolicyNodeImpl childNode = childIter.next();691String childPolicy = childNode.getValidPolicy();692if (curParExpPol.equals(childPolicy)) {693if (debug != null)694debug.println(childPolicy + " in parent's "695+ "expected policy set already appears in "696+ "child node");697continue parentExplicitPolicies;698}699}700701Set<String> expPols = new HashSet<>();702expPols.add(curParExpPol);703704curNode = new PolicyNodeImpl705(curParent, curParExpPol, pQuals,706policiesCritical, expPols, false);707}708} else {709curExpPols = new HashSet<String>();710curExpPols.add(curPolicy);711712curNode = new PolicyNodeImpl713(curParent, curPolicy, pQuals,714policiesCritical, curExpPols, false);715}716}717718return foundMatch;719}720721/**722* Processes policy mappings in the certificate.723*724* @param currCert the Certificate to be processed725* @param certIndex the index of the current certificate726* @param policyMapping an integer which indicates if policy727* mapping is inhibited728* @param rootNode the root node of the valid policy tree729* @param policiesCritical a boolean indicating if the certificate policies730* extension is critical731* @param anyQuals the qualifiers associated with ANY-POLICY, or an empty732* Set if there are no qualifiers associated with ANY-POLICY733* @return the root node of the valid policy tree after modification734* @exception CertPathValidatorException exception thrown if an error735* occurs while processing policy mappings736*/737private static PolicyNodeImpl processPolicyMappings(X509CertImpl currCert,738int certIndex, int policyMapping, PolicyNodeImpl rootNode,739boolean policiesCritical, Set<PolicyQualifierInfo> anyQuals)740throws CertPathValidatorException741{742PolicyMappingsExtension polMappingsExt743= currCert.getPolicyMappingsExtension();744745if (polMappingsExt == null)746return rootNode;747748if (debug != null)749debug.println("PolicyChecker.processPolicyMappings() "750+ "inside policyMapping check");751752List<CertificatePolicyMap> maps = null;753try {754maps = polMappingsExt.get(PolicyMappingsExtension.MAP);755} catch (IOException e) {756if (debug != null) {757debug.println("PolicyChecker.processPolicyMappings() "758+ "mapping exception");759e.printStackTrace();760}761throw new CertPathValidatorException("Exception while checking "762+ "mapping", e);763}764765boolean childDeleted = false;766for (CertificatePolicyMap polMap : maps) {767String issuerDomain768= polMap.getIssuerIdentifier().getIdentifier().toString();769String subjectDomain770= polMap.getSubjectIdentifier().getIdentifier().toString();771if (debug != null) {772debug.println("PolicyChecker.processPolicyMappings() "773+ "issuerDomain = " + issuerDomain);774debug.println("PolicyChecker.processPolicyMappings() "775+ "subjectDomain = " + subjectDomain);776}777778if (issuerDomain.equals(ANY_POLICY)) {779throw new CertPathValidatorException780("encountered an issuerDomainPolicy of ANY_POLICY",781null, null, -1, PKIXReason.INVALID_POLICY);782}783784if (subjectDomain.equals(ANY_POLICY)) {785throw new CertPathValidatorException786("encountered a subjectDomainPolicy of ANY_POLICY",787null, null, -1, PKIXReason.INVALID_POLICY);788}789790Set<PolicyNodeImpl> validNodes =791rootNode.getPolicyNodesValid(certIndex, issuerDomain);792if (!validNodes.isEmpty()) {793for (PolicyNodeImpl curNode : validNodes) {794if ((policyMapping > 0) || (policyMapping == -1)) {795curNode.addExpectedPolicy(subjectDomain);796} else if (policyMapping == 0) {797PolicyNodeImpl parentNode =798(PolicyNodeImpl) curNode.getParent();799if (debug != null)800debug.println("PolicyChecker.processPolicyMappings"801+ "() before deleting: policy tree = "802+ rootNode);803parentNode.deleteChild(curNode);804childDeleted = true;805if (debug != null)806debug.println("PolicyChecker.processPolicyMappings"807+ "() after deleting: policy tree = "808+ rootNode);809}810}811} else { // no node of depth i has a valid policy812if ((policyMapping > 0) || (policyMapping == -1)) {813Set<PolicyNodeImpl> validAnyNodes =814rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);815for (PolicyNodeImpl curAnyNode : validAnyNodes) {816PolicyNodeImpl curAnyNodeParent =817(PolicyNodeImpl) curAnyNode.getParent();818819Set<String> expPols = new HashSet<>();820expPols.add(subjectDomain);821822PolicyNodeImpl curNode = new PolicyNodeImpl823(curAnyNodeParent, issuerDomain, anyQuals,824policiesCritical, expPols, true);825}826}827}828}829830if (childDeleted) {831rootNode.prune(certIndex);832if (!rootNode.getChildren().hasNext()) {833if (debug != null)834debug.println("setting rootNode to null");835rootNode = null;836}837}838839return rootNode;840}841842/**843* Removes those nodes which do not intersect with the initial policies844* specified by the user.845*846* @param rootNode the root node of the valid policy tree847* @param certIndex the index of the certificate being processed848* @param initPolicies the Set of policies required by the user849* @param currCertPolicies the CertificatePoliciesExtension of the850* certificate being processed851* @return the root node of the valid policy tree after modification852* @exception CertPathValidatorException Exception thrown if error occurs.853*/854private static PolicyNodeImpl removeInvalidNodes(PolicyNodeImpl rootNode,855int certIndex, Set<String> initPolicies,856CertificatePoliciesExtension currCertPolicies)857throws CertPathValidatorException858{859List<PolicyInformation> policyInfo = null;860try {861policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES);862} catch (IOException ioe) {863throw new CertPathValidatorException("Exception while "864+ "retrieving policyOIDs", ioe);865}866867boolean childDeleted = false;868for (PolicyInformation curPolInfo : policyInfo) {869String curPolicy =870curPolInfo.getPolicyIdentifier().getIdentifier().toString();871872if (debug != null)873debug.println("PolicyChecker.processPolicies() "874+ "processing policy second time: " + curPolicy);875876Set<PolicyNodeImpl> validNodes =877rootNode.getPolicyNodesValid(certIndex, curPolicy);878for (PolicyNodeImpl curNode : validNodes) {879PolicyNodeImpl parentNode = (PolicyNodeImpl)curNode.getParent();880if (parentNode.getValidPolicy().equals(ANY_POLICY)) {881if ((!initPolicies.contains(curPolicy)) &&882(!curPolicy.equals(ANY_POLICY))) {883if (debug != null)884debug.println("PolicyChecker.processPolicies() "885+ "before deleting: policy tree = " + rootNode);886parentNode.deleteChild(curNode);887childDeleted = true;888if (debug != null)889debug.println("PolicyChecker.processPolicies() "890+ "after deleting: policy tree = " + rootNode);891}892}893}894}895896if (childDeleted) {897rootNode.prune(certIndex);898if (!rootNode.getChildren().hasNext()) {899rootNode = null;900}901}902903return rootNode;904}905906/**907* Gets the root node of the valid policy tree, or null if the908* valid policy tree is null. Marks each node of the returned tree909* immutable and thread-safe.910*911* @return the root node of the valid policy tree, or null if912* the valid policy tree is null913*/914PolicyNode getPolicyTree() {915if (rootNode == null)916return null;917else {918PolicyNodeImpl policyTree = rootNode.copyTree();919policyTree.setImmutable();920return policyTree;921}922}923}924925926