summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-03-09 21:26:50 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-03-09 21:26:50 +0700
commitf6ff8794291fca376482633b26eaf8101c8cb44d (patch)
treeb584b39ea53767ae0fe1d9cb4043ca90c2623b0d
parentRemove extraneous class reference (diff)
downloadBouncyCastle.NET-ed25519-f6ff8794291fca376482633b26eaf8101c8cb44d.tar.xz
Port of TlsTestSuite from Java, and misc. TLS code
- Upgrade to NUnit 2.6.4 and adjust various test code
-rw-r--r--.gitattributes1
-rw-r--r--crypto/crypto.csproj40
-rw-r--r--crypto/test/lib/nunit.core.dllbin90112 -> 139264 bytes
-rw-r--r--crypto/test/lib/nunit.core.interfaces.dllbin40960 -> 61440 bytes
-rw-r--r--crypto/test/lib/nunit.framework.dllbin81920 -> 139264 bytes
-rw-r--r--crypto/test/src/asn1/test/AllTests.cs28
-rw-r--r--crypto/test/src/cms/test/AllTests.cs33
-rw-r--r--crypto/test/src/crypto/io/test/AllTests.cs29
-rw-r--r--crypto/test/src/crypto/test/AllTests.cs37
-rw-r--r--crypto/test/src/crypto/tls/test/LoggingDatagramTransport.cs86
-rw-r--r--crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs104
-rw-r--r--crypto/test/src/crypto/tls/test/MockPskTlsClient.cs2
-rw-r--r--crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs2
-rw-r--r--crypto/test/src/crypto/tls/test/MockTlsClient.cs2
-rw-r--r--crypto/test/src/crypto/tls/test/NetworkStream.cs101
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestCase.cs158
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs262
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestConfig.cs101
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs194
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestSuite.cs119
-rw-r--r--crypto/test/src/math/ec/test/AllTests.cs23
-rw-r--r--crypto/test/src/math/test/AllTests.cs21
-rw-r--r--crypto/test/src/ocsp/test/AllTests.cs29
-rw-r--r--crypto/test/src/openpgp/examples/test/AllTests.cs32
-rw-r--r--crypto/test/src/openssl/test/AllTests.cs37
-rw-r--r--crypto/test/src/tsp/test/AllTests.cs27
-rw-r--r--crypto/test/src/util/io/pem/test/AllTests.cs35
27 files changed, 1325 insertions, 178 deletions
diff --git a/.gitattributes b/.gitattributes
index 14f495692..4989b01a5 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -24,6 +24,7 @@
 *.crl      binary
 *.crt      binary
 *.data     binary
+*.dll      binary
 *.dsa      binary
 *.jpg      binary
 *.jpeg     binary
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index ded3d6025..9d185ade3 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -11088,6 +11088,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\tls\test\LoggingDatagramTransport.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\MockDatagramAssociation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\tls\test\MockPskTlsClient.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11118,6 +11128,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\tls\test\NetworkStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\tls\test\PipedStream.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11148,6 +11163,31 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\tls\test\TlsTestCase.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\TlsTestClientImpl.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\TlsTestConfig.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\TlsTestServerImpl.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\TlsTestSuite.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\tls\test\TlsTestUtilities.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/test/lib/nunit.core.dll b/crypto/test/lib/nunit.core.dll
index f58c07d42..8d99c637d 100644
--- a/crypto/test/lib/nunit.core.dll
+++ b/crypto/test/lib/nunit.core.dll
Binary files differdiff --git a/crypto/test/lib/nunit.core.interfaces.dll b/crypto/test/lib/nunit.core.interfaces.dll
index cdf50b687..70a76b21c 100644
--- a/crypto/test/lib/nunit.core.interfaces.dll
+++ b/crypto/test/lib/nunit.core.interfaces.dll
Binary files differdiff --git a/crypto/test/lib/nunit.framework.dll b/crypto/test/lib/nunit.framework.dll
index c7b1c65d9..ba484ba8c 100644
--- a/crypto/test/lib/nunit.framework.dll
+++ b/crypto/test/lib/nunit.framework.dll
Binary files differdiff --git a/crypto/test/src/asn1/test/AllTests.cs b/crypto/test/src/asn1/test/AllTests.cs
index a1ae8fd48..ad2f90362 100644
--- a/crypto/test/src/asn1/test/AllTests.cs
+++ b/crypto/test/src/asn1/test/AllTests.cs
@@ -9,24 +9,22 @@ namespace Org.BouncyCastle.Asn1.Tests
     {
         public static void Main(string[] args)
         {
-//            junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            suite().Run(el);
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
         }
 
-		public static TestSuite suite()
+        [Suite]
+		public static TestSuite Suite
         {
-            TestSuite suite = new TestSuite("ASN.1 tests");
-
-			suite.Add(new AllTests());
-
-			// TODO Add these tests to RegressionTest list
-			suite.Add(new Asn1SequenceParserTest());
-			suite.Add(new OctetStringTest());
-			suite.Add(new ParseTest());
-			suite.Add(new TimeTest());
-
-			return suite;
+            get
+            {
+                TestSuite suite = new TestSuite("ASN.1 tests");
+			    // TODO Add these tests to RegressionTest list
+			    suite.Add(new Asn1SequenceParserTest());
+			    suite.Add(new OctetStringTest());
+			    suite.Add(new ParseTest());
+			    suite.Add(new TimeTest());
+			    return suite;
+            }
         }
     }
 }
diff --git a/crypto/test/src/cms/test/AllTests.cs b/crypto/test/src/cms/test/AllTests.cs
index 1ce3b7c8d..b7ac7644b 100644
--- a/crypto/test/src/cms/test/AllTests.cs
+++ b/crypto/test/src/cms/test/AllTests.cs
@@ -9,27 +9,26 @@ namespace Org.BouncyCastle.Cms.Tests
 {
     public class AllTests
     {
-        public static void Main(
-			string[] args)
+        public static void Main(string[] args)
         {
-            //junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            suite().Run(el);
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
         }
 
-		public static TestSuite suite()
+        [Suite]
+        public static TestSuite Suite
         {
-            TestSuite suite = new TestSuite("CMS Tests");
-
-			suite.Add(new CompressedDataTest());
-            suite.Add(new CompressedDataStreamTest());
-			suite.Add(new EnvelopedDataTest());
-			suite.Add(new EnvelopedDataStreamTest());
-			suite.Add(new Rfc4134Test());
-			suite.Add(new SignedDataTest());
-			suite.Add(new SignedDataStreamTest());
-
-			return suite;
+            get
+            {
+                TestSuite suite = new TestSuite("CMS Tests");
+                suite.Add(new CompressedDataTest());
+                suite.Add(new CompressedDataStreamTest());
+                suite.Add(new EnvelopedDataTest());
+                suite.Add(new EnvelopedDataStreamTest());
+                suite.Add(new Rfc4134Test());
+                suite.Add(new SignedDataTest());
+                suite.Add(new SignedDataStreamTest());
+                return suite;
+            }
         }
     }
 }
