summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2017-05-20 14:30:13 -0400
committerOren Novotny <oren@novotny.org>2017-05-20 14:30:13 -0400
commit20e8223cb0b11bb07da677242cbde2745616eb90 (patch)
tree1a3cddcdb84d6a92e1de86560beb053c21d2e1b1 /crypto
parentMerge pull request #2 from ctaggart/SourceLink.2.1.0 (diff)
parentAdded validation of integer/enumerated encoding. (diff)
downloadBouncyCastle.NET-ed25519-20e8223cb0b11bb07da677242cbde2745616eb90.tar.xz
merge from master
Diffstat (limited to 'crypto')
-rw-r--r--crypto/crypto.csproj5
-rw-r--r--crypto/src/asn1/DerEnumerated.cs13
-rw-r--r--crypto/src/asn1/DerInteger.cs13
-rw-r--r--crypto/src/asn1/x509/UserNotice.cs8
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs32
-rw-r--r--crypto/src/crypto/tls/AbstractTlsKeyExchange.cs6
-rw-r--r--crypto/src/crypto/tls/AbstractTlsServer.cs6
-rw-r--r--crypto/src/crypto/tls/ByteQueue.cs116
-rw-r--r--crypto/src/crypto/tls/CertificateUrl.cs3
-rw-r--r--crypto/src/crypto/tls/DefaultTlsClient.cs1
-rw-r--r--crypto/src/crypto/tls/DefaultTlsServer.cs4
-rw-r--r--crypto/src/crypto/tls/DigestInputBuffer.cs4
-rw-r--r--crypto/src/crypto/tls/DtlsClientProtocol.cs2
-rw-r--r--crypto/src/crypto/tls/DtlsRecordLayer.cs2
-rw-r--r--crypto/src/crypto/tls/DtlsServerProtocol.cs2
-rw-r--r--crypto/src/crypto/tls/OcspStatusRequest.cs3
-rw-r--r--crypto/src/crypto/tls/PskTlsServer.cs2
-rw-r--r--crypto/src/crypto/tls/RecordStream.cs90
-rw-r--r--crypto/src/crypto/tls/ServerNameList.cs3
-rw-r--r--crypto/src/crypto/tls/SignerInputBuffer.cs4
-rw-r--r--crypto/src/crypto/tls/TlsClientProtocol.cs21
-rw-r--r--crypto/src/crypto/tls/TlsDHKeyExchange.cs46
-rw-r--r--crypto/src/crypto/tls/TlsNoCloseNotifyException.cs19
-rw-r--r--crypto/src/crypto/tls/TlsProtocol.cs264
-rw-r--r--crypto/src/crypto/tls/TlsRsaSigner.cs2
-rw-r--r--crypto/src/crypto/tls/TlsServerProtocol.cs18
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs147
-rw-r--r--crypto/src/util/io/BaseOutputStream.cs7
-rw-r--r--crypto/src/util/io/Streams.cs8
-rw-r--r--crypto/test/src/crypto/test/Poly1305Test.cs11
-rw-r--r--crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs1
-rw-r--r--crypto/test/src/crypto/tls/test/TlsServerTest.cs21
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestSuite.cs5
-rw-r--r--crypto/test/src/tsp/test/ParseTest.cs3
34 files changed, 660 insertions, 232 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 6f1fdcf61..fe6b5fa1c 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -5194,6 +5194,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\TlsNoCloseNotifyException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\TlsNullCipher.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs
index 476b7fa9a..db27065bb 100644
--- a/crypto/src/asn1/DerEnumerated.cs
+++ b/crypto/src/asn1/DerEnumerated.cs
@@ -64,7 +64,18 @@ namespace Org.BouncyCastle.Asn1
         public DerEnumerated(
             byte[]   bytes)
         {
-            this.bytes = bytes;
+            if (bytes.Length > 1)
+            {
+                if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
+                {
+                    throw new ArgumentException("malformed enumerated");
+                }
+                if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
+                {
+                    throw new ArgumentException("malformed enumerated");
+                }
+            }
+            this.bytes = Arrays.Clone(bytes);
         }
 
         public BigInteger Value
diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs
index 3610de588..5b240d281 100644
--- a/crypto/src/asn1/DerInteger.cs
+++ b/crypto/src/asn1/DerInteger.cs
@@ -70,7 +70,18 @@ namespace Org.BouncyCastle.Asn1
 		public DerInteger(
             byte[] bytes)
         {
-            this.bytes = bytes;
+            if (bytes.Length > 1)
+            {
+                if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
+                {
+                    throw new ArgumentException("malformed integer");
+                }
+                if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
+                {
+                    throw new ArgumentException("malformed integer");
+                }
+            }
+            this.bytes = Arrays.Clone(bytes);
         }
 
 		public BigInteger Value
diff --git a/crypto/src/asn1/x509/UserNotice.cs b/crypto/src/asn1/x509/UserNotice.cs
index 5938f7c49..f40916434 100644
--- a/crypto/src/asn1/x509/UserNotice.cs
+++ b/crypto/src/asn1/x509/UserNotice.cs
@@ -58,6 +58,7 @@ namespace Org.BouncyCastle.Asn1.X509
          * calling @{link toASN1Object()} for a <code>UserNotice</code>
          * instance or from parsing it from a DER-encoded stream.</p>
          */
+        [Obsolete("Use GetInstance() instead")]
         public UserNotice(
             Asn1Sequence seq)
         {
@@ -71,12 +72,19 @@ namespace Org.BouncyCastle.Asn1.X509
                 if (seq[0].ToAsn1Object() is Asn1Sequence)
                 {
                     noticeRef = NoticeReference.GetInstance(seq[0]);
+                    explicitText = null;
                 }
                 else
                 {
+                    noticeRef = null;
                     explicitText = DisplayText.GetInstance(seq[0]);
                 }
             }
+            else if (seq.Count == 0)
+            {
+                noticeRef = null;       // neither field set!
+                explicitText = null;
+            }
             else
             {
                 throw new ArgumentException("Bad sequence size: " + seq.Count);
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index 0f66ccccc..c0a660fac 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -219,13 +219,13 @@ namespace Org.BouncyCastle.Crypto.Macs
             ulong tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
             ulong tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
 
-            ulong b;
-            h0 = (uint)tp0 & 0x3ffffff; b = (tp0 >> 26);
-            tp1 += b; h1 = (uint)tp1 & 0x3ffffff; b = (tp1 >> 26);
-            tp2 += b; h2 = (uint)tp2 & 0x3ffffff; b = (tp2 >> 26);
-            tp3 += b; h3 = (uint)tp3 & 0x3ffffff; b = (tp3 >> 26);
-            tp4 += b; h4 = (uint)tp4 & 0x3ffffff; b = (tp4 >> 26);
-            h0 += (uint)(b * 5);
+            h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26);
+            h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26);
+            h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26);
+            h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26);
+            h4 = (uint)tp4 & 0x3ffffff;
+            h0 += (uint)(tp4 >> 26) * 5;
+            h1 += (h0 >> 26); h0 &= 0x3ffffff;
         }
 
         public int DoFinal(byte[] output, int outOff)
@@ -238,17 +238,14 @@ namespace Org.BouncyCastle.Crypto.Macs
                 ProcessBlock();
             }
 
-            ulong f0, f1, f2, f3;
-
-            uint b = h0 >> 26;
-            h0 = h0 & 0x3ffffff;
-            h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff;
-            h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff;
-            h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff;
-            h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff;
-            h0 += b * 5;
+            h1 += (h0 >> 26); h0 &= 0x3ffffff;
+            h2 += (h1 >> 26); h1 &= 0x3ffffff;
+            h3 += (h2 >> 26); h2 &= 0x3ffffff;
+            h4 += (h3 >> 26); h3 &= 0x3ffffff;
+            h0 += (h4 >> 26) * 5; h4 &= 0x3ffffff;
+            h1 += (h0 >> 26); h0 &= 0x3ffffff;
 
