summary refs log tree commit diff
path: root/crypto/test
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-12-16 22:50:41 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-12-16 22:50:41 +0700
commitae227e65ab48b8747c80e1b336a3e6896e9e346e (patch)
treebff90e085f89872399328db0391f9e8b4f7368f0 /crypto/test
parentUpdate version for release (diff)
downloadBouncyCastle.NET-ed25519-ae227e65ab48b8747c80e1b336a3e6896e9e346e.tar.xz
Validate CertificateVerify signature algorithm (TLS 1.2+)
- check the algorithm is in the CertificateRequest list
- add (D)TLS test scenarios for various failure modes
Diffstat (limited to 'crypto/test')
-rw-r--r--crypto/test/UnitTests.csproj4
-rw-r--r--crypto/test/src/crypto/tls/test/DtlsTestCase.cs9
-rw-r--r--crypto/test/src/crypto/tls/test/DtlsTestClientProtocol.cs28
-rw-r--r--crypto/test/src/crypto/tls/test/DtlsTestServerProtocol.cs18
-rw-r--r--crypto/test/src/crypto/tls/test/DtlsTestSuite.cs122
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestCase.cs8
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs11
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestClientProtocol.cs29
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestConfig.cs19
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs27
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestServerProtocol.cs19
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestSuite.cs74
12 files changed, 314 insertions, 54 deletions
diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj
index 71896d203..24a60346e 100644
--- a/crypto/test/UnitTests.csproj
+++ b/crypto/test/UnitTests.csproj
@@ -277,6 +277,8 @@
     <Compile Include="src\crypto\tls\test\ByteQueueStreamTest.cs" />
     <Compile Include="src\crypto\tls\test\DtlsProtocolTest.cs" />
     <Compile Include="src\crypto\tls\test\DtlsTestCase.cs" />
+    <Compile Include="src\crypto\tls\test\DtlsTestClientProtocol.cs" />
+    <Compile Include="src\crypto\tls\test\DtlsTestServerProtocol.cs" />
     <Compile Include="src\crypto\tls\test\DtlsTestSuite.cs" />
     <Compile Include="src\crypto\tls\test\LoggingDatagramTransport.cs" />
     <Compile Include="src\crypto\tls\test\MockDatagramAssociation.cs" />
@@ -299,8 +301,10 @@
     <Compile Include="src\crypto\tls\test\TlsSrpProtocolTest.cs" />
     <Compile Include="src\crypto\tls\test\TlsTestCase.cs" />
     <Compile Include="src\crypto\tls\test\TlsTestClientImpl.cs" />
+    <Compile Include="src\crypto\tls\test\TlsTestClientProtocol.cs" />
     <Compile Include="src\crypto\tls\test\TlsTestConfig.cs" />
     <Compile Include="src\crypto\tls\test\TlsTestServerImpl.cs" />
+    <Compile Include="src\crypto\tls\test\TlsTestServerProtocol.cs" />
     <Compile Include="src\crypto\tls\test\TlsTestSuite.cs" />
     <Compile Include="src\crypto\tls\test\TlsTestUtilities.cs" />
     <Compile Include="src\crypto\tls\test\UnreliableDatagramTransport.cs" />
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestCase.cs b/crypto/test/src/crypto/tls/test/DtlsTestCase.cs
index d4af04fac..5e43337f4 100644
--- a/crypto/test/src/crypto/tls/test/DtlsTestCase.cs
+++ b/crypto/test/src/crypto/tls/test/DtlsTestCase.cs
@@ -28,8 +28,8 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
 
             SecureRandom secureRandom = new SecureRandom();
 
-            DtlsClientProtocol clientProtocol = new DtlsClientProtocol(secureRandom);
-            DtlsServerProtocol serverProtocol = new DtlsServerProtocol(secureRandom);
+            DtlsTestClientProtocol clientProtocol = new DtlsTestClientProtocol(secureRandom, config);
+            DtlsTestServerProtocol serverProtocol = new DtlsTestServerProtocol(secureRandom, config);
 
             MockDatagramAssociation network = new MockDatagramAssociation(1500);
 