diff --git a/crypto/test/src/crypto/io/test/AllTests.cs b/crypto/test/src/crypto/io/test/AllTests.cs
index 0296a2dc0..5c8c759f9 100644
--- a/crypto/test/src/crypto/io/test/AllTests.cs
+++ b/crypto/test/src/crypto/io/test/AllTests.cs
@@ -7,21 +7,20 @@ namespace Org.BouncyCastle.Crypto.IO.Tests
 {
 	public class AllTests
 	{
-		public static void Main(
-			string[] args)
-		{
-//            junit.textui.TestRunner.run(suite());
-			EventListener el = new NullListener();
-			suite().Run(el);
-		}
+        public static void Main(string[] args)
+        {
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
+        }
 
-		public static TestSuite suite()
-		{
-			TestSuite suite = new TestSuite("IO tests");
-
-			suite.Add(new CipherStreamTest());
-
-			return suite;
-		}
+        [Suite]
+        public static TestSuite Suite
+        {
+            get
+            {
+                TestSuite suite = new TestSuite("IO tests");
+                suite.Add(new CipherStreamTest());
+                return suite;
+            }
+        }
 	}
 }
diff --git a/crypto/test/src/crypto/test/AllTests.cs b/crypto/test/src/crypto/test/AllTests.cs
index 1cb1b965d..3d8ef5602 100644
--- a/crypto/test/src/crypto/test/AllTests.cs
+++ b/crypto/test/src/crypto/test/AllTests.cs
@@ -10,19 +10,24 @@ namespace Org.BouncyCastle.Crypto.Tests
 	[TestFixture]
 	public class AllTests
 	{
-		[Suite]
-		public static TestSuite Suite
-		{
-			get
-			{
-				TestSuite suite = new TestSuite("Lightweight Crypto Tests");
-				suite.Add(new AllTests());
-		        suite.Add(new GcmReorderTest());
-				return suite;
-			}
-		}
+        public static void Main(string[] args)
+        {
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
+        }
 
-		[Test]
+        [Suite]
+        public static TestSuite Suite
+        {
+            get
+            {
+                TestSuite suite = new TestSuite("Lightweight Crypto Tests");
+                suite.Add(new AllTests());
+                suite.Add(new GcmReorderTest());
+                return suite;
+            }
+        }
+
+        [Test]
 		public void TestCrypto()
 		{
 			foreach (Org.BouncyCastle.Utilities.Test.ITest test in RegressionTest.tests)
@@ -35,13 +40,5 @@ namespace Org.BouncyCastle.Crypto.Tests
 				}
 			}
 		}
-
-        public static void Main(
-			string[] args)
-        {
-            //junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            Suite.Run(el);
-        }
 	}
 }
