summary refs log tree commit diff
path: root/crypto/test
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-03-09 01:44:59 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-03-09 01:44:59 +0700
commitf7a9c0a501b6af92d3e729e08c73b5499a500c24 (patch)
treec2601bd90ae759a90a15ea41a7e82988dc11abd5 /crypto/test
parentPort TLS-PSK tests from Java (diff)
downloadBouncyCastle.NET-ed25519-f7a9c0a501b6af92d3e729e08c73b5499a500c24.tar.xz
Porting from Java build
- SRP6 evidence messages and standard groups
- TLS_SRP server-side support added
- TLS_DHE server-side fixes
- Improved support for DSA/ECDSA signing in TLS
Diffstat (limited to 'crypto/test')
-rw-r--r--crypto/test/src/crypto/test/SRP6Test.cs49
-rw-r--r--crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs120
-rw-r--r--crypto/test/src/crypto/tls/test/MockSrpTlsServer.cs113
-rw-r--r--crypto/test/src/crypto/tls/test/MockTlsClient.cs23
-rw-r--r--crypto/test/src/crypto/tls/test/MockTlsServer.cs49
-rw-r--r--crypto/test/src/crypto/tls/test/TlsSrpProtocolTest.cs80
6 files changed, 342 insertions, 92 deletions
diff --git a/crypto/test/src/crypto/test/SRP6Test.cs b/crypto/test/src/crypto/test/SRP6Test.cs
index 3b80e2c16..6b64df924 100644
--- a/crypto/test/src/crypto/test/SRP6Test.cs
+++ b/crypto/test/src/crypto/test/SRP6Test.cs
@@ -23,15 +23,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 	        return new BigInteger(1, Hex.Decode(hex));
 	    }
 
-		// 1024 bit example prime from RFC5054 and corresponding generator
-		private static readonly BigInteger N_1024 = FromHex("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
-	            + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
-	            + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
-	            + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
-	            + "FD5138FE8376435B9FC61D2FC0EB06E3");
-		private static readonly BigInteger g_1024 = BigInteger.Two;
-
-		private readonly SecureRandom random = new SecureRandom();
+        private readonly SecureRandom random = new SecureRandom();
 
 	    public override string Name
 	    {
@@ -42,9 +34,9 @@ namespace Org.BouncyCastle.Crypto.Tests
 	    {
 	    	rfc5054AppendixBTestVectors();
 
-	        testMutualVerification(N_1024, g_1024);
-	        testClientCatchesBadB(N_1024, g_1024);
-	        testServerCatchesBadA(N_1024, g_1024);
+            testMutualVerification(Srp6StandardGroups.rfc5054_1024);
+            testClientCatchesBadB(Srp6StandardGroups.rfc5054_1024);
+            testServerCatchesBadA(Srp6StandardGroups.rfc5054_1024);
 
 			testWithRandomParams(256);
 			testWithRandomParams(384);
@@ -56,8 +48,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 	    	byte[] I = Encoding.UTF8.GetBytes("alice");
 	    	byte[] P = Encoding.UTF8.GetBytes("password123");
 	    	byte[] s = Hex.Decode("BEB25379D1A8581EB5A727673A2441EE");
-	    	BigInteger N = N_1024;
-	    	BigInteger g = g_1024;
+            BigInteger N = Srp6StandardGroups.rfc5054_1024.N;
+            BigInteger g = Srp6StandardGroups.rfc5054_1024.G;
 	    	BigInteger a = FromHex("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393");
 	    	BigInteger b = FromHex("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20");
 
@@ -148,13 +140,10 @@ namespace Org.BouncyCastle.Crypto.Tests
 	        paramGen.Init(bits, 25, random);
 	        DHParameters parameters = paramGen.GenerateParameters();
 
-	        BigInteger g = parameters.G;
-	        BigInteger p = parameters.P;
-
-	        testMutualVerification(p, g);
+            testMutualVerification(new Srp6GroupParameters(parameters.P, parameters.G));
 		}
 
-	    private void testMutualVerification(BigInteger N, BigInteger g)
+        private void testMutualVerification(Srp6GroupParameters group)
 	    {
 	        byte[] I = Encoding.UTF8.GetBytes("username");
 	        byte[] P = Encoding.UTF8.GetBytes("password");
@@ -162,16 +151,16 @@ namespace Org.BouncyCastle.Crypto.Tests
 	        random.NextBytes(s);
 
 	        Srp6VerifierGenerator gen = new Srp6VerifierGenerator();
-	        gen.Init(N, g, new Sha256Digest());
+	        gen.Init(group, new Sha256Digest());
 	        BigInteger v = gen.GenerateVerifier(s, I, P);
 
 	        Srp6Client client = new Srp6Client();
-	        client.Init(N, g, new Sha256Digest(), random);
+	        client.Init(group, new Sha256Digest(), random);
 
 	        Srp6Server server = new Srp6Server();
-	        server.Init(N, g, v, new Sha256Digest(), random);
+	        server.Init(group, v, new Sha256Digest(), random);
 
-	        BigInteger A = client.GenerateClientCredentials(s, I, P);
+            BigInteger A = client.GenerateClientCredentials(s, I, P);
 	        BigInteger B = server.GenerateServerCredentials();
 
 	        BigInteger clientS = client.CalculateSecret(B);
@@ -183,7 +172,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 	        }
 	    }
 
