1 /* 2 * Copyright (c) 1997, 2015, 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 (position < bitString.length) && 87 bitString[position]; 88 } 89 90 /** 91 * Set the bit at the specified position. 92 */ set(int position, boolean val)93 private void set(int position, boolean val) { 94 // enlarge bitString if necessary 95 if (position >= bitString.length) { 96 boolean[] tmp = new boolean[position+1]; 97 System.arraycopy(bitString, 0, tmp, 0, bitString.length); 98 bitString = tmp; 99 } 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 */ KeyUsageExtension(byte[] bitString)109 public KeyUsageExtension(byte[] bitString) throws IOException { 110 this.bitString = 111 new BitArray(bitString.length*8,bitString).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 */ KeyUsageExtension(boolean[] bitString)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 */ KeyUsageExtension(BitArray bitString)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 */ KeyUsageExtension(Boolean critical, Object value)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).getOctetString(); 169 } else { 170 this.extensionValue = extValue; 171 } 172 DerValue val = new DerValue(this.extensionValue); 173 this.bitString = val.getUnalignedBitString().toBooleanArray(); 174 } 175 176 /** 177 * Create a default key usage. 178 */ KeyUsageExtension()179 public KeyUsageExtension() { 180 extensionId = PKIXExtensions.KeyUsage_Id; 181 critical = true; 182 bitString = new boolean[0]; 183 } 184 185 /** 186 * Set the attribute value. 187 */ set(String name, Object obj)188 public void set(String name, Object obj) throws IOException { 189 if (!(obj instanceof Boolean)) { 190 throw new IOException("Attribute must be of type Boolean."); 191 } 192 boolean val = ((Boolean)obj).booleanValue(); 193 if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) { 194 set(0,val); 195 } else if (name.equalsIgnoreCase(NON_REPUDIATION)) { 196 set(1,val); 197 } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) { 198 set(2,val); 199 } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) { 200 set(3,val); 201 } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) { 202 set(4,val); 203 } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) { 204 set(5,val); 205 } else if (name.equalsIgnoreCase(CRL_SIGN)) { 206 set(6,val); 207 } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) { 208 set(7,val); 209 } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) { 210 set(8,val); 211 } else { 212 throw new IOException("Attribute name not recognized by" 213 + " CertAttrSet:KeyUsage."); 214 } 215 encodeThis(); 216 } 217 218 /** 219 * Get the attribute value. 220 */ get(String name)221 public Boolean get(String name) throws IOException { 222 if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) { 223 return Boolean.valueOf(isSet(0)); 224 } else if (name.equalsIgnoreCase(NON_REPUDIATION)) { 225 return Boolean.valueOf(isSet(1)); 226 } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) { 227 return Boolean.valueOf(isSet(2)); 228 } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) { 229 return Boolean.valueOf(isSet(3)); 230 } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) { 231 return Boolean.valueOf(isSet(4)); 232 } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) { 233 return Boolean.valueOf(isSet(5)); 234 } else if (name.equalsIgnoreCase(CRL_SIGN)) { 235 return Boolean.valueOf(isSet(6)); 236 } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) { 237 return Boolean.valueOf(isSet(7)); 238 } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) { 239 return Boolean.valueOf(isSet(8)); 240 } else { 241 throw new IOException("Attribute name not recognized by" 242 + " CertAttrSet:KeyUsage."); 243 } 244 } 245 246 /** 247 * Delete the attribute value. 248 */ delete(String name)249 public void delete(String name) throws IOException { 250 if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) { 251 set(0,false); 252 } else if (name.equalsIgnoreCase(NON_REPUDIATION)) { 253 set(1,false); 254 } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) { 255 set(2,false); 256 } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) { 257 set(3,false); 258 } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) { 259 set(4,false); 260 } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) { 261 set(5,false); 262 } else if (name.equalsIgnoreCase(CRL_SIGN)) { 263 set(6,false); 264 } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) { 265 set(7,false); 266 } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) { 267 set(8,false); 268 } else { 269 throw new IOException("Attribute name not recognized by" 270 + " CertAttrSet:KeyUsage."); 271 } 272 encodeThis(); 273 } 274 275 /** 276 * Returns a printable representation of the KeyUsage. 277 */ toString()278 public String toString() { 279 StringBuilder sb = new StringBuilder(); 280 sb.append(super.toString()); 281 sb.append("KeyUsage [\n"); 282 283 if (isSet(0)) { 284 sb.append(" DigitalSignature\n"); 285 } 286 if (isSet(1)) { 287 sb.append(" Non_repudiation\n"); 288 } 289 if (isSet(2)) { 290 sb.append(" Key_Encipherment\n"); 291 } 292 if (isSet(3)) { 293 sb.append(" Data_Encipherment\n"); 294 } 295 if (isSet(4)) { 296 sb.append(" Key_Agreement\n"); 297 } 298 if (isSet(5)) { 299 sb.append(" Key_CertSign\n"); 300 } 301 if (isSet(6)) { 302 sb.append(" Crl_Sign\n"); 303 } 304 if (isSet(7)) { 305 sb.append(" Encipher_Only\n"); 306 } 307 if (isSet(8)) { 308 sb.append(" Decipher_Only\n"); 309 } 310 sb.append("]\n"); 311 312 return sb.toString(); 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