diff options
-rw-r--r-- | crypto/crypto.csproj | 30 | ||||
-rw-r--r-- | crypto/src/crypto/tls/DtlsReliableHandshake.cs | 8 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/DtlsProtocolTest.cs | 102 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/DtlsTestCase.cs | 153 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/DtlsTestSuite.cs | 134 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs | 18 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/MockDtlsClient.cs | 151 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/MockDtlsServer.cs | 100 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/MockPskTlsClient.cs | 2 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs | 2 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/MockTlsClient.cs | 2 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/PskTlsClientTest.cs | 79 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/TlsTestCase.cs | 8 |
13 files changed, 775 insertions, 14 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 9d185ade3..35474aebb 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -11088,6 +11088,21 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\tls\test\DtlsProtocolTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\crypto\tls\test\DtlsTestCase.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\crypto\tls\test\DtlsTestSuite.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\tls\test\LoggingDatagramTransport.cs" SubType = "Code" BuildAction = "Compile" @@ -11098,6 +11113,16 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\tls\test\MockDtlsClient.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\crypto\tls\test\MockDtlsServer.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\tls\test\MockPskTlsClient.cs" SubType = "Code" BuildAction = "Compile" @@ -11138,6 +11163,11 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\tls\test\PskTlsClientTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\tls\test\TlsClientTest.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/src/crypto/tls/DtlsReliableHandshake.cs b/crypto/src/crypto/tls/DtlsReliableHandshake.cs index bf9e61d03..8e4439e67 100644 --- a/crypto/src/crypto/tls/DtlsReliableHandshake.cs +++ b/crypto/src/crypto/tls/DtlsReliableHandshake.cs @@ -114,17 +114,17 @@ namespace Org.BouncyCastle.Crypto.Tls { for (; ; ) { - int Received = mRecordLayer.Receive(buf, 0, receiveLimit, readTimeoutMillis); - if (Received < 0) + int received = mRecordLayer.Receive(buf, 0, receiveLimit, readTimeoutMillis); + if (received < 0) { break; } - if (Received < 12) + if (received < 12) { continue; } int fragment_length = TlsUtilities.ReadUint24(buf, 9); - if (Received != (fragment_length + 12)) + if (received != (fragment_length + 12)) { continue; } diff --git a/crypto/test/src/crypto/tls/test/DtlsProtocolTest.cs b/crypto/test/src/crypto/tls/test/DtlsProtocolTest.cs new file mode 100644 index 000000000..bc99ccc63 --- /dev/null +++ b/crypto/test/src/crypto/tls/test/DtlsProtocolTest.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; +using System.Threading; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +using NUnit.Framework; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + [TestFixture] + public class DtlsProtocolTest + { + [Test] + public void TestClientServer() + { + SecureRandom secureRandom = new SecureRandom(); + + DtlsClientProtocol clientProtocol = new DtlsClientProtocol(secureRandom); + DtlsServerProtocol serverProtocol = new DtlsServerProtocol(secureRandom); + + MockDatagramAssociation network = new MockDatagramAssociation(1500); + + Server server = new Server(serverProtocol, network.Server); + + Thread serverThread = new Thread(new ThreadStart(server.Run)); + serverThread.Start(); + + DatagramTransport clientTransport = network.Client; + + clientTransport = new UnreliableDatagramTransport(clientTransport, secureRandom, 0, 0); + + clientTransport = new LoggingDatagramTransport(clientTransport, Console.Out); + + MockDtlsClient client = new MockDtlsClient(null); + + DtlsTransport dtlsClient = clientProtocol.Connect(client, clientTransport); + + for (int i = 1; i <= 10; ++i) + { + byte[] data = new byte[i]; + Arrays.Fill(data, (byte)i); + dtlsClient.Send(data, 0, data.Length); + } + + byte[] buf = new byte[dtlsClient.GetReceiveLimit()]; + while (dtlsClient.Receive(buf, 0, buf.Length, 100) >= 0) + { + } + + dtlsClient.Close(); + + server.Shutdown(serverThread); + } + + internal class Server + { + private readonly DtlsServerProtocol mServerProtocol; + private readonly DatagramTransport mServerTransport; + private volatile bool isShutdown = false; + + internal Server(DtlsServerProtocol serverProtocol, DatagramTransport serverTransport) + { + this.mServerProtocol = serverProtocol; + this.mServerTransport = serverTransport; + } + + public void Run() + { + try + { + MockDtlsServer server = new MockDtlsServer(); + DtlsTransport dtlsServer = mServerProtocol.Accept(server, mServerTransport); + byte[] buf = new byte[dtlsServer.GetReceiveLimit()]; + while (!isShutdown) + { + int length = dtlsServer.Receive(buf, 0, buf.Length, 1000); + if (length >= 0) + { + dtlsServer.Send(buf, 0, length); + } + } + dtlsServer.Close(); + } + catch (Exception e) + { + Console.Error.WriteLine(e.StackTrace); + } + } + + internal void Shutdown(Thread serverThread) + { + if (!isShutdown) + { + isShutdown = true; + serverThread.Join(); + } + } + } + } +} diff --git a/crypto/test/src/crypto/tls/test/DtlsTestCase.cs b/crypto/test/src/crypto/tls/test/DtlsTestCase.cs new file mode 100644 index 000000000..d4af04fac --- /dev/null +++ b/crypto/test/src/crypto/tls/test/DtlsTestCase.cs @@ -0,0 +1,153 @@ +using System; +using System.IO; +using System.Threading; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +using NUnit.Framework; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + [TestFixture] + public class DtlsTestCase + { + private static void CheckDtlsVersion(ProtocolVersion version) + { + if (version != null && !version.IsDtls) + throw new InvalidOperationException("Non-DTLS version"); + } + + [Test, TestCaseSource(typeof(DtlsTestSuite), "Suite")] + public void RunTest(TlsTestConfig config) + { + CheckDtlsVersion(config.clientMinimumVersion); + CheckDtlsVersion(config.clientOfferVersion); + CheckDtlsVersion(config.serverMaximumVersion); + CheckDtlsVersion(config.serverMinimumVersion); + + SecureRandom secureRandom = new SecureRandom(); + + DtlsClientProtocol clientProtocol = new DtlsClientProtocol(secureRandom); + DtlsServerProtocol serverProtocol = new DtlsServerProtocol(secureRandom); + + MockDatagramAssociation network = new MockDatagramAssociation(1500); + + TlsTestClientImpl clientImpl = new TlsTestClientImpl(config); + TlsTestServerImpl serverImpl = new TlsTestServerImpl(config); + + Server server = new Server(this, serverProtocol, network.Server, serverImpl); + + Thread serverThread = new Thread(new ThreadStart(server.Run)); + serverThread.Start(); + + Exception caught = null; + try + { + DatagramTransport clientTransport = network.Client; + + if (TlsTestConfig.DEBUG) + { + clientTransport = new LoggingDatagramTransport(clientTransport, Console.Out); + } + + DtlsTransport dtlsClient = clientProtocol.Connect(clientImpl, clientTransport); + + for (int i = 1; i <= 10; ++i) + { + byte[] data = new byte[i]; + Arrays.Fill(data, (byte)i); + dtlsClient.Send(data, 0, data.Length); + } + + byte[] buf = new byte[dtlsClient.GetReceiveLimit()]; + while (dtlsClient.Receive(buf, 0, buf.Length, 100) >= 0) + { + } + + dtlsClient.Close(); + } + catch (Exception e) + { + caught = e; + LogException(caught); + } + + server.Shutdown(serverThread); + + // TODO Add checks that the various streams were 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 void LogException(Exception e) + { + if (TlsTestConfig.DEBUG) + { + Console.Error.WriteLine(e.StackTrace); + } + } + + internal class Server + { + private readonly DtlsTestCase mOuter; + private readonly DtlsServerProtocol 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) + { + this.mOuter = outer; + this.mServerProtocol = serverProtocol; + this.mServerTransport = serverTransport; + this.mServerImpl = serverImpl; + } + + public void Run() + { + try + { + DtlsTransport dtlsServer = mServerProtocol.Accept(mServerImpl, mServerTransport); + byte[] buf = new byte[dtlsServer.GetReceiveLimit()]; + while (!isShutdown) + { + int length = dtlsServer.Receive(buf, 0, buf.Length, 100); + if (length >= 0) + { + dtlsServer.Send(buf, 0, length); + } + } + dtlsServer.Close(); + } + catch (Exception e) + { + mCaught = e; + mOuter.LogException(mCaught); + } + } + + internal void Shutdown(Thread serverThread) + { + if (!isShutdown) + { + isShutdown = true; + serverThread.Interrupt(); + serverThread.Join(); + } + } + } + } +} diff --git a/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs b/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs new file mode 100644 index 000000000..eb9d42e5f --- /dev/null +++ b/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; + +using NUnit.Framework; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + public class DtlsTestSuite + { + // Make the access to constants less verbose + internal class C : TlsTestConfig {} + + public DtlsTestSuite() + { + } + + public static IEnumerable Suite() + { + IList testSuite = new ArrayList(); + + AddFallbackTests(testSuite); + AddVersionTests(testSuite, ProtocolVersion.DTLSv10); + AddVersionTests(testSuite, ProtocolVersion.DTLSv12); + + return testSuite; + } + + private static void AddFallbackTests(IList testSuite) + { + { + TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12); + c.clientFallback = true; + + testSuite.Add(new TestCaseData(c).SetName("FallbackGood")); + } + + /* + * NOTE: Temporarily disabled automatic test runs because of problems getting a clean exit + * of the DTLS server after a fatal alert. As of writing, manual runs show the correct + * alerts being raised + */ + + //{ + // TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12); + // c.clientOfferVersion = ProtocolVersion.DTLSv10; + // c.clientFallback = true; + // c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback); + + // testSuite.Add(new TestCaseData(c).SetName("FallbackBad")); + //} + + { + TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12); + c.clientOfferVersion = ProtocolVersion.DTLSv10; + + testSuite.Add(new TestCaseData(c).SetName("FallbackNone")); + } + } + + private static void AddVersionTests(IList testSuite, ProtocolVersion version) + { + string prefix = version.ToString() + .Replace(" ", "") + .Replace("\\", "") + .Replace(".", "") + + "_"; + + /* + * NOTE: Temporarily disabled automatic test runs because of problems getting a clean exit + * of the DTLS server after a fatal alert. As of writing, manual runs show the correct + * alerts being raised + */ + + //{ + // TlsTestConfig c = CreateDtlsTestConfig(version); + // c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY; + // c.ExpectServerFatalAlert(AlertDescription.decrypt_error); + + // testSuite.Add(new TestCaseData(c).SetName(prefix + "BadCertificateVerify")); + //} + + //{ + // TlsTestConfig c = CreateDtlsTestConfig(version); + // c.clientAuth = C.CLIENT_AUTH_INVALID_CERT; + // c.ExpectServerFatalAlert(AlertDescription.bad_certificate); + + // testSuite.Add(new TestCaseData(c).SetName(prefix + "BadClientCertificate")); + //} + + //{ + // TlsTestConfig c = CreateDtlsTestConfig(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 = CreateDtlsTestConfig(version); + + testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodDefault")); + } + + { + TlsTestConfig c = CreateDtlsTestConfig(version); + c.serverCertReq = C.SERVER_CERT_REQ_NONE; + + testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodNoCertReq")); + } + + { + TlsTestConfig c = CreateDtlsTestConfig(version); + c.clientAuth = C.CLIENT_AUTH_NONE; + + testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodOptionalCertReqDeclined")); + } + } + + private static TlsTestConfig CreateDtlsTestConfig(ProtocolVersion version) + { + TlsTestConfig c = new TlsTestConfig(); + c.clientMinimumVersion = ProtocolVersion.DTLSv10; + /* + * TODO We'd like to just set the offer version to DTLSv12, but there is a known issue with + * overly-restrictive version checks b/w BC DTLS 1.2 client, BC DTLS 1.0 server + */ + c.clientOfferVersion = version; + c.serverMaximumVersion = version; + c.serverMinimumVersion = ProtocolVersion.DTLSv10; + return c; + } + } +} diff --git a/crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs b/crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs index 0391f4fef..48df36ca9 100644 --- a/crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs +++ b/crypto/test/src/crypto/tls/test/MockDatagramAssociation.cs @@ -24,14 +24,14 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests this.server = new MockDatagramTransport(this, serverQueue, clientQueue); } - public DatagramTransport getClient() + public virtual DatagramTransport Client { - return client; + get { return client; } } - public DatagramTransport getServer() + public virtual DatagramTransport Server { - return server; + get { return server; } } private class MockDatagramTransport @@ -64,8 +64,14 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests { if (receiveQueue.Count < 1) { - Monitor.Wait(waitMillis); - + try + { + Monitor.Wait(receiveQueue, waitMillis); + } + catch (ThreadInterruptedException) + { + // TODO Keep waiting until full wait expired? + } if (receiveQueue.Count < 1) { return -1; diff --git a/crypto/test/src/crypto/tls/test/MockDtlsClient.cs b/crypto/test/src/crypto/tls/test/MockDtlsClient.cs new file mode 100644 index 000000000..32491c425 --- /dev/null +++ b/crypto/test/src/crypto/tls/test/MockDtlsClient.cs @@ -0,0 +1,151 @@ +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 +{ + public class MockDtlsClient + : DefaultTlsClient + { + protected TlsSession mSession; + + public MockDtlsClient(TlsSession session) + { + 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("DTLS 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("DTLS client received alert: " + AlertLevel.GetText(alertLevel) + + ", " + AlertDescription.GetText(alertDescription)); + } + + public override ProtocolVersion ClientVersion + { + get { return ProtocolVersion.DTLSv12; } + } + + public override ProtocolVersion MinimumVersion + { + get { return ProtocolVersion.DTLSv10; } + } + + //public override int[] GetCipherSuites() + //{ + // return Arrays.Concatenate(base.GetCipherSuites(), + // new int[] + // { + // CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + // CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1, + // CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1, + // CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1, + // CipherSuite.TLS_RSA_WITH_SALSA20_SHA1, + // }); + //} + + public override IDictionary GetClientExtensions() + { + IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions()); + TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions); + // TODO[draft-ietf-tls-session-hash-01] Enable once code-point assigned (only for compatible server though) + //TlsExtensionsUtilities.AddExtendedMasterSecretExtension(clientExtensions); + TlsExtensionsUtilities.AddMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9); + TlsExtensionsUtilities.AddTruncatedHMacExtension(clientExtensions); + return clientExtensions; + } + + public override void NotifyServerVersion(ProtocolVersion serverVersion) + { + base.NotifyServerVersion(serverVersion); + + Console.WriteLine("Negotiated " + serverVersion); + } + + public override TlsAuthentication GetAuthentication() + { + return new MyTlsAuthentication(mContext); + } + + 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; + } + } + + internal class MyTlsAuthentication + : TlsAuthentication + { + private readonly TlsContext mContext; + + internal MyTlsAuthentication(TlsContext context) + { + this.mContext = context; + } + + public virtual void NotifyServerCertificate(Certificate serverCertificate) + { + X509CertificateStructure[] chain = serverCertificate.GetCertificateList(); + Console.WriteLine("DTLS 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) + { + byte[] certificateTypes = certificateRequest.CertificateTypes; + if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign)) + return null; + + return TlsTestUtilities.LoadSignerCredentials(mContext, certificateRequest.SupportedSignatureAlgorithms, + SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); + } + }; + } +} diff --git a/crypto/test/src/crypto/tls/test/MockDtlsServer.cs b/crypto/test/src/crypto/tls/test/MockDtlsServer.cs new file mode 100644 index 000000000..19062181b --- /dev/null +++ b/crypto/test/src/crypto/tls/test/MockDtlsServer.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + public class MockDtlsServer + : DefaultTlsServer + { + public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause) + { + TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out; + output.WriteLine("DTLS 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("DTLS server received alert: " + AlertLevel.GetText(alertLevel) + + ", " + AlertDescription.GetText(alertDescription)); + } + + protected override int[] GetCipherSuites() + { + return Arrays.Concatenate(base.GetCipherSuites(), + new int[] + { + CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1, + CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1, + CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1, + CipherSuite.TLS_RSA_WITH_SALSA20_SHA1, + }); + } + + public override CertificateRequest GetCertificateRequest() + { + 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) + { + X509CertificateStructure[] chain = clientCertificate.GetCertificateList(); + Console.WriteLine("DTLS 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 ProtocolVersion MaximumVersion + { + get { return ProtocolVersion.DTLSv12; } + } + + protected override ProtocolVersion MinimumVersion + { + get { return ProtocolVersion.DTLSv10; } + } + + 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/MockPskTlsClient.cs b/crypto/test/src/crypto/tls/test/MockPskTlsClient.cs index a186a8b58..dfc0e93a0 100644 --- a/crypto/test/src/crypto/tls/test/MockPskTlsClient.cs +++ b/crypto/test/src/crypto/tls/test/MockPskTlsClient.cs @@ -122,7 +122,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests for (int i = 0; i != chain.Length; i++) { X509CertificateStructure entry = chain[i]; - // TODO Create Fingerprint based on certificate signature algorithm digest + // 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/MockSrpTlsClient.cs b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs index 2b9549e82..8a6b9f496 100644 --- a/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs +++ b/crypto/test/src/crypto/tls/test/MockSrpTlsClient.cs @@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests for (int i = 0; i != chain.Length; i++) { X509CertificateStructure entry = chain[i]; - // TODO Create Fingerprint based on certificate signature algorithm digest + // 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/MockTlsClient.cs b/crypto/test/src/crypto/tls/test/MockTlsClient.cs index dbeb3fe41..4d7c59afa 100644 --- a/crypto/test/src/crypto/tls/test/MockTlsClient.cs +++ b/crypto/test/src/crypto/tls/test/MockTlsClient.cs @@ -121,7 +121,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests for (int i = 0; i != chain.Length; i++) { X509CertificateStructure entry = chain[i]; - // TODO Create Fingerprint based on certificate signature algorithm digest + // 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/PskTlsClientTest.cs b/crypto/test/src/crypto/tls/test/PskTlsClientTest.cs new file mode 100644 index 000000000..7072c7105 --- /dev/null +++ b/crypto/test/src/crypto/tls/test/PskTlsClientTest.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Text; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Tls.Tests +{ + /** + * A simple test designed to conduct a TLS handshake with an external TLS server. + * <p> + * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS server. + * </p><p> + * In both cases, extra options are required to enable PSK ciphersuites and configure identities/keys. + * </p> + */ + public class PskTlsClientTest + { + private static readonly SecureRandom secureRandom = new SecureRandom(); + + public static void Main(string[] args) + { + string hostname = "localhost"; + int port = 5556; + + long time1 = DateTime.UtcNow.Ticks; + + /* + * Note: This is the default PSK identity for 'openssl s_server' testing, the server must be + * started with "-psk 6161616161" to make the keys match, and possibly the "-psk_hint" + * option should be present. + */ + string psk_identity = "Client_identity"; + byte[] psk = new byte[]{ 0x61, 0x61, 0x61, 0x61, 0x61 }; + + BasicTlsPskIdentity pskIdentity = new BasicTlsPskIdentity(psk_identity, psk); + + MockPskTlsClient client = new MockPskTlsClient(null, pskIdentity); + TlsClientProtocol protocol = OpenTlsConnection(hostname, port, client); + protocol.Close(); + + long time2 = DateTime.UtcNow.Ticks; + Console.WriteLine("Elapsed 1: " + (time2 - time1)/TimeSpan.TicksPerMillisecond + "ms"); + + client = new MockPskTlsClient(client.GetSessionToResume(), pskIdentity); + protocol = OpenTlsConnection(hostname, port, client); + + long time3 = DateTime.UtcNow.Ticks; + Console.WriteLine("Elapsed 2: " + (time3 - time2)/TimeSpan.TicksPerMillisecond + "ms"); + + byte[] req = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\n\r\n"); + + Stream tlsStream = protocol.Stream; + tlsStream.Write(req, 0, req.Length); + tlsStream.Flush(); + + StreamReader reader = new StreamReader(tlsStream); + + String line; + while ((line = reader.ReadLine()) != null) + { + Console.WriteLine(">>> " + line); + } + + protocol.Close(); + } + + internal static TlsClientProtocol OpenTlsConnection(string hostname, int port, TlsClient client) + { + TcpClient tcp = new TcpClient(hostname, port); + + TlsClientProtocol protocol = new TlsClientProtocol(tcp.GetStream(), secureRandom); + protocol.Connect(client); + return protocol; + } + } +} diff --git a/crypto/test/src/crypto/tls/test/TlsTestCase.cs b/crypto/test/src/crypto/tls/test/TlsTestCase.cs index 8ac1c4ed2..4b0c12710 100644 --- a/crypto/test/src/crypto/tls/test/TlsTestCase.cs +++ b/crypto/test/src/crypto/tls/test/TlsTestCase.cs @@ -149,7 +149,13 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests { while (!mCanExit) { - Monitor.Wait(this); + try + { + Monitor.Wait(this); + } + catch (ThreadInterruptedException) + { + } } } } |