diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 3f713e1c0..7b3dde612 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -11011,11 +11011,21 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\tls\test\PipedStream.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\tls\test\TlsClientTest.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\tls\test\TlsProtocolTest.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\tls\test\TlsServerTest.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -11026,6 +11036,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\tls\test\UnreliableDatagramTransport.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\math\ec\test\AllTests.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/test/src/crypto/tls/test/PipedStream.cs b/crypto/test/src/crypto/tls/test/PipedStream.cs
new file mode 100644
index 000000000..6b2c15059
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/PipedStream.cs
@@ -0,0 +1,134 @@
+using System;
+using System.IO;
+using System.Threading;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+ internal class PipedStream
+ : Stream
+ {
+ private readonly MemoryStream mBuf = new MemoryStream();
+ private bool mClosed = false;
+
+ private PipedStream mOther = null;
+ private long mReadPos = 0;
+
+ internal PipedStream()
+ {
+ }
+
+ internal PipedStream(PipedStream other)
+ {
+ lock (other)
+ {
+ this.mOther = other;
+ other.mOther = this;
+ }
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ public override void Close()
+ {
+ lock (this)
+ {
+ mClosed = true;
+ Monitor.PulseAll(this);
+ }
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override long Length
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override long Position
+ {
+ get { throw new NotImplementedException(); }
+ set { throw new NotImplementedException(); }
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ lock (mOther)
+ {
+ WaitForData();
+ int len = (int)System.Math.Min(count, mOther.mBuf.Position - mReadPos);
+ Array.Copy(mOther.mBuf.GetBuffer(), mReadPos, buffer, offset, len);
+ mReadPos += len;
+ return len;
+ }
+ }
+
+ public override int ReadByte()
+ {
+ lock (mOther)
+ {
+ WaitForData();
+ bool eof = (mReadPos >= mOther.mBuf.Position);
+ return eof ? -1 : mOther.mBuf.GetBuffer()[mReadPos++];
+ }
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ lock (this)
+ {
+ CheckOpen();
+ mBuf.Write(buf, off, len);
+ Monitor.PulseAll(this);
+ }
+ }
+
+ public override void WriteByte(byte value)
+ {
+ lock (this)
+ {
+ CheckOpen();
+ mBuf.WriteByte(value);
+ Monitor.PulseAll(mBuf);
+ }
+ }
+
+ private void CheckOpen()
+ {
+ if (mClosed)
+ throw new ObjectDisposedException(this.GetType().Name);
+ }
+
+ private void WaitForData()
+ {
+ while (mReadPos >= mOther.mBuf.Position && !mOther.mClosed)
+ {
+ Monitor.Wait(mOther);
+ }
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsProtocolTest.cs b/crypto/test/src/crypto/tls/test/TlsProtocolTest.cs
new file mode 100644
index 000000000..4c49420c6
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsProtocolTest.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 TlsProtocolTest
+ {
+ [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(server.Run);
+ serverThread.Start();
+
+ MockTlsClient client = new MockTlsClient(null);
+ 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
+ {
+ MockTlsServer server = new MockTlsServer();
+ mServerProtocol.Accept(server);
+ Streams.PipeAll(mServerProtocol.Stream, mServerProtocol.Stream);
+ mServerProtocol.Close();
+ }
+ catch (Exception)
+ {
+ //throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs b/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs
index 272dfd4fd..a76858ce6 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Globalization;
using System.IO;
using System.Text;
@@ -89,6 +90,34 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
return new DefaultTlsSignerCredentials(context, certificate, privateKey, signatureAndHashAlgorithm);
}
+ internal static TlsSignerCredentials LoadSignerCredentials(TlsContext context, IList supportedSignatureAlgorithms,
+ byte signatureAlgorithm, string certResource, string keyResource)
+ {
+ /*
+ * TODO Note that this code fails to provide default value for the client supported
+ * algorithms if it wasn't sent.
+ */
+
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
+ if (supportedSignatureAlgorithms != null)
+ {
+ foreach (SignatureAndHashAlgorithm alg in supportedSignatureAlgorithms)
+ {
+ if (alg.Signature == signatureAlgorithm)
+ {
+ signatureAndHashAlgorithm = alg;
+ break;
+ }
+ }
+
+ if (signatureAndHashAlgorithm == null)
+ return null;
+ }
+
+ return LoadSignerCredentials(context, new String[]{ certResource, "x509-ca.pem" },
+ keyResource, signatureAndHashAlgorithm);
+ }
+
internal static Certificate LoadCertificateChain(string[] resources)
{
X509CertificateStructure[] chain = new X509CertificateStructure[resources.Length];
diff --git a/crypto/test/src/crypto/tls/test/UnreliableDatagramTransport.cs b/crypto/test/src/crypto/tls/test/UnreliableDatagramTransport.cs
new file mode 100644
index 000000000..b771ab7cf
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/UnreliableDatagramTransport.cs
@@ -0,0 +1,84 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+ public class UnreliableDatagramTransport
+ : DatagramTransport
+ {
+ private readonly DatagramTransport transport;
+ private readonly Random random;
+ private readonly int percentPacketLossReceiving, percentPacketLossSending;
+
+ public UnreliableDatagramTransport(DatagramTransport transport, Random random,
+ int percentPacketLossReceiving, int percentPacketLossSending)
+ {
+ if (percentPacketLossReceiving < 0 || percentPacketLossReceiving > 100)
+ throw new ArgumentException("out of range", "percentPacketLossReceiving");
+ if (percentPacketLossSending < 0 || percentPacketLossSending > 100)
+ throw new ArgumentException("out of range", "percentPacketLossSending");
+
+ this.transport = transport;
+ this.random = random;
+ this.percentPacketLossReceiving = percentPacketLossReceiving;
+ this.percentPacketLossSending = percentPacketLossSending;
+ }
+
+ 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)
+ {
+ long endMillis = DateTimeUtilities.CurrentUnixMs() + waitMillis;
+ for (;;)
+ {
+ int length = transport.Receive(buf, off, len, waitMillis);
+ if (length < 0 || !LostPacket(percentPacketLossReceiving))
+ {
+ return length;
+ }
+
+ Console.WriteLine("PACKET LOSS (" + length + " byte packet not received)");
+
+ long now = DateTimeUtilities.CurrentUnixMs();
+ if (now >= endMillis)
+ {
+ return -1;
+ }
+
+ waitMillis = (int)(endMillis - now);
+ }
+ }
+
+ public virtual void Send(byte[] buf, int off, int len)
+ {
+ if (LostPacket(percentPacketLossSending))
+ {
+ Console.WriteLine("PACKET LOSS (" + len + " byte packet not sent)");
+ }
+ else
+ {
+ transport.Send(buf, off, len);
+ }
+ }
+
+ public virtual void Close()
+ {
+ transport.Close();
+ }
+
+ private bool LostPacket(int percentPacketLoss)
+ {
+ return percentPacketLoss > 0 && random.Next(100) < percentPacketLoss;
+ }
+ }
+}
|