blob: e55f3d331800172233c0ae2b2cbd67e15803fc92 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.provider.certpath;
27
28import java.util.Collections;
29import java.util.HashSet;
30import java.util.Iterator;
31import java.util.Set;
32
33import java.security.cert.*;
34
35/**
36 * Implements the <code>PolicyNode</code> interface.
37 * <p>
38 * This class provides an implementation of the <code>PolicyNode</code>
39 * interface, and is used internally to build and search Policy Trees.
40 * While the implementation is mutable during construction, it is immutable
41 * before returning to a client and no mutable public or protected methods
42 * are exposed by this implementation, as per the contract of PolicyNode.
43 *
44 * @since 1.4
45 * @author Seth Proctor
46 * @author Sean Mullan
47 */
48final class PolicyNodeImpl implements PolicyNode {
49
50 /**
51 * Use to specify the special policy "Any Policy"
52 */
53 private static final String ANY_POLICY = "2.5.29.32.0";
54
55 // every node has one parent, and zero or more children
56 private PolicyNodeImpl mParent;
57 private HashSet<PolicyNodeImpl> mChildren;
58
59 // the 4 fields specified by RFC 3280
60 private String mValidPolicy;
61 private HashSet<PolicyQualifierInfo> mQualifierSet;
62 private boolean mCriticalityIndicator;
63 private HashSet<String> mExpectedPolicySet;
64 private boolean mOriginalExpectedPolicySet;
65
66 // the tree depth
67 private int mDepth;
68 // immutability flag
69 private boolean isImmutable = false;
70
71 /**
72 * Constructor which takes a <code>PolicyNodeImpl</code> representing the
73 * parent in the Policy Tree to this node. If null, this is the
74 * root of the tree. The constructor also takes the associated data
75 * for this node, as found in the certificate. It also takes a boolean
76 * argument specifying whether this node is being created as a result
77 * of policy mapping.
78 *
79 * @param parent the PolicyNode above this in the tree, or null if this
80 * node is the tree's root node
81 * @param validPolicy a String representing this node's valid policy OID
82 * @param qualifierSet the Set of qualifiers for this policy
83 * @param criticalityIndicator a boolean representing whether or not the
84 * extension is critical
85 * @param expectedPolicySet a Set of expected policies
86 * @param generatedByPolicyMapping a boolean indicating whether this
87 * node was generated by a policy mapping
88 */
89 PolicyNodeImpl(PolicyNodeImpl parent, String validPolicy,
90 Set<PolicyQualifierInfo> qualifierSet,
91 boolean criticalityIndicator, Set<String> expectedPolicySet,
92 boolean generatedByPolicyMapping) {
93 mParent = parent;
94 mChildren = new HashSet<PolicyNodeImpl>();
95
96 if (validPolicy != null)
97 mValidPolicy = validPolicy;
98 else
99 mValidPolicy = "";
100
101 if (qualifierSet != null)
102 mQualifierSet = new HashSet<PolicyQualifierInfo>(qualifierSet);
103 else
104 mQualifierSet = new HashSet<PolicyQualifierInfo>();
105
106 mCriticalityIndicator = criticalityIndicator;
107
108 if (expectedPolicySet != null)
109 mExpectedPolicySet = new HashSet<String>(expectedPolicySet);
110 else
111 mExpectedPolicySet = new HashSet<String>();
112
113 mOriginalExpectedPolicySet = !generatedByPolicyMapping;
114
115 // see if we're the root, and act appropriately
116 if (mParent != null) {
117 mDepth = mParent.getDepth() + 1;
118 mParent.addChild(this);
119 } else {
120 mDepth = 0;
121 }
122 }
123
124 /**
125 * Alternate constructor which makes a new node with the policy data
126 * in an existing <code>PolicyNodeImpl</code>.
127 *
128 * @param parent a PolicyNode that's the new parent of the node, or
129 * null if this is the root node
130 * @param node a PolicyNode containing the policy data to copy
131 */
132 PolicyNodeImpl(PolicyNodeImpl parent, PolicyNodeImpl node) {
133 this(parent, node.mValidPolicy, node.mQualifierSet,
134 node.mCriticalityIndicator, node.mExpectedPolicySet, false);
135 }
136
137 public PolicyNode getParent() {
138 return mParent;
139 }
140
141 public Iterator<PolicyNodeImpl> getChildren() {
142 return Collections.unmodifiableSet(mChildren).iterator();
143 }
144
145 public int getDepth() {
146 return mDepth;
147 }
148
149 public String getValidPolicy() {
150 return mValidPolicy;
151 }
152
153 public Set<PolicyQualifierInfo> getPolicyQualifiers() {
154 return Collections.unmodifiableSet(mQualifierSet);
155 }
156
157 public Set<String> getExpectedPolicies() {
158 return Collections.unmodifiableSet(mExpectedPolicySet);
159 }
160
161 public boolean isCritical() {
162 return mCriticalityIndicator;
163 }
164
165 /**
166 * Return a printable representation of the PolicyNode.
167 * Starting at the node on which this method is called,
168 * it recurses through the tree and prints out each node.
169 *
170 * @return a String describing the contents of the Policy Node
171 */
172 public String toString() {
173 StringBuffer buffer = new StringBuffer(this.asString());
174
175 Iterator<PolicyNodeImpl> it = getChildren();
176 while (it.hasNext()) {
177 buffer.append(it.next());
178 }
179 return buffer.toString();
180 }
181
182 // private methods and package private operations
183
184 boolean isImmutable() {
185 return isImmutable;
186 }
187
188 /**
189 * Sets the immutability flag of this node and all of its children
190 * to true.
191 */
192 void setImmutable() {
193 if (isImmutable)
194 return;
195 for (PolicyNodeImpl node : mChildren) {
196 node.setImmutable();
197 }
198 isImmutable = true;
199 }
200
201 /**
202 * Private method sets a child node. This is called from the child's
203 * constructor.
204 *
205 * @param child new <code>PolicyNodeImpl</code> child node
206 */
207 private void addChild(PolicyNodeImpl child) {
208 if (isImmutable) {
209 throw new IllegalStateException("PolicyNode is immutable");
210 }
211 mChildren.add(child);
212 }
213
214 /**
215 * Adds an expectedPolicy to the expected policy set.
216 * If this is the original expected policy set initialized
217 * by the constructor, then the expected policy set is cleared
218 * before the expected policy is added.
219 *
220 * @param expectedPolicy a String representing an expected policy.
221 */
222 void addExpectedPolicy(String expectedPolicy) {
223 if (isImmutable) {
224 throw new IllegalStateException("PolicyNode is immutable");
225 }
226 if (mOriginalExpectedPolicySet) {
227 mExpectedPolicySet.clear();
228 mOriginalExpectedPolicySet = false;
229 }
230 mExpectedPolicySet.add(expectedPolicy);
231 }
232
233 /**
234 * Removes all paths which don't reach the specified depth.
235 *
236 * @param depth an int representing the desired minimum depth of all paths
237 */
238 void prune(int depth) {
239 if (isImmutable)
240 throw new IllegalStateException("PolicyNode is immutable");
241
242 // if we have no children, we can't prune below us...
243 if (mChildren.size() == 0)
244 return;
245
246 Iterator<PolicyNodeImpl> it = mChildren.iterator();
247 while (it.hasNext()) {
248 PolicyNodeImpl node = it.next();
249 node.prune(depth);
250 // now that we've called prune on the child, see if we should
251 // remove it from the tree
252 if ((node.mChildren.size() == 0) && (depth > mDepth + 1))
253 it.remove();
254 }
255 }
256
257 /**
258 * Deletes the specified child node of this node, if it exists.
259 *
260 * @param childNode the child node to be deleted
261 */
262 void deleteChild(PolicyNode childNode) {
263 if (isImmutable) {
264 throw new IllegalStateException("PolicyNode is immutable");
265 }
266 mChildren.remove(childNode);
267 }
268
269 /**
270 * Returns a copy of the tree, without copying the policy-related data,
271 * rooted at the node on which this was called.
272 *
273 * @return a copy of the tree
274 */
275 PolicyNodeImpl copyTree() {
276 return copyTree(null);
277 }
278
279 private PolicyNodeImpl copyTree(PolicyNodeImpl parent) {
280 PolicyNodeImpl newNode = new PolicyNodeImpl(parent, this);
281
282 for (PolicyNodeImpl node : mChildren) {
283 node.copyTree(newNode);
284 }
285
286 return newNode;
287 }
288
289 /**
290 * Returns all nodes at the specified depth in the tree.
291 *
292 * @param depth an int representing the depth of the desired nodes
293 * @return a <code>Set</code> of all nodes at the specified depth
294 */
295 Set<PolicyNodeImpl> getPolicyNodes(int depth) {
296 Set<PolicyNodeImpl> set = new HashSet<PolicyNodeImpl>();
297 getPolicyNodes(depth, set);
298 return set;
299 }
300
301 /**
302 * Add all nodes at depth depth to set and return the Set.
303 * Internal recursion helper.
304 */
305 private void getPolicyNodes(int depth, Set<PolicyNodeImpl> set) {
306 // if we've reached the desired depth, then return ourself
307 if (mDepth == depth) {
308 set.add(this);
309 } else {
310 for (PolicyNodeImpl node : mChildren) {
311 node.getPolicyNodes(depth, set);
312 }
313 }
314 }
315
316 /**
317 * Finds all nodes at the specified depth whose expected_policy_set
318 * contains the specified expected OID (if matchAny is false)
319 * or the special OID "any value" (if matchAny is true).
320 *
321 * @param depth an int representing the desired depth
322 * @param expectedOID a String encoding the valid OID to match
323 * @param matchAny a boolean indicating whether an expected_policy_set
324 * containing ANY_POLICY should be considered a match
325 * @return a Set of matched <code>PolicyNode</code>s
326 */
327 Set<PolicyNodeImpl> getPolicyNodesExpected(int depth,
328 String expectedOID, boolean matchAny) {
329
330 if (expectedOID.equals(ANY_POLICY)) {
331 return getPolicyNodes(depth);
332 } else {
333 return getPolicyNodesExpectedHelper(depth, expectedOID, matchAny);
334 }
335 }
336
337 private Set<PolicyNodeImpl> getPolicyNodesExpectedHelper(int depth,
338 String expectedOID, boolean matchAny) {
339
340 HashSet<PolicyNodeImpl> set = new HashSet<PolicyNodeImpl>();
341
342 if (mDepth < depth) {
343 for (PolicyNodeImpl node : mChildren) {
344 set.addAll(node.getPolicyNodesExpectedHelper(depth,
345 expectedOID,
346 matchAny));
347 }
348 } else {
349 if (matchAny) {
350 if (mExpectedPolicySet.contains(ANY_POLICY))
351 set.add(this);
352 } else {
353 if (mExpectedPolicySet.contains(expectedOID))
354 set.add(this);
355 }
356 }
357
358 return set;
359 }
360
361 /**
362 * Finds all nodes at the specified depth that contains the
363 * specified valid OID
364 *
365 * @param depth an int representing the desired depth
366 * @param validOID a String encoding the valid OID to match
367 * @return a Set of matched <code>PolicyNode</code>s
368 */
369 Set<PolicyNodeImpl> getPolicyNodesValid(int depth, String validOID) {
370 HashSet<PolicyNodeImpl> set = new HashSet<PolicyNodeImpl>();
371
372 if (mDepth < depth) {
373 for (PolicyNodeImpl node : mChildren) {
374 set.addAll(node.getPolicyNodesValid(depth, validOID));
375 }
376 } else {
377 if (mValidPolicy.equals(validOID))
378 set.add(this);
379 }
380
381 return set;
382 }
383
384 private static String policyToString(String oid) {
385 if (oid.equals(ANY_POLICY)) {
386 return "anyPolicy";
387 } else {
388 return oid;
389 }
390 }
391
392 /**
393 * Prints out some data on this node.
394 */
395 String asString() {
396 if (mParent == null) {
397 return "anyPolicy ROOT\n";
398 } else {
399 StringBuffer sb = new StringBuffer();
400 for (int i = 0, n = getDepth(); i < n; i++) {
401 sb.append(" ");
402 }
403 sb.append(policyToString(getValidPolicy()));
404 sb.append(" CRIT: ");
405 sb.append(isCritical());
406 sb.append(" EP: ");
407 for (String policy : getExpectedPolicies()) {
408 sb.append(policyToString(policy));
409 sb.append(" ");
410 }
411 sb.append(" (");
412 sb.append(getDepth());
413 sb.append(")\n");
414 return sb.toString();
415 }
416 }
417}