diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/sun/security/util/ObjectIdentifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/security/util/ObjectIdentifier.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,461 @@ +/* + * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.security.util; + +import java.io.*; + + +/** + * Represent an ISO Object Identifier. + * + *
Object Identifiers are arbitrary length hierarchical identifiers. + * The individual components are numbers, and they define paths from the + * root of an ISO-managed identifier space. You will sometimes see a + * string name used instead of (or in addition to) the numerical id. + * These are synonyms for the numerical IDs, but are not widely used + * since most sites do not know all the requisite strings, while all + * sites can parse the numeric forms. + * + *
So for example, JavaSoft has the sole authority to assign the
+ * meaning to identifiers below the 1.3.6.1.4.1.42.2.17 node in the
+ * hierarchy, and other organizations can easily acquire the ability
+ * to assign such unique identifiers.
+ *
+ *
+ * @author David Brownell
+ * @author Amit Kapoor
+ * @author Hemma Prafullchandra
+ */
+final public
+class ObjectIdentifier implements Serializable
+{
+ /** use serialVersionUID from JDK 1.1. for interoperability */
+ private static final long serialVersionUID = 8697030238860181294L;
+ private static final int maxFirstComponent = 2;
+ private static final int maxSecondComponent = 39;
+
+ /**
+ * Constructs an object identifier from a string. This string
+ * should be of the form 1.23.34.45.56 etc.
+ */
+ public ObjectIdentifier (String oid) throws IOException
+ {
+ int ch = '.';
+ int start = 0;
+ int end = 0;
+
+ // Calculate length of oid
+ componentLen = 0;
+ while ((end = oid.indexOf(ch,start)) != -1) {
+ start = end + 1;
+ componentLen += 1;
+ }
+ componentLen += 1;
+ components = new int[componentLen];
+
+ start = 0;
+ int i = 0;
+ String comp = null;
+ try {
+ while ((end = oid.indexOf(ch,start)) != -1) {
+ comp = oid.substring(start,end);
+ components[i++] = Integer.valueOf(comp).intValue();
+ start = end + 1;
+ }
+ comp = oid.substring(start);
+ components[i] = Integer.valueOf(comp).intValue();
+ } catch (Exception e) {
+ throw new IOException("ObjectIdentifier() -- Invalid format: "
+ + e.toString(), e);
+ }
+ checkValidOid(components, componentLen);
+ this.stringForm = oid;
+ }
+
+ /**
+ * Check if the values make a legal OID. There must be at least 2
+ * components and they must be all non-negative. The first component
+ * should be 0,1 or 2. When the first component is 0 or 1, the
+ * second component should be less than or equal to 39
+ *
+ * @param values the components that will make the OID
+ * @param len the number of components to check. Note that the allocation
+ * size of NOTE: When an exception is thrown, the
+ * input stream has not been returned to its "initial" state.
+ *
+ * @param in DER-encoded data holding an object ID
+ * @exception IOException indicates a decoding error
+ */
+ public ObjectIdentifier (DerInputStream in)
+ throws IOException
+ {
+ byte type_id;
+ int bufferEnd;
+
+ /*
+ * Object IDs are a "universal" type, and their tag needs only
+ * one byte of encoding. Verify that the tag of this datum
+ * is that of an object ID.
+ *
+ * Then get and check the length of the ID's encoding. We set
+ * up so that we can use in.available() to check for the end of
+ * this value in the data stream.
+ */
+ type_id = (byte) in.getByte ();
+ if (type_id != DerValue.tag_ObjectId)
+ throw new IOException (
+ "ObjectIdentifier() -- data isn't an object ID"
+ + " (tag = " + type_id + ")"
+ );
+
+ bufferEnd = in.available () - in.getLength () - 1;
+ if (bufferEnd < 0)
+ throw new IOException (
+ "ObjectIdentifier() -- not enough data");
+
+ initFromEncoding (in, bufferEnd);
+ }
+
+ /*
+ * Build the OID from the rest of a DER input buffer; the tag
+ * and length have been removed/verified
+ */
+ ObjectIdentifier (DerInputBuffer buf) throws IOException
+ {
+ initFromEncoding (new DerInputStream (buf), 0);
+ }
+
+ /**
+ * Private constructor for use by newInternal(). Dummy argument
+ * to avoid clash with the public constructor.
+ */
+ private ObjectIdentifier(int[] components, boolean dummy) {
+ this.components = components;
+ this.componentLen = components.length;
+ }
+
+ /**
+ * Create a new ObjectIdentifier for internal use. The values are
+ * neither checked nor cloned.
+ */
+ public static ObjectIdentifier newInternal(int[] values) {
+ return new ObjectIdentifier(values, true);
+ }
+
+ /*
+ * Helper function -- get the OID from a stream, after tag and
+ * length are verified.
+ */
+ private void initFromEncoding (DerInputStream in, int bufferEnd)
+ throws IOException
+ {
+
+ /*
+ * Now get the components ("sub IDs") one at a time. We fill a
+ * temporary buffer, resizing it as needed.
+ */
+ int component;
+ boolean first_subid = true;
+
+ for (components = new int [allocationQuantum], componentLen = 0;
+ in.available () > bufferEnd;
+ ) {
+ component = getComponent (in);
+ if (component < 0) {
+ throw new IOException(
+ "ObjectIdentifier() -- " +
+ "component values must be nonnegative");
+ }
+ if (first_subid) {
+ int X, Y;
+
+ /*
+ * NOTE: the allocation quantum is large enough that we know
+ * we don't have to reallocate here!
+ */
+ if (component < 40)
+ X = 0;
+ else if (component < 80)
+ X = 1;
+ else
+ X = 2;
+ Y = component - ( X * 40);
+ components [0] = X;
+ components [1] = Y;
+ componentLen = 2;
+
+ first_subid = false;
+
+ } else {
+
+ /*
+ * Other components are encoded less exotically. The only
+ * potential trouble is the need to grow the array.
+ */
+ if (componentLen >= components.length) {
+ int tmp_components [];
+
+ tmp_components = new int [components.length
+ + allocationQuantum];
+ System.arraycopy (components, 0, tmp_components, 0,
+ components.length);
+ components = tmp_components;
+ }
+ components [componentLen++] = component;
+ }
+ }
+
+ checkValidOid(components, componentLen);
+
+ /*
+ * Final sanity check -- if we didn't use exactly the number of bytes
+ * specified, something's quite wrong.
+ */
+ if (in.available () != bufferEnd) {
+ throw new IOException (
+ "ObjectIdentifier() -- malformed input data");
+ }
+ }
+
+
+ /*
+ * n.b. the only public interface is DerOutputStream.putOID()
+ */
+ void encode (DerOutputStream out) throws IOException
+ {
+ DerOutputStream bytes = new DerOutputStream ();
+ int i;
+
+ // According to ISO X.660, when the 1st component is 0 or 1, the 2nd
+ // component is restricted to be less than or equal to 39, thus make
+ // it small enough to be encoded into one single byte.
+ if (components[0] < 2) {
+ bytes.write ((components [0] * 40) + components [1]);
+ } else {
+ putComponent(bytes, (components [0] * 40) + components [1]);
+ }
+ for (i = 2; i < componentLen; i++)
+ putComponent (bytes, components [i]);
+
+ /*
+ * Now that we've constructed the component, encode
+ * it in the stream we were given.
+ */
+ out.write (DerValue.tag_ObjectId, bytes);
+ }
+
+ /*
+ * Tricky OID component parsing technique ... note that one bit
+ * per octet is lost, this returns at most 28 bits of component.
+ * Also, notice this parses in big-endian format.
+ */
+ private static int getComponent (DerInputStream in)
+ throws IOException
+ {
+ int retval, i, tmp;
+
+ for (i = 0, retval = 0; i < 4; i++) {
+ retval <<= 7;
+ tmp = in.getByte ();
+ retval |= (tmp & 0x07f);
+ if ((tmp & 0x080) == 0)
+ return retval;
+ }
+
+ throw new IOException ("ObjectIdentifier() -- component value too big");
+ }
+
+ /*
+ * Reverse of the above routine. Notice it needs to emit in
+ * big-endian form, so it buffers the output until it's ready.
+ * (Minimum length encoding is a DER requirement.)
+ */
+ private static void putComponent (DerOutputStream out, int val)
+ throws IOException
+ {
+ int i;
+ // TODO: val must be <128*128*128*128 here, otherwise, 4 bytes is not
+ // enough to hold it. Will address this later.
+ byte buf [] = new byte [4] ;
+
+ for (i = 0; i < 4; i++) {
+ buf [i] = (byte) (val & 0x07f);
+ val >>>= 7;
+ if (val == 0)
+ break;
+ }
+ for ( ; i > 0; --i)
+ out.write (buf [i] | 0x080);
+ out.write (buf [0]);
+ }
+
+ // XXX this API should probably facilitate the JDK sort utility
+
+ /**
+ * Compares this identifier with another, for sorting purposes.
+ * An identifier does not precede itself.
+ *
+ * @param other identifer that may precede this one.
+ * @return true iff other precedes this one
+ * in a particular sorting order.
+ */
+ public boolean precedes (ObjectIdentifier other)
+ {
+ int i;
+
+ // shorter IDs go first
+ if (other == this || componentLen < other.componentLen)
+ return false;
+ if (other.componentLen < componentLen)
+ return true;
+
+ // for each component, the lesser component goes first
+ for (i = 0; i < componentLen; i++) {
+ if (other.components [i] < components [i])
+ return true;
+ }
+
+ // identical IDs don't precede each other
+ return false;
+ }
+
+ /**
+ * @deprecated Use equals((Object)oid)
+ */
+ @Deprecated
+ public boolean equals(ObjectIdentifier other) {
+ return equals((Object)other);
+ }
+
+ /**
+ * Compares this identifier with another, for equality.
+ *
+ * @return true iff the names are identical.
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ObjectIdentifier == false) {
+ return false;
+ }
+ ObjectIdentifier other = (ObjectIdentifier)obj;
+ if (componentLen != other.componentLen) {
+ return false;
+ }
+ for (int i = 0; i < componentLen; i++) {
+ if (components[i] != other.components[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ int h = componentLen;
+ for (int i = 0; i < componentLen; i++) {
+ h += components[i] * 37;
+ }
+ return h;
+ }
+
+ /**
+ * Returns a string form of the object ID. The format is the
+ * conventional "dot" notation for such IDs, without any
+ * user-friendly descriptive strings, since those strings
+ * will not be understood everywhere.
+ */
+ public String toString() {
+ String s = stringForm;
+ if (s == null) {
+ StringBuffer sb = new StringBuffer(componentLen * 4);
+ for (int i = 0; i < componentLen; i++) {
+ if (i != 0) {
+ sb.append('.');
+ }
+ sb.append(components[i]);
+ }
+ s = sb.toString();
+ stringForm = s;
+ }
+ return s;
+ }
+
+ /*
+ * To simplify, we assume no individual component of an object ID is
+ * larger than 32 bits. Then we represent the path from the root as
+ * an array that's (usually) only filled at the beginning.
+ */
+ private int components []; // path from root
+ private int componentLen; // how much is used.
+
+ private transient volatile String stringForm;
+
+ private static final int allocationQuantum = 5; // >= 2
+}
values
may be longer than len
.
+ * In this case, only the first len
items are checked.
+ * @exception IOException if this is not a legal OID
+ */
+ private void checkValidOid(int[] values, int len) throws IOException {
+ if (values == null || len < 2) {
+ throw new IOException("ObjectIdentifier() -- " +
+ "Must be at least two oid components ");
+ }
+
+ for (int i=0; i