@@ -101,14 +101,15 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
         internal class Server
         {
             private readonly DtlsTestCase mOuter;
-            private readonly DtlsServerProtocol mServerProtocol;
+            private readonly DtlsTestServerProtocol mServerProtocol;
             private readonly DatagramTransport mServerTransport;
             private readonly TlsTestServerImpl mServerImpl;
 
             private volatile bool isShutdown = false;
             internal Exception mCaught = null;
 
-            internal Server(DtlsTestCase outer, DtlsServerProtocol serverProtocol, DatagramTransport serverTransport, TlsTestServerImpl serverImpl)
+            internal Server(DtlsTestCase outer, DtlsTestServerProtocol serverProtocol,
+                DatagramTransport serverTransport, TlsTestServerImpl serverImpl)
             {
                 this.mOuter = outer;
                 this.mServerProtocol = serverProtocol;
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestClientProtocol.cs b/crypto/test/src/crypto/tls/test/DtlsTestClientProtocol.cs
new file mode 100644
index 000000000..41ed93eb0
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/DtlsTestClientProtocol.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class DtlsTestClientProtocol
+        :   DtlsClientProtocol
+    {
+        protected readonly TlsTestConfig config;
+
+        public DtlsTestClientProtocol(SecureRandom secureRandom, TlsTestConfig config)
+            : base(secureRandom)
+        {
+            this.config = config;
+        }
+
+        protected override byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
+        {
+            if (certificateVerify.Algorithm != null && config.clientAuthSigAlgClaimed != null)
+            {
+                certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.Signature);
+            }
+
+            return base.GenerateCertificateVerify(state, certificateVerify);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestServerProtocol.cs b/crypto/test/src/crypto/tls/test/DtlsTestServerProtocol.cs
new file mode 100644
index 000000000..006473cef
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/DtlsTestServerProtocol.cs
@@ -0,0 +1,18 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class DtlsTestServerProtocol
+        :   DtlsServerProtocol
+    {
+        protected readonly TlsTestConfig config;
+
+        public DtlsTestServerProtocol(SecureRandom secureRandom, TlsTestConfig config)
+            : base(secureRandom)
+        {
+            this.config = config;
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs b/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs
index eb9d42e5f..69ce36071 100644
--- a/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs
+++ b/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs
@@ -31,7 +31,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
                 c.clientFallback = true;
 
-                testSuite.Add(new TestCaseData(c).SetName("FallbackGood"));
+                AddTestCase(testSuite, c, "FallbackGood");
             }
 
             /*
@@ -40,20 +40,22 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
              * alerts being raised
              */
 
-            //{
-            //    TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
-            //    c.clientOfferVersion = ProtocolVersion.DTLSv10;
-            //    c.clientFallback = true;
-            //    c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback);
+#if false
+            {
+                TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
+                c.clientOfferVersion = ProtocolVersion.DTLSv10;
+                c.clientFallback = true;
+                c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback);
 
-            //    testSuite.Add(new TestCaseData(c).SetName("FallbackBad"));
-            //}
+                AddTestCase(testSuite, c, "FallbackBad");
+            }
+#endif
 
             {
                 TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
                 c.clientOfferVersion = ProtocolVersion.DTLSv10;
 
-                testSuite.Add(new TestCaseData(c).SetName("FallbackNone"));
+                AddTestCase(testSuite, c, "FallbackNone");
             }
         }
 
@@ -71,52 +73,110 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
              * alerts being raised
              */
 
-            //{
-            //    TlsTestConfig c = CreateDtlsTestConfig(version);
-            //    c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY;
-            //    c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
+#if false
+            /*
+             * Server only declares support for SHA1/RSA, client selects MD5/RSA. Since the client is
+             * NOT actually tracking MD5 over the handshake, we expect fatal alert from the client.
+             */
+            if (TlsUtilities.IsTlsV12(version))
+            {
+                TlsTestConfig c = CreateDtlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_VALID;
+                c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa);
+                c.serverCertReqSigAlgs = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
+                c.ExpectClientFatalAlert(AlertDescription.internal_error);
 
-            //    testSuite.Add(new TestCaseData(c).SetName(prefix + "BadCertificateVerify"));
-            //}
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifyHashAlg");
+            }
 
-            //{
-            //    TlsTestConfig c = CreateDtlsTestConfig(version);
-            //    c.clientAuth = C.CLIENT_AUTH_INVALID_CERT;
-            //    c.ExpectServerFatalAlert(AlertDescription.bad_certificate);
+            /*
+             * Server only declares support for SHA1/ECDSA, client selects SHA1/RSA. Since the client is
+             * actually tracking SHA1 over the handshake, we expect fatal alert to come from the server
+             * when it verifies the selected algorithm against the CertificateRequest supported
+             * algorithms.
+             */
+            if (TlsUtilities.IsTlsV12(version))
+            {
+                TlsTestConfig c = CreateDtlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_VALID;
+                c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+                c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+                c.ExpectServerFatalAlert(AlertDescription.illegal_parameter);
 
-            //    testSuite.Add(new TestCaseData(c).SetName(prefix + "BadClientCertificate"));
-            //}
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlg");
+            }
 
-            //{
-            //    TlsTestConfig c = CreateDtlsTestConfig(version);
-            //    c.clientAuth = C.CLIENT_AUTH_NONE;
-            //    c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY;
-            //    c.ExpectServerFatalAlert(AlertDescription.handshake_failure);
+            /*
+             * Server only declares support for SHA1/ECDSA, client signs with SHA1/RSA, but sends
+             * SHA1/ECDSA in the CertificateVerify. Since the client is actually tracking SHA1 over the
+             * handshake, and the claimed algorithm is in the CertificateRequest supported algorithms,
+             * we expect fatal alert to come from the server when it finds the claimed algorithm
+             * doesn't match the client certificate.
+             */
+            if (TlsUtilities.IsTlsV12(version))
+            {
+                TlsTestConfig c = CreateDtlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_VALID;
+                c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+                c.clientAuthSigAlgClaimed = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa);
+                c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+                c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
 
-            //    testSuite.Add(new TestCaseData(c).SetName(prefix + "BadMandatoryCertReqDeclined"));
-            //}
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlgMismatch");
+            }
 
             {
                 TlsTestConfig c = CreateDtlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY;
+                c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodDefault"));
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifySignature");
+            }
+
+            {
+                TlsTestConfig c = CreateDtlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_INVALID_CERT;
+                c.ExpectServerFatalAlert(AlertDescription.bad_certificate);
+
+                AddTestCase(testSuite, c, prefix + "BadClientCertificate");
+            }
+
+            {
+                TlsTestConfig c = CreateDtlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_NONE;
+                c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY;
+                c.ExpectServerFatalAlert(AlertDescription.handshake_failure);
+
+                AddTestCase(testSuite, c, prefix + "BadMandatoryCertReqDeclined");
+            }
+#endif
+
+            {
+                TlsTestConfig c = CreateDtlsTestConfig(version);
+
+                AddTestCase(testSuite, c, prefix + "GoodDefault");
             }
 
             {
                 TlsTestConfig c = CreateDtlsTestConfig(version);
                 c.serverCertReq = C.SERVER_CERT_REQ_NONE;
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodNoCertReq"));
+                AddTestCase(testSuite, c, prefix + "GoodNoCertReq");
             }
 
             {
                 TlsTestConfig c = CreateDtlsTestConfig(version);
                 c.clientAuth = C.CLIENT_AUTH_NONE;
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodOptionalCertReqDeclined"));
+                AddTestCase(testSuite, c, prefix + "GoodOptionalCertReqDeclined");
             }
         }
 