-            uint g0, g1, g2, g3, g4;
+            uint g0, g1, g2, g3, g4, b;
             g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
             g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
             g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
@@ -263,6 +260,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             h3 = (h3 & nb) | (g3 & b);
             h4 = (h4 & nb) | (g4 & b);
 
+            ulong f0, f1, f2, f3;
             f0 = ((h0      ) | (h1 << 26)) + (ulong)k0;
             f1 = ((h1 >> 6 ) | (h2 << 20)) + (ulong)k1;
             f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2;
diff --git a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
index 09fb8782d..294b24929 100644
--- a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
+++ b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
             {
                 /*
-                 * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension,
+                 * RFC 5246 7.4.1.4.1. If the client does not send the signature_algorithms extension,
                  * the server MUST do the following:
                  * 
                  * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK,
@@ -106,14 +106,14 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (mSupportedSignatureAlgorithms == null)
             {
                 /*
-                 * TODO RFC 2264 7.4.2. Unless otherwise specified, the signing algorithm for the
+                 * TODO RFC 2246 7.4.2. Unless otherwise specified, the signing algorithm for the
                  * certificate must be the same as the algorithm for the certificate key.
                  */
             }
             else
             {
                 /*
-                 * TODO RFC 5264 7.4.2. If the client provided a "signature_algorithms" extension, then
+                 * TODO RFC 5246 7.4.2. If the client provided a "signature_algorithms" extension, then
                  * all certificates provided by the server MUST be signed by a hash/signature algorithm
                  * pair that appears in that extension.
                  */
diff --git a/crypto/src/crypto/tls/AbstractTlsServer.cs b/crypto/src/crypto/tls/AbstractTlsServer.cs
index d87a294f0..52a79c9d8 100644
--- a/crypto/src/crypto/tls/AbstractTlsServer.cs
+++ b/crypto/src/crypto/tls/AbstractTlsServer.cs
@@ -194,11 +194,12 @@ namespace Org.BouncyCastle.Crypto.Tls
         public virtual int GetSelectedCipherSuite()
         {
             /*
-             * TODO RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate
+             * RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate
              * cipher suites against the "signature_algorithms" extension before selecting them. This is
              * somewhat inelegant but is a compromise designed to minimize changes to the original
              * cipher suite design.
              */
+            IList sigAlgs = TlsUtilities.GetUsableSignatureAlgorithms(this.mSupportedSignatureAlgorithms);
 
             /*
              * RFC 4429 5.1. A server that receives a ClientHello containing one or both of these
@@ -216,7 +217,8 @@ namespace Org.BouncyCastle.Crypto.Tls
 
                 if (Arrays.Contains(this.mOfferedCipherSuites, cipherSuite)
                     && (eccCipherSuitesEnabled || !TlsEccUtilities.IsEccCipherSuite(cipherSuite))
-                    && TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion))
+                    && TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion)
+                    && TlsUtilities.IsValidCipherSuiteForSignatureAlgorithms(cipherSuite, sigAlgs))
                 {
                     return this.mSelectedCipherSuite = cipherSuite;
                 }
diff --git a/crypto/src/crypto/tls/ByteQueue.cs b/crypto/src/crypto/tls/ByteQueue.cs
index f9398bbaf..b4df6850e 100644
--- a/crypto/src/crypto/tls/ByteQueue.cs
+++ b/crypto/src/crypto/tls/ByteQueue.cs
@@ -1,4 +1,5 @@
 using System;
+using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
@@ -47,6 +48,8 @@ namespace Org.BouncyCastle.Crypto.Tls
          */
         private int available = 0;
 
+        private bool readOnlyBuf = false;
+
         public ByteQueue()
             : this(DefaultCapacity)
         {
@@ -54,29 +57,15 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public ByteQueue(int capacity)
         {
-            this.databuf = new byte[capacity];
+            this.databuf = capacity == 0 ? TlsUtilities.EmptyBytes : new byte[capacity];
         }
 
-        /// <summary>Read data from the buffer.</summary>
-        /// <param name="buf">The buffer where the read data will be copied to.</param>
-        /// <param name="offset">How many bytes to skip at the beginning of buf.</param>
-        /// <param name="len">How many bytes to read at all.</param>
-        /// <param name="skip">How many bytes from our data to skip.</param>
-        public void Read(
-            byte[]	buf,
-            int		offset,
-            int		len,
-            int		skip)
+        public ByteQueue(byte[] buf, int off, int len)
         {
-            if ((buf.Length - offset) < len)
-            {
-                throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
-            }
-            if ((available - skip) < len)
-            {
-                throw new InvalidOperationException("Not enough data to read");
-            }
-            Array.Copy(databuf, skipped + skip, buf, offset, len);
+            this.databuf = buf;
+            this.skipped = off;
+            this.available = len;
+            this.readOnlyBuf = true;
         }
 
         /// <summary>Add some data to our buffer.</summary>
@@ -84,10 +73,13 @@ namespace Org.BouncyCastle.Crypto.Tls
         /// <param name="offset">How many bytes to skip at the beginning of the array.</param>
         /// <param name="len">How many bytes to read from the array.</param>
         public void AddData(
-            byte[]	data,
-            int		offset,
-            int		len)
+            byte[] data,
+            int offset,
+            int len)
         {
+            if (readOnlyBuf)
+                throw new InvalidOperationException("Cannot add data to read-only buffer");
+
             if ((skipped + available + len) > databuf.Length)
             {
                 int desiredSize = ByteQueue.NextTwoPow(available + len);
@@ -108,6 +100,64 @@ namespace Org.BouncyCastle.Crypto.Tls
             available += len;
         }
 
+        /// <summary>The number of bytes which are available in this buffer.</summary>
+        public int Available
+        {
+            get { return available; }
+        }
+
+        /// <summary>Copy some bytes from the beginning of the data to the provided <c cref="Stream">Stream</c>.</summary>
+        /// <param name="output">The <c cref="Stream">Stream</c> to copy the bytes to.</param>
+        /// <param name="length">How many bytes to copy.</param>
+		/// <exception cref="InvalidOperationException">If insufficient data is available.</exception>
+		/// <exception cref="IOException">If there is a problem copying the data.</exception>
+        public void CopyTo(Stream output, int length)
+        {
+            if (length > available)
+                throw new InvalidOperationException("Cannot copy " + length + " bytes, only got " + available);
+
+            output.Write(databuf, skipped, length);
+        }
+
+        /// <summary>Read data from the buffer.</summary>
+        /// <param name="buf">The buffer where the read data will be copied to.</param>
+        /// <param name="offset">How many bytes to skip at the beginning of buf.</param>
+        /// <param name="len">How many bytes to read at all.</param>
+        /// <param name="skip">How many bytes from our data to skip.</param>
+        public void Read(
+            byte[]	buf,
+            int		offset,
+            int		len,
+            int		skip)
+        {
+            if ((buf.Length - offset) < len)
+            {
+                throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
+            }
+            if ((available - skip) < len)
+            {
+                throw new InvalidOperationException("Not enough data to read");
+            }
+            Array.Copy(databuf, skipped + skip, buf, offset, len);
+        }
+
+        /// <summary>Return a <c cref="MemoryStream">MemoryStream</c> over some bytes at the beginning of the data.</summary>
+        /// <param name="length">How many bytes will be readable.</param>
+        /// <returns>A <c cref="MemoryStream">MemoryStream</c> over the data.</returns>
+		/// <exception cref="InvalidOperationException">If insufficient data is available.</exception>
+        public MemoryStream ReadFrom(int length)
+        {
+            if (length > available)
+                throw new InvalidOperationException("Cannot read " + length + " bytes, only got " + available);
+
+            int position = skipped;
+
+            available -= length;
+            skipped += length;
+
+            return new MemoryStream(databuf, position, length, false);
+        }
+
         /// <summary>Remove some bytes from our data from the beginning.</summary>
         /// <param name="i">How many bytes to remove.</param>
         public void RemoveData(
@@ -138,10 +188,24 @@ namespace Org.BouncyCastle.Crypto.Tls
             return buf;
         }
 
-        /// <summary>The number of bytes which are available in this buffer.</summary>
-        public int Available
+        public void Shrink()
         {
-            get { return available; }
+            if (available == 0)
+            {
+                databuf = TlsUtilities.EmptyBytes;
+                skipped = 0;
+            }
+            else
+            {
+                int desiredSize = ByteQueue.NextTwoPow(available);
+                if (desiredSize < databuf.Length)
+                {
+                    byte[] tmp = new byte[desiredSize];
+                    Array.Copy(databuf, skipped, tmp, 0, available);
+                    databuf = tmp;
+                    skipped = 0;
+                }
+            }
         }
     }
 }
diff --git a/crypto/src/crypto/tls/CertificateUrl.cs b/crypto/src/crypto/tls/CertificateUrl.cs
index d285fa0f6..aff999551 100644
--- a/crypto/src/crypto/tls/CertificateUrl.cs
+++ b/crypto/src/crypto/tls/CertificateUrl.cs
@@ -3,6 +3,7 @@ using System.Collections;
 using System.IO;
 
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
@@ -116,7 +117,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 TlsUtilities.CheckUint16(length);
                 this.Position = 0;
                 TlsUtilities.WriteUint16((int)length, this);
-                this.WriteTo(output);
+                Streams.WriteBufTo(this, output);
                 Platform.Dispose(this);
             }
         }
diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs
index 7dadf8a1a..32a86e503 100644
--- a/crypto/src/crypto/tls/DefaultTlsClient.cs
+++ b/crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -52,6 +52,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             switch (keyExchangeAlgorithm)
             {
+            case KeyExchangeAlgorithm.DH_anon:
             case KeyExchangeAlgorithm.DH_DSS:
             case KeyExchangeAlgorithm.DH_RSA:
                 return CreateDHKeyExchange(keyExchangeAlgorithm);
diff --git a/crypto/src/crypto/tls/DefaultTlsServer.cs b/crypto/src/crypto/tls/DefaultTlsServer.cs
index 44ceb30e3..8b9a7c9a0 100644
--- a/crypto/src/crypto/tls/DefaultTlsServer.cs
+++ b/crypto/src/crypto/tls/DefaultTlsServer.cs
@@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         protected virtual DHParameters GetDHParameters()
         {
-            return DHStandardGroups.rfc5114_2048_256;
+            return DHStandardGroups.rfc3526_2048;
         }
 
         protected override int[] GetCipherSuites()
@@ -79,6 +79,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 case KeyExchangeAlgorithm.DHE_DSS:
                     return GetDsaSignerCredentials();
 
+                case KeyExchangeAlgorithm.DH_anon:
                 case KeyExchangeAlgorithm.ECDH_anon:
                     return null;
 
@@ -104,6 +105,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             switch (keyExchangeAlgorithm)
             {
+            case KeyExchangeAlgorithm.DH_anon:
             case KeyExchangeAlgorithm.DH_DSS:
             case KeyExchangeAlgorithm.DH_RSA:
                 return CreateDHKeyExchange(keyExchangeAlgorithm);
diff --git a/crypto/src/crypto/tls/DigestInputBuffer.cs b/crypto/src/crypto/tls/DigestInputBuffer.cs
index 547bcab54..4435b40a5 100644
--- a/crypto/src/crypto/tls/DigestInputBuffer.cs
+++ b/crypto/src/crypto/tls/DigestInputBuffer.cs
@@ -1,8 +1,6 @@
 using System;
 using System.IO;
 
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
@@ -12,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Tls
     {
         internal void UpdateDigest(IDigest d)
         {
-            WriteTo(new DigStream(d));
+            Streams.WriteBufTo(this, new DigStream(d));
         }
 
         private class DigStream
diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs
index 90430d772..ae6e6a573 100644
--- a/crypto/src/crypto/tls/DtlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs
@@ -776,7 +776,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 securityParameters.CipherSuite);
 
             /*
-             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+             * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
              * a verify_data_length equal to 12. This includes all existing cipher suites.
              */
             securityParameters.verifyDataLength = 12;
diff --git a/crypto/src/crypto/tls/DtlsRecordLayer.cs b/crypto/src/crypto/tls/DtlsRecordLayer.cs
index 4a781b5b5..3c3e1821f 100644
--- a/crypto/src/crypto/tls/DtlsRecordLayer.cs
+++ b/crypto/src/crypto/tls/DtlsRecordLayer.cs
@@ -491,7 +491,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 throw new TlsFatalAlert(AlertDescription.internal_error);
 
             /*
-             * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+             * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
              * or ChangeCipherSpec content types.
              */
             if (len < 1 && contentType != ContentType.application_data)
diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs
index fbf33045b..3032269d1 100644
--- a/crypto/src/crypto/tls/DtlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -425,7 +425,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 securityParameters.CipherSuite);
 
             /*
-             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length
+             * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length
              * has a verify_data_length equal to 12. This includes all existing cipher suites.
              */
             securityParameters.verifyDataLength = 12;
diff --git a/crypto/src/crypto/tls/OcspStatusRequest.cs b/crypto/src/crypto/tls/OcspStatusRequest.cs
index 2dd8371e5..d9203a3c4 100644
--- a/crypto/src/crypto/tls/OcspStatusRequest.cs
+++ b/crypto/src/crypto/tls/OcspStatusRequest.cs
@@ -6,6 +6,7 @@ using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Ocsp;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
@@ -71,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 }
                 TlsUtilities.CheckUint16(buf.Length);
                 TlsUtilities.WriteUint16((int)buf.Length, output);
-                buf.WriteTo(output);
+                Streams.WriteBufTo(buf, output);
             }
 
             if (mRequestExtensions == null)
diff --git a/crypto/src/crypto/tls/PskTlsServer.cs b/crypto/src/crypto/tls/PskTlsServer.cs
index 85f3055fb..d6f54db1f 100644
--- a/crypto/src/crypto/tls/PskTlsServer.cs
+++ b/crypto/src/crypto/tls/PskTlsServer.cs
@@ -28,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         protected virtual DHParameters GetDHParameters()
         {
-            return DHStandardGroups.rfc5114_2048_256;
+            return DHStandardGroups.rfc3526_2048;
         }
 
         protected override int[] GetCipherSuites()
diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs
index d510ed94e..46673cf7e 100644
--- a/crypto/src/crypto/tls/RecordStream.cs
+++ b/crypto/src/crypto/tls/RecordStream.cs
@@ -2,6 +2,7 @@ using System;
 using System.IO;
 
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
@@ -24,6 +25,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         private MemoryStream mBuffer = new MemoryStream();
 
         private TlsHandshakeHash mHandshakeHash = null;
+        private readonly BaseOutputStream mHandshakeHashUpdater;
 
         private ProtocolVersion mReadVersion = null, mWriteVersion = null;
         private bool mRestrictReadVersion = true;
@@ -37,6 +39,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.mOutput = output;
             this.mReadCompression = new TlsNullCompression();
             this.mWriteCompression = this.mReadCompression;
