/*
* Copyright (c) 2000, 2014, 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.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.security.cert.*;
Implements the PolicyNode
interface.
This class provides an implementation of the PolicyNode
interface, and is used internally to build and search Policy Trees.
While the implementation is mutable during construction, it is immutable
before returning to a client and no mutable public or protected methods
are exposed by this implementation, as per the contract of PolicyNode.
Author: Seth Proctor, Sean Mullan Since: 1.4
/**
* Implements the <code>PolicyNode</code> interface.
* <p>
* This class provides an implementation of the <code>PolicyNode</code>
* interface, and is used internally to build and search Policy Trees.
* While the implementation is mutable during construction, it is immutable
* before returning to a client and no mutable public or protected methods
* are exposed by this implementation, as per the contract of PolicyNode.
*
* @since 1.4
* @author Seth Proctor
* @author Sean Mullan
*/
final class PolicyNodeImpl implements PolicyNode {
Use to specify the special policy "Any Policy"
/**
* Use to specify the special policy "Any Policy"
*/
private static final String ANY_POLICY = "2.5.29.32.0";
// every node has one parent, and zero or more children
private PolicyNodeImpl mParent;
private HashSet<PolicyNodeImpl> mChildren;
// the 4 fields specified by RFC 5280
private String mValidPolicy;
private HashSet<PolicyQualifierInfo> mQualifierSet;
private boolean mCriticalityIndicator;
private HashSet<String> mExpectedPolicySet;
private boolean mOriginalExpectedPolicySet;
// the tree depth
private int mDepth;
// immutability flag
private boolean isImmutable = false;
Constructor which takes a PolicyNodeImpl
representing the
parent in the Policy Tree to this node. If null, this is the
root of the tree. The constructor also takes the associated data
for this node, as found in the certificate. It also takes a boolean
argument specifying whether this node is being created as a result
of policy mapping.
Params: - parent – the PolicyNode above this in the tree, or null if this
node is the tree's root node
- validPolicy – a String representing this node's valid policy OID
- qualifierSet – the Set of qualifiers for this policy
- criticalityIndicator – a boolean representing whether or not the
extension is critical
- expectedPolicySet – a Set of expected policies
- generatedByPolicyMapping – a boolean indicating whether this
node was generated by a policy mapping
/**
* Constructor which takes a <code>PolicyNodeImpl</code> representing the
* parent in the Policy Tree to this node. If null, this is the
* root of the tree. The constructor also takes the associated data
* for this node, as found in the certificate. It also takes a boolean
* argument specifying whether this node is being created as a result
* of policy mapping.
*
* @param parent the PolicyNode above this in the tree, or null if this
* node is the tree's root node
* @param validPolicy a String representing this node's valid policy OID
* @param qualifierSet the Set of qualifiers for this policy
* @param criticalityIndicator a boolean representing whether or not the
* extension is critical
* @param expectedPolicySet a Set of expected policies
* @param generatedByPolicyMapping a boolean indicating whether this
* node was generated by a policy mapping
*/
PolicyNodeImpl(PolicyNodeImpl parent, String validPolicy,
Set<PolicyQualifierInfo> qualifierSet,
boolean criticalityIndicator, Set<String> expectedPolicySet,
boolean generatedByPolicyMapping) {
mParent = parent;
mChildren = new HashSet<PolicyNodeImpl>();
if (validPolicy != null)
mValidPolicy = validPolicy;
else
mValidPolicy = "";
if (qualifierSet != null)
mQualifierSet = new HashSet<PolicyQualifierInfo>(qualifierSet);
else
mQualifierSet = new HashSet<PolicyQualifierInfo>();
mCriticalityIndicator = criticalityIndicator;
if (expectedPolicySet != null)
mExpectedPolicySet = new HashSet<String>(expectedPolicySet);
else
mExpectedPolicySet = new HashSet<String>();
mOriginalExpectedPolicySet = !generatedByPolicyMapping;
// see if we're the root, and act appropriately
if (mParent != null) {
mDepth = mParent.getDepth() + 1;
mParent.addChild(this);
} else {
mDepth = 0;
}
}
Alternate constructor which makes a new node with the policy data
in an existing PolicyNodeImpl
.
Params: - parent – a PolicyNode that's the new parent of the node, or
null if this is the root node
- node – a PolicyNode containing the policy data to copy
/**
* Alternate constructor which makes a new node with the policy data
* in an existing <code>PolicyNodeImpl</code>.
*
* @param parent a PolicyNode that's the new parent of the node, or
* null if this is the root node
* @param node a PolicyNode containing the policy data to copy
*/
PolicyNodeImpl(PolicyNodeImpl parent, PolicyNodeImpl node) {
this(parent, node.mValidPolicy, node.mQualifierSet,
node.mCriticalityIndicator, node.mExpectedPolicySet, false);
}
@Override
public PolicyNode getParent() {
return mParent;
}
@Override
public Iterator<PolicyNodeImpl> getChildren() {
return Collections.unmodifiableSet(mChildren).iterator();
}
@Override
public int getDepth() {
return mDepth;
}
@Override
public String getValidPolicy() {
return mValidPolicy;
}
@Override
public Set<PolicyQualifierInfo> getPolicyQualifiers() {
return Collections.unmodifiableSet(mQualifierSet);
}
@Override
public Set<String> getExpectedPolicies() {
return Collections.unmodifiableSet(mExpectedPolicySet);
}
@Override
public boolean isCritical() {
return mCriticalityIndicator;
}
Return a printable representation of the PolicyNode.
Starting at the node on which this method is called,
it recurses through the tree and prints out each node.
Returns: a String describing the contents of the Policy Node
/**
* Return a printable representation of the PolicyNode.
* Starting at the node on which this method is called,
* it recurses through the tree and prints out each node.
*
* @return a String describing the contents of the Policy Node
*/
@Override
public String toString() {
StringBuilder buffer = new StringBuilder(this.asString());
for (PolicyNodeImpl node : mChildren) {
buffer.append(node);
}
return buffer.toString();
}
// private methods and package private operations
boolean isImmutable() {
return isImmutable;
}
Sets the immutability flag of this node and all of its children
to true.
/**
* Sets the immutability flag of this node and all of its children
* to true.
*/
void setImmutable() {
if (isImmutable)
return;
for (PolicyNodeImpl node : mChildren) {
node.setImmutable();
}
isImmutable = true;
}
Private method sets a child node. This is called from the child's
constructor.
Params: - child – new
PolicyNodeImpl
child node
/**
* Private method sets a child node. This is called from the child's
* constructor.
*
* @param child new <code>PolicyNodeImpl</code> child node
*/
private void addChild(PolicyNodeImpl child) {
if (isImmutable) {
throw new IllegalStateException("PolicyNode is immutable");
}
mChildren.add(child);
}
Adds an expectedPolicy to the expected policy set.
If this is the original expected policy set initialized
by the constructor, then the expected policy set is cleared
before the expected policy is added.
Params: - expectedPolicy – a String representing an expected policy.
/**
* Adds an expectedPolicy to the expected policy set.
* If this is the original expected policy set initialized
* by the constructor, then the expected policy set is cleared
* before the expected policy is added.
*
* @param expectedPolicy a String representing an expected policy.
*/
void addExpectedPolicy(String expectedPolicy) {
if (isImmutable) {
throw new IllegalStateException("PolicyNode is immutable");
}
if (mOriginalExpectedPolicySet) {
mExpectedPolicySet.clear();
mOriginalExpectedPolicySet = false;
}
mExpectedPolicySet.add(expectedPolicy);
}
Removes all paths which don't reach the specified depth.
Params: - depth – an int representing the desired minimum depth of all paths
/**
* Removes all paths which don't reach the specified depth.
*
* @param depth an int representing the desired minimum depth of all paths
*/
void prune(int depth) {
if (isImmutable)
throw new IllegalStateException("PolicyNode is immutable");
// if we have no children, we can't prune below us...
if (mChildren.size() == 0)
return;
Iterator<PolicyNodeImpl> it = mChildren.iterator();
while (it.hasNext()) {
PolicyNodeImpl node = it.next();
node.prune(depth);
// now that we've called prune on the child, see if we should
// remove it from the tree
if ((node.mChildren.size() == 0) && (depth > mDepth + 1))
it.remove();
}
}
Deletes the specified child node of this node, if it exists.
Params: - childNode – the child node to be deleted
/**
* Deletes the specified child node of this node, if it exists.
*
* @param childNode the child node to be deleted
*/
void deleteChild(PolicyNode childNode) {
if (isImmutable) {
throw new IllegalStateException("PolicyNode is immutable");
}
mChildren.remove(childNode);
}
Returns a copy of the tree, without copying the policy-related data,
rooted at the node on which this was called.
Returns: a copy of the tree
/**
* Returns a copy of the tree, without copying the policy-related data,
* rooted at the node on which this was called.
*
* @return a copy of the tree
*/
PolicyNodeImpl copyTree() {
return copyTree(null);
}
private PolicyNodeImpl copyTree(PolicyNodeImpl parent) {
PolicyNodeImpl newNode = new PolicyNodeImpl(parent, this);
for (PolicyNodeImpl node : mChildren) {
node.copyTree(newNode);
}
return newNode;
}
Returns all nodes at the specified depth in the tree.
Params: - depth – an int representing the depth of the desired nodes
Returns: a Set
of all nodes at the specified depth
/**
* Returns all nodes at the specified depth in the tree.
*
* @param depth an int representing the depth of the desired nodes
* @return a <code>Set</code> of all nodes at the specified depth
*/
Set<PolicyNodeImpl> getPolicyNodes(int depth) {
Set<PolicyNodeImpl> set = new HashSet<>();
getPolicyNodes(depth, set);
return set;
}
Add all nodes at depth to set and return the Set.
Internal recursion helper.
/**
* Add all nodes at depth to set and return the Set.
* Internal recursion helper.
*/
private void getPolicyNodes(int depth, Set<PolicyNodeImpl> set) {
// if we've reached the desired depth, then return ourself
if (mDepth == depth) {
set.add(this);
} else {
for (PolicyNodeImpl node : mChildren) {
node.getPolicyNodes(depth, set);
}
}
}
Finds all nodes at the specified depth whose expected_policy_set
contains the specified expected OID (if matchAny is false)
or the special OID "any value" (if matchAny is true).
Params: - depth – an int representing the desired depth
- expectedOID – a String encoding the valid OID to match
- matchAny – a boolean indicating whether an expected_policy_set
containing ANY_POLICY should be considered a match
Returns: a Set of matched PolicyNode
s
/**
* Finds all nodes at the specified depth whose expected_policy_set
* contains the specified expected OID (if matchAny is false)
* or the special OID "any value" (if matchAny is true).
*
* @param depth an int representing the desired depth
* @param expectedOID a String encoding the valid OID to match
* @param matchAny a boolean indicating whether an expected_policy_set
* containing ANY_POLICY should be considered a match
* @return a Set of matched <code>PolicyNode</code>s
*/
Set<PolicyNodeImpl> getPolicyNodesExpected(int depth,
String expectedOID, boolean matchAny) {
if (expectedOID.equals(ANY_POLICY)) {
return getPolicyNodes(depth);
} else {
return getPolicyNodesExpectedHelper(depth, expectedOID, matchAny);
}
}
private Set<PolicyNodeImpl> getPolicyNodesExpectedHelper(int depth,
String expectedOID, boolean matchAny) {
HashSet<PolicyNodeImpl> set = new HashSet<>();
if (mDepth < depth) {
for (PolicyNodeImpl node : mChildren) {
set.addAll(node.getPolicyNodesExpectedHelper(depth,
expectedOID,
matchAny));
}
} else {
if (matchAny) {
if (mExpectedPolicySet.contains(ANY_POLICY))
set.add(this);
} else {
if (mExpectedPolicySet.contains(expectedOID))
set.add(this);
}
}
return set;
}
Finds all nodes at the specified depth that contains the
specified valid OID
Params: - depth – an int representing the desired depth
- validOID – a String encoding the valid OID to match
Returns: a Set of matched PolicyNode
s
/**
* Finds all nodes at the specified depth that contains the
* specified valid OID
*
* @param depth an int representing the desired depth
* @param validOID a String encoding the valid OID to match
* @return a Set of matched <code>PolicyNode</code>s
*/
Set<PolicyNodeImpl> getPolicyNodesValid(int depth, String validOID) {
HashSet<PolicyNodeImpl> set = new HashSet<>();
if (mDepth < depth) {
for (PolicyNodeImpl node : mChildren) {
set.addAll(node.getPolicyNodesValid(depth, validOID));
}
} else {
if (mValidPolicy.equals(validOID))
set.add(this);
}
return set;
}
private static String policyToString(String oid) {
if (oid.equals(ANY_POLICY)) {
return "anyPolicy";
} else {
return oid;
}
}
Prints out some data on this node.
/**
* Prints out some data on this node.
*/
String asString() {
if (mParent == null) {
return "anyPolicy ROOT\n";
} else {
StringBuilder sb = new StringBuilder();
for (int i = 0, n = getDepth(); i < n; i++) {
sb.append(" ");
}
sb.append(policyToString(getValidPolicy()));
sb.append(" CRIT: ");
sb.append(isCritical());
sb.append(" EP: ");
for (String policy : getExpectedPolicies()) {
sb.append(policyToString(policy));
sb.append(" ");
}
sb.append(" (");
sb.append(getDepth());
sb.append(")\n");
return sb.toString();
}
}
}