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