View Javadoc
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
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 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      */
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 }