1 /* 2 * Copyright (c) 1997, 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.Enumeration; 31 32 import sun.security.util.*; 33 34 /** 35 * This represents the Subject Alternative Name Extension. 36 * 37 * This extension, if present, allows the subject to specify multiple 38 * alternative names. 39 * 40 * <p>Extensions are represented as a sequence of the extension identifier 41 * (Object Identifier), a boolean flag stating whether the extension is to 42 * be treated as being critical and the extension value itself (this is again 43 * a DER encoding of the extension value). 44 * <p> 45 * The ASN.1 syntax for this is: 46 * <pre> 47 * SubjectAltName ::= GeneralNames 48 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 49 * </pre> 50 * @author Amit Kapoor 51 * @author Hemma Prafullchandra 52 * @see Extension 53 * @see CertAttrSet 54 */ 55 public class SubjectAlternativeNameExtension extends Extension 56 implements CertAttrSet<String> { 57 /** 58 * Identifier for this attribute, to be used with the 59 * get, set, delete methods of Certificate, x509 type. 60 */ 61 public static final String IDENT = 62 "x509.info.extensions.SubjectAlternativeName"; 63 /** 64 * Attribute names. 65 */ 66 public static final String NAME = "SubjectAlternativeName"; 67 public static final String SUBJECT_NAME = "subject_name"; 68 69 // private data members 70 GeneralNames names = null; 71 72 // Encode this extension encodeThis()73 private void encodeThis() throws IOException { 74 if (names == null || names.isEmpty()) { 75 this.extensionValue = null; 76 return; 77 } 78 DerOutputStream os = new DerOutputStream(); 79 names.encode(os); 80 this.extensionValue = os.toByteArray(); 81 } 82 83 /** 84 * Create a SubjectAlternativeNameExtension with the passed GeneralNames. 85 * The extension is marked non-critical. 86 * 87 * @param names the GeneralNames for the subject. 88 * @exception IOException on error. 89 */ SubjectAlternativeNameExtension(GeneralNames names)90 public SubjectAlternativeNameExtension(GeneralNames names) 91 throws IOException { 92 this(Boolean.FALSE, names); 93 } 94 95 /** 96 * Create a SubjectAlternativeNameExtension with the specified 97 * criticality and GeneralNames. 98 * 99 * @param critical true if the extension is to be treated as critical. 100 * @param names the GeneralNames for the subject. 101 * @exception IOException on error. 102 */ SubjectAlternativeNameExtension(Boolean critical, GeneralNames names)103 public SubjectAlternativeNameExtension(Boolean critical, GeneralNames names) 104 throws IOException { 105 this.names = names; 106 this.extensionId = PKIXExtensions.SubjectAlternativeName_Id; 107 this.critical = critical.booleanValue(); 108 encodeThis(); 109 } 110 111 /** 112 * Create a default SubjectAlternativeNameExtension. The extension 113 * is marked non-critical. 114 */ SubjectAlternativeNameExtension()115 public SubjectAlternativeNameExtension() { 116 extensionId = PKIXExtensions.SubjectAlternativeName_Id; 117 critical = false; 118 names = new GeneralNames(); 119 } 120 121 /** 122 * Create the extension from the passed DER encoded value. 123 * 124 * @param critical true if the extension is to be treated as critical. 125 * @param value an array of DER encoded bytes of the actual value. 126 * @exception ClassCastException if value is not an array of bytes 127 * @exception IOException on error. 128 */ SubjectAlternativeNameExtension(Boolean critical, Object value)129 public SubjectAlternativeNameExtension(Boolean critical, Object value) 130 throws IOException { 131 this.extensionId = PKIXExtensions.SubjectAlternativeName_Id; 132 this.critical = critical.booleanValue(); 133 134 this.extensionValue = (byte[]) value; 135 DerValue val = new DerValue(this.extensionValue); 136 if (val.data == null) { 137 names = new GeneralNames(); 138 return; 139 } 140 141 names = new GeneralNames(val); 142 } 143 144 /** 145 * Returns a printable representation of the SubjectAlternativeName. 146 */ toString()147 public String toString() { 148 149 String result = super.toString() + "SubjectAlternativeName [\n"; 150 if(names == null) { 151 result += " null\n"; 152 } else { 153 for(GeneralName name: names.names()) { 154 result += " "+name+"\n"; 155 } 156 } 157 result += "]\n"; 158 return result; 159 } 160 161 /** 162 * Write the extension to the OutputStream. 163 * 164 * @param out the OutputStream to write the extension to. 165 * @exception IOException on encoding errors. 166 */ encode(OutputStream out)167 public void encode(OutputStream out) throws IOException { 168 DerOutputStream tmp = new DerOutputStream(); 169 if (extensionValue == null) { 170 extensionId = PKIXExtensions.SubjectAlternativeName_Id; 171 critical = false; 172 encodeThis(); 173 } 174 super.encode(tmp); 175 out.write(tmp.toByteArray()); 176 } 177 178 /** 179 * Set the attribute value. 180 */ set(String name, Object obj)181 public void set(String name, Object obj) throws IOException { 182 if (name.equalsIgnoreCase(SUBJECT_NAME)) { 183 if (!(obj instanceof GeneralNames)) { 184 throw new IOException("Attribute value should be of " + 185 "type GeneralNames."); 186 } 187 names = (GeneralNames)obj; 188 } else { 189 throw new IOException("Attribute name not recognized by " + 190 "CertAttrSet:SubjectAlternativeName."); 191 } 192 encodeThis(); 193 } 194 195 /** 196 * Get the attribute value. 197 */ get(String name)198 public GeneralNames get(String name) throws IOException { 199 if (name.equalsIgnoreCase(SUBJECT_NAME)) { 200 return (names); 201 } else { 202 throw new IOException("Attribute name not recognized by " + 203 "CertAttrSet:SubjectAlternativeName."); 204 } 205 } 206 207 /** 208 * Delete the attribute value. 209 */ delete(String name)210 public void delete(String name) throws IOException { 211 if (name.equalsIgnoreCase(SUBJECT_NAME)) { 212 names = null; 213 } else { 214 throw new IOException("Attribute name not recognized by " + 215 "CertAttrSet:SubjectAlternativeName."); 216 } 217 encodeThis(); 218 } 219 220 /** 221 * Return an enumeration of names of attributes existing within this 222 * attribute. 223 */ getElements()224 public Enumeration<String> getElements() { 225 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 226 elements.addElement(SUBJECT_NAME); 227 228 return (elements.elements()); 229 } 230 231 /** 232 * Return the name of this attribute. 233 */ getName()234 public String getName() { 235 return (NAME); 236 } 237 } 238