View Javadoc
1   /*
2    * Copyright (c) 1998, 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.lang.reflect.Constructor;
30  import java.util.Arrays;
31  
32  import sun.security.util.*;
33  
34  /**
35   * This class represents the OtherName as required by the GeneralNames
36   * ASN.1 object. It supplies the generic framework to allow specific
37   * Other Name types, and also provides minimal support for unrecognized
38   * Other Name types.
39   *
40   * The ASN.1 definition for OtherName is:
41   * <pre>
42   * OtherName ::= SEQUENCE {
43   *     type-id    OBJECT IDENTIFIER,
44   *     value      [0] EXPLICIT ANY DEFINED BY type-id
45   * }
46   * </pre>
47   * @author Hemma Prafullchandra
48   */
49  public class OtherName implements GeneralNameInterface {
50  
51      private String name;
52      private ObjectIdentifier oid;
53      private byte[] nameValue = null;
54      private GeneralNameInterface gni = null;
55  
56      private static final byte TAG_VALUE = 0;
57  
58      private int myhash = -1;
59  
60      /**
61       * Create the OtherName object from a passed ObjectIdentfier and
62       * byte array name value
63       *
64       * @param oid ObjectIdentifier of this OtherName object
65       * @param value the DER-encoded value of the OtherName
66       * @throws IOException on error
67       */
68      public OtherName(ObjectIdentifier oid, byte[] value) throws IOException {
69          if (oid == null || value == null) {
70              throw new NullPointerException("parameters may not be null");
71          }
72          this.oid = oid;
73          this.nameValue = value;
74          gni = getGNI(oid, value);
75          if (gni != null) {
76              name = gni.toString();
77          } else {
78              name = "Unrecognized ObjectIdentifier: " + oid.toString();
79          }
80      }
81  
82      /**
83       * Create the OtherName object from the passed encoded Der value.
84       *
85       * @param derValue the encoded DER OtherName.
86       * @exception IOException on error.
87       */
88      public OtherName(DerValue derValue) throws IOException {
89          DerInputStream in = derValue.toDerInputStream();
90  
91          oid = in.getOID();
92          DerValue val = in.getDerValue();
93          nameValue = val.toByteArray();
94          gni = getGNI(oid, nameValue);
95          if (gni != null) {
96              name = gni.toString();
97          } else {
98              name = "Unrecognized ObjectIdentifier: " + oid.toString();
99          }
100     }
101 
102     /**
103      * Get ObjectIdentifier
104      */
105     public ObjectIdentifier getOID() {
106         //XXXX May want to consider cloning this
107         return oid;
108     }
109 
110     /**
111      * Get name value
112      */
113     public byte[] getNameValue() {
114         return nameValue.clone();
115     }
116 
117     /**
118      * Get GeneralNameInterface
119      */
120     private GeneralNameInterface getGNI(ObjectIdentifier oid, byte[] nameValue)
121             throws IOException {
122         try {
123             Class<?> extClass = OIDMap.getClass(oid);
124             if (extClass == null) {   // Unsupported OtherName
125                 return null;
126             }
127             Class<?>[] params = { Object.class };
128             Constructor<?> cons = extClass.getConstructor(params);
129 
130             Object[] passed = new Object[] { nameValue };
131             GeneralNameInterface gni =
132                        (GeneralNameInterface)cons.newInstance(passed);
133             return gni;
134         } catch (Exception e) {
135             throw new IOException("Instantiation error: " + e, e);
136         }
137     }
138 
139     /**
140      * Return the type of the GeneralName.
141      */
142     public int getType() {
143         return GeneralNameInterface.NAME_ANY;
144     }
145 
146     /**
147      * Encode the Other name into the DerOutputStream.
148      *
149      * @param out the DER stream to encode the Other-Name to.
150      * @exception IOException on encoding errors.
151      */
152     public void encode(DerOutputStream out) throws IOException {
153         if (gni != null) {
154             // This OtherName has a supported class
155             gni.encode(out);
156             return;
157         } else {
158             // This OtherName has no supporting class
159             DerOutputStream tmp = new DerOutputStream();
160             tmp.putOID(oid);
161             tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_VALUE), nameValue);
162             out.write(DerValue.tag_Sequence, tmp);
163         }
164     }
165 
166     /**
167      * Compares this name with another, for equality.
168      *
169      * @return true iff the names are identical.
170      */
171     public boolean equals(Object other) {
172         if (this == other) {
173             return true;
174         }
175         if (!(other instanceof OtherName)) {
176             return false;
177         }
178         OtherName otherOther = (OtherName)other;
179         if (!(otherOther.oid.equals((Object)oid))) {
180             return false;
181         }
182         GeneralNameInterface otherGNI = null;
183         try {
184             otherGNI = getGNI(otherOther.oid, otherOther.nameValue);
185         } catch (IOException ioe) {
186             return false;
187         }
188 
189         boolean result;
190         if (otherGNI != null) {
191             try {
192                 result = (otherGNI.constrains(this) == NAME_MATCH);
193             } catch (UnsupportedOperationException ioe) {
194                 result = false;
195             }
196         } else {
197             result = Arrays.equals(nameValue, otherOther.nameValue);
198         }
199 
200         return result;
201     }
202 
203     /**
204      * Returns the hash code for this OtherName.
205      *
206      * @return a hash code value.
207      */
208     public int hashCode() {
209         if (myhash == -1) {
210             myhash = 37 + oid.hashCode();
211             for (int i = 0; i < nameValue.length; i++) {
212                 myhash = 37 * myhash + nameValue[i];
213             }
214         }
215         return myhash;
216     }
217 
218     /**
219      * Convert the name into user readable string.
220      */
221     public String toString() {
222         return "Other-Name: " + name;
223     }
224 
225     /**
226      * Return type of constraint inputName places on this name:<ul>
227      *   <li>NAME_DIFF_TYPE = -1: input name is different type from name
228      *       (i.e. does not constrain).
229      *   <li>NAME_MATCH = 0: input name matches name.
230      *   <li>NAME_NARROWS = 1: input name narrows name (is lower in the
231      *       naming subtree)
232      *   <li>NAME_WIDENS = 2: input name widens name (is higher in the
233      *       naming subtree)
234      *   <li>NAME_SAME_TYPE = 3: input name does not match or narrow name,
235      *       but is same type.
236      * </ul>.  These results are used in checking NameConstraints during
237      * certification path verification.
238      *
239      * @param inputName to be checked for being constrained
240      * @returns constraint type above
241      * @throws UnsupportedOperationException if name is same type, but
242      *         comparison operations are not supported for this name type.
243      */
244     public int constrains(GeneralNameInterface inputName) {
245         int constraintType;
246         if (inputName == null) {
247             constraintType = NAME_DIFF_TYPE;
248         } else if (inputName.getType() != NAME_ANY) {
249             constraintType = NAME_DIFF_TYPE;
250         } else {
251             throw new UnsupportedOperationException("Narrowing, widening, "
252                 + "and matching are not supported for OtherName.");
253         }
254         return constraintType;
255     }
256 
257     /**
258      * Return subtree depth of this name for purposes of determining
259      * NameConstraints minimum and maximum bounds.
260      *
261      * @returns distance of name from root
262      * @throws UnsupportedOperationException if not supported for this name type
263      */
264     public int subtreeDepth() {
265         throw new UnsupportedOperationException
266             ("subtreeDepth() not supported for generic OtherName");
267     }
268 
269 }