blob: 9bf990f29a1435d8c87421e2f4a32d326bf9c034 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
26package sun.security.x509;
27
28import java.io.IOException;
29import java.lang.reflect.Constructor;
30import java.util.Arrays;
31
32import 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 */
49public 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}