+        private static void AddTestCase(IList testSuite, TlsTestConfig config, String name)
+        {
+            testSuite.Add(new TestCaseData(config).SetName(name));
+        }
+
         private static TlsTestConfig CreateDtlsTestConfig(ProtocolVersion version)
         {
             TlsTestConfig c = new TlsTestConfig();
diff --git a/crypto/test/src/crypto/tls/test/TlsTestCase.cs b/crypto/test/src/crypto/tls/test/TlsTestCase.cs
index 4b0c12710..7fb5db6ce 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestCase.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestCase.cs
@@ -35,8 +35,8 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             NetworkStream clientNet = new NetworkStream(clientPipe);
             NetworkStream serverNet = new NetworkStream(serverPipe);
 
-            TlsClientProtocol clientProtocol = new TlsClientProtocol(clientNet, secureRandom);
-            TlsServerProtocol serverProtocol = new TlsServerProtocol(serverNet, secureRandom);
+            TlsTestClientProtocol clientProtocol = new TlsTestClientProtocol(clientNet, secureRandom, config);
+            TlsTestServerProtocol serverProtocol = new TlsTestServerProtocol(serverNet, secureRandom, config);
 
             TlsTestClientImpl clientImpl = new TlsTestClientImpl(config);
             TlsTestServerImpl serverImpl = new TlsTestServerImpl(config);
@@ -104,13 +104,13 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
         internal class Server
         {
             protected readonly TlsTestCase mOuter;
-            protected readonly TlsServerProtocol mServerProtocol;
+            protected readonly TlsTestServerProtocol mServerProtocol;
             protected readonly TlsTestServerImpl mServerImpl;
 
             internal bool mCanExit = false;
             internal Exception mCaught = null;
 
-            internal Server(TlsTestCase outer, TlsServerProtocol serverProtocol, TlsTestServerImpl serverImpl)
+            internal Server(TlsTestCase outer, TlsTestServerProtocol serverProtocol, TlsTestServerImpl serverImpl)
             {
                 this.mOuter = outer;
                 this.mServerProtocol = serverProtocol;
diff --git a/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs b/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
index 0cc1883ba..f313f75fe 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 using System.IO;
 
 using Org.BouncyCastle.Asn1;
@@ -201,9 +202,15 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                     return null;
                 }
 
+                IList supportedSigAlgs = certificateRequest.SupportedSignatureAlgorithms;
+                if (supportedSigAlgs != null && mOuter.mConfig.clientAuthSigAlg != null)
+                {
+                    supportedSigAlgs = new ArrayList(1);
+                    supportedSigAlgs.Add(mOuter.mConfig.clientAuthSigAlg);
+                }
+
                 TlsSignerCredentials signerCredentials = TlsTestUtilities.LoadSignerCredentials(mContext,
-                    certificateRequest.SupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
-                    "x509-client.pem", "x509-client-key.pem");
+                    supportedSigAlgs, SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem");
 
                 if (mOuter.mConfig.clientAuth == TlsTestConfig.CLIENT_AUTH_VALID)
                 {
diff --git a/crypto/test/src/crypto/tls/test/TlsTestClientProtocol.cs b/crypto/test/src/crypto/tls/test/TlsTestClientProtocol.cs
new file mode 100644
index 000000000..97b7c91bc
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestClientProtocol.cs
@@ -0,0 +1,29 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class TlsTestClientProtocol
+        :   TlsClientProtocol
+    {
+        protected readonly TlsTestConfig config;
+
+        public TlsTestClientProtocol(Stream stream, SecureRandom secureRandom, TlsTestConfig config)
+            : base(stream, secureRandom)
+        {
+            this.config = config;
+        }
+
+        protected override void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
+        {
+            if (certificateVerify.Algorithm != null && config.clientAuthSigAlgClaimed != null)
+            {
+                certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.Signature);
+            }
+
+            base.SendCertificateVerifyMessage(certificateVerify);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestConfig.cs b/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
index 0d1e7badb..212d2b63c 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 
 namespace Org.BouncyCastle.Crypto.Tls.Tests
 {
@@ -47,6 +48,18 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
         public int clientAuth = CLIENT_AUTH_VALID;
 
         /**
+         * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to
+         * be used for the CertificateVerify signature (if one is sent).
+         */
+        public SignatureAndHashAlgorithm clientAuthSigAlg = null;
+
+        /**
+         * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to
+         * be _claimed_ in the CertificateVerify (if one is sent), independently of what was actually used.
+         */
+        public SignatureAndHashAlgorithm clientAuthSigAlgClaimed = null;
+
+        /**
          * Configures the minimum protocol version the client will accept. If null, uses the library's default.
          */
         public ProtocolVersion clientMinimumVersion = null;
@@ -67,6 +80,12 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
         public int serverCertReq = SERVER_CERT_REQ_OPTIONAL;
 
         /**
+         * If TLS 1.2 or higher is negotiated, configures the set of supported signature algorithms in the
+         * CertificateRequest (if one is sent). If null, uses a default set.
+         */
+        public IList serverCertReqSigAlgs = null;
+
+        /**
          * Configures the maximum protocol version the server will accept. If null, uses the library's default.
          */
         public ProtocolVersion serverMaximumVersion = null;
diff --git a/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs b/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
index 152d5dbdc..6f9d35b5c 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections;
 using System.IO;
+using System.Threading;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
@@ -72,11 +73,11 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                     + ", " + AlertDescription.GetText(alertDescription));
                 if (message != null)
                 {
-                    output.WriteLine("> " + message);
+                    SafeWriteLine(output, "> " + message);
                 }
                 if (cause != null)
                 {
-                    output.WriteLine(cause);
+                    SafeWriteLine(output, cause);
                 }
             }
         }
@@ -92,7 +93,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             if (TlsTestConfig.DEBUG)
             {
                 TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
-                output.WriteLine("TLS server received alert: " + AlertLevel.GetText(alertLevel)
+                SafeWriteLine(output, "TLS server received alert: " + AlertLevel.GetText(alertLevel)
                     + ", " + AlertDescription.GetText(alertDescription));
             }
         }
@@ -122,7 +123,11 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             IList serverSigAlgs = null;
             if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mServerVersion))
             {
-                serverSigAlgs = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
+                serverSigAlgs = mConfig.serverCertReqSigAlgs;
+                if (serverSigAlgs == null)
+                {
+                    serverSigAlgs = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
+                }
             }
 
             IList certificateAuthorities = new ArrayList();