-	    private void testClientCatchesBadB(BigInteger N, BigInteger g)
+        private void testClientCatchesBadB(Srp6GroupParameters group)
 	    {
 	        byte[] I = Encoding.UTF8.GetBytes("username");
 	        byte[] P = Encoding.UTF8.GetBytes("password");
@@ -191,7 +180,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 	        random.NextBytes(s);
 
 	        Srp6Client client = new Srp6Client();
-	        client.Init(N, g, new Sha256Digest(), random);
+	        client.Init(group, new Sha256Digest(), random);
 
 	        client.GenerateClientCredentials(s, I, P);
 
@@ -207,7 +196,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 	        try
 	        {
-	        	client.CalculateSecret(N);
+	        	client.CalculateSecret(group.N);
 	        	Fail("Client failed to detect invalid value for 'B'");
 	        }
 	        catch (CryptoException)
@@ -216,7 +205,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 	        }
 	    }
 
-	    private void testServerCatchesBadA(BigInteger N, BigInteger g)
+        private void testServerCatchesBadA(Srp6GroupParameters group)
 	    {
 	        byte[] I = Encoding.UTF8.GetBytes("username");
 	        byte[] P = Encoding.UTF8.GetBytes("password");
@@ -224,11 +213,11 @@ namespace Org.BouncyCastle.Crypto.Tests
 	        random.NextBytes(s);
 
 	        Srp6VerifierGenerator gen = new Srp6VerifierGenerator();
-	        gen.Init(N, g, new Sha256Digest());
+	        gen.Init(group, new Sha256Digest());
 	        BigInteger v = gen.GenerateVerifier(s, I, P);
 
 	        Srp6Server server = new Srp6Server();
-	        server.Init(N, g, v, new Sha256Digest(), random);
+	        server.Init(group, v, new Sha256Digest(), random);
 
 	        server.GenerateServerCredentials();
 
@@ -244,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 	        try
 	        {
-	        	server.CalculateSecret(N);
+	        	server.CalculateSecret(group.N);
 	        	Fail("Client failed to detect invalid value for 'A'");
 	        }
 	        catch (CryptoException)
diff --git a/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs
new file mode 100644
index 000000000..7225d84ce
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class MockSrpTlsClient
+        :   SrpTlsClient
+    {
+        internal TlsSession mSession;
+
+        internal MockSrpTlsClient(TlsSession session, byte[] identity, byte[] password)
+            :   base(identity, password)
+        {
+            this.mSession = session;
+        }
+
+        public override TlsSession GetSessionToResume()
+        {
+            return this.mSession;
+        }
+
+        public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS-SRP 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)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS-SRP client received alert: " + AlertLevel.GetText(alertLevel)
+                + ", " + AlertDescription.GetText(alertDescription));
+        }
+
+        public override void NotifyHandshakeComplete()
+        {
+            base.NotifyHandshakeComplete();
+
+            TlsSession newSession = mContext.ResumableSession;
+            if (newSession != null)
+            {
+                byte[] newSessionID = newSession.SessionID;
+                string hex = Hex.ToHexString(newSessionID);
+
+                if (this.mSession != null && Arrays.AreEqual(this.mSession.SessionID, newSessionID))
+                {
+                    Console.WriteLine("Resumed session: " + hex);
+                }
+                else
+                {
+                    Console.WriteLine("Established session: " + hex);
+                }
+
+                this.mSession = newSession;
+            }
+        }
+
+        public override ProtocolVersion MinimumVersion
+        {
+            get { return ProtocolVersion.TLSv12; }
+        }
+
+        public override IDictionary GetClientExtensions()
+        {
+            IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions());
+            TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions);
+            return clientExtensions;
+        }
+
+        public override void NotifyServerVersion(ProtocolVersion serverVersion)
+        {
+            base.NotifyServerVersion(serverVersion);
+
+            Console.WriteLine("TLS-SRP client negotiated " + serverVersion);
+        }
+
+        public override TlsAuthentication GetAuthentication()
+        {
+            return new MyTlsAuthentication(mContext);
+        }
+
+        internal class MyTlsAuthentication
+            : ServerOnlyTlsAuthentication
+        {
+            private readonly TlsContext mContext;
+
+            internal MyTlsAuthentication(TlsContext context)
+            {
+                this.mContext = context;
+            }
+
+            public override void NotifyServerCertificate(Certificate serverCertificate)
+            {
+                X509CertificateStructure[] chain = serverCertificate.GetCertificateList();
+                Console.WriteLine("TLS-SRP 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 + ")");
+                }
+            }
+        };
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/MockSrpTlsServer.cs b/crypto/test/src/crypto/tls/test/MockSrpTlsServer.cs
new file mode 100644
index 000000000..c15f63e0b
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/MockSrpTlsServer.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class MockSrpTlsServer
+        :   SrpTlsServer
+    {
+        internal static readonly Srp6GroupParameters TEST_GROUP = Srp6StandardGroups.rfc5054_1024;
+        internal static readonly byte[] TEST_IDENTITY = Strings.ToUtf8ByteArray("client");
+        internal static readonly byte[] TEST_PASSWORD = Strings.ToUtf8ByteArray("password");
+        internal static readonly byte[] TEST_SALT = Strings.ToUtf8ByteArray("salt");
+        internal static readonly byte[] TEST_SEED_KEY = Strings.ToUtf8ByteArray("seed_key");
+
+        internal MockSrpTlsServer()
+            :   base(new MyIdentityManager())
+        {
+        }
+
+        public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS-SRP 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)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS-SRP server received alert: " + AlertLevel.GetText(alertLevel)
+                + ", " + AlertDescription.GetText(alertDescription));
+        }
+
+        public override void NotifyHandshakeComplete()
+        {
+            base.NotifyHandshakeComplete();
+
+            byte[] srpIdentity = mContext.SecurityParameters.SrpIdentity;
+            if (srpIdentity != null)
+            {
+                string name = Strings.FromUtf8ByteArray(srpIdentity);
+                Console.WriteLine("TLS-SRP server completed handshake for SRP identity: " + name);
+            }
+        }
+
+        protected override ProtocolVersion MaximumVersion
+        {
+            get { return ProtocolVersion.TLSv12; }
+        }
+
+        protected override ProtocolVersion MinimumVersion
+        {
+            get { return ProtocolVersion.TLSv12; }
+        }
+
+        public override ProtocolVersion GetServerVersion()
+        {
+            ProtocolVersion serverVersion = base.GetServerVersion();
+
+            Console.WriteLine("TLS-SRP server negotiated " + serverVersion);
+
+            return serverVersion;
+        }
+
+        protected override TlsSignerCredentials GetDsaSignerCredentials()
+        {
+            return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.dsa,
+                "x509-server-dsa.pem", "x509-server-key-dsa.pem");
+        }
+
+        protected override TlsSignerCredentials GetRsaSignerCredentials()
+        {
+            return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
+                "x509-server.pem", "x509-server-key.pem");
+        }
+
+        internal class MyIdentityManager
+            :   TlsSrpIdentityManager
+        {
+            protected SimulatedTlsSrpIdentityManager unknownIdentityManager = SimulatedTlsSrpIdentityManager.GetRfc5054Default(
+                TEST_GROUP, TEST_SEED_KEY);
+
+            public virtual TlsSrpLoginParameters GetLoginParameters(byte[] identity)
+            {
+                if (Arrays.AreEqual(TEST_IDENTITY, identity))
+                {
+                    Srp6VerifierGenerator verifierGenerator = new Srp6VerifierGenerator();
+                    verifierGenerator.Init(TEST_GROUP, TlsUtilities.CreateHash(HashAlgorithm.sha1));
+
+                    BigInteger verifier = verifierGenerator.GenerateVerifier(TEST_SALT, identity, TEST_PASSWORD);
+
+                    return new TlsSrpLoginParameters(TEST_GROUP, verifier, TEST_SALT);
+                }
+
+                return unknownIdentityManager.GetLoginParameters(identity);
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/MockTlsClient.cs b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
index 803989f59..fd673c3b9 100644
--- a/crypto/test/src/crypto/tls/test/MockTlsClient.cs
+++ b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
@@ -133,27 +133,8 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign))
                     return null;
 