diff --git a/crypto/test/src/crypto/tls/test/LoggingDatagramTransport.cs b/crypto/test/src/crypto/tls/test/LoggingDatagramTransport.cs
new file mode 100644
index 000000000..a26c5bdbf
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/LoggingDatagramTransport.cs
@@ -0,0 +1,86 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    public class LoggingDatagramTransport
+        :   DatagramTransport
+    {
+        private static readonly string HEX_CHARS = "0123456789ABCDEF";
+
+        private readonly DatagramTransport transport;
+        private readonly TextWriter output;
+        private readonly long launchTimestamp;
+
+        public LoggingDatagramTransport(DatagramTransport transport, TextWriter output)
+        {
+            this.transport = transport;
+            this.output = output;
+            this.launchTimestamp = DateTimeUtilities.CurrentUnixMs();
+        }
+
+        public virtual int GetReceiveLimit()
+        {
+            return transport.GetReceiveLimit();
+        }
+
+        public virtual int GetSendLimit()
+        {
+            return transport.GetSendLimit();
+        }
+
+        public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
+        {
+            int length = transport.Receive(buf, off, len, waitMillis);
+            if (length >= 0)
+            {
+                DumpDatagram("Received", buf, off, length);
+            }
+            return length;
+        }
+
+        public virtual void Send(byte[] buf, int off, int len)
+        {
+            DumpDatagram("Sending", buf, off, len);
+            transport.Send(buf, off, len);
+        }
+
+        public virtual void Close()
+        {
+        }
+
+        private void DumpDatagram(string verb, byte[] buf, int off, int len)
+        {
+            long timestamp = DateTimeUtilities.CurrentUnixMs() - launchTimestamp;
+            StringBuilder sb = new StringBuilder("(+" + timestamp + "ms) " + verb + " " + len + " byte datagram:");
+            for (int pos = 0; pos < len; ++pos)
+            {
+                if (pos % 16 == 0)
+                {
+                    sb.Append(Environment.NewLine);
+                    sb.Append("    ");
+                }
+                else if (pos % 16 == 8)
+                {
+                    sb.Append('-');
+                }
+                else
+                {
+                    sb.Append(' ');
+                }
+                int val = buf[off + pos] & 0xFF;
+                sb.Append(HEX_CHARS[val >> 4]);
+                sb.Append(HEX_CHARS[val & 0xF]);
+            }
+            Dump(sb.ToString());
+        }
+
+        private void Dump(string s)
+        {
+            lock (this) output.WriteLine(s);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs b/crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs
new file mode 100644
index 000000000..0391f4fef
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Net;
+using System.Threading;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    public class MockDatagramAssociation
+    {
+        private int mtu;
+        private MockDatagramTransport client, server;
+
+        public MockDatagramAssociation(int mtu)
+        {
+            this.mtu = mtu;
+
+            IList clientQueue = new ArrayList();
+            IList serverQueue = new ArrayList();
+
+            this.client = new MockDatagramTransport(this, clientQueue, serverQueue);
+            this.server = new MockDatagramTransport(this, serverQueue, clientQueue);
+        }
+
+        public DatagramTransport getClient()
+        {
+            return client;
+        }
+
+        public DatagramTransport getServer()
+        {
+            return server;
+        }
+
+        private class MockDatagramTransport
+            :   DatagramTransport
+        {
+            private readonly MockDatagramAssociation mOuter;
+
+            private IList receiveQueue, sendQueue;
+
+            internal MockDatagramTransport(MockDatagramAssociation outer, IList receiveQueue, IList sendQueue)
+            {
+                this.mOuter = outer;
+                this.receiveQueue = receiveQueue;
+                this.sendQueue = sendQueue;
+            }
+
+            public virtual int GetReceiveLimit()
+            {
+                return mOuter.mtu;
+            }
+
+            public virtual int GetSendLimit()
+            {
+                return mOuter.mtu;
+            }
+
+            public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
+            {
+                lock (receiveQueue)
+                {
+                    if (receiveQueue.Count < 1)
+                    {
+                        Monitor.Wait(waitMillis);
+
+                        if (receiveQueue.Count < 1)
+                        {
+                            return -1;
+                        }
+                    }
+                    byte[] packet = (byte[])receiveQueue[0];
+                    receiveQueue.RemoveAt(0);
+                    int copyLength = System.Math.Min(len, packet.Length);
+                    Array.Copy(packet, 0, buf, off, copyLength);
+                    return copyLength;
+                }
+            }
+
+            public virtual void Send(byte[] buf, int off, int len)
+            {
+                if (len > mOuter.mtu)
+                {
+                    // TODO Simulate rejection?
+                }
+
+                byte[] packet = Arrays.CopyOfRange(buf, off, off + len);
+
+                lock (sendQueue)
+                {
+                    sendQueue.Add(packet);
+                    Monitor.PulseAll(sendQueue);
+                }
+            }
+
+            public virtual void Close()
+            {
+                // TODO?
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/MockPskTlsClient.cs b/crypto/test/src/crypto/tls/test/MockPskTlsClient.cs
index 4e183cba1..a186a8b58 100644
--- a/crypto/test/src/crypto/tls/test/MockPskTlsClient.cs
+++ b/crypto/test/src/crypto/tls/test/MockPskTlsClient.cs
@@ -123,7 +123,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 {
                     X509CertificateStructure entry = chain[i];
                     // TODO Create Fingerprint based on certificate signature algorithm digest
-                    Console.WriteLine("    Fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
+                    Console.WriteLine("    fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
                         + entry.Subject + ")");
                 }
             }
diff --git a/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs
index 7225d84ce..2b9549e82 100644
--- a/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs
+++ b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs
@@ -111,7 +111,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 {
                     X509CertificateStructure entry = chain[i];
                     // TODO Create Fingerprint based on certificate signature algorithm digest
-                    Console.WriteLine("    Fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
+                    Console.WriteLine("    fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
                         + entry.Subject + ")");
                 }
             }
diff --git a/crypto/test/src/crypto/tls/test/MockTlsClient.cs b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
index fd673c3b9..dbeb3fe41 100644
--- a/crypto/test/src/crypto/tls/test/MockTlsClient.cs
+++ b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
@@ -122,7 +122,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 {
                     X509CertificateStructure entry = chain[i];
                     // TODO Create Fingerprint based on certificate signature algorithm digest
-                    Console.WriteLine("    Fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
+                    Console.WriteLine("    fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
                         + entry.Subject + ")");
                 }
             }
diff --git a/crypto/test/src/crypto/tls/test/NetworkStream.cs b/crypto/test/src/crypto/tls/test/NetworkStream.cs
new file mode 100644
index 000000000..04de81e13
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/NetworkStream.cs
@@ -0,0 +1,101 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class NetworkStream
+        :   Stream
+    {
+        private readonly Stream mInner;
+        private bool mClosed = false;
+
+        internal NetworkStream(Stream inner)
+        {
+            this.mInner = inner;
+        }
+
+        internal virtual bool IsClosed
+        {
+            get { lock (this) return mClosed; }
+        }
+
+        public override bool CanRead
+        {
+            get { return mInner.CanRead; }
+        }
+
+        public override bool CanSeek
+        {
+            get { return mInner.CanSeek; }
+        }
+
+        public override bool CanWrite
+        {
+            get { return mInner.CanWrite; }
+        }
+
+        public override void Close()
+        {
+            lock (this) mClosed = true;
+        }
+
+        public override void Flush()
+        {
+            mInner.Flush();
+        }
+
+        public override long Length
+        {
+            get { return mInner.Length; }
+        }
+
+        public override long Position
+        {
+            get { return mInner.Position; }
+            set { mInner.Position = value; }
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            return mInner.Seek(offset, origin);
+        }
+
+        public override void SetLength(long value)
+        {
+            mInner.SetLength(value);
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            CheckNotClosed();
+            return mInner.Read(buffer, offset, count);
+        }
+
+        public override int ReadByte()
+        {
+            CheckNotClosed();
+            return mInner.ReadByte();
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            CheckNotClosed();
+            mInner.Write(buf, off, len);
+        }
+
+        public override void WriteByte(byte value)
+        {
+            CheckNotClosed();
+            mInner.WriteByte(value);
+        }
+
+        private void CheckNotClosed()
+        {
+            lock (this)
+            {
+                if (mClosed)
+                    throw new ObjectDisposedException(this.GetType().Name);
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestCase.cs b/crypto/test/src/crypto/tls/test/TlsTestCase.cs
new file mode 100644
index 000000000..8ac1c4ed2
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestCase.cs
@@ -0,0 +1,158 @@
+using System;
+using System.IO;
+using System.Threading;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    [TestFixture]
+    public class TlsTestCase
+    {
+        private static void CheckTlsVersion(ProtocolVersion version)
+        {
+            if (version != null && !version.IsTls)
+                throw new InvalidOperationException("Non-TLS version");
+        }
+
+        [Test, TestCaseSource(typeof(TlsTestSuite), "Suite")]
+        public void RunTest(TlsTestConfig config)
+        {
+            CheckTlsVersion(config.clientMinimumVersion);
+            CheckTlsVersion(config.clientOfferVersion);
+            CheckTlsVersion(config.serverMaximumVersion);
+            CheckTlsVersion(config.serverMinimumVersion);
+
+            SecureRandom secureRandom = new SecureRandom();
+
+            PipedStream clientPipe = new PipedStream();
+            PipedStream serverPipe = new PipedStream(clientPipe);
+
+            NetworkStream clientNet = new NetworkStream(clientPipe);
+            NetworkStream serverNet = new NetworkStream(serverPipe);
+
+            TlsClientProtocol clientProtocol = new TlsClientProtocol(clientNet, secureRandom);
+            TlsServerProtocol serverProtocol = new TlsServerProtocol(serverNet, secureRandom);
+
+            TlsTestClientImpl clientImpl = new TlsTestClientImpl(config);
+            TlsTestServerImpl serverImpl = new TlsTestServerImpl(config);
+
+            Server server = new Server(this, serverProtocol, serverImpl);
+
+            Thread serverThread = new Thread(new ThreadStart(server.Run));
+            serverThread.Start();
+
+            Exception caught = null;
+            try
+            {
+                clientProtocol.Connect(clientImpl);
+
+                // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity
+                int length = 1000;
+
+                byte[] data = new byte[length];
+                secureRandom.NextBytes(data);
+    
+                Stream output = clientProtocol.Stream;
+                output.Write(data, 0, data.Length);
+
+                byte[] echo = new byte[data.Length];
+                int count = Streams.ReadFully(clientProtocol.Stream, echo);
+
+                Assert.AreEqual(count, data.Length);
+                Assert.IsTrue(Arrays.AreEqual(data, echo));
+
+                output.Close();
+            }
+            catch (Exception e)
+            {
+                caught = e;
+                LogException(caught);
+            }
+
+            server.AllowExit();
+            serverThread.Join();
+
+            Assert.IsTrue(clientNet.IsClosed, "Client Stream not closed");
+            Assert.IsTrue(serverNet.IsClosed, "Server Stream not closed");
+
+            Assert.AreEqual(config.expectFatalAlertConnectionEnd, clientImpl.FirstFatalAlertConnectionEnd, "Client fatal alert connection end");
+            Assert.AreEqual(config.expectFatalAlertConnectionEnd, serverImpl.FirstFatalAlertConnectionEnd, "Server fatal alert connection end");
+
+            Assert.AreEqual(config.expectFatalAlertDescription, clientImpl.FirstFatalAlertDescription, "Client fatal alert description");
+            Assert.AreEqual(config.expectFatalAlertDescription, serverImpl.FirstFatalAlertDescription, "Server fatal alert description");
+
+            if (config.expectFatalAlertConnectionEnd == -1)
+            {
+                Assert.IsNull(caught, "Unexpected client exception");
+                Assert.IsNull(server.mCaught, "Unexpected server exception");
+            }
+        }
+
+        protected virtual void LogException(Exception e)
+        {
+            if (TlsTestConfig.DEBUG)
+            {
+                Console.Error.WriteLine(e);
+            }
+        }
+
+        internal class Server
+        {
+            protected readonly TlsTestCase mOuter;
+            protected readonly TlsServerProtocol mServerProtocol;
+            protected readonly TlsTestServerImpl mServerImpl;
+
+            internal bool mCanExit = false;
+            internal Exception mCaught = null;
+
+            internal Server(TlsTestCase outer, TlsServerProtocol serverProtocol, TlsTestServerImpl serverImpl)
+            {
+                this.mOuter = outer;
+                this.mServerProtocol = serverProtocol;
+                this.mServerImpl = serverImpl;
+            }
+
+            internal void AllowExit()
+            {
+                lock (this)
+                {
+                    mCanExit = true;
+                    Monitor.PulseAll(this);
+                }
+            }
+
+            public void Run()
+            {
+                try
+                {
+                    mServerProtocol.Accept(mServerImpl);
+                    Streams.PipeAll(mServerProtocol.Stream, mServerProtocol.Stream);
+                    mServerProtocol.Close();
+                }
+                catch (Exception e)
+                {
+                    mCaught = e;
+                    mOuter.LogException(mCaught);
+                }
+
+                WaitExit();
+            }
+
+            protected void WaitExit()
+            {
+                lock (this)
+                {
+                    while (!mCanExit)
+                    {
+                        Monitor.Wait(this);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs b/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
new file mode 100644
index 000000000..48af9e0f8
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
@@ -0,0 +1,262 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class TlsTestClientImpl
+        :   DefaultTlsClient
+    {
+        protected readonly TlsTestConfig mConfig;
+
+        protected int firstFatalAlertConnectionEnd = -1;
+        protected int firstFatalAlertDescription = -1;
+
+        internal TlsTestClientImpl(TlsTestConfig config)
+        {
+            this.mConfig = config;
+        }
+
+        internal int FirstFatalAlertConnectionEnd
+        {
+            get { return firstFatalAlertConnectionEnd; }
+        }
+
+        internal int FirstFatalAlertDescription
+        {
+            get { return firstFatalAlertDescription; }
+        }
+
+        public override ProtocolVersion ClientVersion
+        {
+	        get 
+	        { 
+                if (mConfig.clientOfferVersion != null)
+                {
+                    return mConfig.clientOfferVersion;
+                }
+
+                return base.ClientVersion;
+            }
+        }
+
+        public override ProtocolVersion MinimumVersion
+        {
+	        get 
+	        { 
+                if (mConfig.clientMinimumVersion != null)
+                {
+                    return mConfig.clientMinimumVersion;
+                }
+
+                return base.MinimumVersion;
+	        }
+        }
+
+        public override bool IsFallback
+        {
+            get { return mConfig.clientFallback; }
+        }
+
+        public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1)
+            {
+                firstFatalAlertConnectionEnd = ConnectionEnd.client;
+                firstFatalAlertDescription = alertDescription;
+            }
+
+            if (TlsTestConfig.DEBUG)
+            {
+                TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+                output.WriteLine("TLS client raised alert: " + AlertLevel.GetText(alertLevel)
+                    + ", " + AlertDescription.GetText(alertDescription));
+                if (message != null)
+                {
+                    output.WriteLine("> " + message);
+                }
+                if (cause != null)
+                {
+                    output.WriteLine(cause);
+                }
+            }
+        }
+
+        public override void NotifyAlertReceived(byte alertLevel, byte alertDescription)
+        {
+            if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1)
+            {
+                firstFatalAlertConnectionEnd = ConnectionEnd.server;
+                firstFatalAlertDescription = alertDescription;
+            }
+
+            if (TlsTestConfig.DEBUG)
+            {
+                TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+                output.WriteLine("TLS client received alert: " + AlertLevel.GetText(alertLevel)
+                    + ", " + AlertDescription.GetText(alertDescription));
+            }
+        }
+
+        public override void NotifyServerVersion(ProtocolVersion serverVersion)
+        {
+            base.NotifyServerVersion(serverVersion);
+
+            if (TlsTestConfig.DEBUG)
+            {
+                Console.WriteLine("TLS client negotiated " + serverVersion);
+            }
+        }
+
+        public override TlsAuthentication GetAuthentication()
+        {
+            return new MyTlsAuthentication(this, mContext);
+        }
+
+        protected virtual Certificate CorruptCertificate(Certificate cert)
+        {
+            X509CertificateStructure[] certList = cert.GetCertificateList();
+            certList[0] = CorruptCertificateSignature(certList[0]);
+            return new Certificate(certList);
+        }
+
+        protected virtual X509CertificateStructure CorruptCertificateSignature(X509CertificateStructure cert)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+            v.Add(cert.TbsCertificate);
+            v.Add(cert.SignatureAlgorithm);
+            v.Add(CorruptBitString(cert.Signature));
+
+            return X509CertificateStructure.GetInstance(new DerSequence(v));
+        }
+
+        protected virtual DerBitString CorruptBitString(DerBitString bs)
+        {
+            return new DerBitString(CorruptBit(bs.GetBytes()));
+        }
+
+        protected virtual byte[] CorruptBit(byte[] bs)
+        {
+            bs = Arrays.Clone(bs);
+
+            // Flip a random bit
+            int bit = mContext.SecureRandom.Next(bs.Length << 3); 
+            bs[bit >> 3] ^= (byte)(1 << (bit & 7));
+
+            return bs;
+        }
+
+        internal class MyTlsAuthentication
+            :   TlsAuthentication
+        {
+            private readonly TlsTestClientImpl mOuter;
+            private readonly TlsContext mContext;
+
+            internal MyTlsAuthentication(TlsTestClientImpl outer, TlsContext context)
+            {
+                this.mOuter = outer;
+                this.mContext = context;
+            }
+
+            public virtual void NotifyServerCertificate(Certificate serverCertificate)
+            {
+                bool isEmpty = serverCertificate == null || serverCertificate.IsEmpty;
+
+                X509CertificateStructure[] chain = serverCertificate.GetCertificateList();
+
+                // TODO Cache test resources?
+                if (isEmpty || !(chain[0].Equals(TlsTestUtilities.LoadCertificateResource("x509-server.pem"))
+                    || chain[0].Equals(TlsTestUtilities.LoadCertificateResource("x509-server-dsa.pem"))
+                    || chain[0].Equals(TlsTestUtilities.LoadCertificateResource("x509-server-ecdsa.pem"))))
+                {
+                    throw new TlsFatalAlert(AlertDescription.bad_certificate);
+                }
+
+                if (TlsTestConfig.DEBUG)
+                {
+                    Console.WriteLine("TLS client received server certificate chain of length " + chain.Length);
+                    for (int i = 0; i != chain.Length; i++)
+                    {
+                        X509CertificateStructure entry = chain[i];
+                        // TODO Create fingerprint based on certificate signature algorithm digest
+                        Console.WriteLine("    fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
+                            + entry.Subject + ")");
+                    }
+                }
+            }
+
+            public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+            {
+                if (mOuter.mConfig.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_NONE)
+                    throw new InvalidOperationException();
+                if (mOuter.mConfig.clientAuth == TlsTestConfig.CLIENT_AUTH_NONE)
+                    return null;
+
+                byte[] certificateTypes = certificateRequest.CertificateTypes;
+                if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign))
+                {
+                    return null;
+                }
+
+                TlsSignerCredentials signerCredentials = TlsTestUtilities.LoadSignerCredentials(mContext,
+                    certificateRequest.SupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
+                    "x509-client.pem", "x509-client-key.pem");
+
+                if (mOuter.mConfig.clientAuth == TlsTestConfig.CLIENT_AUTH_VALID)
+                {
+                    return signerCredentials;
+                }
+
+                return new MyTlsSignerCredentials(mOuter, signerCredentials);
+            }
+        };
+
+        internal class MyTlsSignerCredentials
+            :   TlsSignerCredentials
+        {
+            private readonly TlsTestClientImpl mOuter;
+            private readonly TlsSignerCredentials mInner;
+
+            internal MyTlsSignerCredentials(TlsTestClientImpl outer, TlsSignerCredentials inner)
+            {
+                this.mOuter = outer;
+                this.mInner = inner;
+            }
+
+            public virtual byte[] GenerateCertificateSignature(byte[] hash)
+            {
+                byte[] sig = mInner.GenerateCertificateSignature(hash);
+
+                if (mOuter.mConfig.clientAuth == TlsTestConfig.CLIENT_AUTH_INVALID_VERIFY)
+                {
+                    sig = mOuter.CorruptBit(sig);
+                }
+
+                return sig;
+            }
+
+            public virtual Certificate Certificate
+            {
+                get
+                {
+                    Certificate cert = mInner.Certificate;
+
+                    if (mOuter.mConfig.clientAuth == TlsTestConfig.CLIENT_AUTH_INVALID_CERT)
+                    {
+                        cert = mOuter.CorruptCertificate(cert);
+                    }
+
+                    return cert;
+                }
+            }
+
+            public virtual SignatureAndHashAlgorithm SignatureAndHashAlgorithm
+            {
+                get { return mInner.SignatureAndHashAlgorithm; }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestConfig.cs b/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
new file mode 100644
index 000000000..0d1e7badb
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
@@ -0,0 +1,101 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    public class TlsTestConfig
+    {
+        public static readonly bool DEBUG = false;
+
+        /**
+         * Client does not authenticate, ignores any certificate request
+         */
+        public const int CLIENT_AUTH_NONE = 0;
+
+        /**
+         * Client will authenticate if it receives a certificate request
+         */
+        public const int CLIENT_AUTH_VALID = 1;
+
+        /**
+         * Client will authenticate if it receives a certificate request, with an invalid certificate
+         */
+        public const int CLIENT_AUTH_INVALID_CERT = 2;
+
+        /**
+         * Client will authenticate if it receives a certificate request, with an invalid CertificateVerify signature
+         */
+        public const int CLIENT_AUTH_INVALID_VERIFY = 3;
+
+        /**
+         * Server will not request a client certificate
+         */
+        public const int SERVER_CERT_REQ_NONE = 0;
+
+        /**
+         * Server will request a client certificate but receiving one is optional
+         */
+        public const int SERVER_CERT_REQ_OPTIONAL = 1;
+
+        /**
+         * Server will request a client certificate and receiving one is mandatory
+         */
+        public const int SERVER_CERT_REQ_MANDATORY = 2;
+
+        /**
+         * Configures the client authentication behaviour of the test client. Use CLIENT_AUTH_* constants.
+         */
+        public int clientAuth = CLIENT_AUTH_VALID;
+
+        /**
+         * Configures the minimum protocol version the client will accept. If null, uses the library's default.
+         */
+        public ProtocolVersion clientMinimumVersion = null;
+
+        /**
+         * Configures the protocol version the client will offer. If null, uses the library's default.
+         */
+        public ProtocolVersion clientOfferVersion = null;
+
+        /**
+         * Configures whether the client will indicate version fallback via TLS_FALLBACK_SCSV.
+         */
+        public bool clientFallback = false;
+
+        /**
+         * Configures whether the test server will send a certificate request.
+         */
+        public int serverCertReq = SERVER_CERT_REQ_OPTIONAL;
+
+        /**
+         * Configures the maximum protocol version the server will accept. If null, uses the library's default.
+         */
+        public ProtocolVersion serverMaximumVersion = null;
+
+        /**
+         * Configures the minimum protocol version the server will accept. If null, uses the library's default.
+         */
+        public ProtocolVersion serverMinimumVersion = null;
+
+        /**
+         * Configures the connection end that a fatal alert is expected to be raised. Use ConnectionEnd.* constants.
+         */
+        public int expectFatalAlertConnectionEnd = -1;
+
+        /**
+         * Configures the type of fatal alert expected to be raised. Use AlertDescription.* constants.
+         */
+        public int expectFatalAlertDescription = -1;
+
+        public void ExpectClientFatalAlert(byte alertDescription)
+        {
+            this.expectFatalAlertConnectionEnd = ConnectionEnd.client;
+            this.expectFatalAlertDescription = alertDescription;
+        }
+
+        public void ExpectServerFatalAlert(byte alertDescription)
+        {
+            this.expectFatalAlertConnectionEnd = ConnectionEnd.server;
+            this.expectFatalAlertDescription = alertDescription;
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs b/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
new file mode 100644
index 000000000..152d5dbdc
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
@@ -0,0 +1,194 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class TlsTestServerImpl
+        :   DefaultTlsServer
+    {
+        protected readonly TlsTestConfig mConfig;
+
+        protected int firstFatalAlertConnectionEnd = -1;
+        protected int firstFatalAlertDescription = -1;
+
+        internal TlsTestServerImpl(TlsTestConfig config)
+        {
+            this.mConfig = config;
+        }
+
+        internal int FirstFatalAlertConnectionEnd
+        {
+            get { return firstFatalAlertConnectionEnd; }
+        }
+
+        internal int FirstFatalAlertDescription
+        {
+            get { return firstFatalAlertDescription; }
+        }
+
+        protected override ProtocolVersion MaximumVersion
+        {
+	        get 
+	        { 
+                if (mConfig.serverMaximumVersion != null)
+                {
+                    return mConfig.serverMaximumVersion;
+                }
+
+                return base.MaximumVersion;
+	        }
+        }
+
+        protected override ProtocolVersion MinimumVersion
+        {
+	        get 
+	        { 
+                if (mConfig.serverMinimumVersion != null)
+                {
+                    return mConfig.serverMinimumVersion;
+                }
+
+                return base.MinimumVersion;
+	        }
+        }
+
+        public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1)
+            {
+                firstFatalAlertConnectionEnd = ConnectionEnd.server;
+                firstFatalAlertDescription = alertDescription;
+            }
+
+            if (TlsTestConfig.DEBUG)
+            {
+                TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+                output.WriteLine("TLS server raised alert: " + AlertLevel.GetText(alertLevel)
+                    + ", " + AlertDescription.GetText(alertDescription));
+                if (message != null)
+                {
+                    output.WriteLine("> " + message);
+                }
+                if (cause != null)
+                {
+                    output.WriteLine(cause);
+                }
+            }
+        }
+
+        public override void NotifyAlertReceived(byte alertLevel, byte alertDescription)
+        {
+            if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1)
+            {
+                firstFatalAlertConnectionEnd = ConnectionEnd.client;
+                firstFatalAlertDescription = alertDescription;
+            }
+
+            if (TlsTestConfig.DEBUG)
+            {
+                TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+                output.WriteLine("TLS server received alert: " + AlertLevel.GetText(alertLevel)
+                    + ", " + AlertDescription.GetText(alertDescription));
+            }
+        }
+
+        public override ProtocolVersion GetServerVersion()
+        {
+            ProtocolVersion serverVersion = base.GetServerVersion();
+
+            if (TlsTestConfig.DEBUG)
+            {
+                Console.WriteLine("TLS server negotiated " + serverVersion);
+            }
+
+            return serverVersion;
+        }
+
+        public override CertificateRequest GetCertificateRequest()
+        {
+            if (mConfig.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_NONE)
+            {
+                return null;
+            }
+
+            byte[] certificateTypes = new byte[]{ ClientCertificateType.rsa_sign,
+                ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign };
+
+            IList serverSigAlgs = null;
+            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mServerVersion))
+            {
+                serverSigAlgs = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
+            }
+
+            IList certificateAuthorities = new ArrayList();
+            certificateAuthorities.Add(TlsTestUtilities.LoadCertificateResource("x509-ca.pem").Subject);
+
+            return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities);
+        }
+
+        public override void NotifyClientCertificate(Certificate clientCertificate)
+        {
+            bool isEmpty = (clientCertificate == null || clientCertificate.IsEmpty);
+
+            if (isEmpty != (mConfig.clientAuth == TlsTestConfig.CLIENT_AUTH_NONE))
+            {
+                throw new InvalidOperationException();
+            }
+            if (isEmpty && (mConfig.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_MANDATORY))
+            {
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+            }
+
+            X509CertificateStructure[] chain = clientCertificate.GetCertificateList();
+
+            // TODO Cache test resources?
+            if (!isEmpty && !(chain[0].Equals(TlsTestUtilities.LoadCertificateResource("x509-client.pem"))
+                || chain[0].Equals(TlsTestUtilities.LoadCertificateResource("x509-client-dsa.pem"))
+                || chain[0].Equals(TlsTestUtilities.LoadCertificateResource("x509-client-ecdsa.pem"))))
+            {
+                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+            }
+
+            if (TlsTestConfig.DEBUG)
+            {
+                Console.WriteLine("TLS server received client certificate chain of length " + chain.Length);
+                for (int i = 0; i != chain.Length; i++)
+                {
+                    X509CertificateStructure entry = chain[i];
+                    // TODO Create fingerprint based on certificate signature algorithm digest
+                    Console.WriteLine("    fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
+                        + entry.Subject + ")");
+                }
+            }
+        }
+
+        protected override TlsSignerCredentials GetDsaSignerCredentials()
+        {
+            return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.dsa,
+                "x509-server-dsa.pem", "x509-server-key-dsa.pem");
+        }
+
+        protected override TlsSignerCredentials GetECDsaSignerCredentials()
+        {
+            return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.ecdsa,
+                "x509-server-ecdsa.pem", "x509-server-key-ecdsa.pem");
+        }
+
+        protected override TlsEncryptionCredentials GetRsaEncryptionCredentials()
+        {
+            return TlsTestUtilities.LoadEncryptionCredentials(mContext, new string[]{ "x509-server.pem", "x509-ca.pem" },
+                "x509-server-key.pem");
+        }
+
+        protected override TlsSignerCredentials GetRsaSignerCredentials()
+        {
+            return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
+                "x509-server.pem", "x509-server-key.pem");
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
new file mode 100644
index 000000000..dfd09d06e
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    public class TlsTestSuite
+    {
+        // Make the access to constants less verbose 
+        internal class C : TlsTestConfig {}
+
+        public TlsTestSuite()
+        {
+        }
+
+        public static IEnumerable Suite()
+        {
+            IList testSuite = new ArrayList();
+
+            AddFallbackTests(testSuite);
+            AddVersionTests(testSuite, ProtocolVersion.TLSv10);
+            AddVersionTests(testSuite, ProtocolVersion.TLSv11);
+            AddVersionTests(testSuite, ProtocolVersion.TLSv12);
+
+            return testSuite;
+        }
+
+        private static void AddFallbackTests(IList testSuite)
+        {
+            {
+                TlsTestConfig c = CreateTlsTestConfig(ProtocolVersion.TLSv12);
+                c.clientFallback = true;
+
+                testSuite.Add(new TestCaseData(c).SetName("FallbackGood"));
+            }
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(ProtocolVersion.TLSv12);
+                c.clientOfferVersion = ProtocolVersion.TLSv11;
+                c.clientFallback = true;
+                c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback);
+
+                testSuite.Add(new TestCaseData(c).SetName("FallbackBad"));
+            }
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(ProtocolVersion.TLSv12);
+                c.clientOfferVersion = ProtocolVersion.TLSv11;
+
+                testSuite.Add(new TestCaseData(c).SetName("FallbackNone"));
+            }
+        }
+
+        private static void AddVersionTests(IList testSuite, ProtocolVersion version)
+        {
+            string prefix = version.ToString()
+                .Replace(" ", "")
+                .Replace("\\", "")
+                .Replace(".", "")
+                + "_";
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+
+                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodDefault"));
+            }
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY;
+                c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
+
+                testSuite.Add(new TestCaseData(c).SetName(prefix + "BadCertificateVerify"));
+            }
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_INVALID_CERT;
+                c.ExpectServerFatalAlert(AlertDescription.bad_certificate);
+
+                testSuite.Add(new TestCaseData(c).SetName(prefix + "BadClientCertificate"));
+            }
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_NONE;
+                c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY;
+                c.ExpectServerFatalAlert(AlertDescription.handshake_failure);
+
+                testSuite.Add(new TestCaseData(c).SetName(prefix + "BadMandatoryCertReqDeclined"));
+            }
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.serverCertReq = C.SERVER_CERT_REQ_NONE;
+
+                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodNoCertReq"));
+            }
+
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_NONE;
+
+                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodOptionalCertReqDeclined"));
+            }
+        }
+
+        private static TlsTestConfig CreateTlsTestConfig(ProtocolVersion version)
+        {
+            TlsTestConfig c = new TlsTestConfig();
+            c.clientMinimumVersion = ProtocolVersion.TLSv10;
+            c.clientOfferVersion = ProtocolVersion.TLSv12;
+            c.serverMaximumVersion = version;
+            c.serverMinimumVersion = ProtocolVersion.TLSv10;
+            return c;
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/AllTests.cs b/crypto/test/src/math/ec/test/AllTests.cs
index d4c7dc768..3e014ffd2 100644
--- a/crypto/test/src/math/ec/test/AllTests.cs
+++ b/crypto/test/src/math/ec/test/AllTests.cs
@@ -7,22 +7,21 @@ namespace Org.BouncyCastle.Math.EC.Tests
 {
     public class AllTests
     {
-        public static void Main(
-            string[] args)
+        public static void Main(string[] args)
         {
-//            junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            suite().Run(el);
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
         }
 
-        public static TestSuite suite()
+        [Suite]
+        public static TestSuite Suite
         {
-            TestSuite suite = new TestSuite("EC Math tests");
-
-            suite.Add(new ECAlgorithmsTest());
-            suite.Add(new ECPointTest());
-
-            return suite;
+            get
+            {
+                TestSuite suite = new TestSuite("EC Math tests");
+                suite.Add(new ECAlgorithmsTest());
+                suite.Add(new ECPointTest());
+                return suite;
+            }
         }
     }
 }
diff --git a/crypto/test/src/math/test/AllTests.cs b/crypto/test/src/math/test/AllTests.cs
index 6f2b50140..40cfe3774 100644
--- a/crypto/test/src/math/test/AllTests.cs
+++ b/crypto/test/src/math/test/AllTests.cs
@@ -7,21 +7,20 @@ namespace Org.BouncyCastle.Math.Tests
 {
     public class AllTests
     {
-        public static void Main(
-			string[] args)
+        public static void Main(string[] args)
         {
-//            junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            suite().Run(el);
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
         }
 
-        public static TestSuite suite()
+        [Suite]
+        public static TestSuite Suite
         {
-			TestSuite suite = new TestSuite("Math tests");
-
-			suite.Add(new BigIntegerTest());
-
-			return suite;
+            get
+            {
+                TestSuite suite = new TestSuite("Math tests");
+                suite.Add(new BigIntegerTest());
+                return suite;
+            }
         }
     }
 }
diff --git a/crypto/test/src/ocsp/test/AllTests.cs b/crypto/test/src/ocsp/test/AllTests.cs
index 2b30e3ad4..5e919fd91 100644
--- a/crypto/test/src/ocsp/test/AllTests.cs
+++ b/crypto/test/src/ocsp/test/AllTests.cs
@@ -9,21 +9,20 @@ namespace Org.BouncyCastle.Ocsp.Tests
 {
 	public class AllTests
 	{
-		public static void Main(
-			string[] args)
-		{
-			//junit.textui.TestRunner.run(suite());
-			EventListener el = new NullListener();
-			suite().Run(el);
-		}
+        public static void Main(string[] args)
+        {
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
+        }
 
-		public static TestSuite suite()
-		{
-			TestSuite suite = new TestSuite("OCSP Tests");
-
-			suite.Add(new OcspTest());
-
-			return suite;
-		}
+        [Suite]
+        public static TestSuite Suite
+        {
+            get
+            {
+                TestSuite suite = new TestSuite("OCSP Tests");
+                suite.Add(new OcspTest());
+                return suite;
+            }
+        }
 	}
 }
diff --git a/crypto/test/src/openpgp/examples/test/AllTests.cs b/crypto/test/src/openpgp/examples/test/AllTests.cs
index 180d2fa80..e9a7a744d 100644
--- a/crypto/test/src/openpgp/examples/test/AllTests.cs
+++ b/crypto/test/src/openpgp/examples/test/AllTests.cs
@@ -382,22 +382,20 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples.Tests
 			return bRd.ReadLine();
 		}
 