@@ -190,5 +195,19 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
                 "x509-server.pem", "x509-server-key.pem");
         }
+
+        private static void SafeWriteLine(TextWriter output, object line)
+        {
+            try
+            {
+                output.WriteLine(line);
+            }
+            catch (ThreadInterruptedException)
+            {
+                /*
+                 * For some reason the NUnit plugin in Visual Studio started throwing these during alert logging
+                 */
+            }
+        }
     }
 }
diff --git a/crypto/test/src/crypto/tls/test/TlsTestServerProtocol.cs b/crypto/test/src/crypto/tls/test/TlsTestServerProtocol.cs
new file mode 100644
index 000000000..845b7f0b9
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestServerProtocol.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class TlsTestServerProtocol
+        :   TlsServerProtocol
+    {
+        protected readonly TlsTestConfig config;
+
+        public TlsTestServerProtocol(Stream stream, SecureRandom secureRandom, TlsTestConfig config)
+            : base(stream, secureRandom)
+        {
+            this.config = config;
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
index dfd09d06e..0770187d5 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
@@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 TlsTestConfig c = CreateTlsTestConfig(ProtocolVersion.TLSv12);
                 c.clientFallback = true;
 
-                testSuite.Add(new TestCaseData(c).SetName("FallbackGood"));
+                AddTestCase(testSuite, c, "FallbackGood");
             }
 
             {
@@ -41,14 +41,14 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 c.clientFallback = true;
                 c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback);
 
-                testSuite.Add(new TestCaseData(c).SetName("FallbackBad"));
+                AddTestCase(testSuite, c, "FallbackBad");
             }
 
             {
                 TlsTestConfig c = CreateTlsTestConfig(ProtocolVersion.TLSv12);
                 c.clientOfferVersion = ProtocolVersion.TLSv11;
 
-                testSuite.Add(new TestCaseData(c).SetName("FallbackNone"));
+                AddTestCase(testSuite, c, "FallbackNone");
             }
         }
 