-                SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
-                IList sigAlgs = certificateRequest.SupportedSignatureAlgorithms;
-                if (sigAlgs != null)
-                {
-                    foreach (SignatureAndHashAlgorithm sigAlg in sigAlgs)
-                    {
-                        if (sigAlg.Signature == SignatureAlgorithm.rsa)
-                        {
-                            signatureAndHashAlgorithm = sigAlg;
-                            break;
-                        }
-                    }
-
-                    if (signatureAndHashAlgorithm == null)
-                    {
-                        return null;
-                    }
-                }
-
-                return TlsTestUtilities.LoadSignerCredentials(mContext, new string[] { "x509-client.pem", "x509-ca.pem" },
-                    "x509-client-key.pem", signatureAndHashAlgorithm);
+                return TlsTestUtilities.LoadSignerCredentials(mContext, certificateRequest.SupportedSignatureAlgorithms,
+                    SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem");
             }
         };
     }
diff --git a/crypto/test/src/crypto/tls/test/MockTlsServer.cs b/crypto/test/src/crypto/tls/test/MockTlsServer.cs
index 14d6b9839..8fce95d63 100644
--- a/crypto/test/src/crypto/tls/test/MockTlsServer.cs
+++ b/crypto/test/src/crypto/tls/test/MockTlsServer.cs
@@ -61,29 +61,19 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
 
         public override CertificateRequest GetCertificateRequest()
         {
-            IList serverSigAlgs = null;
+            byte[] certificateTypes = new byte[]{ ClientCertificateType.rsa_sign,
+                ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign };
 
+            IList serverSigAlgs = null;
             if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mServerVersion))
             {
-                byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha512, HashAlgorithm.sha384, HashAlgorithm.sha256,
-                    HashAlgorithm.sha224, HashAlgorithm.sha1 };
-                byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa };
-
-                serverSigAlgs = new ArrayList();
-                for (int i = 0; i < hashAlgorithms.Length; ++i)
-                {
-                    for (int j = 0; j < signatureAlgorithms.Length; ++j)
-                    {
-                        serverSigAlgs.Add(new SignatureAndHashAlgorithm(hashAlgorithms[i],
-                            signatureAlgorithms[j]));
-                    }
-                }
+                serverSigAlgs = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
             }
 
             IList certificateAuthorities = new ArrayList();
             certificateAuthorities.Add(TlsTestUtilities.LoadCertificateResource("x509-ca.pem").Subject);
 
