001: /*
002: * @(#)PolicyConstraintsExtension.java 1.24 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.security.x509;
029:
030: import java.io.IOException;
031: import java.io.InputStream;
032: import java.io.OutputStream;
033: import java.lang.reflect.Array;
034: import java.security.cert.CertificateException;
035: import java.util.Enumeration;
036: import java.util.Vector;
037:
038: import sun.security.util.*;
039:
040: /**
041: * This class defines the certificate extension which specifies the
042: * Policy constraints.
043: * <p>
044: * The policy constraints extension can be used in certificates issued
045: * to CAs. The policy constraints extension constrains path validation
046: * in two ways. It can be used to prohibit policy mapping or require
047: * that each certificate in a path contain an acceptable policy
048: * identifier.<p>
049: * The ASN.1 syntax for this is (IMPLICIT tagging is defined in the
050: * module definition):
051: * <pre>
052: * PolicyConstraints ::= SEQUENCE {
053: * requireExplicitPolicy [0] SkipCerts OPTIONAL,
054: * inhibitPolicyMapping [1] SkipCerts OPTIONAL
055: * }
056: * SkipCerts ::= INTEGER (0..MAX)
057: * </pre>
058: * @author Amit Kapoor
059: * @author Hemma Prafullchandra
060: * @version 1.9
061: * @see Extension
062: * @see CertAttrSet
063: */
064: public class PolicyConstraintsExtension extends Extension implements
065: CertAttrSet {
066: /**
067: * Identifier for this attribute, to be used with the
068: * get, set, delete methods of Certificate, x509 type.
069: */
070: public static final String IDENT = "x509.info.extensions.PolicyConstraints";
071: /**
072: * Attribute names.
073: */
074: public static final String NAME = "PolicyConstraints";
075: public static final String REQUIRE = "require";
076: public static final String INHIBIT = "inhibit";
077:
078: private static final byte TAG_REQUIRE = 0;
079: private static final byte TAG_INHIBIT = 1;
080:
081: private int require = -1;
082: private int inhibit = -1;
083:
084: // Encode this extension value.
085: private void encodeThis() throws IOException {
086: if (require == -1 && inhibit == -1) {
087: this .extensionValue = null;
088: return;
089: }
090: DerOutputStream tagged = new DerOutputStream();
091: DerOutputStream seq = new DerOutputStream();
092:
093: if (require != -1) {
094: DerOutputStream tmp = new DerOutputStream();
095: tmp.putInteger(require);
096: tagged.writeImplicit(DerValue.createTag(
097: DerValue.TAG_CONTEXT, false, TAG_REQUIRE), tmp);
098: }
099: if (inhibit != -1) {
100: DerOutputStream tmp = new DerOutputStream();
101: tmp.putInteger(inhibit);
102: tagged.writeImplicit(DerValue.createTag(
103: DerValue.TAG_CONTEXT, false, TAG_INHIBIT), tmp);
104: }
105: seq.write(DerValue.tag_Sequence, tagged);
106: this .extensionValue = seq.toByteArray();
107: }
108:
109: /**
110: * Create a PolicyConstraintsExtension object with both
111: * require explicit policy and inhibit policy mapping. The
112: * extension is marked non-critical.
113: *
114: * @param require require explicit policy (-1 for optional).
115: * @param inhibit inhibit policy mapping (-1 for optional).
116: */
117: public PolicyConstraintsExtension(int require, int inhibit)
118: throws IOException {
119: this (Boolean.FALSE, require, inhibit);
120: }
121:
122: /**
123: * Create a PolicyConstraintsExtension object with specified
124: * criticality and both require explicit policy and inhibit
125: * policy mapping.
126: *
127: * @param critical true if the extension is to be treated as critical.
128: * @param require require explicit policy (-1 for optional).
129: * @param inhibit inhibit policy mapping (-1 for optional).
130: */
131: public PolicyConstraintsExtension(Boolean critical, int require,
132: int inhibit) throws IOException {
133: this .require = require;
134: this .inhibit = inhibit;
135: this .extensionId = PKIXExtensions.PolicyConstraints_Id;
136: this .critical = critical.booleanValue();
137: encodeThis();
138: }
139:
140: /**
141: * Create the extension from its DER encoded value and criticality.
142: *
143: * @param critical true if the extension is to be treated as critical.
144: * @param value Array of DER encoded bytes of the actual value.
145: * @exception IOException on error.
146: */
147: public PolicyConstraintsExtension(Boolean critical, Object value)
148: throws IOException {
149: this .extensionId = PKIXExtensions.PolicyConstraints_Id;
150: this .critical = critical.booleanValue();
151:
152: if (!(value instanceof byte[]))
153: throw new IOException("Illegal argument type");
154:
155: int len = Array.getLength(value);
156: byte[] extValue = new byte[len];
157: System.arraycopy(value, 0, extValue, 0, len);
158:
159: this .extensionValue = extValue;
160: DerValue val = new DerValue(extValue);
161: if (val.tag != DerValue.tag_Sequence) {
162: throw new IOException(
163: "Sequence tag missing for PolicyConstraint.");
164: }
165: DerInputStream in = val.data;
166: while (in != null && in.available() != 0) {
167: DerValue next = in.getDerValue();
168:
169: if (next.isContextSpecific(TAG_REQUIRE)
170: && !next.isConstructed()) {
171: if (this .require != -1)
172: throw new IOException(
173: "Duplicate requireExplicitPolicy"
174: + "found in the PolicyConstraintsExtension");
175: next.resetTag(DerValue.tag_Integer);
176: this .require = next.getInteger();
177:
178: } else if (next.isContextSpecific(TAG_INHIBIT)
179: && !next.isConstructed()) {
180: if (this .inhibit != -1)
181: throw new IOException(
182: "Duplicate inhibitPolicyMapping"
183: + "found in the PolicyConstraintsExtension");
184: next.resetTag(DerValue.tag_Integer);
185: this .inhibit = next.getInteger();
186: } else
187: throw new IOException(
188: "Invalid encoding of PolicyConstraint");
189: }
190: }
191:
192: /**
193: * Return the extension as user readable string.
194: */
195: public String toString() {
196: String s;
197: s = super .toString() + "PolicyConstraints: [" + " Require: ";
198: if (require == -1)
199: s += "unspecified;";
200: else
201: s += require + ";";
202: s += "\tInhibit: ";
203: if (inhibit == -1)
204: s += "unspecified";
205: else
206: s += inhibit;
207: s += " ]\n";
208: return s;
209: }
210:
211: /**
212: * Decode the extension from the InputStream.
213: *
214: * @param in the InputStream to unmarshal the contents from.
215: * @exception IOException on decoding or validity errors.
216: */
217: public void decode(InputStream in) throws IOException {
218: throw new IOException("Method not to be called directly.");
219: }
220:
221: /**
222: * Write the extension to the DerOutputStream.
223: *
224: * @param out the DerOutputStream to write the extension to.
225: * @exception IOException on encoding errors.
226: */
227: public void encode(OutputStream out) throws IOException {
228: DerOutputStream tmp = new DerOutputStream();
229: if (extensionValue == null) {
230: extensionId = PKIXExtensions.PolicyConstraints_Id;
231: critical = false;
232: encodeThis();
233: }
234: super .encode(tmp);
235: out.write(tmp.toByteArray());
236: }
237:
238: /**
239: * Set the attribute value.
240: */
241: public void set(String name, Object obj) throws IOException {
242: if (!(obj instanceof Integer)) {
243: throw new IOException(
244: "Attribute value should be of type Integer.");
245: }
246: if (name.equalsIgnoreCase(REQUIRE)) {
247: require = ((Integer) obj).intValue();
248: } else if (name.equalsIgnoreCase(INHIBIT)) {
249: inhibit = ((Integer) obj).intValue();
250: } else {
251: throw new IOException("Attribute name " + "[" + name + "]"
252: + " not recognized by "
253: + "CertAttrSet:PolicyConstraints.");
254: }
255: encodeThis();
256: }
257:
258: /**
259: * Get the attribute value.
260: */
261: public Object get(String name) throws IOException {
262: if (name.equalsIgnoreCase(REQUIRE)) {
263: return new Integer(require);
264: } else if (name.equalsIgnoreCase(INHIBIT)) {
265: return new Integer(inhibit);
266: } else {
267: throw new IOException("Attribute name not recognized by "
268: + "CertAttrSet:PolicyConstraints.");
269: }
270: }
271:
272: /**
273: * Delete the attribute value.
274: */
275: public void delete(String name) throws IOException {
276: if (name.equalsIgnoreCase(REQUIRE)) {
277: require = -1;
278: } else if (name.equalsIgnoreCase(INHIBIT)) {
279: inhibit = -1;
280: } else {
281: throw new IOException("Attribute name not recognized by "
282: + "CertAttrSet:PolicyConstraints.");
283: }
284: encodeThis();
285: }
286:
287: /**
288: * Return an enumeration of names of attributes existing within this
289: * attribute.
290: */
291: public Enumeration getElements() {
292: AttributeNameEnumeration elements = new AttributeNameEnumeration();
293: elements.addElement(REQUIRE);
294: elements.addElement(INHIBIT);
295:
296: return (elements.elements());
297: }
298:
299: /**
300: * Return the name of this attribute.
301: */
302: public String getName() {
303: return (NAME);
304: }
305: }
|