1 /* 2 * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.x509; 27 28 import java.io.IOException; 29 import java.io.OutputStream; 30 import java.util.Enumeration; 31 32 import 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 */ 48 public class KeyUsageExtension extends Extension 49 implements 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 encodeThis()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 */ isSet(int position)85 private boolean isSet(int position) { 86 return bitString[position]; 87 } 88 89 /** 90 * Set the bit at the specified position. 91 */ set(int position, boolean val)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 */ KeyUsageExtension(byte[] bitString)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 */ KeyUsageExtension(boolean[] bitString)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 */ KeyUsageExtension(BitArray bitString)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 */ KeyUsageExtension(Boolean critical, Object value)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 */ KeyUsageExtension()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 */ set(String name, Object obj)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 */ get(String name)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 */ delete(String name)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 */ toString()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 */ encode(OutputStream out)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 */ getElements()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 getBits()353 public boolean[] getBits() { 354 return bitString.clone(); 355 } 356 357 /** 358 * Return the name of this attribute. 359 */ getName()360 public String getName() { 361 return (NAME); 362 } 363 } 364