1 /* 2 * Copyright (c) 2000, 2011, 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.ArrayList; 31 import java.util.Enumeration; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Vector; 36 37 import sun.security.util.DerValue; 38 import sun.security.util.DerOutputStream; 39 import sun.security.util.ObjectIdentifier; 40 41 /** 42 * This class defines the Extended Key Usage Extension, which 43 * indicates one or more purposes for which the certified public key 44 * may be used, in addition to or in place of the basic purposes 45 * indicated in the key usage extension field. This field is defined 46 * as follows:<p> 47 * 48 * id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37}<p> 49 * 50 * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId<p> 51 * 52 * KeyPurposeId ::= OBJECT IDENTIFIER<p> 53 * 54 * Key purposes may be defined by any organization with a need. Object 55 * identifiers used to identify key purposes shall be assigned in 56 * accordance with IANA or ITU-T Rec. X.660 | ISO/IEC/ITU 9834-1.<p> 57 * 58 * This extension may, at the option of the certificate issuer, be 59 * either critical or non-critical.<p> 60 * 61 * If the extension is flagged critical, then the certificate MUST be 62 * used only for one of the purposes indicated.<p> 63 * 64 * If the extension is flagged non-critical, then it indicates the 65 * intended purpose or purposes of the key, and may be used in finding 66 * the correct key/certificate of an entity that has multiple 67 * keys/certificates. It is an advisory field and does not imply that 68 * usage of the key is restricted by the certification authority to 69 * the purpose indicated. Certificate using applications may 70 * nevertheless require that a particular purpose be indicated in 71 * order for the certificate to be acceptable to that application.<p> 72 73 * If a certificate contains both a critical key usage field and a 74 * critical extended key usage field, then both fields MUST be 75 * processed independently and the certificate MUST only be used for a 76 * purpose consistent with both fields. If there is no purpose 77 * consistent with both fields, then the certificate MUST NOT be used 78 * for any purpose.<p> 79 * 80 * @since 1.4 81 */ 82 public class ExtendedKeyUsageExtension extends Extension 83 implements CertAttrSet<String> { 84 85 /** 86 * Identifier for this attribute, to be used with the 87 * get, set, delete methods of Certificate, x509 type. 88 */ 89 public static final String IDENT = "x509.info.extensions.ExtendedKeyUsage"; 90 91 /** 92 * Attribute names. 93 */ 94 public static final String NAME = "ExtendedKeyUsage"; 95 public static final String USAGES = "usages"; 96 97 // OID defined in RFC 3280 Sections 4.2.1.13 98 // more from http://www.alvestrand.no/objectid/1.3.6.1.5.5.7.3.html 99 private static final Map <ObjectIdentifier, String> map = 100 new HashMap <ObjectIdentifier, String> (); 101 102 private static final int[] anyExtendedKeyUsageOidData = {2, 5, 29, 37, 0}; 103 private static final int[] serverAuthOidData = {1, 3, 6, 1, 5, 5, 7, 3, 1}; 104 private static final int[] clientAuthOidData = {1, 3, 6, 1, 5, 5, 7, 3, 2}; 105 private static final int[] codeSigningOidData = {1, 3, 6, 1, 5, 5, 7, 3, 3}; 106 private static final int[] emailProtectionOidData = {1, 3, 6, 1, 5, 5, 7, 3, 4}; 107 private static final int[] ipsecEndSystemOidData = {1, 3, 6, 1, 5, 5, 7, 3, 5}; 108 private static final int[] ipsecTunnelOidData = {1, 3, 6, 1, 5, 5, 7, 3, 6}; 109 private static final int[] ipsecUserOidData = {1, 3, 6, 1, 5, 5, 7, 3, 7}; 110 private static final int[] timeStampingOidData = {1, 3, 6, 1, 5, 5, 7, 3, 8}; 111 private static final int[] OCSPSigningOidData = {1, 3, 6, 1, 5, 5, 7, 3, 9}; 112 113 static { ObjectIdentifier.newInternal(anyExtendedKeyUsageOidData)114 map.put(ObjectIdentifier.newInternal(anyExtendedKeyUsageOidData), "anyExtendedKeyUsage"); ObjectIdentifier.newInternal(serverAuthOidData)115 map.put(ObjectIdentifier.newInternal(serverAuthOidData), "serverAuth"); ObjectIdentifier.newInternal(clientAuthOidData)116 map.put(ObjectIdentifier.newInternal(clientAuthOidData), "clientAuth"); ObjectIdentifier.newInternal(codeSigningOidData)117 map.put(ObjectIdentifier.newInternal(codeSigningOidData), "codeSigning"); ObjectIdentifier.newInternal(emailProtectionOidData)118 map.put(ObjectIdentifier.newInternal(emailProtectionOidData), "emailProtection"); ObjectIdentifier.newInternal(ipsecEndSystemOidData)119 map.put(ObjectIdentifier.newInternal(ipsecEndSystemOidData), "ipsecEndSystem"); ObjectIdentifier.newInternal(ipsecTunnelOidData)120 map.put(ObjectIdentifier.newInternal(ipsecTunnelOidData), "ipsecTunnel"); ObjectIdentifier.newInternal(ipsecUserOidData)121 map.put(ObjectIdentifier.newInternal(ipsecUserOidData), "ipsecUser"); ObjectIdentifier.newInternal(timeStampingOidData)122 map.put(ObjectIdentifier.newInternal(timeStampingOidData), "timeStamping"); ObjectIdentifier.newInternal(OCSPSigningOidData)123 map.put(ObjectIdentifier.newInternal(OCSPSigningOidData), "OCSPSigning"); 124 }; 125 126 /** 127 * Vector of KeyUsages for this object. 128 */ 129 private Vector<ObjectIdentifier> keyUsages; 130 131 // Encode this extension value. encodeThis()132 private void encodeThis() throws IOException { 133 if (keyUsages == null || keyUsages.isEmpty()) { 134 this.extensionValue = null; 135 return; 136 } 137 DerOutputStream os = new DerOutputStream(); 138 DerOutputStream tmp = new DerOutputStream(); 139 140 for (int i = 0; i < keyUsages.size(); i++) { 141 tmp.putOID(keyUsages.elementAt(i)); 142 } 143 144 os.write(DerValue.tag_Sequence, tmp); 145 this.extensionValue = os.toByteArray(); 146 } 147 148 /** 149 * Create a ExtendedKeyUsageExtension object from 150 * a Vector of Key Usages; the criticality is set to false. 151 * 152 * @param keyUsages the Vector of KeyUsages (ObjectIdentifiers) 153 */ ExtendedKeyUsageExtension(Vector<ObjectIdentifier> keyUsages)154 public ExtendedKeyUsageExtension(Vector<ObjectIdentifier> keyUsages) 155 throws IOException { 156 this(Boolean.FALSE, keyUsages); 157 } 158 159 /** 160 * Create a ExtendedKeyUsageExtension object from 161 * a Vector of KeyUsages with specified criticality. 162 * 163 * @param critical true if the extension is to be treated as critical. 164 * @param keyUsages the Vector of KeyUsages (ObjectIdentifiers) 165 */ ExtendedKeyUsageExtension(Boolean critical, Vector<ObjectIdentifier> keyUsages)166 public ExtendedKeyUsageExtension(Boolean critical, Vector<ObjectIdentifier> keyUsages) 167 throws IOException { 168 this.keyUsages = keyUsages; 169 this.extensionId = PKIXExtensions.ExtendedKeyUsage_Id; 170 this.critical = critical.booleanValue(); 171 encodeThis(); 172 } 173 174 /** 175 * Create the extension from its DER encoded value and criticality. 176 * 177 * @param critical true if the extension is to be treated as critical. 178 * @param value an array of DER encoded bytes of the actual value. 179 * @exception ClassCastException if value is not an array of bytes 180 * @exception IOException on error. 181 */ ExtendedKeyUsageExtension(Boolean critical, Object value)182 public ExtendedKeyUsageExtension(Boolean critical, Object value) 183 throws IOException { 184 this.extensionId = PKIXExtensions.ExtendedKeyUsage_Id; 185 this.critical = critical.booleanValue(); 186 this.extensionValue = (byte[]) value; 187 DerValue val = new DerValue(this.extensionValue); 188 if (val.tag != DerValue.tag_Sequence) { 189 throw new IOException("Invalid encoding for " + 190 "ExtendedKeyUsageExtension."); 191 } 192 keyUsages = new Vector<ObjectIdentifier>(); 193 while (val.data.available() != 0) { 194 DerValue seq = val.data.getDerValue(); 195 ObjectIdentifier usage = seq.getOID(); 196 keyUsages.addElement(usage); 197 } 198 } 199 200 /** 201 * Return the extension as user readable string. 202 */ toString()203 public String toString() { 204 if (keyUsages == null) return ""; 205 String usage = " "; 206 boolean first = true; 207 for (ObjectIdentifier oid: keyUsages) { 208 if(!first) { 209 usage += "\n "; 210 } 211 212 String result = map.get(oid); 213 if (result != null) { 214 usage += result; 215 } else { 216 usage += oid.toString(); 217 } 218 first = false; 219 } 220 return super.toString() + "ExtendedKeyUsages [\n" 221 + usage + "\n]\n"; 222 } 223 224 /** 225 * Write the extension to the DerOutputStream. 226 * 227 * @param out the DerOutputStream to write the extension to. 228 * @exception IOException on encoding errors. 229 */ encode(OutputStream out)230 public void encode(OutputStream out) throws IOException { 231 DerOutputStream tmp = new DerOutputStream(); 232 if (extensionValue == null) { 233 extensionId = PKIXExtensions.ExtendedKeyUsage_Id; 234 critical = false; 235 encodeThis(); 236 } 237 super.encode(tmp); 238 out.write(tmp.toByteArray()); 239 } 240 241 /** 242 * Set the attribute value. 243 */ 244 @SuppressWarnings("unchecked") // Checked with instanceof set(String name, Object obj)245 public void set(String name, Object obj) throws IOException { 246 if (name.equalsIgnoreCase(USAGES)) { 247 if (!(obj instanceof Vector)) { 248 throw new IOException("Attribute value should be of type Vector."); 249 } 250 this.keyUsages = (Vector<ObjectIdentifier>)obj; 251 } else { 252 throw new IOException("Attribute name [" + name + 253 "] not recognized by " + 254 "CertAttrSet:ExtendedKeyUsageExtension."); 255 } 256 encodeThis(); 257 } 258 259 /** 260 * Get the attribute value. 261 */ get(String name)262 public Vector<ObjectIdentifier> get(String name) throws IOException { 263 if (name.equalsIgnoreCase(USAGES)) { 264 //XXXX May want to consider cloning this 265 return keyUsages; 266 } else { 267 throw new IOException("Attribute name [" + name + 268 "] not recognized by " + 269 "CertAttrSet:ExtendedKeyUsageExtension."); 270 } 271 } 272 273 /** 274 * Delete the attribute value. 275 */ delete(String name)276 public void delete(String name) throws IOException { 277 if (name.equalsIgnoreCase(USAGES)) { 278 keyUsages = null; 279 } else { 280 throw new IOException("Attribute name [" + name + 281 "] not recognized by " + 282 "CertAttrSet:ExtendedKeyUsageExtension."); 283 } 284 encodeThis(); 285 } 286 287 /** 288 * Return an enumeration of names of attributes existing within this 289 * attribute. 290 */ getElements()291 public Enumeration<String> getElements() { 292 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 293 elements.addElement(USAGES); 294 295 return (elements.elements()); 296 } 297 298 /** 299 * Return the name of this attribute. 300 */ getName()301 public String getName() { 302 return (NAME); 303 } 304 getExtendedKeyUsage()305 public List<String> getExtendedKeyUsage() { 306 List<String> al = new ArrayList<String>(keyUsages.size()); 307 for (ObjectIdentifier oid : keyUsages) { 308 al.add(oid.toString()); 309 } 310 return al; 311 } 312 313 } 314