001: /*
002: * @(#)ObjectIdentifier.java 1.37 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.security.util;
029:
030: import java.io.*;
031:
032: /**
033: * Represent an ISO Object Identifier.
034: *
035: * <P>Object Identifiers are arbitrary length hierarchical identifiers.
036: * The individual components are numbers, and they define paths from the
037: * root of an ISO-managed identifier space. You will sometimes see a
038: * string name used instead of (or in addition to) the numerical id.
039: * These are synonyms for the numerical IDs, but are not widely used
040: * since most sites do not know all the requisite strings, while all
041: * sites can parse the numeric forms.
042: *
043: * <P>So for example, JavaSoft has the sole authority to assign the
044: * meaning to identifiers below the 1.3.6.1.4.1.42.2.17 node in the
045: * hierarchy, and other organizations can easily acquire the ability
046: * to assign such unique identifiers.
047: *
048: * @version 1.28
049: *
050: * @author David Brownell
051: * @author Amit Kapoor
052: * @author Hemma Prafullchandra
053: */
054: final public class ObjectIdentifier implements Serializable {
055: /** use serialVersionUID from JDK 1.1. for interoperability */
056: private static final long serialVersionUID = 8697030238860181294L;
057: private static final int maxFirstComponent = 2;
058: private static final int maxSecondComponent = 39;
059:
060: /**
061: * Constructs an object identifier from a string. This string
062: * should be of the form 1.23.34.45.56 etc. The first component
063: * should be 0,1 or 2 and the second component should be greater
064: * than or equal to 0 and less than or equal to 39.
065: */
066: public ObjectIdentifier(String oid) throws IOException {
067: int ch = '.';
068: int start = 0;
069: int end = 0;
070:
071: // Calculate length of oid
072: componentLen = 0;
073: while ((end = oid.indexOf(ch, start)) != -1) {
074: start = end + 1;
075: componentLen += 1;
076: }
077: componentLen += 1;
078: components = new int[componentLen];
079:
080: start = 0;
081: int i = 0;
082: String comp = null;
083: while ((end = oid.indexOf(ch, start)) != -1) {
084: comp = oid.substring(start, end);
085: if ((components[i++] = Integer.valueOf(comp).intValue()) < 0)
086: throw new IOException(
087: "oid components must be nonnegative");
088: start = end + 1;
089: }
090: comp = oid.substring(start);
091: components[i] = Integer.valueOf(comp).intValue();
092: if (components[0] < 0 || components[0] > maxFirstComponent) {
093: throw new IOException("First oid component is invalid ");
094: }
095: if (components[1] < 0 || components[1] > maxSecondComponent) {
096: throw new IOException("Second oid component is invalid ");
097: }
098: this .stringForm = oid;
099: }
100:
101: /**
102: * Constructs an object ID from an array of integers. This
103: * is used to construct constant object IDs. The first component
104: * should be 0,1 or 2 and the second component should be greater
105: * than or equal to 0 and less than or equal to 39.
106: */
107: public ObjectIdentifier(int values[]) throws IOException {
108: if (values.length >= 1) {
109: if (values[0] < 0 || values[0] > maxFirstComponent) {
110: throw new IOException("First oid component is invalid ");
111: }
112: }
113: if (values.length >= 2) {
114: if (values[1] < 0 || values[1] > maxSecondComponent) {
115: throw new IOException(
116: "Second oid component is invalid ");
117: }
118: }
119: components = (int[]) values.clone();
120: componentLen = values.length;
121: }
122:
123: /**
124: * Constructs an object ID from an ASN.1 encoded input stream.
125: * The encoding of the ID in the stream uses "DER", a BER/1 subset.
126: * In this case, that means a triple { typeId, length, data }.
127: *
128: * <P><STRONG>NOTE:</STRONG> When an exception is thrown, the
129: * input stream has not been returned to its "initial" state.
130: *
131: * @param in DER-encoded data holding an object ID
132: * @exception IOException indicates a decoding error
133: */
134: public ObjectIdentifier(DerInputStream in) throws IOException {
135: byte type_id;
136: int bufferEnd;
137:
138: /*
139: * Object IDs are a "universal" type, and their tag needs only
140: * one byte of encoding. Verify that the tag of this datum
141: * is that of an object ID.
142: *
143: * Then get and check the length of the ID's encoding. We set
144: * up so that we can use in.available() to check for the end of
145: * this value in the data stream.
146: */
147: type_id = (byte) in.getByte();
148: if (type_id != DerValue.tag_ObjectId)
149: throw new IOException(
150: "X509.ObjectIdentifier() -- data isn't an object ID"
151: + " (tag = " + type_id + ")");
152:
153: bufferEnd = in.available() - in.getLength() - 1;
154: if (bufferEnd < 0)
155: throw new IOException(
156: "X509.ObjectIdentifier() -- not enough data");
157:
158: initFromEncoding(in, bufferEnd);
159: }
160:
161: /*
162: * Build the OID from the rest of a DER input buffer; the tag
163: * and length have been removed/verified
164: */
165: ObjectIdentifier(DerInputBuffer buf) throws IOException {
166: initFromEncoding(new DerInputStream(buf), 0);
167: }
168:
169: /**
170: * Private constructor for use by newInternal(). Dummy argument
171: * to avoid clash with the public constructor.
172: */
173: private ObjectIdentifier(int[] components, boolean dummy) {
174: this .components = components;
175: this .componentLen = components.length;
176: }
177:
178: /**
179: * Create a new ObjectIdentifier for internal use. The values are
180: * neither checked nor cloned.
181: */
182: public static ObjectIdentifier newInternal(int[] values) {
183: return new ObjectIdentifier(values, true);
184: }
185:
186: /*
187: * Helper function -- get the OID from a stream, after tag and
188: * length are verified.
189: */
190: private void initFromEncoding(DerInputStream in, int bufferEnd)
191: throws IOException {
192:
193: /*
194: * Now get the components ("sub IDs") one at a time. We fill a
195: * temporary buffer, resizing it as needed.
196: */
197: int component;
198: boolean first_subid = true;
199:
200: for (components = new int[allocationQuantum], componentLen = 0; in
201: .available() > bufferEnd;) {
202: component = getComponent(in);
203: if (component < 0) {
204: throw new IOException("X509.ObjectIdentifier() -- "
205: + "component values must be nonnegative");
206: }
207: if (first_subid) {
208: int X, Y;
209:
210: /*
211: * The ISO root has three children (0, 1, 2) and those nodes
212: * aren't allowed to assign IDs larger than 39. These rules
213: * are memorialized by some special casing in the BER encoding
214: * of object IDs ... or maybe it's vice versa.
215: *
216: * NOTE: the allocation quantum is large enough that we know
217: * we don't have to reallocate here!
218: */
219: if (component < 40)
220: X = 0;
221: else if (component < 80)
222: X = 1;
223: else
224: X = 2;
225: Y = component - (X * 40);
226: if (Y > maxSecondComponent) {
227: throw new IOException(
228: "X509.ObjectIdentifier() -- Invalid second component");
229: }
230: components[0] = X;
231: components[1] = Y;
232: componentLen = 2;
233:
234: first_subid = false;
235:
236: } else {
237:
238: /*
239: * Other components are encoded less exotically. The only
240: * potential trouble is the need to grow the array.
241: */
242: if (componentLen >= components.length) {
243: int tmp_components[];
244:
245: tmp_components = new int[components.length
246: + allocationQuantum];
247: System.arraycopy(components, 0, tmp_components, 0,
248: components.length);
249: components = tmp_components;
250: }
251: components[componentLen++] = component;
252: }
253: }
254:
255: /*
256: * Final sanity check -- if we didn't use exactly the number of bytes
257: * specified, something's quite wrong.
258: */
259: if (in.available() != bufferEnd) {
260: throw new IOException(
261: "X509.ObjectIdentifier() -- malformed input data");
262: }
263: }
264:
265: /*
266: * n.b. the only public interface is DerOutputStream.putOID()
267: */
268: void encode(DerOutputStream out) throws IOException {
269: DerOutputStream bytes = new DerOutputStream();
270: int i;
271:
272: bytes.write((components[0] * 40) + components[1]);
273: for (i = 2; i < componentLen; i++)
274: putComponent(bytes, components[i]);
275:
276: /*
277: * Now that we've constructed the component, encode
278: * it in the stream we were given.
279: */
280: out.write(DerValue.tag_ObjectId, bytes);
281: }
282:
283: /*
284: * OID component parsing technique ... note that one bit
285: * per octet is lost, this returns at most 28 bits of component.
286: * Also, notice this parses in big-endian format.
287: */
288: private static int getComponent(DerInputStream in)
289: throws IOException {
290: int retval, i, tmp;
291:
292: for (i = 0, retval = 0; i < 4; i++) {
293: retval <<= 7;
294: tmp = in.getByte();
295: retval |= (tmp & 0x07f);
296: if ((tmp & 0x080) == 0)
297: return retval;
298: }
299:
300: throw new IOException("X509.OID, component value too big");
301: }
302:
303: /*
304: * Reverse of the above routine. Notice it needs to emit in
305: * big-endian form, so it buffers the output until it's ready.
306: * (Minimum length encoding is a DER requirement.)
307: */
308: private static void putComponent(DerOutputStream out, int val)
309: throws IOException {
310: int i;
311: byte buf[] = new byte[4];
312:
313: for (i = 0; i < 4; i++) {
314: buf[i] = (byte) (val & 0x07f);
315: val >>>= 7;
316: if (val == 0)
317: break;
318: }
319: for (; i > 0; --i)
320: out.write(buf[i] | 0x080);
321: out.write(buf[0]);
322: }
323:
324: // TODO: this API should probably facilitate the JDK sort utility
325:
326: /**
327: * Compares this identifier with another, for sorting purposes.
328: * An identifier does not precede itself.
329: *
330: * @param other identifer that may precede this one.
331: * @return true iff <em>other</em> precedes this one
332: * in a particular sorting order.
333: */
334: public boolean precedes(ObjectIdentifier other) {
335: int i;
336:
337: // shorter IDs go first
338: if (other == this || componentLen < other.componentLen)
339: return false;
340: if (other.componentLen < componentLen)
341: return true;
342:
343: // for each component, the lesser component goes first
344: for (i = 0; i < componentLen; i++) {
345: if (other.components[i] < components[i])
346: return true;
347: }
348:
349: // identical IDs don't precede each other
350: return false;
351: }
352:
353: /**
354: * @deprecated Use equals((Object)oid)
355: */
356: public boolean equals(ObjectIdentifier other) {
357: return equals((Object) other);
358: }
359:
360: /**
361: * Compares this identifier with another, for equality.
362: *
363: * @return true iff the names are identical.
364: */
365: public boolean equals(Object obj) {
366: if (this == obj) {
367: return true;
368: }
369: if (obj instanceof ObjectIdentifier == false) {
370: return false;
371: }
372: ObjectIdentifier other = (ObjectIdentifier) obj;
373: if (componentLen != other.componentLen) {
374: return false;
375: }
376: for (int i = 0; i < componentLen; i++) {
377: if (components[i] != other.components[i]) {
378: return false;
379: }
380: }
381: return true;
382: }
383:
384: public int hashCode() {
385: int h = componentLen;
386: for (int i = 0; i < componentLen; i++) {
387: h += components[i] * 37;
388: }
389: return h;
390: }
391:
392: /**
393: * Returns a string form of the object ID. The format is the
394: * conventional "dot" notation for such IDs, without any
395: * user-friendly descriptive strings, since those strings
396: * will not be understood everywhere.
397: */
398: public String toString() {
399: String s = stringForm;
400: if (s == null) {
401: StringBuffer sb = new StringBuffer(componentLen * 4);
402: for (int i = 0; i < componentLen; i++) {
403: if (i != 0) {
404: sb.append('.');
405: }
406: sb.append(components[i]);
407: }
408: s = sb.toString();
409: stringForm = s;
410: }
411: return s;
412: }
413:
414: /*
415: * To simplify, we assume no individual component of an object ID is
416: * larger than 32 bits. Then we represent the path from the root as
417: * an array that's (usually) only filled at the beginning.
418: */
419: private int components[]; // path from root
420: private int componentLen; // how much is used.
421:
422: private transient volatile String stringForm;
423:
424: private static final int allocationQuantum = 5; // >= 2
425: }
|