+            this.mHandshakeHashUpdater = new HandshakeHashUpdateStream(this);
         }
 
         internal virtual void Init(TlsContext context)
@@ -121,6 +124,40 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.mPendingCipher = null;
         }
 
+        internal virtual void CheckRecordHeader(byte[] recordHeader)
+        {
+            byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);
+
+            /*
+             * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
+             * unexpected_message alert.
+             */
+            CheckType(type, AlertDescription.unexpected_message);
+
+            if (!mRestrictReadVersion)
+            {
+                int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
+                if ((version & 0xffffff00) != 0x0300)
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+            else
+            {
+                ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
+                if (mReadVersion == null)
+                {
+                    // Will be set later in 'readRecord'
+                }
+                else if (!version.Equals(mReadVersion))
+                {
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+
+            int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);
+
+            CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow);
+        }
+
         internal virtual bool ReadRecord()
         {
             byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput);
@@ -155,6 +192,9 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
 
             int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);
+
+            CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow);
+
             byte[] plaintext = DecodeAndVerify(type, mInput, length);
             mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length);
             return true;
@@ -162,15 +202,13 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         internal virtual byte[] DecodeAndVerify(byte type, Stream input, int len)
         {
-            CheckLength(len, mCiphertextLimit, AlertDescription.record_overflow);
-
             byte[] buf = TlsUtilities.ReadFully(len, input);
             byte[] decoded = mReadCipher.DecodeCiphertext(mReadSeqNo++, type, buf, 0, buf.Length);
 
             CheckLength(decoded.Length, mCompressedLimit, AlertDescription.record_overflow);
 
             /*
-             * TODO RFC5264 6.2.2. Implementation note: Decompression functions are responsible for
+             * TODO 5246 6.2.2. Implementation note: Decompression functions are responsible for
              * ensuring that messages cannot cause internal buffer overflows.
              */
             Stream cOut = mReadCompression.Decompress(mBuffer);
@@ -182,14 +220,14 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
 
             /*
-             * RFC 5264 6.2.2. If the decompression function encounters a TLSCompressed.fragment that
+             * RFC 5246 6.2.2. If the decompression function encounters a TLSCompressed.fragment that
              * would decompress to a length in excess of 2^14 bytes, it should report a fatal
              * decompression failure error.
              */
             CheckLength(decoded.Length, mPlaintextLimit, AlertDescription.decompression_failure);
 
             /*
-             * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+             * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
              * or ChangeCipherSpec content types.
              */
             if (decoded.Length < 1 && type != ContentType.application_data)
@@ -205,28 +243,23 @@ namespace Org.BouncyCastle.Crypto.Tls
                 return;
 
             /*
-             * RFC 5264 6. Implementations MUST NOT send record types not defined in this document
+             * RFC 5246 6. Implementations MUST NOT send record types not defined in this document
              * unless negotiated by some extension.
              */
             CheckType(type, AlertDescription.internal_error);
 
             /*
-             * RFC 5264 6.2.1 The length should not exceed 2^14.
+             * RFC 5246 6.2.1 The length should not exceed 2^14.
              */
             CheckLength(plaintextLength, mPlaintextLimit, AlertDescription.internal_error);
 
             /*
-             * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+             * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
              * or ChangeCipherSpec content types.
              */
             if (plaintextLength < 1 && type != ContentType.application_data)
                 throw new TlsFatalAlert(AlertDescription.internal_error);
 
-            if (type == ContentType.handshake)
-            {
-                UpdateHandshakeData(plaintext, plaintextOffset, plaintextLength);
-            }
-
             Stream cOut = mWriteCompression.Compress(mBuffer);
 
             byte[] ciphertext;
@@ -241,7 +274,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 byte[] compressed = GetBufferContents();
 
                 /*
-                 * RFC5264 6.2.2. Compression must be lossless and may not increase the content length
+                 * RFC 5246 6.2.2. Compression must be lossless and may not increase the content length
                  * by more than 1024 bytes.
                  */
                 CheckLength(compressed.Length, plaintextLength + 1024, AlertDescription.internal_error);
@@ -250,7 +283,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
 
             /*
-             * RFC 5264 6.2.3. The length may not exceed 2^14 + 2048.
+             * RFC 5246 6.2.3. The length may not exceed 2^14 + 2048.
              */
             CheckLength(ciphertext.Length, mCiphertextLimit, AlertDescription.internal_error);
 
@@ -273,6 +306,11 @@ namespace Org.BouncyCastle.Crypto.Tls
             get { return mHandshakeHash; }
         }
 
+        internal virtual Stream HandshakeHashUpdater
+        {
+            get { return mHandshakeHashUpdater; }
+        }
+
         internal virtual TlsHandshakeHash PrepareToFinish()
         {
             TlsHandshakeHash result = mHandshakeHash;
@@ -280,11 +318,6 @@ namespace Org.BouncyCastle.Crypto.Tls
             return result;
         }
 
-        internal virtual void UpdateHandshakeData(byte[] message, int offset, int len)
-        {
-            mHandshakeHash.BlockUpdate(message, offset, len);
-        }
-
         internal virtual void SafeClose()
         {
             try
@@ -324,7 +357,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             case ContentType.alert:
             case ContentType.change_cipher_spec:
             case ContentType.handshake:
-            case ContentType.heartbeat:
+            //case ContentType.heartbeat:
                 break;
             default:
                 throw new TlsFatalAlert(alertDescription);
@@ -336,5 +369,20 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (length > limit)
                 throw new TlsFatalAlert(alertDescription);
         }
+
+        private class HandshakeHashUpdateStream
+            : BaseOutputStream
+        {
+            private readonly RecordStream mOuter;
+            public HandshakeHashUpdateStream(RecordStream mOuter)
+            {
+                this.mOuter = mOuter;
+            }
+
+            public override void Write(byte[] buf, int off, int len)
+            {
+                mOuter.mHandshakeHash.BlockUpdate(buf, off, len);
+            }
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/ServerNameList.cs b/crypto/src/crypto/tls/ServerNameList.cs
index 5b5b90e58..ed4e59359 100644
--- a/crypto/src/crypto/tls/ServerNameList.cs
+++ b/crypto/src/crypto/tls/ServerNameList.cs
@@ -3,6 +3,7 @@ using System.Collections;
 using System.IO;
 
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
@@ -52,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             TlsUtilities.CheckUint16(buf.Length);
             TlsUtilities.WriteUint16((int)buf.Length, output);
-            buf.WriteTo(output);
+            Streams.WriteBufTo(buf, output);
         }
 
         /**
diff --git a/crypto/src/crypto/tls/SignerInputBuffer.cs b/crypto/src/crypto/tls/SignerInputBuffer.cs
index ef2827c4d..7bc69624c 100644
--- a/crypto/src/crypto/tls/SignerInputBuffer.cs
+++ b/crypto/src/crypto/tls/SignerInputBuffer.cs
@@ -1,8 +1,6 @@
 using System;
 using System.IO;
 
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
@@ -12,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Tls
     {
         internal void UpdateSigner(ISigner s)
         {
-            WriteTo(new SigStream(s));
+            Streams.WriteBufTo(this, new SigStream(s));
         }
 
         private class SigStream
diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
index 4c2a0a545..0ea84c05c 100644
--- a/crypto/src/crypto/tls/TlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -135,10 +135,8 @@ namespace Org.BouncyCastle.Crypto.Tls
             get { return mTlsClient; }
         }
 
-        protected override void HandleHandshakeMessage(byte type, byte[] data)
+        protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
         {
-            MemoryStream buf = new MemoryStream(data, false);
-
             if (this.mResumedSession)
             {
                 if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
@@ -149,7 +147,6 @@ namespace Org.BouncyCastle.Crypto.Tls
 
                 SendFinishedMessage();
                 this.mConnectionState = CS_CLIENT_FINISHED;
-                this.mConnectionState = CS_END;
 
                 CompleteHandshake();
                 return;
@@ -243,7 +240,6 @@ namespace Org.BouncyCastle.Crypto.Tls
 
                     ProcessFinishedMessage(buf);
                     this.mConnectionState = CS_SERVER_FINISHED;
-                    this.mConnectionState = CS_END;
 
                     CompleteHandshake();
                     break;
@@ -384,10 +380,19 @@ namespace Org.BouncyCastle.Crypto.Tls
                     SendClientKeyExchangeMessage();
                     this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
 
+                    if (TlsUtilities.IsSsl(Context))
+                    {
+                        EstablishMasterSecret(Context, mKeyExchange);
+                    }
+
                     TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
                     this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null);
 
-                    EstablishMasterSecret(Context, mKeyExchange);
+                    if (!TlsUtilities.IsSsl(Context))
+                    {
+                        EstablishMasterSecret(Context, mKeyExchange);
+                    }
+
                     mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
 
                     if (clientCreds != null && clientCreds is TlsSignerCredentials)
@@ -422,7 +427,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                     break;
                 }
                 default:
-                    throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                 }
 
                 this.mConnectionState = CS_CLIENT_FINISHED;
@@ -785,7 +790,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);
 
             /*
-             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
+             * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify
              * verify_data_length has a verify_data_length equal to 12. This includes all
              * existing cipher suites.
              */
diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
index 93ef1fa4a..eec9daaca 100644
--- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -27,6 +27,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             switch (keyExchange)
             {
+            case KeyExchangeAlgorithm.DH_anon:
             case KeyExchangeAlgorithm.DH_RSA:
             case KeyExchangeAlgorithm.DH_DSS:
                 this.mTlsSigner = null;
@@ -56,11 +57,14 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public override void SkipServerCredentials()
         {
-            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            if (mKeyExchange != KeyExchangeAlgorithm.DH_anon)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
         }
 
         public override void ProcessServerCertificate(Certificate serverCertificate)
         {
+            if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
             if (serverCertificate.IsEmpty)
                 throw new TlsFatalAlert(AlertDescription.bad_certificate);
 
@@ -109,9 +113,9 @@ namespace Org.BouncyCastle.Crypto.Tls
             {
                 switch (mKeyExchange)
                 {
+                case KeyExchangeAlgorithm.DH_anon:
                 case KeyExchangeAlgorithm.DHE_DSS:
                 case KeyExchangeAlgorithm.DHE_RSA:
-                case KeyExchangeAlgorithm.DH_anon:
                     return true;
                 default:
                     return false;
@@ -119,6 +123,32 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
+        public override byte[] GenerateServerKeyExchange()
+        {
+            if (!RequiresServerKeyExchange)
+                return null;
+
+            // DH_anon is handled here, DHE_* in a subclass
+
+            MemoryStream buf = new MemoryStream();
+            this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+                this.mDHParameters, buf);
+            return buf.ToArray();
+        }
+
+        public override void ProcessServerKeyExchange(Stream input)
+        {
+            if (!RequiresServerKeyExchange)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+            // DH_anon is handled here, DHE_* in a subclass
+
+            ServerDHParams dhParams = ServerDHParams.Parse(input);
+
+            this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey);
+            this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters);
+        }
+
         public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
         {
             byte[] types = certificateRequest.CertificateTypes;
@@ -140,6 +170,9 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public override void ProcessClientCredentials(TlsCredentials clientCredentials)
         {
+            if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
             if (clientCredentials is TlsAgreementCredentials)
             {
                 // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
@@ -172,12 +205,11 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public override void ProcessClientCertificate(Certificate clientCertificate)
         {
-            // TODO Extract the public key and validate
+            if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
 
-            /*
-             * TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey and check
-             * that the parameters match the server's (see 'areCompatibleParameters').
-             */
+            // TODO Extract the public key
+            // TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey
         }
 
         public override void ProcessClientKeyExchange(Stream input)
diff --git a/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs b/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs
new file mode 100644
index 000000000..72159ba47
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>
+    /// This exception will be thrown(only) when the connection is closed by the peer without sending a
+    /// <code cref="AlertDescription.close_notify">close_notify</code> warning alert.
+    /// </summary>
+    /// <remarks>
+    /// If this happens, the TLS protocol cannot rule out truncation of the connection data (potentially
+    /// malicious). It may be possible to check for truncation via some property of a higher level protocol
+    /// built upon TLS, e.g.the Content-Length header for HTTPS.
+    /// </remarks>
+    public class TlsNoCloseNotifyException
+        :   EndOfStreamException
+    {
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index 6d5c93f40..490580fad 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -43,9 +43,9 @@ namespace Org.BouncyCastle.Crypto.Tls
         /*
          * Queues for data from some protocols.
          */
-        private ByteQueue mApplicationDataQueue = new ByteQueue();
+        private ByteQueue mApplicationDataQueue = new ByteQueue(0);
         private ByteQueue mAlertQueue = new ByteQueue(2);
-        private ByteQueue mHandshakeQueue = new ByteQueue();
+        private ByteQueue mHandshakeQueue = new ByteQueue(0);
     //    private ByteQueue mHeartbeatQueue = new ByteQueue();
 
         /*
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
         }
 
-        protected abstract void HandleHandshakeMessage(byte type, byte[] buf);
+        protected abstract void HandleHandshakeMessage(byte type, MemoryStream buf);
 
         protected virtual void HandleWarningMessage(byte description)
         {
@@ -169,7 +169,8 @@ namespace Org.BouncyCastle.Crypto.Tls
                 {
                     if (this.mClosed)
                     {
-                        // TODO What kind of exception/alert?
+                        // NOTE: Any close during the handshake should have raised an exception.
+                        throw new TlsFatalAlert(AlertDescription.internal_error);
                     }
 
                     SafeReadRecord();
@@ -181,6 +182,11 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             try
             {
+                this.mConnectionState = CS_END;
+
+                this.mAlertQueue.Shrink();
+                this.mHandshakeQueue.Shrink();
+
                 this.mRecordStream.FinaliseHandshake();
 
                 this.mAppDataSplitEnabled = !TlsUtilities.IsTlsV11(Context);
@@ -227,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
-        protected internal void ProcessRecord(byte protocol, byte[] buf, int offset, int len)
+        protected internal void ProcessRecord(byte protocol, byte[] buf, int off, int len)
         {
             /*
              * Have a look at the protocol type, and add it to the correct queue.
@@ -236,8 +242,8 @@ namespace Org.BouncyCastle.Crypto.Tls
             {
             case ContentType.alert:
             {
-                mAlertQueue.AddData(buf, offset, len);
-                ProcessAlert();
+                mAlertQueue.AddData(buf, off, len);
+                ProcessAlertQueue();
                 break;
             }
             case ContentType.application_data:
@@ -245,107 +251,108 @@ namespace Org.BouncyCastle.Crypto.Tls
                 if (!mAppDataReady)
                     throw new TlsFatalAlert(AlertDescription.unexpected_message);
 
-                mApplicationDataQueue.AddData(buf, offset, len);
-                ProcessApplicationData();
+                mApplicationDataQueue.AddData(buf, off, len);
+                ProcessApplicationDataQueue();
                 break;
             }
             case ContentType.change_cipher_spec:
             {
-                ProcessChangeCipherSpec(buf, offset, len);
+                ProcessChangeCipherSpec(buf, off, len);
                 break;
             }
             case ContentType.handshake:
             {
-                mHandshakeQueue.AddData(buf, offset, len);
-                ProcessHandshake();
-                break;
-            }
-            case ContentType.heartbeat:
-            {
-                if (!mAppDataReady)
-                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
-
-                // TODO[RFC 6520]
-    //            mHeartbeatQueue.AddData(buf, offset, len);
-    //            ProcessHeartbeat();
+                if (mHandshakeQueue.Available > 0)
+                {
+                    mHandshakeQueue.AddData(buf, off, len);
+                    ProcessHandshakeQueue(mHandshakeQueue);
+                }
+                else
+                {
+                    ByteQueue tmpQueue = new ByteQueue(buf, off, len);
+                    ProcessHandshakeQueue(tmpQueue);
+                    int remaining = tmpQueue.Available;
+                    if (remaining > 0)
+                    {
+                        mHandshakeQueue.AddData(buf, off + len - remaining, remaining);
+                    }
+                }
                 break;
             }
+            //case ContentType.heartbeat:
+            //{
+            //    if (!mAppDataReady)
+            //        throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+            //    // TODO[RFC 6520]
+            //    //mHeartbeatQueue.AddData(buf, offset, len);
+            //    //ProcessHeartbeat();
+            //    break;
+            //}
             default:
-                /*
-                 * Uh, we don't know this protocol.
-                 * 
-                 * RFC2246 defines on page 13, that we should ignore this.
-                 */
-                break;
+                // Record type should already have been checked
+                throw new TlsFatalAlert(AlertDescription.internal_error);
             }
         }
 
-        private void ProcessHandshake()
+        private void ProcessHandshakeQueue(ByteQueue queue)
         {
-            bool read;
-            do
+            while (queue.Available >= 4)
             {
-                read = false;
                 /*
                  * We need the first 4 bytes, they contain type and length of the message.
                  */
-                if (mHandshakeQueue.Available >= 4)
-                {
-                    byte[] beginning = new byte[4];
-                    mHandshakeQueue.Read(beginning, 0, 4, 0);
-                    byte type = TlsUtilities.ReadUint8(beginning, 0);
-                    int len = TlsUtilities.ReadUint24(beginning, 1);
+                byte[] beginning = new byte[4];
+                queue.Read(beginning, 0, 4, 0);
+                byte type = TlsUtilities.ReadUint8(beginning, 0);
+                int length = TlsUtilities.ReadUint24(beginning, 1);
+                int totalLength = 4 + length;
 
-                    /*
-                     * Check if we have enough bytes in the buffer to read the full message.
-                     */
-                    if (mHandshakeQueue.Available >= (len + 4))
-                    {
-                        /*
-                         * Read the message.
-                         */
-                        byte[] buf = mHandshakeQueue.RemoveData(len, 4);
-
-                        CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
+                /*
+                 * Check if we have enough bytes in the buffer to read the full message.
+                 */
+                if (queue.Available < totalLength)
+                    break;
 
-                        /*
-                         * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
-                         * starting at client hello up to, but not including, this finished message.
-                         * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
-                         */
-                        switch (type)
-                        {
-                        case HandshakeType.hello_request:
-                            break;
-                        case HandshakeType.finished:
-                        default:
-                        {
-                            TlsContext ctx = Context;
-                            if (type == HandshakeType.finished
-                                && this.mExpectedVerifyData == null
-                                && ctx.SecurityParameters.MasterSecret != null)
-                            {
-                                this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
-                            }
-
-                            mRecordStream.UpdateHandshakeData(beginning, 0, 4);
-                            mRecordStream.UpdateHandshakeData(buf, 0, len);
-                            break;
-                        }
-                        }
+                CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
 
-                        /*
-                         * Now, parse the message.
-                         */
-                        HandleHandshakeMessage(type, buf);
-                        read = true;
+                /*
+                 * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
+                 * starting at client hello up to, but not including, this finished message.
+                 * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
+                 */
+                switch (type)
+                {
+                case HandshakeType.hello_request:
+                    break;
+                case HandshakeType.finished:
+                default:
+                {
+                    TlsContext ctx = Context;
+                    if (type == HandshakeType.finished
+                        && this.mExpectedVerifyData == null
+                        && ctx.SecurityParameters.MasterSecret != null)
+                    {
+                        this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
                     }
+
+                    queue.CopyTo(mRecordStream.HandshakeHashUpdater, totalLength);
+                    break;
+                }
                 }
+
+                queue.RemoveData(4);
+
+                MemoryStream buf = queue.ReadFrom(length);
+
+                /*
+                 * Now, parse the message.
+                 */
+                HandleHandshakeMessage(type, buf);
             }
-            while (read);
         }
 
-        private void ProcessApplicationData()
+        private void ProcessApplicationDataQueue()
         {
             /*
              * There is nothing we need to do here.
@@ -354,7 +361,7 @@ namespace Org.BouncyCastle.Crypto.Tls
              */
         }
 
-        private void ProcessAlert()
+        private void ProcessAlertQueue()
         {
             while (mAlertQueue.Available >= 2)
             {
@@ -384,14 +391,16 @@ namespace Org.BouncyCastle.Crypto.Tls
                 }
                 else
                 {
-
                     /*
                      * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own
                      * and close down the connection immediately, discarding any pending writes.
                      */
-                    // TODO Can close_notify be a fatal alert?
                     if (description == AlertDescription.close_notify)
                     {
+                        if (!mAppDataReady)
+                        {
+                            throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                        }
                         HandleClose(false);
                     }
 
@@ -482,15 +491,35 @@ namespace Org.BouncyCastle.Crypto.Tls
             return len;
         }
 
+        protected virtual void SafeCheckRecordHeader(byte[] recordHeader)
+        {
+            try
+            {
+                mRecordStream.CheckRecordHeader(recordHeader);
+            }
+            catch (TlsFatalAlert e)
+            {
+                this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to read record", e);
+                throw e;
+            }
+            catch (Exception e)
+            {
+                this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e);
+                throw e;
+            }
+        }
+
         protected virtual void SafeReadRecord()
         {
             try
             {
                 if (!mRecordStream.ReadRecord())
                 {
-                    // TODO It would be nicer to allow graceful connection close if between records
-    //                this.FailWithError(AlertLevel.warning, AlertDescription.close_notify);
-                    throw new EndOfStreamException();
+                    if (!mAppDataReady)
+                    {
+                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                    }
+                    throw new TlsNoCloseNotifyException();
                 }
             }
             catch (TlsFatalAlert e)
@@ -610,14 +639,24 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len)
         {
-            while (len > 0)
+            if (len < 4)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            byte type = TlsUtilities.ReadUint8(buf, off);
+            if (type != HandshakeType.hello_request)
+            {
+                mRecordStream.HandshakeHashUpdater.Write(buf, off, len);
+            }
+
+            int total = 0;
+            do
             {
                 // Fragment data according to the current fragment limit.
-                int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
-                SafeWriteRecord(ContentType.handshake, buf, off, toWrite);
-                off += toWrite;
-                len -= toWrite;
+                int toWrite = System.Math.Min(len - total, mRecordStream.GetPlaintextLimit());
+                SafeWriteRecord(ContentType.handshake, buf, off + total, toWrite);
+                total += toWrite;
             }
+            while (total < len);
         }
 
         /// <summary>The secure bidirectional stream for this connection</summary>
@@ -633,6 +672,26 @@ namespace Org.BouncyCastle.Crypto.Tls
         }
 
         /**
+         * Should be called in non-blocking mode when the input data reaches EOF.
+         */
+        public virtual void CloseInput()
+        {
+            if (mBlocking)
+                throw new InvalidOperationException("Cannot use CloseInput() in blocking mode!");
+
+            if (mClosed)
+                return;
+
+            if (mInputBuffers.Available > 0)
+                throw new EndOfStreamException();
+
+            if (!mAppDataReady)
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+            throw new TlsNoCloseNotifyException();
+        }
+
+        /**
          * Offer input from an arbitrary source. Only allowed in non-blocking mode.<br/>
          * <br/>
          * After this method returns, the input buffer is "owned" by this object. Other code
@@ -662,17 +721,28 @@ namespace Org.BouncyCastle.Crypto.Tls
             // loop while there are enough bytes to read the length of the next record
             while (mInputBuffers.Available >= RecordStream.TLS_HEADER_SIZE)
             {
-                byte[] header = new byte[RecordStream.TLS_HEADER_SIZE];
-                mInputBuffers.Peek(header);
+                byte[] recordHeader = new byte[RecordStream.TLS_HEADER_SIZE];
+                mInputBuffers.Peek(recordHeader);
 
-                int totalLength = TlsUtilities.ReadUint16(header, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE;
+                int totalLength = TlsUtilities.ReadUint16(recordHeader, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE;
                 if (mInputBuffers.Available < totalLength)
                 {
                     // not enough bytes to read a whole record
+                    SafeCheckRecordHeader(recordHeader);
                     break;
                 }
 
                 SafeReadRecord();
+
+                if (mClosed)
+                {
+                    if (mConnectionState != CS_END)
+                    {
+                        // NOTE: Any close during the handshake should have raised an exception.
+                        throw new TlsFatalAlert(AlertDescription.internal_error);
+                    }
+                    break;
+                }
             }
         }
 
@@ -1164,6 +1234,9 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             switch (ciphersuite)
             {
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
             case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
             case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
@@ -1267,6 +1340,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
 
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
             case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
             case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
diff --git a/crypto/src/crypto/tls/TlsRsaSigner.cs b/crypto/src/crypto/tls/TlsRsaSigner.cs
index 6da1c5e9b..1614f503b 100644
--- a/crypto/src/crypto/tls/TlsRsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsRsaSigner.cs
@@ -91,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         protected virtual IAsymmetricBlockCipher CreateRsaImpl()
         {
             /*
-             * RFC 5264 7.4.7.1. Implementation note: It is now known that remote timing-based attacks
+             * RFC 5246 7.4.7.1. Implementation note: It is now known that remote timing-based attacks
              * on TLS are possible, at least when the client and server are on the same LAN.
              * Accordingly, implementations that use static RSA keys MUST use RSA blinding or some other
              * anti-timing technique, as described in [TIMING].
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index 38f2befea..5f3ce18e2 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -124,10 +124,8 @@ namespace Org.BouncyCastle.Crypto.Tls
             get { return mTlsServer; }
         }
 
-        protected override void HandleHandshakeMessage(byte type, byte[] data)
+        protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
         {
-            MemoryStream buf = new MemoryStream(data);
-
             switch (type)
             {
             case HandshakeType.client_hello:
@@ -367,7 +365,6 @@ namespace Org.BouncyCastle.Crypto.Tls
 
                     SendFinishedMessage();
                     this.mConnectionState = CS_SERVER_FINISHED;
-                    this.mConnectionState = CS_END;
 
                     CompleteHandshake();
                     break;
@@ -625,10 +622,19 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             AssertEmpty(buf);
 
+            if (TlsUtilities.IsSsl(Context))
+            {
+                EstablishMasterSecret(Context, mKeyExchange);
+            }
+
             this.mPrepareFinishHash = mRecordStream.PrepareToFinish();
             this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, mPrepareFinishHash, null);
 
-            EstablishMasterSecret(Context, mKeyExchange);
+            if (!TlsUtilities.IsSsl(Context))
+            {
+                EstablishMasterSecret(Context, mKeyExchange);
+            }
+
             mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
 
             if (!mExpectSessionTicket)
@@ -780,7 +786,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
 
             /*
-             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+             * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
              * a verify_data_length equal to 12. This includes all existing cipher suites.
              */
             mSecurityParameters.verifyDataLength = 12;
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index d51a8ff48..48e51a7b6 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -571,6 +571,16 @@ namespace Org.BouncyCastle.Crypto.Tls
             buf[offset + 1] = (byte)version.MinorVersion;
         }
 
+        public static IList GetAllSignatureAlgorithms()
+        {
+            IList v = Platform.CreateArrayList(4);
+            v.Add(SignatureAlgorithm.anonymous);
+            v.Add(SignatureAlgorithm.rsa);
+            v.Add(SignatureAlgorithm.dsa);
+            v.Add(SignatureAlgorithm.ecdsa);
+            return v;
+        }
+
         public static IList GetDefaultDssSignatureAlgorithms()
         {
             return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.dsa));
@@ -1260,6 +1270,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             switch (ciphersuite)
             {
+            case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
             case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
             case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
@@ -1279,6 +1290,8 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
                 return EncryptionAlgorithm.cls_3DES_EDE_CBC;
 
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
             case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
@@ -1325,6 +1338,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
                 return EncryptionAlgorithm.AES_128_CCM_8;
 
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
             case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
             case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
@@ -1347,6 +1361,8 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
                 return EncryptionAlgorithm.AES_128_OCB_TAGLEN96;
 
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
             case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
@@ -1393,6 +1409,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
                 return EncryptionAlgorithm.AES_256_CCM_8;
 
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
             case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
             case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
             case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
@@ -1415,17 +1432,16 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
                 return EncryptionAlgorithm.AES_256_OCB_TAGLEN96;
 
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
-            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
-            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
-            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
-            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
-                return EncryptionAlgorithm.CAMELLIA_128_CBC;
-
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
             case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
             case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
             case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
@@ -1433,10 +1449,12 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
-            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
             case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
                 return EncryptionAlgorithm.CAMELLIA_128_CBC;
 
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
             case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
             case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
@@ -1451,30 +1469,29 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
                 return EncryptionAlgorithm.CAMELLIA_128_GCM;
 
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
-            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
-            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
-            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
-            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
-                return EncryptionAlgorithm.CAMELLIA_256_CBC;
-
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
             case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
             case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
-            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
-                return EncryptionAlgorithm.CAMELLIA_256_CBC;
-
             case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
             case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
             case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
             case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
             case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
             case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
             case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
             case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
                 return EncryptionAlgorithm.CAMELLIA_256_CBC;
 
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
             case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
             case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
@@ -1542,6 +1559,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
                 return EncryptionAlgorithm.RC4_128;
 
+            case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
             case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
             case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
@@ -1558,6 +1576,23 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             switch (ciphersuite)
             {
+            case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
+            case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA:
+                return KeyExchangeAlgorithm.DH_anon;
+
             case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
@@ -1837,6 +1872,10 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             switch (ciphersuite)
             {
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
@@ -1926,10 +1965,17 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
                 return MacAlgorithm.cls_null;
 
+            case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
             case CipherSuite.TLS_RSA_WITH_NULL_MD5:
             case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
                 return MacAlgorithm.hmac_md5;
 
+            case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
             case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
@@ -2018,6 +2064,10 @@ namespace Org.BouncyCastle.Crypto.Tls
             case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
                 return MacAlgorithm.hmac_sha1;
 
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
             case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
@@ -2092,6 +2142,10 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             switch (ciphersuite)
             {
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
             case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
             case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
             case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
@@ -2242,9 +2296,68 @@ namespace Org.BouncyCastle.Crypto.Tls
             return CipherType.stream == GetCipherType(ciphersuite);
         }
 
+        public static bool IsValidCipherSuiteForSignatureAlgorithms(int cipherSuite, IList sigAlgs)
+        {
+            int keyExchangeAlgorithm;
+            try
+            {
+                keyExchangeAlgorithm = GetKeyExchangeAlgorithm(cipherSuite);
+            }
+            catch (IOException e)
+            {
+                return true;
+            }
+
+            switch (keyExchangeAlgorithm)
+            {
+            case KeyExchangeAlgorithm.DH_anon:
+            case KeyExchangeAlgorithm.DH_anon_EXPORT:
+            case KeyExchangeAlgorithm.ECDH_anon:
+                return sigAlgs.Contains(SignatureAlgorithm.anonymous);
+
+            case KeyExchangeAlgorithm.DHE_RSA:
+            case KeyExchangeAlgorithm.DHE_RSA_EXPORT:
+            case KeyExchangeAlgorithm.ECDHE_RSA:
+            case KeyExchangeAlgorithm.SRP_RSA:
+                return sigAlgs.Contains(SignatureAlgorithm.rsa);
+
+            case KeyExchangeAlgorithm.DHE_DSS:
+            case KeyExchangeAlgorithm.DHE_DSS_EXPORT:
+            case KeyExchangeAlgorithm.SRP_DSS:
+                return sigAlgs.Contains(SignatureAlgorithm.dsa);
+
+            case KeyExchangeAlgorithm.ECDHE_ECDSA:
+                return sigAlgs.Contains(SignatureAlgorithm.ecdsa);
+
+            default:
+                return true;
+            }
+        }
+
         public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion)
         {
             return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion());
         }
+
+        public static IList GetUsableSignatureAlgorithms(IList sigHashAlgs)
+        {
+            if (sigHashAlgs == null)
+                return GetAllSignatureAlgorithms();
+
+            IList v = Platform.CreateArrayList(4);
+            v.Add(SignatureAlgorithm.anonymous);
+            foreach (SignatureAndHashAlgorithm sigHashAlg in sigHashAlgs)
+            {
+                //if (sigHashAlg.Hash >= MINIMUM_HASH_STRICT)
+                {
+                    byte sigAlg = sigHashAlg.Signature;
+                    if (!v.Contains(sigAlg))
+                    {
+                        v.Add(sigAlg);
+                    }
+                }
+            }
+            return v;
+        }
     }
 }
diff --git a/crypto/src/util/io/BaseOutputStream.cs b/crypto/src/util/io/BaseOutputStream.cs
index a0608d111..0dbe821de 100644
--- a/crypto/src/util/io/BaseOutputStream.cs
+++ b/crypto/src/util/io/BaseOutputStream.cs
@@ -60,5 +60,10 @@ namespace Org.BouncyCastle.Utilities.IO
 		{
 			Write(buffer, 0, buffer.Length);
 		}
-	}
+
+        public override void WriteByte(byte b)
+        {
+            Write(new byte[]{ b }, 0, 1);
+        }
+    }
 }
diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs
index 70957acc7..cc7fa924c 100644
--- a/crypto/src/util/io/Streams.cs
+++ b/crypto/src/util/io/Streams.cs
@@ -90,5 +90,11 @@ namespace Org.BouncyCastle.Utilities.IO
 			}
 			return total;
 		}
-	}
+
+        /// <exception cref="IOException"></exception>
+        public static void WriteBufTo(MemoryStream buf, Stream output)
+        {
+            buf.WriteTo(output);
+        }
+    }
 }
diff --git a/crypto/test/src/crypto/test/Poly1305Test.cs b/crypto/test/src/crypto/test/Poly1305Test.cs
index eee9bcca5..7375b09be 100644
--- a/crypto/test/src/crypto/test/Poly1305Test.cs
+++ b/crypto/test/src/crypto/test/Poly1305Test.cs
@@ -86,7 +86,16 @@ namespace Org.BouncyCastle.Crypto.Tests
                 null,
                 "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
                 "045be28cc52009f506bdbfabedacf0b4"),
-		};
+            // Test case from JIRA issue BJA-620
+            new TestCase(
+                "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff",
+                null,
+                  "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff"
+                + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff"
+                + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff"
+                + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffff",
+                "c80cb43844f387946e5aa6085bdf67da")
+        };
 
 		public override string Name
 		{
diff --git a/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs b/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs
index 477e287f1..68f2341ee 100644
--- a/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs
+++ b/crypto/test/src/crypto/tls/test/TlsProtocolNonBlockingTest.cs
@@ -52,6 +52,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             // close the connection
             clientProtocol.Close();
             PumpData(clientProtocol, serverProtocol, fragment);
+            serverProtocol.CloseInput();
             CheckClosed(serverProtocol);
             CheckClosed(clientProtocol);
         }
