2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / gnu / java / security / OID.java
blobc27ec9253abe9f5f74b59f6acc1fcaebe30ddac4
1 /* OID.java -- numeric representation of an object identifier
2 Copyright (C) 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.security;
41 import java.io.ByteArrayInputStream;
42 import java.io.ByteArrayOutputStream;
43 import java.io.InputStream;
44 import java.io.IOException;
46 import java.util.StringTokenizer;
48 import gnu.java.security.der.DEREncodingException;
50 /**
51 * This immutable class represents an object identifier, or OID.
53 * <p>OIDs are represented as a series of hierarcical tokens, each of
54 * which is usually represented as a single, unsigned integer. The
55 * hierarchy works so that later tokens are considered within the group
56 * of earlier tokens. Thus, the OID for the Serpent block cipher,
57 * 1.3.6.1.4.1.11591.13.2, is maintained by the GNU project, whose OID
58 * is 1.3.6.1.4.1.11591 (which is, in turn, part of bigger, more general
59 * bodies; the topmost, 1, stands for the OIDs assigned by the
60 * International Standards Organization, ISO).
62 * <p>OIDs can be represented in a variety of ways, including the
63 * dotted-decimal form we use here.
65 * <p>OIDs may be relative, in which case the first two elements of the
66 * OID are omitted.
68 * @author Casey Marshall (rsdio@metastatic.org)
70 public class OID implements Cloneable, Comparable, java.io.Serializable
73 // Fields.
74 // ------------------------------------------------------------------------
76 /**
77 * The numeric ID structure.
79 private int[] components;
81 /**
82 * The string representation of this OID, in dotted-decimal format.
84 private transient String strRep;
86 /**
87 * The DER encoding of this OID.
89 private transient byte[] der;
91 /**
92 * Whether or not this OID is relative.
94 private boolean relative;
96 // Constructors.
97 // ------------------------------------------------------------------------
99 /**
100 * Create a new OID from the given byte array. The argument (which can
101 * neither be null nor zero-length) is copied to prevent subsequent
102 * modification.
104 * @param components The numeric IDs.
105 * @throws IllegalArgumentException If <i>components</i> is null or empty.
107 public OID(int[] components)
109 this(components, false);
113 * Create a new OID from the given byte array. The argument (which can
114 * neither be null nor zero-length) is copied to prevent subsequent
115 * modification.
117 * @param components The numeric IDs.
118 * @param relative The relative flag.
119 * @throws IllegalArgumentException If <i>components</i> is null or empty.
121 public OID(int[] components, boolean relative)
123 if (components == null || components.length == 0)
124 throw new IllegalArgumentException();
125 this.components = (int[]) components.clone();
126 this.relative = relative;
130 * Create a new OID from the given dotted-decimal representation.
132 * @param strRep The string representation of the OID.
133 * @throws IllegalArgumentException If the string does not contain at
134 * least one integer.
135 * @throws NumberFormatException If the string does not contain only
136 * numbers and periods ('.').
138 public OID(String strRep)
140 this(strRep, false);
144 * Create a new OID from the given dotted-decimal representation.
146 * @param strRep The string representation of the OID.
147 * @param relative The relative flag.
148 * @throws IllegalArgumentException If the string does not contain at
149 * least one integer.
150 * @throws NumberFormatException If the string does not contain only
151 * numbers and periods ('.').
153 public OID(String strRep, boolean relative)
155 this.relative = relative;
156 this.strRep = strRep;
157 components = fromString(strRep);
161 * Construct a new OID from the DER bytes in an input stream. This method
162 * does not read the tag or the length field from the input stream, so
163 * the caller must supply the number of octets in this OID's encoded
164 * form.
166 * @param derIn The DER input stream.
167 * @param len The number of bytes in the encoded form.
168 * @throws IOException If an error occurs reading the OID.
170 public OID(InputStream derIn, int len) throws IOException
172 this(derIn, len, false);
176 * Construct a new OID from the DER bytes in an input stream. This method
177 * does not read the tag or the length field from the input stream, so
178 * the caller must supply the number of octets in this OID's encoded
179 * form.
181 * @param derIn The DER input stream.
182 * @param len The number of bytes in the encoded form.
183 * @param relative The relative flag.
184 * @throws IOException If an error occurs reading the OID.
186 public OID(InputStream derIn, int len, boolean relative) throws IOException
188 der = new byte[len];
189 derIn.read(der);
190 this.relative = relative;
193 components = fromDER(der, relative);
195 catch (ArrayIndexOutOfBoundsException aioobe)
197 aioobe.printStackTrace();
198 throw aioobe;
203 * Construct a new OID from the given DER bytes.
205 * @param encoded The DER encoded OID.
206 * @throws IOException If an error occurs reading the OID.
208 public OID(byte[] encoded) throws IOException
210 this(encoded, false);
214 * Construct a new OID from the given DER bytes.
216 * @param root The root OID.
217 * @param encoded The encoded relative OID.
218 * @param relative The relative flag.
220 public OID(byte[] encoded, boolean relative) throws IOException
222 der = (byte[]) encoded.clone();
223 this.relative = relative;
226 components = fromDER(der, relative);
228 catch (ArrayIndexOutOfBoundsException aioobe)
230 aioobe.printStackTrace();
231 throw aioobe;
236 * Our private constructor.
238 private OID()
242 // Instance methods.
243 // ------------------------------------------------------------------------
246 * Return the numeric IDs of this OID. The value returned is copied to
247 * prevent modification.
249 * @return The IDs in a new integer array.
251 public int[] getIDs()
253 return (int[]) components.clone();
257 * Get the DER encoding of this OID, minus the tag and length fields.
259 * @return The DER bytes.
261 public byte[] getDER()
263 if (der == null)
265 ByteArrayOutputStream bout = new ByteArrayOutputStream();
266 int i = 0;
267 if (!relative)
269 int b = components[i++] * 40 + (components.length > 1
270 ? components[i++] : 0);
271 encodeSubID(bout, b);
273 for ( ; i < components.length; i++)
274 encodeSubID(bout, components[i]);
275 der = bout.toByteArray();
277 return (byte[]) der.clone();
281 * Get the parent OID of this OID. That is, if this OID is "1.2.3.4",
282 * then the parent OID will be "1.2.3". If this OID is a top-level
283 * OID, this method returns null.
285 * @return The parent OID, or null.
287 public OID getParent()
289 if (components.length == 1)
290 return null;
291 int[] parent = new int[components.length - 1];
292 System.arraycopy(components, 0, parent, 0, parent.length);
293 return new OID(parent);
296 public OID getChild(int id)
298 int[] child = new int[components.length + 1];
299 System.arraycopy(components, 0, child, 0, components.length);
300 child[child.length - 1] = id;
301 return new OID(child);
305 * Get the root OID of this OID. That is, the first two components.
307 * @return The root OID.
309 public OID getRoot()
311 if (components.length <= 2)
312 return this;
313 int[] root = new int[2];
314 root[0] = components[0];
315 root[1] = components[1];
316 return new OID(root);
319 public boolean isRelative()
321 return relative;
325 * Returns a copy of this OID.
327 * @return The copy.
329 public Object clone()
331 OID oid = new OID();
332 oid.components = this.components;
333 oid.strRep = this.strRep;
334 return oid;
337 /* Nice idea, but possibly too expensive for whatever benefit it
338 * provides.
340 public String getShortName()
342 return OIDTable.getShortName(this);
345 public String getLongName()
347 return OIDTable.getLongName(this);
353 * Returns the value of this OID in dotted-decimal format.
355 * @return The string representation.
357 public String toString()
359 if (strRep != null)
360 return strRep;
361 else
363 StringBuffer buf = new StringBuffer();
364 for (int i = 0; i < components.length; i++)
366 buf.append((long) components[i] & 0xFFFFFFFFL);
367 if (i < components.length - 1)
368 buf.append('.');
370 return (strRep = buf.toString());
375 * Computes a hash code for this OID.
377 * @return The hash code.
379 public int hashCode()
381 int ret = 0;
382 for (int i = 0; i < components.length; i++)
383 ret += components[i] << (i & 31);
384 return ret;
388 * Tests whether or not this OID equals another.
390 * @return Whether or not this OID equals the other.
392 public boolean equals(Object o)
394 if (this == o)
395 return true;
396 return java.util.Arrays.equals(components, ((OID) o).components);
400 * Compares this OID to another. The comparison is essentially
401 * lexicographic, where the two OIDs are compared until their
402 * first difference, then that difference is returned. If one OID is
403 * shorter, but all elements equal between the two for the shorter
404 * length, then the shorter OID is lesser than the longer.
406 * @param o The object to compare.
407 * @return An integer less than, equal to, or greater than zero if
408 * this object is less than, equal to, or greater than the
409 * argument.
410 * @throws ClassCastException If <i>o</i> is not an OID.
412 public int compareTo(Object o)
414 if (o == this)
415 return 0;
416 int[] components2 = ((OID) o).components;
417 int len = Math.min(components.length, components2.length);
418 for (int i = 0; i < len; i++)
420 if (components[i] != components2[i])
421 return (components[i] < components2[i]) ? -1 : 1;
423 if (components.length == components2.length)
424 return 0;
425 return (components.length < components2.length) ? -1 : 1;
428 // Own methods.
429 // ------------------------------------------------------------------------
431 private static int[] fromDER(byte[] der, boolean relative)
432 throws DEREncodingException
434 // cannot be longer than this.
435 int[] components = new int[der.length + 1];
436 int count = 0;
437 int i = 0;
438 if (!relative && i < der.length)
440 // Non-relative OIDs have the first two arcs coded as:
442 // i = first_arc * 40 + second_arc;
444 int j = (der[i] & 0xFF);
445 components[count++] = j / 40;
446 components[count++] = j % 40;
447 i++;
449 while (i < der.length)
451 int j = 0;
454 j = der[i++] & 0xFF;
455 components[count] <<= 7;
456 components[count] |= j & 0x7F;
457 if (i >= der.length && (j & 0x80) != 0)
458 throw new DEREncodingException("malformed OID");
460 while ((j & 0x80) != 0);
461 count++;
463 if (count == components.length)
464 return components;
465 int[] ret = new int[count];
466 System.arraycopy(components, 0, ret, 0, count);
467 return ret;
470 private static int[] fromString(String strRep) throws NumberFormatException
472 if (strRep.startsWith("OID.") || strRep.startsWith("oid."))
473 strRep = strRep.substring(4);
474 StringTokenizer tok = new StringTokenizer(strRep, ".");
475 if (tok.countTokens() == 0)
476 throw new IllegalArgumentException();
477 int[] components = new int[tok.countTokens()];
478 int i = 0;
479 while (tok.hasMoreTokens())
481 components[i++] = Integer.parseInt(tok.nextToken());
483 return components;
486 private static void encodeSubID(ByteArrayOutputStream out, int id)
488 if (id < 128)
490 out.write(id);
492 else if (id < 16384)
494 out.write((id >>> 7) | 0x80);
495 out.write(id & 0x7F);
497 else if (id < 2097152)
499 out.write((id >>> 14) | 0x80);
500 out.write(((id >>> 7) | 0x80) & 0xFF);
501 out.write(id & 0x7F);
503 else if (id < 268435456)
505 out.write( (id >>> 21) | 0x80);
506 out.write(((id >>> 14) | 0x80) & 0xFF);
507 out.write(((id >>> 7) | 0x80) & 0xFF);
508 out.write(id & 0x7F);