-            return new CertificateRequest(new byte[]{ ClientCertificateType.rsa_sign }, serverSigAlgs, certificateAuthorities);
+            return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities);
         }
 
         public override void NotifyClientCertificate(Certificate clientCertificate)
@@ -101,37 +91,14 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
 
         protected override TlsEncryptionCredentials GetRsaEncryptionCredentials()
         {
-            return TlsTestUtilities.LoadEncryptionCredentials(mContext, new string[]{"x509-server.pem", "x509-ca.pem"},
+            return TlsTestUtilities.LoadEncryptionCredentials(mContext, new string[]{ "x509-server.pem", "x509-ca.pem" },
                 "x509-server-key.pem");
         }
 
         protected override TlsSignerCredentials GetRsaSignerCredentials()
         {
-            /*
-             * TODO Note that this code fails to provide default value for the client supported
-             * algorithms if it wasn't sent.
-             */
-            SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
-            IList sigAlgs = mSupportedSignatureAlgorithms;
-            if (sigAlgs != null)
-            {
-                foreach (SignatureAndHashAlgorithm sigAlg in sigAlgs)
-                {
-                    if (sigAlg.Signature == SignatureAlgorithm.rsa)
-                    {
-                        signatureAndHashAlgorithm = sigAlg;
-                        break;
-                    }
-                }
-
-                if (signatureAndHashAlgorithm == null)
-                {
-                    return null;
-                }
-            }
-
-            return TlsTestUtilities.LoadSignerCredentials(mContext, new string[]{"x509-server.pem", "x509-ca.pem"},
-                "x509-server-key.pem", signatureAndHashAlgorithm);
+            return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
+                "x509-server.pem", "x509-server-key.pem");
         }
     }
 }