@@ -63,7 +63,58 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
             {
                 TlsTestConfig c = CreateTlsTestConfig(version);
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodDefault"));
+                AddTestCase(testSuite, c, prefix + "GoodDefault");
+            }
+
+            /*
+             * Server only declares support for SHA1/RSA, client selects MD5/RSA. Since the client is
+             * NOT actually tracking MD5 over the handshake, we expect fatal alert from the client.
+             */
+            if (TlsUtilities.IsTlsV12(version))
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_VALID;
+                c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa);
+                c.serverCertReqSigAlgs = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
+                c.ExpectClientFatalAlert(AlertDescription.internal_error);
+
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifyHashAlg");
+            }
+
+            /*
+             * Server only declares support for SHA1/ECDSA, client selects SHA1/RSA. Since the client is
+             * actually tracking SHA1 over the handshake, we expect fatal alert to come from the server
+             * when it verifies the selected algorithm against the CertificateRequest supported
+             * algorithms.
+             */
+            if (TlsUtilities.IsTlsV12(version))
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_VALID;
+                c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+                c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+                c.ExpectServerFatalAlert(AlertDescription.illegal_parameter);
+
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlg");
+            }
+
+            /*
+             * Server only declares support for SHA1/ECDSA, client signs with SHA1/RSA, but sends
+             * SHA1/ECDSA in the CertificateVerify. Since the client is actually tracking SHA1 over the
+             * handshake, and the claimed algorithm is in the CertificateRequest supported algorithms,
+             * we expect fatal alert to come from the server when it finds the claimed algorithm
+             * doesn't match the client certificate.
+             */
+            if (TlsUtilities.IsTlsV12(version))
+            {
+                TlsTestConfig c = CreateTlsTestConfig(version);
+                c.clientAuth = C.CLIENT_AUTH_VALID;
+                c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+                c.clientAuthSigAlgClaimed = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa);
+                c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+                c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
+
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlgMismatch");
             }
 
             {
@@ -71,7 +122,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY;
                 c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "BadCertificateVerify"));
