Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: gnu/java/security/OID.java


1   /* OID.java -- numeric representation of an object identifier
2      Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
3   
4   This file is part of GNU Classpath.
5   
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.
10  
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.
15  
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., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301 USA.
20  
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.
25  
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. */
37  
38  
39  package gnu.java.security;
40  
41  import gnu.java.security.der.DEREncodingException;
42  
43  import java.io.ByteArrayOutputStream;
44  import java.io.IOException;
45  import java.io.InputStream;
46  import java.util.StringTokenizer;
47  
48  /**
49   * This immutable class represents an object identifier, or OID.
50   *
51   * <p>OIDs are represented as a series of hierarchical tokens, each of
52   * which is usually represented as a single, unsigned integer. The
53   * hierarchy works so that later tokens are considered within the group
54   * of earlier tokens. Thus, the OID for the Serpent block cipher,
55   * 1.3.6.1.4.1.11591.13.2, is maintained by the GNU project, whose OID
56   * is 1.3.6.1.4.1.11591 (which is, in turn, part of bigger, more general
57   * bodies; the topmost, 1, stands for the OIDs assigned by the
58   * International Standards Organization, ISO).
59   *
60   * <p>OIDs can be represented in a variety of ways, including the
61   * dotted-decimal form we use here.
62   *
63   * <p>OIDs may be relative, in which case the first two elements of the
64   * OID are omitted.
65   *
66   * @author Casey Marshall (csm@gnu.org)
67   */
68  public class OID implements Cloneable, Comparable, java.io.Serializable
69  {
70  
71    // Fields.
72    // ------------------------------------------------------------------------
73  
74    /**
75     * The numeric ID structure.
76     */
77    private int[] components;
78  
79    /**
80     * The string representation of this OID, in dotted-decimal format.
81     */
82    private transient String strRep;
83  
84    /**
85     * The DER encoding of this OID.
86     */
87    private transient byte[] der;
88  
89    /**
90     * Whether or not this OID is relative.
91     */
92    private boolean relative;
93  
94    // Constructors.
95    // ------------------------------------------------------------------------
96  
97    /**
98     * Create a new OID from the given byte array. The argument (which can
99     * neither be null nor zero-length) is copied to prevent subsequent
100    * modification.
101    *
102    * @param components The numeric IDs.
103    * @throws IllegalArgumentException If <i>components</i> is null or empty.
104    */
105   public OID(int[] components)
106   {
107     this(components, false);
108   }
109 
110   /**
111    * Create a new OID from the given byte array. The argument (which can
112    * neither be null nor zero-length) is copied to prevent subsequent
113    * modification.
114    *
115    * @param components The numeric IDs.
116    * @param relative The relative flag.
117    * @throws IllegalArgumentException If <i>components</i> is null or empty.
118    */
119   public OID(int[] components, boolean relative)
120   {
121     if (components == null || components.length == 0)
122       throw new IllegalArgumentException();
123     this.components = (int[]) components.clone();
124     this.relative = relative;
125   }
126 
127   /**
128    * Create a new OID from the given dotted-decimal representation.
129    *
130    * @param strRep The string representation of the OID.
131    * @throws IllegalArgumentException If the string does not contain at
132    * least one integer.
133    * @throws NumberFormatException If the string does not contain only
134    * numbers and periods ('.').
135    */
136   public OID(String strRep)
137   {
138     this(strRep, false);
139   }
140 
141   /**
142    * Create a new OID from the given dotted-decimal representation.
143    *
144    * @param strRep The string representation of the OID.
145    * @param relative The relative flag.
146    * @throws IllegalArgumentException If the string does not contain at
147    * least one integer.
148    * @throws NumberFormatException If the string does not contain only
149    * numbers and periods ('.').
150    */
151   public OID(String strRep, boolean relative)
152   {
153     this.relative = relative;
154     this.strRep = strRep;
155     components = fromString(strRep);
156   }
157 
158   /**
159    * Construct a new OID from the DER bytes in an input stream. This method
160    * does not read the tag or the length field from the input stream, so
161    * the caller must supply the number of octets in this OID's encoded
162    * form.
163    *
164    * @param derIn The DER input stream.
165    * @param len   The number of bytes in the encoded form.
166    * @throws IOException If an error occurs reading the OID.
167    */
168   public OID(InputStream derIn, int len) throws IOException
169   {
170     this(derIn, len, false);
171   }
172 
173   /**
174    * Construct a new OID from the DER bytes in an input stream. This method
175    * does not read the tag or the length field from the input stream, so
176    * the caller must supply the number of octets in this OID's encoded
177    * form.
178    *
179    * @param derIn The DER input stream.
180    * @param len   The number of bytes in the encoded form.
181    * @param relative The relative flag.
182    * @throws IOException If an error occurs reading the OID.
183    */
184   public OID(InputStream derIn, int len, boolean relative) throws IOException
185   {
186     der = new byte[len];
187     derIn.read(der);
188     this.relative = relative;
189     try
190       {
191         components = fromDER(der, relative);
192       }
193     catch (ArrayIndexOutOfBoundsException aioobe)
194       {
195         aioobe.printStackTrace();
196         throw aioobe;
197       }
198   }
199 
200   /**
201    * Construct a new OID from the given DER bytes.
202    *
203    * @param encoded The DER encoded OID.
204    * @throws IOException If an error occurs reading the OID.
205    */
206   public OID(byte[] encoded) throws IOException
207   {
208     this(encoded, false);
209   }
210 
211   /**
212    * Construct a new OID from the given DER bytes.
213    *
214    * @param root The root OID.
215    * @param encoded The encoded relative OID.
216    * @param relative The relative flag.
217    */
218   public OID(byte[] encoded, boolean relative) throws IOException
219   {
220     der = (byte[]) encoded.clone();
221     this.relative = relative;
222     try
223       {
224         components = fromDER(der, relative);
225       }
226     catch (ArrayIndexOutOfBoundsException aioobe)
227       {
228         aioobe.printStackTrace();
229         throw aioobe;
230       }
231   }
232 
233   /**
234    * Our private constructor.
235    */
236   private OID()
237   {
238   }
239 
240   // Instance methods.
241   // ------------------------------------------------------------------------
242 
243   /**
244    * Return the numeric IDs of this OID. The value returned is copied to
245    * prevent modification.
246    *
247    * @return The IDs in a new integer array.
248    */
249   public int[] getIDs()
250   {
251     return (int[]) components.clone();
252   }
253 
254   /**
255    * Get the DER encoding of this OID, minus the tag and length fields.
256    *
257    * @return The DER bytes.
258    */
259   public byte[] getDER()
260   {
261     if (der == null)
262       {
263         ByteArrayOutputStream bout = new ByteArrayOutputStream();
264         int i = 0;
265         if (!relative)
266           {
267             int b = components[i++] * 40 + (components.length > 1
268               ? components[i++] : 0);
269             encodeSubID(bout, b);
270           }
271         for ( ; i < components.length; i++)
272           encodeSubID(bout, components[i]);
273         der = bout.toByteArray();
274       }
275     return (byte[]) der.clone();
276   }
277 
278   /**
279    * Get the parent OID of this OID. That is, if this OID is "1.2.3.4",
280    * then the parent OID will be "1.2.3". If this OID is a top-level
281    * OID, this method returns null.
282    *
283    * @return The parent OID, or null.
284    */
285   public OID getParent()
286   {
287     if (components.length == 1)
288       return null;
289     int[] parent = new int[components.length - 1];
290     System.arraycopy(components, 0, parent, 0, parent.length);
291     return new OID(parent);
292   }
293 
294   public OID getChild(int id)
295   {
296     int[] child = new int[components.length + 1];
297     System.arraycopy(components, 0, child, 0, components.length);
298     child[child.length - 1] = id;
299     return new OID(child);
300   }
301 
302   /**
303    * Get the root OID of this OID. That is, the first two components.
304    *
305    * @return The root OID.
306    */
307   public OID getRoot()
308   {
309     if (components.length <= 2)
310       return this;
311     int[] root = new int[2];
312     root[0] = components[0];
313     root[1] = components[1];
314     return new OID(root);
315   }
316 
317   public boolean isRelative()
318   {
319     return relative;
320   }
321 
322   /**
323    * Returns a copy of this OID.
324    *
325    * @return The copy.
326    */
327   public Object clone()
328   {
329     OID oid = new OID();
330     oid.components = this.components;
331     oid.strRep = this.strRep;
332     return oid;
333   }
334 
335   /* Nice idea, but possibly too expensive for whatever benefit it
336    * provides.
337 
338   public String getShortName()
339   {
340     return OIDTable.getShortName(this);
341   }
342 
343   public String getLongName()
344   {
345     return OIDTable.getLongName(this);
346   }
347 
348   */
349 
350   /**
351    * Returns the value of this OID in dotted-decimal format.
352    *
353    * @return The string representation.
354    */
355   public String toString()
356   {
357     if (strRep != null)
358       return strRep;
359     else
360       {
361         StringBuffer buf = new StringBuffer();
362         for (int i = 0; i < components.length; i++)
363           {
364             buf.append((long) components[i] & 0xFFFFFFFFL);
365             if (i < components.length - 1)
366               buf.append('.');
367           }
368         return (strRep = buf.toString());
369       }
370   }
371 
372   /**
373    * Computes a hash code for this OID.
374    *
375    * @return The hash code.
376    */
377   public int hashCode()
378   {
379     int ret = 0;
380     for (int i = 0; i < components.length; i++)
381       ret += components[i] << (i & 31);
382     return ret;
383   }
384 
385   /**
386    * Tests whether or not this OID equals another.
387    *
388    * @return Whether or not this OID equals the other.
389    */
390   public boolean equals(Object o)
391   {
392     if (!(o instanceof OID))
393       return false;
394     return java.util.Arrays.equals(components, ((OID) o).components);
395   }
396 
397   /**
398    * Compares this OID to another. The comparison is essentially
399    * lexicographic, where the two OIDs are compared until their
400    * first difference, then that difference is returned. If one OID is
401    * shorter, but all elements equal between the two for the shorter
402    * length, then the shorter OID is lesser than the longer.
403    *
404    * @param o The object to compare.
405    * @return An integer less than, equal to, or greater than zero if
406    *         this object is less than, equal to, or greater than the
407    *         argument.
408    * @throws ClassCastException If <i>o</i> is not an OID.
409    */
410   public int compareTo(Object o)
411   {
412     if (equals(o))
413       return 0;
414     int[] components2 = ((OID) o).components;
415     int len = Math.min(components.length, components2.length);
416     for (int i = 0; i < len; i++)
417       {
418         if (components[i] != components2[i])
419           return (components[i] < components2[i]) ? -1 : 1;
420       }
421     if (components.length == components2.length)
422       return 0;
423     return (components.length < components2.length) ? -1 : 1;
424   }
425 
426   // Own methods.
427   // ------------------------------------------------------------------------
428 
429   private static int[] fromDER(byte[] der, boolean relative)
430     throws DEREncodingException
431   {
432     // cannot be longer than this.
433     int[] components = new int[der.length + 1];
434     int count = 0;
435     int i = 0;
436     if (!relative && i < der.length)
437       {
438         // Non-relative OIDs have the first two arcs coded as:
439         //
440         //   i = first_arc * 40 + second_arc;
441         //
442         int j = (der[i] & 0xFF);
443         components[count++] = j / 40;
444         components[count++] = j % 40;
445         i++;
446       }
447     while (i < der.length)
448       {
449         int j = 0;
450         do
451           {
452             j = der[i++] & 0xFF;
453             components[count] <<= 7;
454             components[count]  |= j & 0x7F;
455             if (i >= der.length && (j & 0x80) != 0)
456               throw new DEREncodingException("malformed OID");
457           }
458         while ((j & 0x80) != 0);
459         count++;
460       }
461     if (count == components.length)
462       return components;
463     int[] ret = new int[count];
464     System.arraycopy(components, 0, ret, 0, count);
465     return ret;
466   }
467 
468   private static int[] fromString(String strRep) throws NumberFormatException
469   {
470     if (strRep.startsWith("OID.") || strRep.startsWith("oid."))
471       strRep = strRep.substring(4);
472     StringTokenizer tok = new StringTokenizer(strRep, ".");
473     if (tok.countTokens() == 0)
474       throw new IllegalArgumentException();
475     int[] components = new int[tok.countTokens()];
476     int i = 0;
477     while (tok.hasMoreTokens())
478       {
479         components[i++] = Integer.parseInt(tok.nextToken());
480       }
481     return components;
482   }
483 
484   private static void encodeSubID(ByteArrayOutputStream out, int id)
485   {
486     if (id < 128)
487       {
488         out.write(id);
489       }
490     else if (id < 16384)
491       {
492         out.write((id >>> 7) | 0x80);
493         out.write(id & 0x7F);
494       }
495     else if (id < 2097152)
496       {
497         out.write((id >>> 14) | 0x80);
498         out.write(((id >>> 7) | 0x80) & 0xFF);
499         out.write(id & 0x7F);
500       }
501     else if (id < 268435456)
502       {
503         out.write( (id >>> 21) | 0x80);
504         out.write(((id >>> 14) | 0x80) & 0xFF);
505         out.write(((id >>>  7) | 0x80) & 0xFF);
506         out.write(id & 0x7F);
507       }
508   }
509 }