|
1 /* |
|
2 * Copyright 1998-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 |
|
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 = ((Class<?>)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 (IOException)new IOException("Instantiation error: " + e).initCause(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(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 } |