+                AddTestCase(testSuite, c, prefix + "BadCertificateVerifySignature");
             }
 
             {
@@ -79,7 +130,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 c.clientAuth = C.CLIENT_AUTH_INVALID_CERT;
                 c.ExpectServerFatalAlert(AlertDescription.bad_certificate);
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "BadClientCertificate"));
+                AddTestCase(testSuite, c, prefix + "BadClientCertificate");
             }
 
             {
@@ -88,24 +139,29 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
                 c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY;
                 c.ExpectServerFatalAlert(AlertDescription.handshake_failure);
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "BadMandatoryCertReqDeclined"));
+                AddTestCase(testSuite, c, prefix + "BadMandatoryCertReqDeclined");
             }
 
             {
                 TlsTestConfig c = CreateTlsTestConfig(version);
                 c.serverCertReq = C.SERVER_CERT_REQ_NONE;
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodNoCertReq"));
+                AddTestCase(testSuite, c, prefix + "GoodNoCertReq");
             }
 
             {
                 TlsTestConfig c = CreateTlsTestConfig(version);
                 c.clientAuth = C.CLIENT_AUTH_NONE;
 
-                testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodOptionalCertReqDeclined"));
+                AddTestCase(testSuite, c, prefix + "GoodOptionalCertReqDeclined");
             }
         }
 
+        private static void AddTestCase(IList testSuite, TlsTestConfig config, string name)
+        {
+            testSuite.Add(new TestCaseData(config).SetName(name));
+        }
+
         private static TlsTestConfig CreateTlsTestConfig(ProtocolVersion version)
         {
             TlsTestConfig c = new TlsTestConfig();