diff options
Diffstat (limited to 'libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java')
-rw-r--r-- | libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java | 315 |
1 files changed, 151 insertions, 164 deletions
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java index 259051df129..54d7f8b4d74 100644 --- a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java @@ -38,216 +38,203 @@ exception statement from your version. */ package gnu.javax.net.ssl.provider; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; import java.io.PrintWriter; -import java.io.StringReader; import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; -import javax.net.ssl.SSLProtocolException; - -final class ClientHello implements Handshake.Body +/** + * A ClientHello handshake message. + * + * <pre> +struct +{ + ProtocolVersion client_version; // 2 + Random random; // 32 + SessionID session_id; // 1 + 0..32 + CipherSuite cipher_suites<2..2^16-1> + CompressionMethod compression_methods<1..2^8-1> + Extension client_hello_extension_list<0..2^16-1> +} ClientHello; +</pre> + */ +public class ClientHello implements Handshake.Body { // Fields. // ------------------------------------------------------------------------- - private ProtocolVersion version; - private Random random; - private byte[] sessionId; - private List suites; - private List comp; - private List extensions; + // To help track offsets into the message: + // The location of the 'random' field. + protected static final int RANDOM_OFFSET = 2; + // The location of the sesion_id length. + protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET; + // The location of the session_id bytes (if any). + protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1; + + protected ByteBuffer buffer; + protected boolean disableExtensions; // Constructor. // ------------------------------------------------------------------------- - ClientHello(ProtocolVersion version, Random random, - byte[] sessionId, List suites, List comp) + public ClientHello (final ByteBuffer buffer) { - this(version, random, sessionId, suites, comp, null); + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + disableExtensions = false; } - ClientHello(ProtocolVersion version, Random random, - byte[] sessionId, List suites, List comp, List extensions) + // Instance methods. + // ------------------------------------------------------------------------- + + public int length() { - this.version = version; - this.random = random; - this.sessionId = sessionId; - this.suites = suites; - this.comp = comp; - this.extensions = extensions; + int len = SESSID_OFFSET2 + buffer.get(SESSID_OFFSET); + len += (buffer.getShort(len) & 0xFFFF) + 2; + len += (buffer.get(len) & 0xFF) + 1; + if (!disableExtensions && len + 1 < buffer.capacity()) + len += (buffer.getShort(len) & 0xFFFF) + 2; + return len; } - // Class methods. - // ------------------------------------------------------------------------- + /** + * Gets the protocol version field. + * + * @return The protocol version field. + */ + public ProtocolVersion version() + { + return ProtocolVersion.getInstance (buffer.getShort (0)); + } - static ClientHello read(InputStream in) throws IOException + /** + * Gets the SSL nonce. + * + * @return The nonce. + */ + public Random random() { - ProtocolVersion vers = ProtocolVersion.read(in); - Random rand = Random.read(in); - byte[] id = new byte[in.read() & 0xFF]; - in.read(id); - int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); - ArrayList suites = new ArrayList(len / 2); - for (int i = 0; i < len; i += 2) - { - suites.add(CipherSuite.read(in).resolve(vers)); - } - len = in.read() & 0xFF; - ArrayList comp = new ArrayList(len); - for (int i = 0; i < len; i++) - { - comp.add(CompressionMethod.read(in)); - } - - List ext = null; - // Since parsing MAY need to continue into the extensions fields, or it - // may end here, the specified input stream MUST be a ByteArrayInputStream - // over all the data this hello contains. Otherwise this will mess up - // the data stream. - if (in.available() > 0) // then we have extensions. - { - ext = new LinkedList(); - len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); - int count = 0; - while (count < len) - { - Extension e = Extension.read(in); - ext.add(e); - count += e.getValue().length + 4; - } - } - return new ClientHello(vers, rand, id, suites, comp, ext); + ByteBuffer randomBuf = + ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET) + .limit (SESSID_OFFSET)).slice (); + return new Random (randomBuf); } - // Instance methods. - // ------------------------------------------------------------------------- + public byte[] sessionId() + { + int idlen = buffer.get (SESSID_OFFSET) & 0xFF; + byte[] sessionId = new byte[idlen]; + buffer.position (SESSID_OFFSET2); + buffer.get (sessionId); + return sessionId; + } - public void write(OutputStream out) throws IOException + public CipherSuiteList cipherSuites() { - version.write(out); - random.write(out); - out.write(sessionId.length); - out.write(sessionId); - out.write((suites.size() << 1) >>> 8 & 0xFF); - out.write((suites.size() << 1) & 0xFF); - for (Iterator i = suites.iterator(); i.hasNext(); ) - { - ((CipherSuite) i.next()).write(out); - } - out.write(comp.size()); - for (Iterator i = comp.iterator(); i.hasNext(); ) - { - out.write(((CompressionMethod) i.next()).getValue()); - } - if (extensions != null) - { - ByteArrayOutputStream out2 = new ByteArrayOutputStream(); - for (Iterator i = extensions.iterator(); i.hasNext(); ) - { - ((Extension) i.next()).write(out2); - } - out.write(out2.size() >>> 8 & 0xFF); - out.write(out2.size() & 0xFF); - out2.writeTo(out); - } + int offset = getCipherSuitesOffset (); + + // We give the CipherSuiteList all the remaining bytes to play with, + // since this might be an in-construction packet that will fill in + // the length field itself. + ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset) + .limit (buffer.capacity ())).slice (); + return new CipherSuiteList (listBuf, version ()); } - ProtocolVersion getVersion() + public CompressionMethodList compressionMethods() { - return version; + int offset = getCompressionMethodsOffset (); + ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset) + .limit (buffer.capacity ())).slice (); + return new CompressionMethodList (listBuf); + } + + public boolean hasExtensions() + { + int offset = getExtensionsOffset(); + return (offset + 1 < buffer.limit()); } - Random getRandom() + public ExtensionList extensions() + { + int offset = getExtensionsOffset (); + if (offset + 1 >= buffer.limit()) + return null; + int len = buffer.getShort(offset) & 0xFFFF; + if (len == 0) + len = buffer.limit() - offset - 2; + ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset) + .limit(offset + len + 2)).slice (); + return new ExtensionList(ebuf); + } + + public int extensionsLength() { - return random; + if (hasExtensions()) + return 0; + return buffer.getShort(getExtensionsOffset()) & 0xFFFF; } - byte[] getSessionId() + protected int getCipherSuitesOffset () { - return sessionId; + return (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF)); } - List getCipherSuites() + protected int getCompressionMethodsOffset () { - return suites; + int csOffset = getCipherSuitesOffset (); + int csLen = buffer.getShort (csOffset) & 0xFFFF; + return csOffset + csLen + 2; } - List getCompressionMethods() + protected int getExtensionsOffset () { - return comp; + int cmOffset = getCompressionMethodsOffset (); + return (buffer.get (cmOffset) & 0xFF) + cmOffset + 1; } - List getExtensions() + public String toString () { - return extensions; + return toString (null); } - public String toString() + public String toString (final String prefix) { - StringWriter str = new StringWriter(); - PrintWriter out = new PrintWriter(str); - out.println("struct {"); - out.println(" version = " + version + ";"); - BufferedReader r = new BufferedReader(new StringReader(random.toString())); - String s; - try - { - while ((s = r.readLine()) != null) - { - out.print(" "); - out.println(s); - } - } - catch (IOException ignored) - { - } - out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";"); - out.println(" cipherSuites = {"); - for (Iterator i = suites.iterator(); i.hasNext(); ) - { - out.print(" "); - out.println(i.next()); - } - out.println(" };"); - out.print(" compressionMethods = { "); - for (Iterator i = comp.iterator(); i.hasNext(); ) - { - out.print(i.next()); - if (i.hasNext()) - out.print(", "); - } - out.println(" };"); - if (extensions != null) - { - out.println(" extensions = {"); - for (Iterator i = extensions.iterator(); i.hasNext(); ) - { - r = new BufferedReader(new StringReader(i.next().toString())); - try - { - while ((s = r.readLine()) != null) - { - out.print(" "); - out.println(s); - } - } - catch (IOException ignored) - { - } - } - out.println(" };"); - } - out.println("} ClientHello;"); + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + String subprefix = " "; + if (prefix != null) + subprefix += prefix; + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + if (prefix != null) + out.print (prefix); + out.print (" version: "); + out.print (version ()); + out.println (";"); + out.print (subprefix); + out.println ("random:"); + out.print (random ().toString (subprefix)); + if (prefix != null) + out.print (prefix); + out.print (" sessionId: "); + out.print (Util.toHexString (sessionId (), ':')); + out.println (";"); + out.print (subprefix); + out.println ("cipher_suites:"); + out.println (cipherSuites ().toString (subprefix)); + out.print (subprefix); + out.println ("compression_methods:"); + out.println (compressionMethods ().toString (subprefix)); + out.print (subprefix); + out.print ("extensions: "); + ExtensionList el = extensions(); + out.println (el != null ? el.toString(subprefix+" ") : "(nil)"); + if (prefix != null) + out.print (prefix); + out.print ("} ClientHello;"); return str.toString(); } } |