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