diff --git a/crypto/test/src/crypto/tls/test/TlsSrpProtocolTest.cs b/crypto/test/src/crypto/tls/test/TlsSrpProtocolTest.cs
new file mode 100644
index 000000000..32e126ff2
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsSrpProtocolTest.cs
@@ -0,0 +1,80 @@
+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 TlsSrpProtocolTest
+    {
+        [Test]
+        public void TestClientServer()
+        {
+            SecureRandom secureRandom = new SecureRandom();
+
+            PipedStream clientPipe = new PipedStream();
+            PipedStream serverPipe = new PipedStream(clientPipe);
+
+            TlsClientProtocol clientProtocol = new TlsClientProtocol(clientPipe, secureRandom);
+            TlsServerProtocol serverProtocol = new TlsServerProtocol(serverPipe, secureRandom);
+
+            Server server = new Server(serverProtocol);
+
+            Thread serverThread = new Thread(new ThreadStart(server.Run));
+            serverThread.Start();
+
+            MockSrpTlsClient client = new MockSrpTlsClient(null, MockSrpTlsServer.TEST_IDENTITY, MockSrpTlsServer.TEST_PASSWORD);
+            clientProtocol.Connect(client);
+
+            // 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();
+
+            serverThread.Join();
+        }
+
+        internal class Server
+        {
+            private readonly TlsServerProtocol mServerProtocol;
+
+            internal Server(TlsServerProtocol serverProtocol)
+            {
+                this.mServerProtocol = serverProtocol;
+            }
+
+            public void Run()
+            {
+                try
+                {
+                    MockSrpTlsServer server = new MockSrpTlsServer();
+                    mServerProtocol.Accept(server);
+                    Streams.PipeAll(mServerProtocol.Stream, mServerProtocol.Stream);
+                    mServerProtocol.Close();
+                }
+                catch (Exception)
+                {
+                    //throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+}