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.util.Enumeration;
031:
032: import sun.security.util.*;
033:
034: /**
035: * Represent the Key Usage Extension.
036: *
037: * <p>This extension, if present, defines the purpose (e.g., encipherment,
038: * signature, certificate signing) of the key contained in the certificate.
039: * The usage restriction might be employed when a multipurpose key is to be
040: * restricted (e.g., when an RSA key should be used only for signing or only
041: * for key encipherment).
042: *
043: * @author Amit Kapoor
044: * @author Hemma Prafullchandra
045: * @version 1.31
046: * @see Extension
047: * @see CertAttrSet
048: */
049: public class KeyUsageExtension extends Extension implements
050: CertAttrSet<String> {
051:
052: /**
053: * Identifier for this attribute, to be used with the
054: * get, set, delete methods of Certificate, x509 type.
055: */
056: public static final String IDENT = "x509.info.extensions.KeyUsage";
057: /**
058: * Attribute names.
059: */
060: public static final String NAME = "KeyUsage";
061: public static final String DIGITAL_SIGNATURE = "digital_signature";
062: public static final String NON_REPUDIATION = "non_repudiation";
063: public static final String KEY_ENCIPHERMENT = "key_encipherment";
064: public static final String DATA_ENCIPHERMENT = "data_encipherment";
065: public static final String KEY_AGREEMENT = "key_agreement";
066: public static final String KEY_CERTSIGN = "key_certsign";
067: public static final String CRL_SIGN = "crl_sign";
068: public static final String ENCIPHER_ONLY = "encipher_only";
069: public static final String DECIPHER_ONLY = "decipher_only";
070:
071: // Private data members
072: private boolean[] bitString;
073:
074: // Encode this extension value
075: private void encodeThis() throws IOException {
076: DerOutputStream os = new DerOutputStream();
077: os.putTruncatedUnalignedBitString(new BitArray(this .bitString));
078: this .extensionValue = os.toByteArray();
079: }
080:
081: /**
082: * Check if bit is set.
083: *
084: * @param position the position in the bit string to check.
085: */
086: private boolean isSet(int position) {
087: return bitString[position];
088: }
089:
090: /**
091: * Set the bit at the specified position.
092: */
093: private void set(int position, boolean val) {
094: // enlarge bitString if necessary
095: if (position >= bitString.length) {
096: boolean[] tmp = new boolean[position + 1];
097: System.arraycopy(bitString, 0, tmp, 0, bitString.length);
098: bitString = tmp;
099: }
100: bitString[position] = val;
101: }
102:
103: /**
104: * Create a KeyUsageExtension with the passed bit settings. The criticality
105: * is set to true.
106: *
107: * @param bitString the bits to be set for the extension.
108: */
109: public KeyUsageExtension(byte[] bitString) throws IOException {
110: this .bitString = new BitArray(bitString.length * 8, bitString)
111: .toBooleanArray();
112: this .extensionId = PKIXExtensions.KeyUsage_Id;
113: this .critical = true;
114: encodeThis();
115: }
116:
117: /**
118: * Create a KeyUsageExtension with the passed bit settings. The criticality
119: * is set to true.
120: *
121: * @param bitString the bits to be set for the extension.
122: */
123: public KeyUsageExtension(boolean[] bitString) throws IOException {
124: this .bitString = bitString;
125: this .extensionId = PKIXExtensions.KeyUsage_Id;
126: this .critical = true;
127: encodeThis();
128: }
129:
130: /**
131: * Create a KeyUsageExtension with the passed bit settings. The criticality
132: * is set to true.
133: *
134: * @param bitString the bits to be set for the extension.
135: */
136: public KeyUsageExtension(BitArray bitString) throws IOException {
137: this .bitString = bitString.toBooleanArray();
138: this .extensionId = PKIXExtensions.KeyUsage_Id;
139: this .critical = true;
140: encodeThis();
141: }
142:
143: /**
144: * Create the extension from the passed DER encoded value of the same.
145: * The DER encoded value may be wrapped in an OCTET STRING.
146: *
147: * @param critical true if the extension is to be treated as critical.
148: * @param value an array of DER encoded bytes of the actual value (possibly
149: * wrapped in an OCTET STRING).
150: * @exception ClassCastException if value is not an array of bytes
151: * @exception IOException on error.
152: */
153: public KeyUsageExtension(Boolean critical, Object value)
154: throws IOException {
155: this .extensionId = PKIXExtensions.KeyUsage_Id;
156: this .critical = critical.booleanValue();
157: /*
158: * The following check should be activated again after
159: * the PKIX profiling work becomes standard and the check
160: * is not a barrier to interoperability !
161: * if (!this.critical) {
162: * throw new IOException("KeyUsageExtension not marked critical,"
163: * + " invalid profile.");
164: * }
165: */
166: byte[] extValue = (byte[]) value;
167: if (extValue[0] == DerValue.tag_OctetString) {
168: this .extensionValue = new DerValue(extValue)
169: .getOctetString();
170: } else {
171: this .extensionValue = extValue;
172: }
173: DerValue val = new DerValue(this .extensionValue);
174: this .bitString = val.getUnalignedBitString().toBooleanArray();
175: }
176:
177: /**
178: * Create a default key usage.
179: */
180: public KeyUsageExtension() {
181: extensionId = PKIXExtensions.KeyUsage_Id;
182: critical = true;
183: bitString = new boolean[0];
184: }
185:
186: /**
187: * Set the attribute value.
188: */
189: public void set(String name, Object obj) throws IOException {
190: if (!(obj instanceof Boolean)) {
191: throw new IOException("Attribute must be of type Boolean.");
192: }
193: boolean val = ((Boolean) obj).booleanValue();
194: if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
195: set(0, val);
196: } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
197: set(1, val);
198: } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
199: set(2, val);
200: } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
201: set(3, val);
202: } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
203: set(4, val);
204: } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
205: set(5, val);
206: } else if (name.equalsIgnoreCase(CRL_SIGN)) {
207: set(6, val);
208: } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
209: set(7, val);
210: } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
211: set(8, val);
212: } else {
213: throw new IOException("Attribute name not recognized by"
214: + " CertAttrSet:KeyUsage.");
215: }
216: encodeThis();
217: }
218:
219: /**
220: * Get the attribute value.
221: */
222: public Object get(String name) throws IOException {
223: if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
224: return Boolean.valueOf(isSet(0));
225: } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
226: return Boolean.valueOf(isSet(1));
227: } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
228: return Boolean.valueOf(isSet(2));
229: } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
230: return Boolean.valueOf(isSet(3));
231: } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
232: return Boolean.valueOf(isSet(4));
233: } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
234: return Boolean.valueOf(isSet(5));
235: } else if (name.equalsIgnoreCase(CRL_SIGN)) {
236: return Boolean.valueOf(isSet(6));
237: } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
238: return Boolean.valueOf(isSet(7));
239: } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
240: return Boolean.valueOf(isSet(8));
241: } else {
242: throw new IOException("Attribute name not recognized by"
243: + " CertAttrSet:KeyUsage.");
244: }
245: }
246:
247: /**
248: * Delete the attribute value.
249: */
250: public void delete(String name) throws IOException {
251: if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
252: set(0, false);
253: } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
254: set(1, false);
255: } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
256: set(2, false);
257: } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
258: set(3, false);
259: } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
260: set(4, false);
261: } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
262: set(5, false);
263: } else if (name.equalsIgnoreCase(CRL_SIGN)) {
264: set(6, false);
265: } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
266: set(7, false);
267: } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
268: set(8, false);
269: } else {
270: throw new IOException("Attribute name not recognized by"
271: + " CertAttrSet:KeyUsage.");
272: }
273: encodeThis();
274: }
275:
276: /**
277: * Returns a printable representation of the KeyUsage.
278: */
279: public String toString() {
280: String s = super .toString() + "KeyUsage [\n";
281:
282: try {
283: if (isSet(0)) {
284: s += " DigitalSignature\n";
285: }
286: if (isSet(1)) {
287: s += " Non_repudiation\n";
288: }
289: if (isSet(2)) {
290: s += " Key_Encipherment\n";
291: }
292: if (isSet(3)) {
293: s += " Data_Encipherment\n";
294: }
295: if (isSet(4)) {
296: s += " Key_Agreement\n";
297: }
298: if (isSet(5)) {
299: s += " Key_CertSign\n";
300: }
301: if (isSet(6)) {
302: s += " Crl_Sign\n";
303: }
304: if (isSet(7)) {
305: s += " Encipher_Only\n";
306: }
307: if (isSet(8)) {
308: s += " Decipher_Only\n";
309: }
310: } catch (ArrayIndexOutOfBoundsException ex) {
311: }
312:
313: s += "]\n";
314:
315: return (s);
316: }
317:
318: /**
319: * Write the extension to the DerOutputStream.
320: *
321: * @param out the DerOutputStream to write the extension to.
322: * @exception IOException on encoding errors.
323: */
324: public void encode(OutputStream out) throws IOException {
325: DerOutputStream tmp = new DerOutputStream();
326:
327: if (this .extensionValue == null) {
328: this .extensionId = PKIXExtensions.KeyUsage_Id;
329: this .critical = true;
330: encodeThis();
331: }
332: super .encode(tmp);
333: out.write(tmp.toByteArray());
334: }
335:
336: /**
337: * Return an enumeration of names of attributes existing within this
338: * attribute.
339: */
340: public Enumeration<String> getElements() {
341: AttributeNameEnumeration elements = new AttributeNameEnumeration();
342: elements.addElement(DIGITAL_SIGNATURE);
343: elements.addElement(NON_REPUDIATION);
344: elements.addElement(KEY_ENCIPHERMENT);
345: elements.addElement(DATA_ENCIPHERMENT);
346: elements.addElement(KEY_AGREEMENT);
347: elements.addElement(KEY_CERTSIGN);
348: elements.addElement(CRL_SIGN);
349: elements.addElement(ENCIPHER_ONLY);
350: elements.addElement(DECIPHER_ONLY);
351:
352: return (elements.elements());
353: }
354:
355: public boolean[] getBits() {
356: return (boolean[]) bitString.clone();
357: }
358:
359: /**
360: * Return the name of this attribute.
361: */
362: public String getName() {
363: return (NAME);
364: }
365: }
|