-		public static void Main(
-			string[] args)
-		{
-			//junit.textui.TestRunner.run(suite());
-			EventListener el = new NullListener();
-			suite().Run(el);
-		}
-
-		public static TestSuite suite()
-		{
-			TestSuite suite = new TestSuite("OpenPGP Example Tests");
-
-			suite.Add(new AllTests());
-
-			return suite;
-		}
-
+        public static void Main(string[] args)
+        {
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
+        }
+
+        [Suite]
+        public static TestSuite Suite
+        {
+            get
+            {
+                TestSuite suite = new TestSuite("OpenPGP Example Tests");
+                suite.Add(new AllTests());
+                return suite;
+            }
+        }
 	}
 }
diff --git a/crypto/test/src/openssl/test/AllTests.cs b/crypto/test/src/openssl/test/AllTests.cs
index 921208179..f843d0479 100644
--- a/crypto/test/src/openssl/test/AllTests.cs
+++ b/crypto/test/src/openssl/test/AllTests.cs
@@ -32,19 +32,24 @@ namespace Org.BouncyCastle.OpenSsl.Tests
 				return (char[]) password.Clone();
 			}
 		}
-		
-		[Suite]
-		public static TestSuite Suite
-		{
-			get
-			{
-				TestSuite suite = new TestSuite("OpenSSL Tests");
-				suite.Add(new AllTests());
-				return suite;
-			}
-		}
 
