blob: 84c1d440abbfbe9859873778def284f5338f939e [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 * 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 */
55public class SubjectAlternativeNameExtension extends Extension
56implements 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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
198 public Object 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 */
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 */
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 */
234 public String getName() {
235 return (NAME);
236 }
237}