diff --git a/crypto/test/src/crypto/tls/test/TlsServerTest.cs b/crypto/test/src/crypto/tls/test/TlsServerTest.cs
index df31e1c0e..28272169b 100644
--- a/crypto/test/src/crypto/tls/test/TlsServerTest.cs
+++ b/crypto/test/src/crypto/tls/test/TlsServerTest.cs
@@ -27,14 +27,21 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             TcpListener ss = new TcpListener(IPAddress.Any, port);
             ss.Start();
             Stream stdout = Console.OpenStandardOutput();
-            while (true)
+            try
             {
-                TcpClient s = ss.AcceptTcpClient();
-                Console.WriteLine("--------------------------------------------------------------------------------");
-                Console.WriteLine("Accepted " + s);
-                ServerThread st = new ServerThread(s, stdout);
-                Thread t = new Thread(new ThreadStart(st.Run));
-                t.Start();
+                while (true)
+                {
+                    TcpClient s = ss.AcceptTcpClient();
+                    Console.WriteLine("--------------------------------------------------------------------------------");
+                    Console.WriteLine("Accepted " + s);
+                    ServerThread st = new ServerThread(s, stdout);
+                    Thread t = new Thread(new ThreadStart(st.Run));
+                    t.Start();
+                }
+            }
+            finally
+            {
+                ss.Stop();
             }
         }
 
