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