# HG changeset patch # User weijun # Date 1239170074 -28800 # Node ID a89e7cabf6fd4ad9057f899f97a67b2621bce50e # Parent 509945aa3d2a3e9e8e9e208a45685034a493f79c 4811968: ASN.1 (X509Certificate) implementations don't handle large OID components Reviewed-by: xuelei diff -r 509945aa3d2a -r a89e7cabf6fd jdk/src/share/classes/sun/security/util/ObjectIdentifier.java --- a/jdk/src/share/classes/sun/security/util/ObjectIdentifier.java Mon Apr 06 18:52:03 2009 -0700 +++ b/jdk/src/share/classes/sun/security/util/ObjectIdentifier.java Wed Apr 08 13:54:34 2009 +0800 @@ -26,7 +26,8 @@ package sun.security.util; import java.io.*; - +import java.math.BigInteger; +import java.util.Arrays; /** * Represent an ISO Object Identifier. @@ -44,105 +45,186 @@ * 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 */ + /** + * We use the DER value (no tag, no length) as the internal format + * @serial + */ + private byte[] encoding = null; + + private transient volatile String stringForm; + + /* + * IMPORTANT NOTES FOR CODE CHANGES (bug 4811968) IN JDK 1.7.0 + * =========================================================== + * + * (Almost) serialization compatibility with old versions: + * + * serialVersionUID is unchanged. Old field "component" is changed to + * type Object so that "poison" (unknown object type for old versions) + * can be put inside if there are huge components that cannot be saved + * as integers. + * + * New version use the new filed "encoding" only. + * + * Below are all 4 cases in a serialization/deserialization process: + * + * 1. old -> old: Not covered here + * 2. old -> new: There's no "encoding" field, new readObject() reads + * "components" and "componentLen" instead and inits correctly. + * 3. new -> new: "encoding" field exists, new readObject() uses it + * (ignoring the other 2 fields) and inits correctly. + * 4. new -> old: old readObject() only recognizes "components" and + * "componentLen" fields. If no huge components are involved, they + * are serialized as legal values and old object can init correctly. + * Otherwise, old object cannot recognize the form (component not int[]) + * and throw a ClassNotFoundException at deserialization time. + * + * Therfore, for the first 3 cases, exact compatibility is preserved. In + * the 4th case, non-huge OID is still supportable in old versions, while + * huge OID is not. + */ 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. + * Changed to Object + * @serial + */ + private Object components = null; // path from root + /** + * @serial + */ + private int componentLen = -1; // how much is used. + + // Is the components field calculated? + transient private boolean componentsCalculated = false; + + private void readObject(ObjectInputStream is) + throws IOException, ClassNotFoundException { + is.defaultReadObject(); + + if (encoding == null) { // from an old version + init((int[])components, componentLen); + } + } + + private void writeObject(ObjectOutputStream os) + throws IOException { + if (!componentsCalculated) { + int[] comps = toIntArray(); + if (comps != null) { // every one understands this + components = comps; + componentLen = comps.length; + } else { + components = HugeOidNotSupportedByOldJDK.theOne; + } + componentsCalculated = true; + } + os.defaultWriteObject(); + } + + static class HugeOidNotSupportedByOldJDK implements Serializable { + private static final long serialVersionUID = 1L; + static HugeOidNotSupportedByOldJDK theOne = new HugeOidNotSupportedByOldJDK(); + } + + /** + * Constructs, from a string. This string should be of the form 1.23.56. + * Validity check included. */ public ObjectIdentifier (String oid) throws IOException { int ch = '.'; - int start = 0; + 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]; + int pos = 0; + byte[] tmp = new byte[oid.length()]; + int first = 0, second; + int count = 0; + + try { + String comp = null; + do { + int length = 0; // length of one section + end = oid.indexOf(ch,start); + if (end == -1) { + comp = oid.substring(start); + length = oid.length() - start; + } else { + comp = oid.substring(start,end); + length = end - start; + } - 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(); + if (length > 9) { + BigInteger bignum = new BigInteger(comp); + if (count == 0) { + checkFirstComponent(bignum); + first = bignum.intValue(); + } else { + if (count == 1) { + checkSecondComponent(first, bignum); + bignum = bignum.add(BigInteger.valueOf(40*first)); + } else { + checkOtherComponent(count, bignum); + } + pos += pack7Oid(bignum, tmp, pos); + } + } else { + int num = Integer.parseInt(comp); + if (count == 0) { + checkFirstComponent(num); + first = num; + } else { + if (count == 1) { + checkSecondComponent(first, num); + num += 40 * first; + } else { + checkOtherComponent(count, num); + } + pos += pack7Oid(num, tmp, pos); + } + } start = end + 1; - } - comp = oid.substring(start); - components[i] = Integer.valueOf(comp).intValue(); + count++; + } while (end != -1); + + checkCount(count); + encoding = new byte[pos]; + System.arraycopy(tmp, 0, encoding, 0, pos); + this.stringForm = oid; + } catch (IOException ioe) { // already detected by checkXXX + throw ioe; } 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 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 maxFirstComponent) { - throw new IOException("ObjectIdentifier() -- " + - "First oid component is invalid "); - } - - if (values[0] < 2 && values[1] > maxSecondComponent) { - throw new IOException("ObjectIdentifier() -- " + - "Second oid component is invalid "); - } - } - /** - * Constructs an object ID from an array of integers. This - * is used to construct constant object IDs. + * Constructor, from an array of integers. + * Validity check included. */ public ObjectIdentifier (int values []) throws IOException { - checkValidOid(values, values.length); - components = values.clone(); - componentLen = values.length; + checkCount(values.length); + checkFirstComponent(values[0]); + checkSecondComponent(values[0], values[1]); + for (int i=2; i bufferEnd; - ) { - component = getComponent (in); - if (component < 0) { - throw new IOException( - "ObjectIdentifier() -- " + - "component values must be nonnegative"); - } - if (first_subid) { - int X, Y; + DerInputStream in = new DerInputStream(buf); + encoding = new byte[in.available()]; + in.getBytes(encoding); + check(encoding); + } - /* - * 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; + private void init(int[] components, int length) { + int pos = 0; + byte[] tmp = new byte[length*5+1]; // +1 for empty input - } 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; - } + if (components[1] < Integer.MAX_VALUE - components[0]*40) + pos += pack7Oid(components[0]*40+components[1], tmp, pos); + else { + BigInteger big = BigInteger.valueOf(components[1]); + big = big.add(BigInteger.valueOf(components[0]*40)); + pos += pack7Oid(big, tmp, pos); } - checkValidOid(components, componentLen); + for (int i=2; i>>= 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; + out.write (DerValue.tag_ObjectId, encoding); } /** @@ -398,6 +331,7 @@ * * @return true iff the names are identical. */ + @Override public boolean equals(Object obj) { if (this == obj) { return true; @@ -406,23 +340,71 @@ 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 Arrays.equals(encoding, other.encoding); + } + + @Override + public int hashCode() { + return Arrays.hashCode(encoding); + } + + /** + * Private helper method for serialization. To be compatible with old + * versions of JDK. + * @return components in an int array, if all the components are less than + * Integer.MAX_VALUE. Otherwise, null. + */ + private int[] toIntArray() { + int length = encoding.length; + int[] result = new int[20]; + int which = 0; + int fromPos = 0; + for (int i = 0; i < length; i++) { + if ((encoding[i] & 0x80) == 0) { + // one section [fromPos..i] + if (i - fromPos + 1 > 4) { + BigInteger big = new BigInteger(pack(encoding, fromPos, i-fromPos+1, 7, 8)); + if (fromPos == 0) { + result[which++] = 2; + BigInteger second = big.subtract(BigInteger.valueOf(80)); + if (second.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == 1) { + return null; + } else { + result[which++] = second.intValue(); + } + } else { + if (big.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == 1) { + return null; + } else { + result[which++] = big.intValue(); + } + } + } else { + int retval = 0; + for (int j = fromPos; j <= i; j++) { + retval <<= 7; + byte tmp = encoding[j]; + retval |= (tmp & 0x07f); + } + if (fromPos == 0) { + if (retval < 80) { + result[which++] = retval / 40; + result[which++] = retval % 40; + } else { + result[which++] = 2; + result[which++] = retval - 80; + } + } else { + result[which++] = retval; + } + } + fromPos = i+1; + } + if (which >= result.length) { + result = Arrays.copyOf(result, which + 10); } } - return true; - } - - public int hashCode() { - int h = componentLen; - for (int i = 0; i < componentLen; i++) { - h += components[i] * 37; - } - return h; + return Arrays.copyOf(result, which); } /** @@ -431,15 +413,52 @@ * user-friendly descriptive strings, since those strings * will not be understood everywhere. */ + @Override 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('.'); + int length = encoding.length; + StringBuffer sb = new StringBuffer(length * 4); + + int fromPos = 0; + for (int i = 0; i < length; i++) { + if ((encoding[i] & 0x80) == 0) { + // one section [fromPos..i] + if (fromPos != 0) { // not the first segment + sb.append('.'); + } + if (i - fromPos + 1 > 4) { // maybe big integer + BigInteger big = new BigInteger(pack(encoding, fromPos, i-fromPos+1, 7, 8)); + if (fromPos == 0) { + // first section encoded with more than 4 bytes, + // must be 2.something + sb.append("2."); + sb.append(big.subtract(BigInteger.valueOf(80))); + } else { + sb.append(big); + } + } else { // small integer + int retval = 0; + for (int j = fromPos; j <= i; j++) { + retval <<= 7; + byte tmp = encoding[j]; + retval |= (tmp & 0x07f); + } + if (fromPos == 0) { + if (retval < 80) { + sb.append(retval/40); + sb.append('.'); + sb.append(retval%40); + } else { + sb.append("2."); + sb.append(retval - 80); + } + } else { + sb.append(retval); + } + } + fromPos = i+1; } - sb.append(components[i]); } s = sb.toString(); stringForm = s; @@ -447,15 +466,197 @@ 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. + /** + * Repack all bits from input to output. On the both sides, only a portion + * (from the least significant bit) of the 8 bits in a byte is used. This + * number is defined as the number of useful bits (NUB) for the array. All the + * used bits from the input byte array and repacked into the output in the + * exactly same order. The output bits are aligned so that the final bit of + * the input (the least significant bit in the last byte), when repacked as + * the final bit of the output, is still at the least significant position. + * Zeroes will be padded on the left side of the first output byte if + * necessary. All unused bits in the output are also zeroed. + * + * For example: if the input is 01001100 with NUB 8, the output which + * has a NUB 6 will look like: + * 00000001 00001100 + * The first 2 bits of the output bytes are unused bits. The other bits + * turn out to be 000001 001100. While the 8 bits on the right are from + * the input, the left 4 zeroes are padded to fill the 6 bits space. + * + * @param in the input byte array + * @param ioffset start point inside in + * @param ilength number of bytes to repack + * @param iw NUB for input + * @param ow NUB for output + * @return the repacked bytes + */ + private static byte[] pack(byte[] in, int ioffset, int ilength, int iw, int ow) { + assert (iw > 0 && iw <= 8): "input NUB must be between 1 and 8"; + assert (ow > 0 && ow <= 8): "output NUB must be between 1 and 8"; + + if (iw == ow) { + return in.clone(); + } + + int bits = ilength * iw; // number of all used bits + byte[] out = new byte[(bits+ow-1)/ow]; + + // starting from the 0th bit in the input + int ipos = 0; + + // the number of padding 0's needed in the output, skip them + int opos = (bits+ow-1)/ow*ow-bits; + + while(ipos < bits) { + int count = iw - ipos%iw; // unpacked bits in current input byte + if (count > ow - opos%ow) { // free space available in output byte + count = ow - opos%ow; // choose the smaller number + } + // and move them! + out[opos/ow] |= // paste! + (((in[ioffset+ipos/iw]+256) // locate the byte (+256 so that it's never negative) + >> (iw-ipos%iw-count)) // move to the end of a byte + & ((1 << (count))-1)) // zero out all other bits + << (ow-opos%ow-count); // move to the output position + ipos += count; // advance + opos += count; // advance + } + return out; + } + + /** + * Repack from NUB 8 to a NUB 7 OID sub-identifier, remove all + * unnecessary 0 headings, set the first bit of all non-tail + * output bytes to 1 (as ITU-T Rec. X.690 8.19.2 says), and + * paste it into an existing byte array. + * @param out the existing array to be pasted into + * @param ooffset the starting position to paste + * @return the number of bytes pasted + */ + private static int pack7Oid(byte[] in, int ioffset, int ilength, byte[] out, int ooffset) { + byte[] pack = pack(in, ioffset, ilength, 8, 7); + int firstNonZero = pack.length-1; // paste at least one byte + for (int i=pack.length-2; i>=0; i--) { + if (pack[i] != 0) { + firstNonZero = i; + } + pack[i] |= 0x80; + } + System.arraycopy(pack, firstNonZero, out, ooffset, pack.length-firstNonZero); + return pack.length-firstNonZero; + } + + /** + * Repack from NUB 7 to NUB 8, remove all unnecessary 0 + * headings, and paste it into an existing byte array. + * @param out the existing array to be pasted into + * @param ooffset the starting position to paste + * @return the number of bytes pasted */ - private int components []; // path from root - private int componentLen; // how much is used. + private static int pack8(byte[] in, int ioffset, int ilength, byte[] out, int ooffset) { + byte[] pack = pack(in, ioffset, ilength, 7, 8); + int firstNonZero = pack.length-1; // paste at least one byte + for (int i=pack.length-2; i>=0; i--) { + if (pack[i] != 0) { + firstNonZero = i; + } + } + System.arraycopy(pack, firstNonZero, out, ooffset, pack.length-firstNonZero); + return pack.length-firstNonZero; + } + + /** + * Pack the int into a OID sub-identifier DER encoding + */ + private static int pack7Oid(int input, byte[] out, int ooffset) { + byte[] b = new byte[4]; + b[0] = (byte)(input >> 24); + b[1] = (byte)(input >> 16); + b[2] = (byte)(input >> 8); + b[3] = (byte)(input); + return pack7Oid(b, 0, 4, out, ooffset); + } + + /** + * Pack the BigInteger into a OID subidentifier DER encoding + */ + private static int pack7Oid(BigInteger input, byte[] out, int ooffset) { + byte[] b = input.toByteArray(); + return pack7Oid(b, 0, b.length, out, ooffset); + } + + /** + * Private methods to check validity of OID. They must be -- + * 1. at least 2 components + * 2. all components must be non-negative + * 3. the first must be 0, 1 or 2 + * 4. if the first is 0 or 1, the second must be <40 + */ - private transient volatile String stringForm; - - private static final int allocationQuantum = 5; // >= 2 + /** + * Check the DER encoding. Since DER encoding defines that the integer bits + * are unsigned, so there's no need to check the MSB. + */ + private static void check(byte[] encoding) throws IOException { + int length = encoding.length; + if (length < 1 || // too short + (encoding[length - 1] & 0x80) != 0) { // not ended + throw new IOException("ObjectIdentifier() -- " + + "Invalid DER encoding, not ended"); + } + for (int i=0; i 2) { + throw new IOException("ObjectIdentifier() -- " + + "First oid component is invalid "); + } + } + private static void checkFirstComponent(BigInteger first) throws IOException { + if (first.signum() == -1 || + first.compareTo(BigInteger.valueOf(2)) == 1) { + throw new IOException("ObjectIdentifier() -- " + + "First oid component is invalid "); + } + } + private static void checkSecondComponent(int first, int second) throws IOException { + if (second < 0 || first != 2 && second > 39) { + throw new IOException("ObjectIdentifier() -- " + + "Second oid component is invalid "); + } + } + private static void checkSecondComponent(int first, BigInteger second) throws IOException { + if (second.signum() == -1 || + first != 2 && + second.compareTo(BigInteger.valueOf(39)) == 1) { + throw new IOException("ObjectIdentifier() -- " + + "Second oid component is invalid "); + } + } + private static void checkOtherComponent(int i, int num) throws IOException { + if (num < 0) { + throw new IOException("ObjectIdentifier() -- " + + "oid component #" + (i+1) + " must be non-negative "); + } + } + private static void checkOtherComponent(int i, BigInteger num) throws IOException { + if (num.signum() == -1) { + throw new IOException("ObjectIdentifier() -- " + + "oid component #" + (i+1) + " must be non-negative "); + } + } } diff -r 509945aa3d2a -r a89e7cabf6fd jdk/test/sun/security/util/Oid/OidFormat.java --- a/jdk/test/sun/security/util/Oid/OidFormat.java Mon Apr 06 18:52:03 2009 -0700 +++ b/jdk/test/sun/security/util/Oid/OidFormat.java Wed Apr 08 13:54:34 2009 +0800 @@ -63,9 +63,22 @@ "1.2.3", "1.2.3445", "1.3.6.1.4.1.42.2.17", // 4811968: ASN.1 cannot handle huge OID components - //"2.16.764.1.3101555394.1.0.100.2.1", - //"1.2.2147483647.4", - //"1.2.268435456.4", + "2.16.764.1.3101555394.1.0.100.2.1", + "2.2726957624935694386592435", // as huge as possible + "1.2.777777777777777777", + "1.2.888888888888888888.111111111111111.2222222222222.33333333333333333.44444444444444", + "1.2." + + "1111111111111111111111111111111111111111111111111111111111111." + + "2222222222222222222222222222222222222222222222222222222222222222." + + "333333333333333333333333333333333333333333333333333333333333333." + + "4444444444444444444444444444444444444444444444444444444." + + "55555555555555555555555555555555555555555555555555555555555555555555555." + + "666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666." + + "77777777777777777777777777777777777777777777777777777777777777777777777777." + + "8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888." + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", + "1.2.2147483647.4", + "1.2.268435456.4", }; for (String s: goodOids) { diff -r 509945aa3d2a -r a89e7cabf6fd jdk/test/sun/security/util/Oid/S11N.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/util/Oid/S11N.sh Wed Apr 08 13:54:34 2009 +0800 @@ -0,0 +1,164 @@ +# +# Copyright 2004-2005 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. +# +# 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. +# +# @test +# @bug 4811968 +# @summary Serialization compatibility with old versions +# @author Weijun Wang +# +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory + +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES="." +fi +if [ "${TESTJAVA}" = "" ] ; then + echo "TESTJAVA not set. Test cannot execute." + echo "FAILED!!!" + exit 1 +fi + +# set platform-dependent variables +PF="" + +OS=`uname -s` +case "$OS" in + SunOS ) + FS="/" + ARCH=`isainfo` + case "$ARCH" in + sparc* ) + PF="solaris-sparc" + ;; + i[3-6]86 ) + PF="solaris-i586" + ;; + amd64* ) + PF="solaris-amd64" + ;; + * ) + echo "Unsupported System: Solaris ${ARCH}" + exit 0; + ;; + esac + ;; + Linux ) + ARCH=`uname -m` + FS="/" + case "$ARCH" in + i[3-6]86 ) + PF="linux-i586" + ;; + amd64* ) + PF="linux-amd64" + ;; + * ) + echo "Unsupported System: Linux ${ARCH}" + exit 0; + ;; + esac + ;; + Windows* ) + FS="\\" + PF="windows-i586" + + # 'uname -m' does not give us enough information - + # should rely on $PROCESSOR_IDENTIFIER (as is done in Defs-windows.gmk), + # but JTREG does not pass this env variable when executing a shell script. + # + # execute test program - rely on it to exit if platform unsupported + + ;; + * ) + echo "Unsupported System: ${OS}" + exit 0; + ;; +esac + +# the test code + +${TESTJAVA}${FS}bin${FS}javac -source 1.3 -target 1.3 -d . ${TESTSRC}${FS}SerialTest.java || exit 10 + +OLDJAVA=" + /java/re/j2se/1.6.0/latest/binaries/${PF} + /java/re/j2se/1.5.0/latest/binaries/${PF} + /java/re/j2se/1.4.2/latest/binaries/${PF} +" + +SMALL=" + 0.0 + 1.1 + 2.2 + 1.2.3456 + 1.2.2147483647.4 + 1.2.268435456.4 +" + +HUGE=" + 2.16.764.1.3101555394.1.0.100.2.1 + 1.2.2147483648.4 + 2.3.4444444444444444444444 + 1.2.888888888888888888.111111111111111.2222222222222.33333333333333333.44444444444444 +" + +for oid in ${SMALL}; do + echo ${oid} + # new -> + ${TESTJAVA}${FS}bin${FS}java SerialTest out ${oid} > tmp.oid.serial || exit 1 + # -> new + ${TESTJAVA}${FS}bin${FS}java SerialTest in ${oid} < tmp.oid.serial || exit 2 + for oldj in ${OLDJAVA}; do + if [ -d ${oldj} ]; then + echo ${oldj} + # -> old + ${oldj}${FS}bin${FS}java SerialTest in ${oid} < tmp.oid.serial || exit 3 + # old -> + ${oldj}${FS}bin${FS}java SerialTest out ${oid} > tmp.oid.serial.old || exit 4 + # -> new + ${TESTJAVA}${FS}bin${FS}java SerialTest in ${oid} < tmp.oid.serial.old || exit 5 + fi + done +done + +for oid in ${HUGE}; do + echo ${oid} + # new -> + ${TESTJAVA}${FS}bin${FS}java SerialTest out ${oid} > tmp.oid.serial || exit 1 + # -> new + ${TESTJAVA}${FS}bin${FS}java SerialTest in ${oid} < tmp.oid.serial || exit 2 + for oldj in ${OLDJAVA}; do + if [ -d ${oldj} ]; then + echo ${oldj} + # -> old + ${oldj}${FS}bin${FS}java SerialTest badin < tmp.oid.serial || exit 3 + fi + done +done + +rm -f tmp.oid.serial +rm -f tmp.oid.serial.old +rm -f SerialTest.class + +exit 0 diff -r 509945aa3d2a -r a89e7cabf6fd jdk/test/sun/security/util/Oid/SerialTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/util/Oid/SerialTest.java Wed Apr 08 13:54:34 2009 +0800 @@ -0,0 +1,66 @@ +/* + * Copyright 2004 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. + * + * 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. + */ + +/* + * read S11.sh + */ +import java.io.*; +import sun.security.util.*; + +/** + * Test OID serialization between versions + * + * java SerialTest out oid // write a OID into System.out + * java SerialTest in oid // read from System.in and compare it with oid + * java SerialTest badin // make sure *cannot* read from System.in + */ +class SerialTest { + public static void main(String[] args) throws Exception { + if (args[0].equals("out")) + out(args[1]); + else if (args[0].equals("in")) + in(args[1]); + else + badin(); + } + + static void in(String oid) throws Exception { + ObjectIdentifier o = (ObjectIdentifier) (new ObjectInputStream(System.in).readObject()); + if (!o.toString().equals(oid)) + throw new Exception("Read Fail " + o + ", not " + oid); + } + + static void badin() throws Exception { + boolean pass = true; + try { + new ObjectInputStream(System.in).readObject(); + } catch (Exception e) { + pass = false; + } + if (pass) throw new Exception("Should fail but not"); + } + + static void out(String oid) throws Exception { + new ObjectOutputStream(System.out).writeObject(new ObjectIdentifier(oid)); + } +}