diff --git a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
index 77cebe0a6..5dd9cf0f5 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
@@ -19,6 +19,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             IList testSuite = new ArrayList();
 
             AddFallbackTests(testSuite);
+            AddVersionTests(testSuite, ProtocolVersion.SSLv3);
             AddVersionTests(testSuite, ProtocolVersion.TLSv10);
             AddVersionTests(testSuite, ProtocolVersion.TLSv11);
             AddVersionTests(testSuite, ProtocolVersion.TLSv12);
@@ -194,10 +195,10 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
         private static TlsTestConfig CreateTlsTestConfig(ProtocolVersion version)
         {
             TlsTestConfig c = new TlsTestConfig();
-            c.clientMinimumVersion = ProtocolVersion.TLSv10;
+            c.clientMinimumVersion = ProtocolVersion.SSLv3;
             c.clientOfferVersion = ProtocolVersion.TLSv12;
             c.serverMaximumVersion = version;
-            c.serverMinimumVersion = ProtocolVersion.TLSv10;
+            c.serverMinimumVersion = ProtocolVersion.SSLv3;
             return c;
         }
     }
diff --git a/crypto/test/src/tsp/test/ParseTest.cs b/crypto/test/src/tsp/test/ParseTest.cs
index ec9ba72f6..e9489a278 100644
--- a/crypto/test/src/tsp/test/ParseTest.cs
+++ b/crypto/test/src/tsp/test/ParseTest.cs
@@ -360,7 +360,8 @@ namespace Org.BouncyCastle.Tsp.Tests
 		[Test]
 		public void TestGeneralizedTime()
 		{
-			generalizedTimeParse(generalizedTime);
+            // TODO: response is invalid - malformed integer
+			// generalizedTimeParse(generalizedTime);
 		}
 
 		[Test]