CVSROOT: /cvsroot/classpath Module name: classpath Branch: ssl Changes by: Casey Marshall <rsdio> 06/06/06 01:01:21
Modified files: . : ChangeLog-ssl-nio gnu/javax/net/ssl/provider: Extension.java jessie-tests : run-tests.sh Added files: gnu/javax/net/ssl/provider: ExtensionList.java jessie-tests : testExtensionsList.java Log message: 2006-06-05 Casey Marshall <[EMAIL PROTECTED]> * gnu/javax/net/ssl/provider/Extension.java: add Javadoc. (length): return the length of the extension value. (setLength, setType, setValue, setValue): new methods. * gnu/javax/net/ssl/provider/ExtensionList.java: new file. * jessie-tests/run-tests.sh: add testExtensionList. * jessie-tests/testExtensionList.java: new file. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog-ssl-nio?cvsroot=classpath&only_with_tag=ssl&r1=1.1.2.3&r2=1.1.2.4 http://cvs.savannah.gnu.org/viewcvs/classpath/gnu/javax/net/ssl/provider/Extension.java?cvsroot=classpath&only_with_tag=ssl&r1=1.1.4.1.2.1&r2=1.1.4.1.2.2 http://cvs.savannah.gnu.org/viewcvs/classpath/gnu/javax/net/ssl/provider/ExtensionList.java?cvsroot=classpath&only_with_tag=ssl&rev=1.1.2.1 http://cvs.savannah.gnu.org/viewcvs/classpath/jessie-tests/run-tests.sh?cvsroot=classpath&only_with_tag=ssl&r1=1.1.4.2&r2=1.1.4.3 http://cvs.savannah.gnu.org/viewcvs/classpath/jessie-tests/testExtensionsList.java?cvsroot=classpath&only_with_tag=ssl&rev=1.1.2.1 Patches: Index: ChangeLog-ssl-nio =================================================================== RCS file: /cvsroot/classpath/classpath/Attic/ChangeLog-ssl-nio,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -u -b -r1.1.2.3 -r1.1.2.4 --- ChangeLog-ssl-nio 6 Jun 2006 00:47:28 -0000 1.1.2.3 +++ ChangeLog-ssl-nio 6 Jun 2006 01:01:19 -0000 1.1.2.4 @@ -1,5 +1,14 @@ 2006-06-05 Casey Marshall <[EMAIL PROTECTED]> + * gnu/javax/net/ssl/provider/Extension.java: add Javadoc. + (length): return the length of the extension value. + (setLength, setType, setValue, setValue): new methods. + * gnu/javax/net/ssl/provider/ExtensionList.java: new file. + * jessie-tests/run-tests.sh: add testExtensionList. + * jessie-tests/testExtensionList.java: new file. + +2006-06-05 Casey Marshall <[EMAIL PROTECTED]> + * gnu/javax/net/ssl/provider/CipherSuiteList.java: implement Iterable<CipherSuite>. (iterator): new method. @@ -20,4 +29,3 @@ * gnu/javax/net/ssl/provider/ServerHelloDone.java: made public. * jessie-tests/run-tests.sh: add `testServerHelloDone.' * jessie-tests/testServerHelloDone.java: new test. - Index: gnu/javax/net/ssl/provider/Extension.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/javax/net/ssl/provider/Extension.java,v retrieving revision 1.1.4.1.2.1 retrieving revision 1.1.4.1.2.2 diff -u -b -r1.1.4.1.2.1 -r1.1.4.1.2.2 --- gnu/javax/net/ssl/provider/Extension.java 3 Jun 2006 07:49:53 -0000 1.1.4.1.2.1 +++ gnu/javax/net/ssl/provider/Extension.java 6 Jun 2006 01:01:19 -0000 1.1.4.1.2.2 @@ -43,6 +43,17 @@ import java.nio.ByteBuffer; +/** + * An SSL hello extension. + * + * <pre> + * struct { + * ExtensionType extension_type; + * opaque extension_data<0..2^16-1>; + * } Extension;</pre> + * + * @author [EMAIL PROTECTED] + */ public final class Extension implements Constructed { @@ -64,7 +75,7 @@ public int length () { - return (buffer.getShort (2) & 0xFFFF) + 4; + return (buffer.getShort (2) & 0xFFFF); } public Type type() @@ -80,6 +91,30 @@ return value; } + public void setLength (final int newLength) + { + if (newLength < 0 || newLength > 65535) + throw new IllegalArgumentException ("length is out of bounds"); + buffer.putShort (2, (short) newLength); + } + + public void setType (final Type type) + { + buffer.putShort(0, (short) type.getValue()); + } + + public void setValue (byte[] value) + { + setValue (value, 0, value.length); + } + + public void setValue (final byte[] value, final int offset, final int length) + { + if (length != length ()) + throw new IllegalArgumentException ("length is different than claimed length"); + ((ByteBuffer) buffer.duplicate().position(4)).put(value, offset, length); + } + public String toString() { return toString(null); Index: jessie-tests/run-tests.sh =================================================================== RCS file: /cvsroot/classpath/classpath/jessie-tests/Attic/run-tests.sh,v retrieving revision 1.1.4.2 retrieving revision 1.1.4.3 diff -u -b -r1.1.4.2 -r1.1.4.3 --- jessie-tests/run-tests.sh 3 Jun 2006 19:52:52 -0000 1.1.4.2 +++ jessie-tests/run-tests.sh 6 Jun 2006 01:01:20 -0000 1.1.4.3 @@ -7,7 +7,7 @@ tests="testAlert testCertificate testCertificateRequest \ testCipherSuiteList testClientHello testCompressionMethodList \ - testHelloRequest testRecord testServerDHParams \ + testExtensionList testHelloRequest testRecord testServerDHParams \ testServerHello testServerHelloDone testServerKeyExchange \ testServerRSAParams testSignature" Index: gnu/javax/net/ssl/provider/ExtensionList.java =================================================================== RCS file: gnu/javax/net/ssl/provider/ExtensionList.java diff -N gnu/javax/net/ssl/provider/ExtensionList.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/javax/net/ssl/provider/ExtensionList.java 6 Jun 2006 01:01:19 -0000 1.1.2.1 @@ -0,0 +1,270 @@ +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +/** + * A list of extensions, that may appear in either the [EMAIL PROTECTED] ClientHello} or + * [EMAIL PROTECTED] ServerHello}. The form of the extensions list is: + * + * <tt> Extension extensions_list<1..2^16-1></tt> + * + * @author csm + */ +public class ExtensionList implements Iterable<Extension> +{ + private final ByteBuffer buffer; + private int modCount; + + public ExtensionList (ByteBuffer buffer) + { + this.buffer = buffer; + modCount = 0; + } + + public Extension get (final int index) + { + int length = length (); + int i; + int n = 0; + for (i = 2; i < length && n < index; ) + { + int l = buffer.getShort (i+2) & 0xFFFF; + i += l + 4; + n++; + } + if (n < index) + throw new IndexOutOfBoundsException ("no elemenet at " + index); + int el = buffer.getShort (i+2) & 0xFFFF; + return new Extension (((ByteBuffer) buffer.duplicate().position(i).limit(i+el+4)).slice()); + } + + /** + * Returns the number of extensions this list contains. + * + * @return The number of extensions. + */ + public int size () + { + int length = length (); + if (length == 0) + return 0; + int n = 0; + for (int i = 2; i < length; ) + { + int len = buffer.getShort (i+2) & 0xFFFF; + i += len + 4; + n++; + } + return n; + } + + /** + * Returns the length of this extension list, in bytes. + * + * @return The length of this extension list, in bytes. + */ + public int length () + { + return buffer.getShort (0) & 0xFFFF; + } + + /** + * Sets the extension at index <i>i</i> to <i>e</i>. Note that setting an + * element at an index <b>may</b> invalidate any other elements that come + * after element at index <i>i</i>. In other words, no attempt is made to + * move existing elements in this list, and since extensions are variable + * length, you can <em>not</em> guarantee that extensions later in the list + * will still be valid. + * + * <p>Thus, elements of this list <b>must</b> be set in order of increasing + * index. + * + * @param index The index to set the extension at. + * @param e The extension. + * @throws java.nio.BufferOverflowException If setting the extension overflows + * the buffer. + * @throws IllegalArgumentException If it isn't possible to find the given index + * in the current list (say, if no element index - 1 is set), or if setting + * the extension will overflow the current list length (given by [EMAIL PROTECTED] + * #length()}). + */ + public void set (final int index, Extension e) + { + int length = length(); + int n = 0; + int i; + for (i = 2; i < length && n < index; ) + { + int len = buffer.getShort(i+2) & 0xFFFF; + i += len + 4; + n++; + } + if (n < index) + throw new IllegalArgumentException("nothing set at index " + (index-1) + + " or insufficient space"); + if (i + e.length() + 2 > length) + throw new IllegalArgumentException("adding this element will exceed the " + + "list length"); + buffer.putShort(i, (short) e.type().getValue()); + buffer.putShort(i+2, (short) e.length()); + ((ByteBuffer) buffer.duplicate().position(i+4)).put (e.value()); + modCount++; + } + + /** + * Reserve space for an extension at index <i>i</i> in the list. In other + * words, this does the job of [EMAIL PROTECTED] #set(int, Extension)}, but does not + * copy the extension value to the underlying buffer. + * + * @param index The index of the extension to reserve space for. + * @param t The type of the extension. + * @param eLength The number of bytes to reserve for this extension. The total + * number of bytes used by this method is this length, plus four. + */ + public void set (final int index, Extension.Type t, final int eLength) + { + int length = length (); + int n = 0; + int i; + for (i = 2; i < length && n < index; ) + { + int len = buffer.getShort (i+2) & 0xFFFF; + i += len + 4; + n++; + } + if (n < index) + throw new IllegalArgumentException ("nothing set at index " + (index-1) + + " or insufficient space"); + if (i + eLength + 2 > length) + throw new IllegalArgumentException ("adding this element will exceed the " + + "list length"); + buffer.putShort(i, (short) t.getValue()); + buffer.putShort(i+2, (short) eLength); + modCount++; + } + + /** + * Set the total length of this list, in bytes. + * + * @param newLength The new list length. + */ + public void setLength (final int newLength) + { + if (newLength < 0 || newLength > 65535) + throw new IllegalArgumentException ("invalid length"); + buffer.putShort (0, (short) newLength); + modCount++; + } + + public Iterator<Extension> iterator() + { + return new ExtensionsIterator (); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println ("ExtensionList {"); + if (prefix != null) out.print (prefix); + out.print (" length = "); + out.print (length ()); + out.println (";"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + for (Extension e : this) + out.println (e.toString(subprefix)); + if (prefix != null) out.print (prefix); + out.println ("};"); + return str.toString(); + } + + /** + * List iterator interface to an extensions list. + * + * @author [EMAIL PROTECTED] + */ + public final class ExtensionsIterator implements ListIterator<Extension> + { + private final int modCount; + private int index; + private final int size; + + public ExtensionsIterator () + { + this.modCount = ExtensionList.this.modCount; + index = 0; + size = size (); + } + + public boolean hasNext() + { + return index < size; + } + + public boolean hasPrevious() + { + return index > 0; + } + + public Extension next() throws NoSuchElementException + { + if (modCount != ExtensionList.this.modCount) + throw new ConcurrentModificationException (); + if (!hasNext ()) + throw new NoSuchElementException (); + return get (index++); + } + + public Extension previous() throws NoSuchElementException + { + if (modCount != ExtensionList.this.modCount) + throw new ConcurrentModificationException (); + if (!hasPrevious ()) + throw new NoSuchElementException (); + return get (--index); + } + + public int nextIndex() + { + if (hasNext ()) + return index + 1; + return index; + } + + public int previousIndex() + { + if (hasPrevious ()) + return index - 1; + return -1; + } + + public void add(Extension e) + { + throw new UnsupportedOperationException ("cannot add items to this iterator"); + } + + public void remove() + { + throw new UnsupportedOperationException ("cannot remove items from this iterator"); + } + + public void set(Extension e) + { + ExtensionList.this.set (index, e); + } + } +} Index: jessie-tests/testExtensionsList.java =================================================================== RCS file: jessie-tests/testExtensionsList.java diff -N jessie-tests/testExtensionsList.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ jessie-tests/testExtensionsList.java 6 Jun 2006 01:01:20 -0000 1.1.2.1 @@ -0,0 +1,64 @@ +import gnu.javax.net.ssl.provider.Extension; +import gnu.javax.net.ssl.provider.ExtensionList; +import gnu.javax.net.ssl.provider.Extension.Type; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +class testExtensionList +{ + public static void main (String[] argv) + { + try + { + check (); + } + catch (Exception x) + { + System.out.println ("FAIL: caught exception " + x); + x.printStackTrace (System.err); + } + } + + static void check () throws Exception + { + ByteBuffer buf = ByteBuffer.allocate(4096); + ExtensionList list = new ExtensionList(buf); + + list.setLength (12); + // Max fragment length of 2^9-1 + list.set (0, Extension.Type.MAX_FRAGMENT_LENGTH, 1); // 2 + 2 + 1 + list.get (0).setValue (new byte[] { 1 }); + // Zero-length server name. + list.set (1, Extension.Type.SERVER_NAME, 3); // 2 + 2 + 3 + list.get(1).setValue(new byte[3]); + // This is a valid extension list now. + + if (list.length () == 12) + System.out.println ("PASS: length"); + else + System.out.println ("FAIL: length"); + + Extension e = list.get (0); + if (e.type() == Extension.Type.MAX_FRAGMENT_LENGTH) + System.out.println ("PASS: get(0).type()"); + else + System.out.println ("FAIL: get(0).type()"); + if (Arrays.equals (e.value(), new byte[] { 1 })) + System.out.println ("PASS: get(0).value()"); + else + System.out.println ("FAIL: get(0).value()"); + + e = list.get(1); + if (e.type () == Extension.Type.SERVER_NAME) + System.out.println ("PASS: get(1).type()"); + else + System.out.println ("FAIL: get(1).type()"); + if (Arrays.equals(e.value(), new byte[3])) + System.out.println ("PASS: get(1).value()"); + else + System.out.println ("FAIL: get(1).value()"); + + System.err.println (list); + } +} \ No newline at end of file