-		[Test]
+        public static void Main(string[] args)
+        {
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
+        }
+
+        [Suite]
+        public static TestSuite Suite
+        {
+            get
+            {
+                TestSuite suite = new TestSuite("OpenSSL Tests");
+                suite.Add(new AllTests());
+                return suite;
+            }
+        }
+
+        [Test]
 		public void TestOpenSsl()
 		{
 			Org.BouncyCastle.Utilities.Test.ITest[] tests = new Org.BouncyCastle.Utilities.Test.ITest[]{
@@ -121,13 +126,5 @@ namespace Org.BouncyCastle.OpenSsl.Tests
 
 			Assert.AreEqual(privKey, rdKey);
 		}
-
-        public static void Main(
-			string[] args)
-        {
-            //junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            Suite.Run(el);
-        }
 	}
 }
diff --git a/crypto/test/src/tsp/test/AllTests.cs b/crypto/test/src/tsp/test/AllTests.cs
index 66dc9c480..3e8b0cd5e 100644
--- a/crypto/test/src/tsp/test/AllTests.cs
+++ b/crypto/test/src/tsp/test/AllTests.cs
@@ -9,24 +9,23 @@ namespace Org.BouncyCastle.Tsp.Tests
 {
     public class AllTests
     {
-        public static void Main(
-			string[] args)
+        public static void Main(string[] args)
         {
-            //junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            suite().Run(el);
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
         }
 
-		public static TestSuite suite()
+        [Suite]
+        public static TestSuite Suite
         {
-            TestSuite suite = new TestSuite("TSP Tests");
-
-			suite.Add(new GenTimeAccuracyUnitTest());
-			suite.Add(new ParseTest());
-			suite.Add(new TimeStampTokenInfoUnitTest());
-			suite.Add(new TspTest());
-
-			return suite;
+            get
+            {
+                TestSuite suite = new TestSuite("TSP Tests");
+                suite.Add(new GenTimeAccuracyUnitTest());
+                suite.Add(new ParseTest());
+                suite.Add(new TimeStampTokenInfoUnitTest());
+                suite.Add(new TspTest());
+                return suite;
+            }
         }
     }
 }
