diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-04-16 08:12:37 +0400 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-04-16 08:12:37 +0400 |
commit | a55cbaeb973b4a51c2ba01269e4665494aa48951 (patch) | |
tree | 7fa430da8104a17a4d43ab7dd3ed840f94e9bd78 /core/src/test/java | |
parent | 1290f929d9157b7b2bd7edebb5576d6217500f70 (diff) |
Add a DTLS test suite for client-auth use cases
Tests pass, but some disabled for automatic testing due to lack of clean
exit
Diffstat (limited to 'core/src/test/java')
7 files changed, 309 insertions, 14 deletions
diff --git a/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSProtocolTest.java b/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSProtocolTest.java index 441423b1..df5a3f87 100644 --- a/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSProtocolTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSProtocolTest.java @@ -44,9 +44,8 @@ public class DTLSProtocolTest } byte[] buf = new byte[dtlsClient.getReceiveLimit()]; - while (dtlsClient.receive(buf, 0, buf.length, 1000) >= 0) + while (dtlsClient.receive(buf, 0, buf.length, 100) >= 0) { - ; } dtlsClient.close(); diff --git a/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSTestCase.java b/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSTestCase.java new file mode 100644 index 00000000..928647c1 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSTestCase.java @@ -0,0 +1,161 @@ +package org.bouncycastle.crypto.tls.test; + +import java.security.SecureRandom; + +import junit.framework.TestCase; + +import org.bouncycastle.crypto.tls.DTLSClientProtocol; +import org.bouncycastle.crypto.tls.DTLSServerProtocol; +import org.bouncycastle.crypto.tls.DTLSTransport; +import org.bouncycastle.crypto.tls.DatagramTransport; +import org.bouncycastle.crypto.tls.ProtocolVersion; +import org.bouncycastle.util.Arrays; + +public class DTLSTestCase extends TestCase +{ + private static void checkDTLSVersion(ProtocolVersion version) + { + if (version != null && !version.isDTLS()) + { + throw new IllegalStateException("Non-DTLS version"); + } + } + + protected final TlsTestConfig config; + + public DTLSTestCase(TlsTestConfig config, String name) + { + checkDTLSVersion(config.clientMinimumVersion); + checkDTLSVersion(config.clientOfferVersion); + checkDTLSVersion(config.serverMaximumVersion); + checkDTLSVersion(config.serverMinimumVersion); + + this.config = config; + + setName(name); + } + + protected void runTest() throws Throwable + { + 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); + + ServerThread serverThread = new ServerThread(serverProtocol, network.getServer(), serverImpl); + serverThread.start(); + + Exception caught = null; + try + { + DatagramTransport clientTransport = network.getClient(); + + if (TlsTestConfig.DEBUG) + { + clientTransport = new LoggingDatagramTransport(clientTransport, System.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); + } + + serverThread.shutdown(); + + // TODO Add checks that the various streams were closed + + assertEquals("Client fatal alert connection end", config.expectFatalAlertConnectionEnd, clientImpl.firstFatalAlertConnectionEnd); + assertEquals("Server fatal alert connection end", config.expectFatalAlertConnectionEnd, serverImpl.firstFatalAlertConnectionEnd); + + assertEquals("Client fatal alert description", config.expectFatalAlertDescription, clientImpl.firstFatalAlertDescription); + assertEquals("Server fatal alert description", config.expectFatalAlertDescription, serverImpl.firstFatalAlertDescription); + + if (config.expectFatalAlertConnectionEnd == -1) + { + assertNull("Unexpected client exception", caught); + assertNull("Unexpected server exception", serverThread.caught); + } + } + + protected void logException(Exception e) + { + if (TlsTestConfig.DEBUG) + { + e.printStackTrace(); + } + } + + class ServerThread + extends Thread + { + private final DTLSServerProtocol serverProtocol; + private final DatagramTransport serverTransport; + private final TlsTestServerImpl serverImpl; + + private volatile boolean isShutdown = false; + Exception caught = null; + + ServerThread(DTLSServerProtocol serverProtocol, DatagramTransport serverTransport, TlsTestServerImpl serverImpl) + { + this.serverProtocol = serverProtocol; + this.serverTransport = serverTransport; + this.serverImpl = serverImpl; + } + + public void run() + { + try + { + DTLSTransport dtlsServer = serverProtocol.accept(serverImpl, serverTransport); + 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) + { + caught = e; + logException(caught); + } + } + + void shutdown() + throws InterruptedException + { + if (!isShutdown) + { + isShutdown = true; + this.interrupt(); + this.join(); + } + } + } +} diff --git a/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSTestSuite.java b/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSTestSuite.java new file mode 100644 index 00000000..bd066f85 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/tls/test/DTLSTestSuite.java @@ -0,0 +1,92 @@ +package org.bouncycastle.crypto.tls.test; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.bouncycastle.crypto.tls.ProtocolVersion; + +public class DTLSTestSuite extends TestSuite +{ + // Make the access to constants less verbose + static abstract class C extends TlsTestConfig {} + + public static Test suite() + { + DTLSTestSuite testSuite = new DTLSTestSuite(); + + addVersionTests(testSuite, ProtocolVersion.DTLSv10); + addVersionTests(testSuite, ProtocolVersion.DTLSv12); + + return testSuite; + } + + private static void addVersionTests(TestSuite testSuite, ProtocolVersion version) + { + String prefix = version.toString().replaceAll("[ \\.]", "") + "_"; + + /* + * 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.addTest(new DTLSTestCase(c, prefix + "BadCertificateVerify")); +// } +// +// { +// TlsTestConfig c = createDTLSTestConfig(version); +// c.clientAuth = C.CLIENT_AUTH_INVALID_CERT; +// c.expectServerFatalAlert(AlertDescription.bad_certificate); +// +// testSuite.addTest(new DTLSTestCase(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); +// +// testSuite.addTest(new DTLSTestCase(c, prefix + "BadMandatoryCertReqDeclined")); +// } + + { + TlsTestConfig c = createDTLSTestConfig(version); + + testSuite.addTest(new DTLSTestCase(c, prefix + "GoodDefault")); + } + + { + TlsTestConfig c = createDTLSTestConfig(version); + c.serverCertReq = C.SERVER_CERT_REQ_NONE; + + testSuite.addTest(new DTLSTestCase(c, prefix + "GoodNoCertReq")); + } + + { + TlsTestConfig c = createDTLSTestConfig(version); + c.clientAuth = C.CLIENT_AUTH_NONE; + + testSuite.addTest(new DTLSTestCase(c, 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/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestCase.java b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestCase.java index 9cdd8014..79ad7844 100644 --- a/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestCase.java +++ b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestCase.java @@ -7,6 +7,7 @@ import java.security.SecureRandom; import junit.framework.TestCase; +import org.bouncycastle.crypto.tls.ProtocolVersion; import org.bouncycastle.crypto.tls.TlsClientProtocol; import org.bouncycastle.crypto.tls.TlsServerProtocol; import org.bouncycastle.util.Arrays; @@ -14,10 +15,23 @@ import org.bouncycastle.util.io.Streams; public class TlsTestCase extends TestCase { + private static void checkTLSVersion(ProtocolVersion version) + { + if (version != null && !version.isTLS()) + { + throw new IllegalStateException("Non-TLS version"); + } + } + protected final TlsTestConfig config; public TlsTestCase(TlsTestConfig config, String name) { + checkTLSVersion(config.clientMinimumVersion); + checkTLSVersion(config.clientOfferVersion); + checkTLSVersion(config.serverMaximumVersion); + checkTLSVersion(config.serverMinimumVersion); + this.config = config; setName(name); @@ -71,6 +85,7 @@ public class TlsTestCase extends TestCase catch (Exception e) { caught = e; + logException(caught); } serverThread.allowExit(); @@ -94,6 +109,14 @@ public class TlsTestCase extends TestCase } } + protected void logException(Exception e) + { + if (TlsTestConfig.DEBUG) + { + e.printStackTrace(); + } + } + class ServerThread extends Thread { protected final TlsServerProtocol serverProtocol; @@ -125,6 +148,7 @@ public class TlsTestCase extends TestCase catch (Exception e) { caught = e; + logException(caught); } waitExit(); diff --git a/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestClientImpl.java b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestClientImpl.java index 4f5be8e3..4bc76e68 100644 --- a/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestClientImpl.java +++ b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestClientImpl.java @@ -56,6 +56,16 @@ class TlsTestClientImpl return super.getClientVersion(); } + public ProtocolVersion getMinimumVersion() + { + if (config.clientMinimumVersion != null) + { + return config.clientMinimumVersion; + } + + return super.getMinimumVersion(); + } + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Exception cause) { if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) diff --git a/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestConfig.java b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestConfig.java index 3784bc23..6110458e 100644 --- a/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestConfig.java +++ b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestConfig.java @@ -48,6 +48,11 @@ public class TlsTestConfig public int clientAuth = CLIENT_AUTH_VALID; /** + * Configures the minimum protocol version the client will accept. If null, uses the library's default. + */ + public ProtocolVersion clientMinimumVersion = null; + + /** * Configures the protocol version the client will offer. If null, uses the library's default. */ public ProtocolVersion clientOfferVersion = null; diff --git a/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestSuite.java b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestSuite.java index 9028cbe4..eed9b071 100644 --- a/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestSuite.java +++ b/core/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestSuite.java @@ -27,54 +27,58 @@ public class TlsTestSuite extends TestSuite String prefix = version.toString().replaceAll("[ \\.]", "") + "_"; { - TlsTestConfig c = new TlsTestConfig(); - c.serverMaximumVersion = version; + TlsTestConfig c = createTlsTestConfig(version); testSuite.addTest(new TlsTestCase(c, prefix + "GoodDefault")); } { - TlsTestConfig c = new TlsTestConfig(); + TlsTestConfig c = createTlsTestConfig(version); c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY; - c.serverMaximumVersion = version; c.expectServerFatalAlert(AlertDescription.decrypt_error); testSuite.addTest(new TlsTestCase(c, prefix + "BadCertificateVerify")); } { - TlsTestConfig c = new TlsTestConfig(); + TlsTestConfig c = createTlsTestConfig(version); c.clientAuth = C.CLIENT_AUTH_INVALID_CERT; - c.serverMaximumVersion = version; c.expectServerFatalAlert(AlertDescription.bad_certificate); testSuite.addTest(new TlsTestCase(c, prefix + "BadClientCertificate")); } { - TlsTestConfig c = new TlsTestConfig(); + TlsTestConfig c = createTlsTestConfig(version); c.clientAuth = C.CLIENT_AUTH_NONE; c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY; - c.serverMaximumVersion = version; c.expectServerFatalAlert(AlertDescription.handshake_failure); testSuite.addTest(new TlsTestCase(c, prefix + "BadMandatoryCertReqDeclined")); } { - TlsTestConfig c = new TlsTestConfig(); + TlsTestConfig c = createTlsTestConfig(version); c.serverCertReq = C.SERVER_CERT_REQ_NONE; - c.serverMaximumVersion = version; testSuite.addTest(new TlsTestCase(c, prefix + "GoodNoCertReq")); } { - TlsTestConfig c = new TlsTestConfig(); + TlsTestConfig c = createTlsTestConfig(version); c.clientAuth = C.CLIENT_AUTH_NONE; - c.serverMaximumVersion = version; testSuite.addTest(new TlsTestCase(c, prefix + "GoodOptionalCertReqDeclined")); } } + + private static TlsTestConfig createTlsTestConfig(ProtocolVersion version) + { + TlsTestConfig c = new TlsTestConfig(); + c.clientMinimumVersion = ProtocolVersion.TLSv10; + c.clientOfferVersion = ProtocolVersion.TLSv12; + c.serverMaximumVersion = version; + c.serverMinimumVersion = ProtocolVersion.TLSv10; + return c; + } } |