blob: 1f595f318b1830dc13ac1706cc7c1d4961a11554 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-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.x509;
27
28import java.io.IOException;
29import java.io.OutputStream;
30import java.util.Enumeration;
31
32import sun.security.util.*;
33
34/**
35 * Represent the Key Usage Extension.
36 *
37 * <p>This extension, if present, defines the purpose (e.g., encipherment,
38 * signature, certificate signing) of the key contained in the certificate.
39 * The usage restriction might be employed when a multipurpose key is to be
40 * restricted (e.g., when an RSA key should be used only for signing or only
41 * for key encipherment).
42 *
43 * @author Amit Kapoor
44 * @author Hemma Prafullchandra
45 * @see Extension
46 * @see CertAttrSet
47 */
48public class KeyUsageExtension extends Extension
49implements CertAttrSet<String> {
50
51 /**
52 * Identifier for this attribute, to be used with the
53 * get, set, delete methods of Certificate, x509 type.
54 */
55 public static final String IDENT = "x509.info.extensions.KeyUsage";
56 /**
57 * Attribute names.
58 */
59 public static final String NAME = "KeyUsage";
60 public static final String DIGITAL_SIGNATURE = "digital_signature";
61 public static final String NON_REPUDIATION = "non_repudiation";
62 public static final String KEY_ENCIPHERMENT = "key_encipherment";
63 public static final String DATA_ENCIPHERMENT = "data_encipherment";
64 public static final String KEY_AGREEMENT = "key_agreement";
65 public static final String KEY_CERTSIGN = "key_certsign";
66 public static final String CRL_SIGN = "crl_sign";
67 public static final String ENCIPHER_ONLY = "encipher_only";
68 public static final String DECIPHER_ONLY = "decipher_only";
69
70 // Private data members
71 private boolean[] bitString;
72
73 // Encode this extension value
74 private void encodeThis() throws IOException {
75 DerOutputStream os = new DerOutputStream();
76 os.putTruncatedUnalignedBitString(new BitArray(this.bitString));
77 this.extensionValue = os.toByteArray();
78 }
79
80 /**
81 * Check if bit is set.
82 *
83 * @param position the position in the bit string to check.
84 */
85 private boolean isSet(int position) {
86 return bitString[position];
87 }
88
89 /**
90 * Set the bit at the specified position.
91 */
92 private void set(int position, boolean val) {
93 // enlarge bitString if necessary
94 if (position >= bitString.length) {
95 boolean[] tmp = new boolean[position+1];
96 System.arraycopy(bitString, 0, tmp, 0, bitString.length);
97 bitString = tmp;
98 }
99 bitString[position] = val;
100 }
101
102 /**
103 * Create a KeyUsageExtension with the passed bit settings. The criticality
104 * is set to true.
105 *
106 * @param bitString the bits to be set for the extension.
107 */
108 public KeyUsageExtension(byte[] bitString) throws IOException {
109 this.bitString =
110 new BitArray(bitString.length*8,bitString).toBooleanArray();
111 this.extensionId = PKIXExtensions.KeyUsage_Id;
112 this.critical = true;
113 encodeThis();
114 }
115
116 /**
117 * Create a KeyUsageExtension with the passed bit settings. The criticality
118 * is set to true.
119 *
120 * @param bitString the bits to be set for the extension.
121 */
122 public KeyUsageExtension(boolean[] bitString) throws IOException {
123 this.bitString = bitString;
124 this.extensionId = PKIXExtensions.KeyUsage_Id;
125 this.critical = true;
126 encodeThis();
127 }
128
129 /**
130 * Create a KeyUsageExtension with the passed bit settings. The criticality
131 * is set to true.
132 *
133 * @param bitString the bits to be set for the extension.
134 */
135 public KeyUsageExtension(BitArray bitString) throws IOException {
136 this.bitString = bitString.toBooleanArray();
137 this.extensionId = PKIXExtensions.KeyUsage_Id;
138 this.critical = true;
139 encodeThis();
140 }
141
142 /**
143 * Create the extension from the passed DER encoded value of the same.
144 * The DER encoded value may be wrapped in an OCTET STRING.
145 *
146 * @param critical true if the extension is to be treated as critical.
147 * @param value an array of DER encoded bytes of the actual value (possibly
148 * wrapped in an OCTET STRING).
149 * @exception ClassCastException if value is not an array of bytes
150 * @exception IOException on error.
151 */
152 public KeyUsageExtension(Boolean critical, Object value)
153 throws IOException {
154 this.extensionId = PKIXExtensions.KeyUsage_Id;
155 this.critical = critical.booleanValue();
156 /*
157 * The following check should be activated again after
158 * the PKIX profiling work becomes standard and the check
159 * is not a barrier to interoperability !
160 * if (!this.critical) {
161 * throw new IOException("KeyUsageExtension not marked critical,"
162 * + " invalid profile.");
163 * }
164 */
165 byte[] extValue = (byte[]) value;
166 if (extValue[0] == DerValue.tag_OctetString) {
167 this.extensionValue = new DerValue(extValue).getOctetString();
168 } else {
169 this.extensionValue = extValue;
170 }
171 DerValue val = new DerValue(this.extensionValue);
172 this.bitString = val.getUnalignedBitString().toBooleanArray();
173 }
174
175 /**
176 * Create a default key usage.
177 */
178 public KeyUsageExtension() {
179 extensionId = PKIXExtensions.KeyUsage_Id;
180 critical = true;
181 bitString = new boolean[0];
182 }
183
184 /**
185 * Set the attribute value.
186 */
187 public void set(String name, Object obj) throws IOException {
188 if (!(obj instanceof Boolean)) {
189 throw new IOException("Attribute must be of type Boolean.");
190 }
191 boolean val = ((Boolean)obj).booleanValue();
192 if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
193 set(0,val);
194 } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
195 set(1,val);
196 } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
197 set(2,val);
198 } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
199 set(3,val);
200 } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
201 set(4,val);
202 } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
203 set(5,val);
204 } else if (name.equalsIgnoreCase(CRL_SIGN)) {
205 set(6,val);
206 } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
207 set(7,val);
208 } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
209 set(8,val);
210 } else {
211 throw new IOException("Attribute name not recognized by"
212 + " CertAttrSet:KeyUsage.");
213 }
214 encodeThis();
215 }
216
217 /**
218 * Get the attribute value.
219 */
220 public Object get(String name) throws IOException {
221 if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
222 return Boolean.valueOf(isSet(0));
223 } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
224 return Boolean.valueOf(isSet(1));
225 } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
226 return Boolean.valueOf(isSet(2));
227 } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
228 return Boolean.valueOf(isSet(3));
229 } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
230 return Boolean.valueOf(isSet(4));
231 } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
232 return Boolean.valueOf(isSet(5));
233 } else if (name.equalsIgnoreCase(CRL_SIGN)) {
234 return Boolean.valueOf(isSet(6));
235 } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
236 return Boolean.valueOf(isSet(7));
237 } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
238 return Boolean.valueOf(isSet(8));
239 } else {
240 throw new IOException("Attribute name not recognized by"
241 + " CertAttrSet:KeyUsage.");
242 }
243 }
244
245 /**
246 * Delete the attribute value.
247 */
248 public void delete(String name) throws IOException {
249 if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
250 set(0,false);
251 } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
252 set(1,false);
253 } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
254 set(2,false);
255 } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
256 set(3,false);
257 } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
258 set(4,false);
259 } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
260 set(5,false);
261 } else if (name.equalsIgnoreCase(CRL_SIGN)) {
262 set(6,false);
263 } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
264 set(7,false);
265 } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
266 set(8,false);
267 } else {
268 throw new IOException("Attribute name not recognized by"
269 + " CertAttrSet:KeyUsage.");
270 }
271 encodeThis();
272 }
273
274 /**
275 * Returns a printable representation of the KeyUsage.
276 */
277 public String toString() {
278 String s = super.toString() + "KeyUsage [\n";
279
280 try {
281 if (isSet(0)) {
282 s += " DigitalSignature\n";
283 }
284 if (isSet(1)) {
285 s += " Non_repudiation\n";
286 }
287 if (isSet(2)) {
288 s += " Key_Encipherment\n";
289 }
290 if (isSet(3)) {
291 s += " Data_Encipherment\n";
292 }
293 if (isSet(4)) {
294 s += " Key_Agreement\n";
295 }
296 if (isSet(5)) {
297 s += " Key_CertSign\n";
298 }
299 if (isSet(6)) {
300 s += " Crl_Sign\n";
301 }
302 if (isSet(7)) {
303 s += " Encipher_Only\n";
304 }
305 if (isSet(8)) {
306 s += " Decipher_Only\n";
307 }
308 } catch (ArrayIndexOutOfBoundsException ex) {}
309
310 s += "]\n";
311
312 return (s);
313 }
314
315 /**
316 * Write the extension to the DerOutputStream.
317 *
318 * @param out the DerOutputStream to write the extension to.
319 * @exception IOException on encoding errors.
320 */
321 public void encode(OutputStream out) throws IOException {
322 DerOutputStream tmp = new DerOutputStream();
323
324 if (this.extensionValue == null) {
325 this.extensionId = PKIXExtensions.KeyUsage_Id;
326 this.critical = true;
327 encodeThis();
328 }
329 super.encode(tmp);
330 out.write(tmp.toByteArray());
331 }
332
333 /**
334 * Return an enumeration of names of attributes existing within this
335 * attribute.
336 */
337 public Enumeration<String> getElements() {
338 AttributeNameEnumeration elements = new AttributeNameEnumeration();
339 elements.addElement(DIGITAL_SIGNATURE);
340 elements.addElement(NON_REPUDIATION);
341 elements.addElement(KEY_ENCIPHERMENT);
342 elements.addElement(DATA_ENCIPHERMENT);
343 elements.addElement(KEY_AGREEMENT);
344 elements.addElement(KEY_CERTSIGN);
345 elements.addElement(CRL_SIGN);
346 elements.addElement(ENCIPHER_ONLY);
347 elements.addElement(DECIPHER_ONLY);
348
349 return (elements.elements());
350 }
351
352
353 public boolean[] getBits() {
354 return bitString.clone();
355 }
356
357 /**
358 * Return the name of this attribute.
359 */
360 public String getName() {
361 return (NAME);
362 }
363}