diff --git a/crypto/test/src/util/io/pem/test/AllTests.cs b/crypto/test/src/util/io/pem/test/AllTests.cs
index b44949383..c36f79304 100644
--- a/crypto/test/src/util/io/pem/test/AllTests.cs
+++ b/crypto/test/src/util/io/pem/test/AllTests.cs
@@ -19,18 +19,23 @@ namespace Org.BouncyCastle.Utilities.IO.Pem.Tests
 	[TestFixture]
 	public class AllTests
 	{
-		[Suite]
-		public static TestSuite Suite
-		{
-			get
-			{
-				TestSuite suite = new TestSuite("PEM Utilities Tests");
-				suite.Add(new AllTests());
-				return suite;
-			}
-		}
+        public static void Main(string[] args)
+        {
+            Suite.Run(new NullListener(), NUnit.Core.TestFilter.Empty);
+        }
 
-		[Test]
+        [Suite]
+        public static TestSuite Suite
+        {
+            get
+            {
+                TestSuite suite = new TestSuite("PEM Utilities Tests");
+                suite.Add(new AllTests());
+                return suite;
+            }
+        }
+
+        [Test]
 		public void TestPemLength()
 		{
 			for (int i = 1; i != 60; i++)
@@ -65,13 +70,5 @@ namespace Org.BouncyCastle.Utilities.IO.Pem.Tests
 
 			Assert.AreEqual(sw.ToString().Length, pWrt.GetOutputSize(pemObj));
 		}
-
-		public static void Main(
-			string[] args)
-        {
-            //junit.textui.TestRunner.run(suite());
-            EventListener el = new NullListener();
-            Suite.Run(el);
-        }
 	}
 }