summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasey Marshall <csm@gnu.org>2006-06-11 07:05:28 +0000
committerCasey Marshall <csm@gnu.org>2006-06-11 07:05:28 +0000
commitbbc0c3289deeb1a685316abd0bffee15bd40a46a (patch)
treecc9b024caf4fd040213309adbfb772e45b94eaed
parent61dcae3967de896a92e7e61754738b1c80ed5482 (diff)
downloadclasspath-bbc0c3289deeb1a685316abd0bffee15bd40a46a.tar.gz
2006-06-10 Casey Marshall <csm@gnu.org>
* gnu/javax/net/ssl/provider/ServerHello.java (extensions): return an ExtensionList. (setExtensionsLength): set the length in the buffer. (toString): print out individual extensions. * gnu/javax/net/ssl/provider/Extension.java (valueBytes): new method. (valueBuffer): new method. (value): return an Extenion.Value. (toString): print out extension value. (Value): new abstract inner class. * gnu/javax/net/ssl/provider/ClientHello.java (extensions): return an ExtensionList. (setExtensionListLength): set the length in the buffer. (toString): print out extensions. * gnu/javax/net/ssl/provider/ServerHandshake.java (chooseSuite, chooseCompression): use generics and foreach loops. * gnu/javax/net/ssl/provider/ExtensionList.java: new class. * gnu/javax/net/ssl/provider/MaxFragmentLength.java: new class. * gnu/javax/net/ssl/provider/CertificateURL.java: new class. * gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java: new class. * gnu/javax/net/ssl/provider/TruncatedHMAC.java: new class. * gnu/javax/net/ssl/provider/ServerNameList.java: new class. * gnu/javax/net/ssl/provider/TrustedAuthorities.java: new class. * gnu/javax/net/ssl/provider/CertificateStatusType.java: new class. * gnu/javax/net/ssl/provider/CertificateStatusRequest.java: new class.
-rw-r--r--gnu/javax/net/ssl/provider/CertificateStatusRequest.java204
-rw-r--r--gnu/javax/net/ssl/provider/CertificateStatusType.java13
-rw-r--r--gnu/javax/net/ssl/provider/CertificateURL.java300
-rw-r--r--gnu/javax/net/ssl/provider/ClientHello.java28
-rw-r--r--gnu/javax/net/ssl/provider/Extension.java53
-rw-r--r--gnu/javax/net/ssl/provider/ExtensionList.java2
-rw-r--r--gnu/javax/net/ssl/provider/MaxFragmentLength.java52
-rw-r--r--gnu/javax/net/ssl/provider/ServerHandshake.java17
-rw-r--r--gnu/javax/net/ssl/provider/ServerHello.java31
-rw-r--r--gnu/javax/net/ssl/provider/ServerNameList.java225
-rw-r--r--gnu/javax/net/ssl/provider/TruncatedHMAC.java31
-rw-r--r--gnu/javax/net/ssl/provider/TrustedAuthorities.java252
-rw-r--r--gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java40
13 files changed, 1213 insertions, 35 deletions
diff --git a/gnu/javax/net/ssl/provider/CertificateStatusRequest.java b/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
new file mode 100644
index 000000000..8bce9d549
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
@@ -0,0 +1,204 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * <pre>
+struct {
+ CertificateStatusType status_type;
+ select (status_type) {
+ case ocsp: OCSPStatusRequest;
+ } request;
+} CertificateStatusRequest;
+
+enum { ocsp(1), (255) } CertificateStatusType;
+
+struct {
+ ResponderID responder_id_list&lt;0..2^16-1&gt;;
+ Extensions request_extensions;
+} OCSPStatusRequest;
+
+opaque ResponderID&lt;1..2^16-1&gt;;
+opaque Extensions&lt;0..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class CertificateStatusRequest extends Value implements Iterable<byte[]>
+{
+ private final ByteBuffer buffer;
+
+ public CertificateStatusRequest(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ int l = 3 + (buffer.getShort(1) & 0xFFFF);
+ return l + (buffer.getShort(l) & 0xFFFF) + 2;
+ }
+
+ public CertificateStatusType statusType()
+ {
+ int x = buffer.get(0) & 0xFF;
+ if (x == 1)
+ return CertificateStatusType.OCSP;
+ throw new IllegalArgumentException ("invalid type: " + x);
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ for (int i = 3; i < len; )
+ {
+ int l = buffer.getShort(i);
+ i += l + 2;
+ n++;
+ }
+ return n;
+ }
+
+ public byte[] responderId(int index)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i = 3;
+ while (i < len && n <= index)
+ {
+ int l = buffer.getShort(i) & 0xFFFF;
+ if (n == index)
+ {
+ byte[] b = new byte[l];
+ ((ByteBuffer) buffer.duplicate().position(i+2)).get(b);
+ return b;
+ }
+ i += l + 2;
+ n++;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ public byte[] requestExtensions()
+ {
+ int l = 2 + (buffer.getShort(0) & 0xFFFF);
+ int ll = buffer.getShort(l) & 0xFFFF;
+ byte[] b = new byte[ll];
+ ((ByteBuffer) buffer.duplicate().position(ll+2)).get(b);
+ return b;
+ }
+
+ public void setStatusType(CertificateStatusType type)
+ {
+ buffer.put(0, (byte) type.value);
+ }
+
+ public void setRequestIdListLength(int newLength)
+ {
+ if (newLength < 0 || newLength > 0xFFFF)
+ throw new IllegalArgumentException("length out of range");
+ buffer.putShort(1, (short) newLength);
+ }
+
+ public void putRequestId(int index, byte[] id)
+ {
+ if (id.length > 0xFFFF)
+ throw new IllegalArgumentException("request ID too large");
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i = 3;
+ while (i < len && n < index)
+ {
+ int l = buffer.getShort(i) & 0xFFFF;
+ i += l + 2;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException();
+ buffer.putShort(i, (short) id.length);
+ ((ByteBuffer) buffer.duplicate().position(i)).put(id);
+ }
+
+ public void setRequestExtensions(int index, byte[] ext)
+ {
+ if (ext.length > 0xFFFF)
+ throw new IllegalArgumentException("exceptions too large");
+ int off = 3 + (buffer.getShort(1) & 0xFFFF);
+ buffer.putShort(off, (short) ext.length);
+ ((ByteBuffer) buffer.duplicate().position(off+2)).put(ext);
+ }
+
+ public Iterator<byte[]> iterator()
+ {
+ return new ResponderIdIterator();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" status_type = ");
+ out.print(statusType());
+ out.println(";");
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
+ if (prefix != null) out.print(prefix);
+ out.println(" responder_id_list = {");
+ for (byte[] b : this)
+ out.print(Util.hexDump(b, subprefix));
+ if (prefix != null) out.print(prefix);
+ out.println(" };");
+ if (prefix != null) out.print(prefix);
+ out.println(" request_extensions =");
+ out.print(Util.hexDump(requestExtensions(), subprefix));
+ if (prefix != null) out.print(prefix);
+ out.print("} CertificateStatus;");
+ return str.toString();
+ }
+
+ public class ResponderIdIterator implements Iterator<byte[]>
+ {
+ private int index;
+
+ public ResponderIdIterator()
+ {
+ index = 0;
+ }
+
+ public byte[] next() throws NoSuchElementException
+ {
+ try
+ {
+ return responderId(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/CertificateStatusType.java b/gnu/javax/net/ssl/provider/CertificateStatusType.java
new file mode 100644
index 000000000..7cddf168f
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CertificateStatusType.java
@@ -0,0 +1,13 @@
+package gnu.javax.net.ssl.provider;
+
+public enum CertificateStatusType
+{
+ OCSP (1);
+
+ public final int value;
+
+ private CertificateStatusType (final int value)
+ {
+ this.value = value;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/CertificateURL.java b/gnu/javax/net/ssl/provider/CertificateURL.java
new file mode 100644
index 000000000..107b164e2
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/CertificateURL.java
@@ -0,0 +1,300 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.NoSuchElementException;
+
+/**
+ * The CertificateURL extension value.
+ *
+ * <pre>
+enum {
+ individual_certs(0), pkipath(1), (255)
+} CertChainType;
+
+enum {
+ false(0), true(1)
+} Boolean;
+
+struct {
+ CertChainType type;
+ URLAndOptionalHash url_and_hash_list&lt;1..2^16-1&gt;;
+} CertificateURL;
+
+struct {
+ opaque url&lt;1..2^16-1&gt;;
+ Boolean hash_present;
+ select (hash_present) {
+ case false: struct {};
+ case true: SHA1Hash;
+ } hash;
+} URLAndOptionalHash;
+
+opaque SHA1Hash[20];</pre>
+ *
+ * @author csm
+ *
+ */
+public class CertificateURL extends Value implements Iterable<CertificateURL.URLAndOptionalHash>
+{
+ private final ByteBuffer buffer;
+
+ public CertificateURL(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ return 3 + (buffer.getShort(1) & 0xFFFF);
+ }
+
+ public CertChainType type()
+ {
+ switch (buffer.get(0))
+ {
+ case 0: return CertChainType.INDIVIDUAL_CERTS;
+ case 1: return CertChainType.PKIPATH;
+ }
+ throw new IllegalArgumentException("unknown certificate URL type");
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ for (int i = 3; i < len; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ int l = u.length();
+ i += l;
+ n++;
+ }
+ return n;
+ }
+
+ public URLAndOptionalHash get(int index)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int l = 0;
+ int i;
+ for (i = 3; i < len && n < index; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ l = u.length();
+ i += l;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException();
+ return new URLAndOptionalHash(((ByteBuffer) buffer.duplicate().position(i).limit(i+l)).slice());
+ }
+
+ public void set(int index, URLAndOptionalHash url)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i;
+ for (i = 3; i < len && n < index-1; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ int l = u.length();
+ i += l;
+ n++;
+ }
+ if (n < index - 1)
+ throw new IndexOutOfBoundsException();
+ int l = url.urlLength();
+ buffer.putShort(i, (short) l);
+ ((ByteBuffer) buffer.duplicate().position(i+2)).put(url.urlBuffer());
+ buffer.put(i+l+2, (byte) (url.hashPresent() ? 1 : 0));
+ if (url.hashPresent())
+ ((ByteBuffer) buffer.duplicate().position(i+l+3)).put (url.sha1Hash());
+ }
+
+ public void setLength(final int length)
+ {
+ if (length < 0 || length > 65535)
+ throw new IllegalArgumentException("length must be between 0 and 65535");
+ buffer.putShort(1, (short) length);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" type = ");
+ out.print(type());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.println(" url_and_hash_list = {");
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
+ for (URLAndOptionalHash url : this)
+ {
+ out.println(url.toString(subprefix));
+ }
+ if (prefix != null) out.print(prefix);
+ out.println(" };");
+ if (prefix != null) out.print(prefix);
+ out.print("} CertificateURL;");
+ return str.toString();
+ }
+
+ public java.util.Iterator<URLAndOptionalHash> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<URLAndOptionalHash>
+ {
+ private int index;
+
+ public Iterator()
+ {
+ index = 0;
+ }
+
+ public URLAndOptionalHash next() throws NoSuchElementException
+ {
+ try
+ {
+ return get(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static enum CertChainType
+ {
+ INDIVIDUAL_CERTS (0), PKIPATH (1);
+
+ private final int value;
+
+ private CertChainType (final int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+
+ public static class URLAndOptionalHash implements Constructed
+ {
+ private final ByteBuffer buffer;
+
+ public URLAndOptionalHash (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ return ((buffer.getShort(0) & 0xFFFF)
+ + (hashPresent() ? 23 : 3));
+ }
+
+ public String url()
+ {
+ Charset cs = Charset.forName("ASCII");
+ return cs.decode(urlBuffer()).toString();
+ }
+
+ public int urlLength()
+ {
+ return buffer.getShort(0) & 0xFFFF;
+ }
+
+ public ByteBuffer urlBuffer()
+ {
+ int len = urlLength();
+ return ((ByteBuffer) buffer.duplicate().position(2).limit(2+len)).slice();
+ }
+
+ public boolean hashPresent()
+ {
+ int i = (buffer.getShort(0) & 0xFFFF) + 2;
+ byte b = buffer.get(i);
+ if (b == 0)
+ return false;
+ if (b == 1)
+ return true;
+ throw new IllegalArgumentException("expecting 0 or 1: " + (b & 0xFF));
+ }
+
+ public byte[] sha1Hash()
+ {
+ int i = (buffer.getShort(0) & 0xFFFF) + 2;
+ byte b = buffer.get(i);
+ if (b == 0)
+ return null;
+ byte[] buf = new byte[20];
+ ((ByteBuffer) buffer.duplicate().position(i+1)).get(buf);
+ return buf;
+ }
+
+ 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("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" url = ");
+ out.print(url());
+ out.println(";");
+ boolean has_hash = hashPresent();
+ if (prefix != null) out.print(prefix);
+ out.print(" hash_present = ");
+ out.print(has_hash);
+ out.println(";");
+ if (has_hash)
+ {
+ if (prefix != null) out.print(prefix);
+ out.print(" sha1Hash = ");
+ out.print(Util.toHexString(sha1Hash(), ':'));
+ out.println(";");
+ }
+ if (prefix != null) out.print(prefix);
+ out.print("} URLAndOptionalHash;");
+ return str.toString();
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ClientHello.java b/gnu/javax/net/ssl/provider/ClientHello.java
index 14351c1fd..ab3309520 100644
--- a/gnu/javax/net/ssl/provider/ClientHello.java
+++ b/gnu/javax/net/ssl/provider/ClientHello.java
@@ -67,6 +67,7 @@ struct
SessionID session_id; // 1 + 0..32
CipherSuite cipher_suites&lt;2..2^16-1&gt;
CompressionMethod compression_methods&lt;1..2^8-1&gt;
+ Extension client_hello_extension_list&lt;0..2^16-1&gt;
} ClientHello;
</pre>
*/
@@ -156,11 +157,17 @@ public final class ClientHello implements Handshake.Body
return new CompressionMethodList (listBuf);
}
- public ByteBuffer extensions()
+ public ExtensionList extensions()
{
int offset = getExtensionsOffset ();
- return ((ByteBuffer) buffer.duplicate ().position (offset)
- .limit (totalLength)).slice ();
+ if (offset >= 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 void setVersion (final ProtocolVersion version)
@@ -183,7 +190,9 @@ public final class ClientHello implements Handshake.Body
public void setExtensionsLength (final int length)
{
- this.totalLength = getExtensionsOffset () + length;
+ int offset = getExtensionsOffset();
+ this.totalLength = offset + length + 4;
+ buffer.putShort(offset, (short) length);
}
private int getCipherSuitesOffset ()
@@ -238,13 +247,10 @@ public final class ClientHello implements Handshake.Body
out.print (subprefix);
out.println ("compression_methods:");
out.println (compressionMethods ().toString (subprefix));
- ByteBuffer extbuf = extensions ();
- if (extbuf.limit () > 0)
- {
- out.print (subprefix);
- out.println ("extensions:");
- out.print (Util.hexDump (extbuf, 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;");
diff --git a/gnu/javax/net/ssl/provider/Extension.java b/gnu/javax/net/ssl/provider/Extension.java
index 9e2b69e3b..cd0285ed3 100644
--- a/gnu/javax/net/ssl/provider/Extension.java
+++ b/gnu/javax/net/ssl/provider/Extension.java
@@ -83,7 +83,7 @@ public final class Extension implements Constructed
return Type.forValue (buffer.getShort (0) & 0xFFFF);
}
- public byte[] value()
+ public byte[] valueBytes()
{
int len = buffer.getShort (2) & 0xFFFF;
byte[] value = new byte[len];
@@ -91,6 +91,48 @@ public final class Extension implements Constructed
return value;
}
+ public ByteBuffer valueBuffer()
+ {
+ int len = buffer.getShort(2) & 0xFFFF;
+ return ((ByteBuffer) buffer.duplicate().position(4).limit(len+4)).slice();
+ }
+
+ public Value value()
+ {
+ switch (type ())
+ {
+ case SERVER_NAME:
+ return new ServerNameList(valueBuffer());
+
+ case MAX_FRAGMENT_LENGTH:
+ switch (valueBuffer().get() & 0xFF)
+ {
+ case 1: return MaxFragmentLength.LEN_2_9;
+ case 2: return MaxFragmentLength.LEN_2_10;
+ case 3: return MaxFragmentLength.LEN_2_11;
+ case 4: return MaxFragmentLength.LEN_2_12;
+ default:
+ throw new IllegalArgumentException("invalid max_fragment_len");
+ }
+
+ case TRUNCATED_HMAC:
+ return new TruncatedHMAC();
+
+ case CLIENT_CERTIFICATE_URL:
+ return new CertificateURL(valueBuffer());
+
+ case TRUSTED_CA_KEYS:
+ return new TrustedAuthorities(valueBuffer());
+
+ case STATUS_REQUEST:
+ return new CertificateStatusRequest(valueBuffer());
+
+ case SRP:
+ case CERT_TYPE:
+ }
+ return new UnresolvedExtensionValue(valueBuffer());
+ }
+
public void setLength (final int newLength)
{
if (newLength < 0 || newLength > 65535)
@@ -130,13 +172,14 @@ public final class Extension implements Constructed
out.println(" type = " + type () + ";");
if (prefix != null) out.print (prefix);
out.println(" value =");
- out.println(Util.hexDump(value (), (prefix != null) ? prefix + " " : " "));
+// out.println(Util.hexDump(value (), (prefix != null) ? prefix + " " : " "));
+ out.println(value());
if (prefix != null) out.print (prefix);
out.print("} Extension;");
return str.toString();
}
- // Inner class.
+ // Inner classes.
// -------------------------------------------------------------------------
public static enum Type
@@ -178,4 +221,8 @@ public final class Extension implements Constructed
return value;
}
}
+
+ public static abstract class Value implements Constructed
+ {
+ }
}
diff --git a/gnu/javax/net/ssl/provider/ExtensionList.java b/gnu/javax/net/ssl/provider/ExtensionList.java
index ddb104491..686eae000 100644
--- a/gnu/javax/net/ssl/provider/ExtensionList.java
+++ b/gnu/javax/net/ssl/provider/ExtensionList.java
@@ -113,7 +113,7 @@ public class ExtensionList implements Iterable<Extension>
+ "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());
+ ((ByteBuffer) buffer.duplicate().position(i+4)).put (e.valueBuffer());
modCount++;
}
diff --git a/gnu/javax/net/ssl/provider/MaxFragmentLength.java b/gnu/javax/net/ssl/provider/MaxFragmentLength.java
new file mode 100644
index 000000000..c680b0774
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/MaxFragmentLength.java
@@ -0,0 +1,52 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+/**
+ * Extension value
+ * @author csm
+ */
+public class MaxFragmentLength extends Value
+{
+ public static final MaxFragmentLength LEN_2_9 = new MaxFragmentLength(1, 1 << 9);
+ public static final MaxFragmentLength LEN_2_10 = new MaxFragmentLength(2, 1 << 10);
+ public static final MaxFragmentLength LEN_2_11 = new MaxFragmentLength(3, 1 << 11);
+ public static final MaxFragmentLength LEN_2_12 = new MaxFragmentLength(4, 1 << 12);
+
+ private final int value;
+ private final int length;
+
+ private MaxFragmentLength(int value, int length)
+ {
+ this.value = value;
+ this.length = length;
+ }
+
+ public int length()
+ {
+ return 1;
+ }
+
+ public int getValue ()
+ {
+ return value;
+ }
+
+ public int maxLength()
+ {
+ return length;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ String s = "max_fragment_length = ";
+ if (prefix != null)
+ s = prefix + s;
+ return s + maxLength() + ";";
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/ServerHandshake.java b/gnu/javax/net/ssl/provider/ServerHandshake.java
index 878f89bdc..7830b2113 100644
--- a/gnu/javax/net/ssl/provider/ServerHandshake.java
+++ b/gnu/javax/net/ssl/provider/ServerHandshake.java
@@ -127,19 +127,18 @@ class ServerHandshake extends AbstractHandshake
final ProtocolVersion version)
throws SSLException
{
- HashSet suites = new HashSet (enabledSuites.length);
- for (int i = 0; i < enabledSuites.length; i++)
+ HashSet<CipherSuite> suites = new HashSet<CipherSuite> (enabledSuites.length);
+ for (String s : enabledSuites)
{
- CipherSuite suite = CipherSuite.forName (enabledSuites[i]);
+ CipherSuite suite = CipherSuite.forName (s);
if (suite != null)
{
suite = suite.resolve (version);
suites.add (suite);
}
}
- for (int i = 0; i < clientSuites.size (); i++)
+ for (CipherSuite suite : clientSuites)
{
- CipherSuite suite = clientSuites.get (i);
if (suites.contains (suite))
return suite.resolve (version);
}
@@ -159,14 +158,14 @@ class ServerHandshake extends AbstractHandshake
throws SSLException
{
// Scan for ZLIB first.
- for (int i = 0; i < comps.size (); i++)
+ for (CompressionMethod cm : comps)
{
- if (comps.get (i).equals (CompressionMethod.ZLIB))
+ if (cm.equals (CompressionMethod.ZLIB))
return CompressionMethod.ZLIB;
}
- for (int i = 0; i < comps.size (); i++)
+ for (CompressionMethod cm : comps)
{
- if (comps.get (i).equals (CompressionMethod.NULL))
+ if (cm.equals (CompressionMethod.NULL))
return CompressionMethod.NULL;
}
diff --git a/gnu/javax/net/ssl/provider/ServerHello.java b/gnu/javax/net/ssl/provider/ServerHello.java
index da490f174..cd69f14b1 100644
--- a/gnu/javax/net/ssl/provider/ServerHello.java
+++ b/gnu/javax/net/ssl/provider/ServerHello.java
@@ -67,6 +67,7 @@ struct
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
+ Extensions server_hello_extension_list&lt;0..2^16-1&gt;
} ServerHello;
</pre>
*
@@ -171,11 +172,19 @@ public class ServerHello implements Handshake.Body
return CompressionMethod.getInstance (buffer.get (offset) & 0xFF);
}
- public ByteBuffer extensions ()
+ public ExtensionList extensions ()
{
int offset = SESSID_OFFSET + (buffer.get (SESSID_OFFSET) & 0xFF) + 4;
- return ((ByteBuffer) buffer.duplicate ().position (offset)
- .limit (totalLength)).slice ();
+ if (offset == totalLength)
+ return null;
+ if (buffer.limit() <= offset)
+ 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 void setVersion (final ProtocolVersion version)
@@ -213,7 +222,9 @@ public class ServerHello implements Handshake.Body
public void setExtensionsLength (final int length)
{
totalLength = (SESSID_OFFSET + (buffer.get (SESSID_OFFSET) & 0xFF)
- + 4 + length);
+ + 4 + length + 4);
+ buffer.putShort (SESSID_OFFSET + (buffer.get (SESSID_OFFSET) & 0xFF) + 4,
+ (short) length);
}
public String toString ()
@@ -250,13 +261,11 @@ public class ServerHello implements Handshake.Body
out.print ("compressionMethod: ");
out.print (compressionMethod ());
out.println (";");
- ByteBuffer extbuf = extensions ();
- if (extbuf.limit () > 0)
- {
- out.print (subprefix);
- out.println ("extensions:");
- out.print (Util.hexDump (extbuf, subprefix));
- }
+ ExtensionList exts = extensions ();
+ out.print (subprefix);
+ out.println ("extensions:");
+ out.println (exts != null ? exts.toString (subprefix+" ")
+ : subprefix + " (nil)");
if (prefix != null)
out.print (prefix);
out.print ("} ServerHello;");
diff --git a/gnu/javax/net/ssl/provider/ServerNameList.java b/gnu/javax/net/ssl/provider/ServerNameList.java
new file mode 100644
index 000000000..218e04a34
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/ServerNameList.java
@@ -0,0 +1,225 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.NoSuchElementException;
+
+/**
+ * The ServerName extension.
+ *
+ * <pre>
+ struct {
+ NameType name_type;
+ select (name_type) {
+ case host_name: HostName;
+ } name;
+} ServerName;
+
+enum {
+ host_name(0), (255)
+} NameType;
+
+opaque HostName<1..2^16-1>;
+
+struct {
+ ServerName server_name_list<1..2^16-1>
+} ServerNameList;</pre>
+ *
+ * <p><b>Implementation note: this class does not currently contain a
+ * <code>set</code> method. If you are modifying this list, then use the
+ * {@link #get(int)} method, and modify the returned {@link ServerName}.
+ *
+ * @author csm
+ */
+public class ServerNameList extends Value implements Iterable<ServerNameList.ServerName>
+{
+ private final ByteBuffer buffer;
+
+ public ServerNameList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ return buffer.getShort(0) & 0xFFFF;
+ }
+
+ public int size()
+ {
+ int n = 0;
+ final int len = length();
+ for (int i = 2; i < len; )
+ {
+ int l = buffer.getShort(i+1);
+ i += l + 3;
+ n++;
+ }
+ return n;
+ }
+
+ public ServerName get (int index)
+ {
+ final int len = length();
+ if (len == 0)
+ throw new IndexOutOfBoundsException("0; " + index);
+ int n = 0;
+ int i;
+ int l = 0;
+ for (i = 2; i < len && n < index; )
+ {
+ l = buffer.getShort(i+1);
+ i += l + 3;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException(n + "; " + index);
+ ByteBuffer buf = ((ByteBuffer) buffer.duplicate().position(i).limit(i+l+3)).slice();
+ return new ServerName (buf);
+ }
+
+ public void setLength(final int newLength)
+ {
+ if (newLength < 0 || newLength > 65535)
+ throw new IllegalArgumentException("length must be between 0 and 65535");
+ buffer.putShort(0, (short) newLength);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println ("ServerNameList {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for (ServerName name : this)
+ {
+ out.println (name.toString(subprefix));
+ }
+ if (prefix != null) out.print(prefix);
+ out.print ("};");
+ return str.toString();
+ }
+
+ public java.util.Iterator<ServerName> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<ServerName>
+ {
+ private int index;
+
+ public Iterator()
+ {
+ index = 0;
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public ServerName next() throws NoSuchElementException
+ {
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class ServerName implements Constructed
+ {
+ private final ByteBuffer buffer;
+
+ public ServerName(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ return buffer.getShort(1) & 0xFFFF;
+ }
+
+ public NameType type()
+ {
+ int v = (buffer.get(0) & 0xFF);
+ if (v == 0)
+ {
+ return NameType.HOST_NAME;
+ }
+ throw new IllegalArgumentException ("illegal name type: " + v);
+ }
+
+ public String name()
+ {
+ int len = length();
+ Charset cs = Charset.forName ("UTF-8");
+ return cs.decode(((ByteBuffer) buffer.duplicate().position(3).limit(len))).toString();
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" name_type = ");
+ out.print (type());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print (" server_name = ");
+ out.print (name());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerName;");
+ return str.toString();
+ }
+ }
+
+ public static enum NameType
+ {
+ HOST_NAME (0);
+
+ private final int value;
+
+ private NameType (int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/TruncatedHMAC.java b/gnu/javax/net/ssl/provider/TruncatedHMAC.java
new file mode 100644
index 000000000..147b8ed1d
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/TruncatedHMAC.java
@@ -0,0 +1,31 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+/**
+ * The value type for the {@link Extension.Type#TRUNCATED_HMAC} extension.
+ * This extension has an empty value; this class is thusly empty.
+ *
+ * @author csm
+ */
+public class TruncatedHMAC extends Value
+{
+
+ public int length()
+ {
+ return 0;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ String s = "TruncatedHMAC;";
+ if (prefix != null)
+ s = prefix + s;
+ return s;
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/TrustedAuthorities.java b/gnu/javax/net/ssl/provider/TrustedAuthorities.java
new file mode 100644
index 000000000..89cf868b8
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/TrustedAuthorities.java
@@ -0,0 +1,252 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.x509.X500DistinguishedName;
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The trusted authorities hello extension.
+ *
+ * <pre>
+struct {
+ TrustedAuthority trusted_authorities_list&lt;0..2^16-1&gt;;
+} TrustedAuthorities;
+
+struct {
+ IdentifierType identifier_type;
+ select (identifier_type) {
+ case pre_agreed: struct {};
+ case key_sha1_hash: SHA1Hash;
+ case x509_name: DistinguishedName;
+ case cert_sha1_hash: SHA1Hash;
+ } identifier;
+} TrustedAuthority;
+
+enum {
+ pre_agreed(0), key_sha1_hash(1), x509_name(2),
+ cert_sha1_hash(3), (255)
+} IdentifierType;
+
+opaque DistinguishedName&lt;1..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class TrustedAuthorities extends Value
+ implements Iterable<TrustedAuthorities.TrustedAuthority>
+{
+ private final ByteBuffer buffer;
+
+ public TrustedAuthorities(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ return 2 + (buffer.getShort(0) & 0xFFFF);
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ int n = 0;
+ for (int i = 2; i < len; i++)
+ {
+ TrustedAuthority auth =
+ new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+ i += auth.length();
+ n++;
+ }
+ return n;
+ }
+
+ public TrustedAuthority get(final int index)
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ int n = 0;
+ int i = 2;
+ while (i < len && n <= index)
+ {
+ TrustedAuthority auth =
+ new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+ if (n == index)
+ return auth;
+ i += auth.length();
+ n++;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for(TrustedAuthority ta : this)
+ out.println(ta);
+ if (prefix != null) out.print(prefix);
+ out.print("} TrustedAuthorities;");
+ return str.toString();
+ }
+
+ public Iterator<TrustedAuthority> iterator()
+ {
+ return new AuthoritiesIterator();
+ }
+
+ public class AuthoritiesIterator implements Iterator<TrustedAuthority>
+ {
+ private int index;
+
+ public AuthoritiesIterator()
+ {
+ index = 0;
+ }
+
+ public TrustedAuthority next() throws NoSuchElementException
+ {
+ try
+ {
+ return get(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class TrustedAuthority implements Constructed
+ {
+ private final ByteBuffer buffer;
+
+ public TrustedAuthority(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ switch (type().getValue())
+ {
+ case 0: return 1;
+ case 1:
+ case 3: return 21;
+ case 2: return 3 + (buffer.getShort(1) & 0xFFFF);
+ }
+ throw new IllegalArgumentException("unknown authority type");
+ }
+
+ public byte[] sha1Hash()
+ {
+ IdentifierType t = type();
+ if (t != IdentifierType.CERT_SHA1_HASH
+ && t != IdentifierType.KEY_SHA1_HASH)
+ throw new IllegalArgumentException(t + " does not have a hash value");
+ byte[] b = new byte[20];
+ ((ByteBuffer) buffer.duplicate().position(1)).get(b);
+ return b;
+ }
+
+ public X500Principal name()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ byte[] b = new byte[len];
+ ((ByteBuffer) buffer.duplicate().position(3)).get(b);
+ return new X500Principal(b);
+ }
+
+ public IdentifierType type()
+ {
+ switch (buffer.get(0))
+ {
+ case 0: return IdentifierType.PRE_AGREED;
+ case 1: return IdentifierType.KEY_SHA1_HASH;
+ case 2: return IdentifierType.X509_NAME;
+ case 3: return IdentifierType.CERT_SHA1_HASH;
+ }
+
+ throw new IllegalArgumentException("invalid IdentifierType");
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identifier_type = ");
+ out.print(type());
+ out.println(";");
+ switch (type().getValue())
+ {
+ case 0: break;
+ case 1:
+ case 3:
+ if (prefix != null) out.print(prefix);
+ out.print(" sha1_hash = ");
+ out.print(Util.toHexString(sha1Hash(), ':'));
+ out.println(";");
+ break;
+
+ case 2:
+ if (prefix != null) out.print(prefix);
+ out.print(" name = ");
+ out.print(name());
+ out.println(";");
+ }
+ if (prefix != null) out.print(prefix);
+ out.print("} TrustedAuthority;");
+ return str.toString();
+ }
+ }
+
+ public static enum IdentifierType
+ {
+ PRE_AGREED (0), KEY_SHA1_HASH (1), X509_NAME (2), CERT_SHA1_HASH (3);
+
+ private final int value;
+
+ private IdentifierType(final int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
new file mode 100644
index 000000000..720249e85
--- /dev/null
+++ b/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
@@ -0,0 +1,40 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
+public class UnresolvedExtensionValue extends Value
+{
+ private final ByteBuffer buffer;
+
+ public UnresolvedExtensionValue (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ return buffer.limit();
+ }
+
+ public ByteBuffer value()
+ {
+ return buffer.slice();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(final String prefix)
+ {
+ String s = Util.hexDump(buffer);
+ if (prefix != null)
+ s = prefix + s;
+ return s;
+ }
+}