blob: 2ad04c0b36081d6d9fd8fa3b433f5b68c3b9c5e0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-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.util;
27
28import java.io.*;
29
30
31/**
32 * Represent an ISO Object Identifier.
33 *
34 * <P>Object Identifiers are arbitrary length hierarchical identifiers.
35 * The individual components are numbers, and they define paths from the
36 * root of an ISO-managed identifier space. You will sometimes see a
37 * string name used instead of (or in addition to) the numerical id.
38 * These are synonyms for the numerical IDs, but are not widely used
39 * since most sites do not know all the requisite strings, while all
40 * sites can parse the numeric forms.
41 *
42 * <P>So for example, JavaSoft has the sole authority to assign the
43 * meaning to identifiers below the 1.3.6.1.4.1.42.2.17 node in the
44 * hierarchy, and other organizations can easily acquire the ability
45 * to assign such unique identifiers.
46 *
47 *
48 * @author David Brownell
49 * @author Amit Kapoor
50 * @author Hemma Prafullchandra
51 */
52final public
53class ObjectIdentifier implements Serializable
54{
55 /** use serialVersionUID from JDK 1.1. for interoperability */
56 private static final long serialVersionUID = 8697030238860181294L;
57 private static final int maxFirstComponent = 2;
58 private static final int maxSecondComponent = 39;
59
60 /**
61 * Constructs an object identifier from a string. This string
62 * should be of the form 1.23.34.45.56 etc.
63 */
64 public ObjectIdentifier (String oid) throws IOException
65 {
66 int ch = '.';
67 int start = 0;
68 int end = 0;
69
70 // Calculate length of oid
71 componentLen = 0;
72 while ((end = oid.indexOf(ch,start)) != -1) {
73 start = end + 1;
74 componentLen += 1;
75 }
76 componentLen += 1;
77 components = new int[componentLen];
78
79 start = 0;
80 int i = 0;
81 String comp = null;
82 try {
83 while ((end = oid.indexOf(ch,start)) != -1) {
84 comp = oid.substring(start,end);
85 components[i++] = Integer.valueOf(comp).intValue();
86 start = end + 1;
87 }
88 comp = oid.substring(start);
89 components[i] = Integer.valueOf(comp).intValue();
90 } catch (Exception e) {
91 throw new IOException("ObjectIdentifier() -- Invalid format: "
92 + e.toString(), e);
93 }
94 checkValidOid(components, componentLen);
95 this.stringForm = oid;
96 }
97
98 /**
99 * Check if the values make a legal OID. There must be at least 2
100 * components and they must be all non-negative. The first component
101 * should be 0,1 or 2. When the first component is 0 or 1, the
102 * second component should be less than or equal to 39
103 *
104 * @param values the components that will make the OID
105 * @param len the number of components to check. Note that the allocation
106 * size of <code>values</code> may be longer than <code>len</code>.
107 * In this case, only the first <code>len</code> items are checked.
108 * @exception IOException if this is not a legal OID
109 */
110 private void checkValidOid(int[] values, int len) throws IOException {
111 if (values == null || len < 2) {
112 throw new IOException("ObjectIdentifier() -- " +
113 "Must be at least two oid components ");
114 }
115
116 for (int i=0; i<len; i++) {
117 if (values[i] < 0) {
118 throw new IOException("ObjectIdentifier() -- " +
119 "oid component #" + (i+1) + " must be non-negative ");
120 }
121 }
122
123 if (values[0] > maxFirstComponent) {
124 throw new IOException("ObjectIdentifier() -- " +
125 "First oid component is invalid ");
126 }
127
128 if (values[0] < 2 && values[1] > maxSecondComponent) {
129 throw new IOException("ObjectIdentifier() -- " +
130 "Second oid component is invalid ");
131 }
132 }
133 /**
134 * Constructs an object ID from an array of integers. This
135 * is used to construct constant object IDs.
136 */
137 public ObjectIdentifier (int values []) throws IOException
138 {
139 checkValidOid(values, values.length);
140 components = values.clone();
141 componentLen = values.length;
142 }
143
144 /**
145 * Constructs an object ID from an ASN.1 encoded input stream.
146 * The encoding of the ID in the stream uses "DER", a BER/1 subset.
147 * In this case, that means a triple { typeId, length, data }.
148 *
149 * <P><STRONG>NOTE:</STRONG> When an exception is thrown, the
150 * input stream has not been returned to its "initial" state.
151 *
152 * @param in DER-encoded data holding an object ID
153 * @exception IOException indicates a decoding error
154 */
155 public ObjectIdentifier (DerInputStream in)
156 throws IOException
157 {
158 byte type_id;
159 int bufferEnd;
160
161 /*
162 * Object IDs are a "universal" type, and their tag needs only
163 * one byte of encoding. Verify that the tag of this datum
164 * is that of an object ID.
165 *
166 * Then get and check the length of the ID's encoding. We set
167 * up so that we can use in.available() to check for the end of
168 * this value in the data stream.
169 */
170 type_id = (byte) in.getByte ();
171 if (type_id != DerValue.tag_ObjectId)
172 throw new IOException (
173 "ObjectIdentifier() -- data isn't an object ID"
174 + " (tag = " + type_id + ")"
175 );
176
177 bufferEnd = in.available () - in.getLength () - 1;
178 if (bufferEnd < 0)
179 throw new IOException (
180 "ObjectIdentifier() -- not enough data");
181
182 initFromEncoding (in, bufferEnd);
183 }
184
185 /*
186 * Build the OID from the rest of a DER input buffer; the tag
187 * and length have been removed/verified
188 */
189 ObjectIdentifier (DerInputBuffer buf) throws IOException
190 {
191 initFromEncoding (new DerInputStream (buf), 0);
192 }
193
194 /**
195 * Private constructor for use by newInternal(). Dummy argument
196 * to avoid clash with the public constructor.
197 */
198 private ObjectIdentifier(int[] components, boolean dummy) {
199 this.components = components;
200 this.componentLen = components.length;
201 }
202
203 /**
204 * Create a new ObjectIdentifier for internal use. The values are
205 * neither checked nor cloned.
206 */
207 public static ObjectIdentifier newInternal(int[] values) {
208 return new ObjectIdentifier(values, true);
209 }
210
211 /*
212 * Helper function -- get the OID from a stream, after tag and
213 * length are verified.
214 */
215 private void initFromEncoding (DerInputStream in, int bufferEnd)
216 throws IOException
217 {
218
219 /*
220 * Now get the components ("sub IDs") one at a time. We fill a
221 * temporary buffer, resizing it as needed.
222 */
223 int component;
224 boolean first_subid = true;
225
226 for (components = new int [allocationQuantum], componentLen = 0;
227 in.available () > bufferEnd;
228 ) {
229 component = getComponent (in);
230 if (component < 0) {
231 throw new IOException(
232 "ObjectIdentifier() -- " +
233 "component values must be nonnegative");
234 }
235 if (first_subid) {
236 int X, Y;
237
238 /*
239 * NOTE: the allocation quantum is large enough that we know
240 * we don't have to reallocate here!
241 */
242 if (component < 40)
243 X = 0;
244 else if (component < 80)
245 X = 1;
246 else
247 X = 2;
248 Y = component - ( X * 40);
249 components [0] = X;
250 components [1] = Y;
251 componentLen = 2;
252
253 first_subid = false;
254
255 } else {
256
257 /*
258 * Other components are encoded less exotically. The only
259 * potential trouble is the need to grow the array.
260 */
261 if (componentLen >= components.length) {
262 int tmp_components [];
263
264 tmp_components = new int [components.length
265 + allocationQuantum];
266 System.arraycopy (components, 0, tmp_components, 0,
267 components.length);
268 components = tmp_components;
269 }
270 components [componentLen++] = component;
271 }
272 }
273
274 checkValidOid(components, componentLen);
275
276 /*
277 * Final sanity check -- if we didn't use exactly the number of bytes
278 * specified, something's quite wrong.
279 */
280 if (in.available () != bufferEnd) {
281 throw new IOException (
282 "ObjectIdentifier() -- malformed input data");
283 }
284 }
285
286
287 /*
288 * n.b. the only public interface is DerOutputStream.putOID()
289 */
290 void encode (DerOutputStream out) throws IOException
291 {
292 DerOutputStream bytes = new DerOutputStream ();
293 int i;
294
295 // According to ISO X.660, when the 1st component is 0 or 1, the 2nd
296 // component is restricted to be less than or equal to 39, thus make
297 // it small enough to be encoded into one single byte.
298 if (components[0] < 2) {
299 bytes.write ((components [0] * 40) + components [1]);
300 } else {
301 putComponent(bytes, (components [0] * 40) + components [1]);
302 }
303 for (i = 2; i < componentLen; i++)
304 putComponent (bytes, components [i]);
305
306 /*
307 * Now that we've constructed the component, encode
308 * it in the stream we were given.
309 */
310 out.write (DerValue.tag_ObjectId, bytes);
311 }
312
313 /*
314 * Tricky OID component parsing technique ... note that one bit
315 * per octet is lost, this returns at most 28 bits of component.
316 * Also, notice this parses in big-endian format.
317 */
318 private static int getComponent (DerInputStream in)
319 throws IOException
320 {
321 int retval, i, tmp;
322
323 for (i = 0, retval = 0; i < 4; i++) {
324 retval <<= 7;
325 tmp = in.getByte ();
326 retval |= (tmp & 0x07f);
327 if ((tmp & 0x080) == 0)
328 return retval;
329 }
330
331 throw new IOException ("ObjectIdentifier() -- component value too big");
332 }
333
334 /*
335 * Reverse of the above routine. Notice it needs to emit in
336 * big-endian form, so it buffers the output until it's ready.
337 * (Minimum length encoding is a DER requirement.)
338 */
339 private static void putComponent (DerOutputStream out, int val)
340 throws IOException
341 {
342 int i;
343 // TODO: val must be <128*128*128*128 here, otherwise, 4 bytes is not
344 // enough to hold it. Will address this later.
345 byte buf [] = new byte [4] ;
346
347 for (i = 0; i < 4; i++) {
348 buf [i] = (byte) (val & 0x07f);
349 val >>>= 7;
350 if (val == 0)
351 break;
352 }
353 for ( ; i > 0; --i)
354 out.write (buf [i] | 0x080);
355 out.write (buf [0]);
356 }
357
358 // XXX this API should probably facilitate the JDK sort utility
359
360 /**
361 * Compares this identifier with another, for sorting purposes.
362 * An identifier does not precede itself.
363 *
364 * @param other identifer that may precede this one.
365 * @return true iff <em>other</em> precedes this one
366 * in a particular sorting order.
367 */
368 public boolean precedes (ObjectIdentifier other)
369 {
370 int i;
371
372 // shorter IDs go first
373 if (other == this || componentLen < other.componentLen)
374 return false;
375 if (other.componentLen < componentLen)
376 return true;
377
378 // for each component, the lesser component goes first
379 for (i = 0; i < componentLen; i++) {
380 if (other.components [i] < components [i])
381 return true;
382 }
383
384 // identical IDs don't precede each other
385 return false;
386 }
387
388 /**
389 * @deprecated Use equals((Object)oid)
390 */
391 @Deprecated
392 public boolean equals(ObjectIdentifier other) {
393 return equals((Object)other);
394 }
395
396 /**
397 * Compares this identifier with another, for equality.
398 *
399 * @return true iff the names are identical.
400 */
401 public boolean equals(Object obj) {
402 if (this == obj) {
403 return true;
404 }
405 if (obj instanceof ObjectIdentifier == false) {
406 return false;
407 }
408 ObjectIdentifier other = (ObjectIdentifier)obj;
409 if (componentLen != other.componentLen) {
410 return false;
411 }
412 for (int i = 0; i < componentLen; i++) {
413 if (components[i] != other.components[i]) {
414 return false;
415 }
416 }
417 return true;
418 }
419
420 public int hashCode() {
421 int h = componentLen;
422 for (int i = 0; i < componentLen; i++) {
423 h += components[i] * 37;
424 }
425 return h;
426 }
427
428 /**
429 * Returns a string form of the object ID. The format is the
430 * conventional "dot" notation for such IDs, without any
431 * user-friendly descriptive strings, since those strings
432 * will not be understood everywhere.
433 */
434 public String toString() {
435 String s = stringForm;
436 if (s == null) {
437 StringBuffer sb = new StringBuffer(componentLen * 4);
438 for (int i = 0; i < componentLen; i++) {
439 if (i != 0) {
440 sb.append('.');
441 }
442 sb.append(components[i]);
443 }
444 s = sb.toString();
445 stringForm = s;
446 }
447 return s;
448 }
449
450 /*
451 * To simplify, we assume no individual component of an object ID is
452 * larger than 32 bits. Then we represent the path from the root as
453 * an array that's (usually) only filled at the beginning.
454 */
455 private int components []; // path from root
456 private int componentLen; // how much is used.
457
458 private transient volatile String stringForm;
459
460 private static final int allocationQuantum = 5; // >= 2
461}