See More

package javaforce.tests; import java.net.*; import java.io.*; import javax.net.*; import javax.net.ssl.*; import java.nio.*; import java.util.*; import java.security.cert.*; import java.security.*; import static javax.net.ssl.SSLEngineResult.*; import javaforce.*; /** Test SSL. * * Note : use keytool to generate a keystore : testssl.key * * You could create the keystore using the following ant build file (ant -f testssl.xml) * * @author pquiring */ public class TestSSL { public static void main(String[] args) { try { testTcp(); testUdp(); } catch (Exception e) { JFLog.log(e); } } public static void _log(String side, boolean client, String msg) { JFLog.log(side + ":" + (client ? "client" : "server") + ":" + msg); } public static TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {} public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {} } }; public static void initCtx(SSLContext ctx) { try { char[] passphrase = "password".toCharArray(); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream("testssl.key"), passphrase); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passphrase); ctx.init(kmf.getKeyManagers(), trustAllCerts, new java.security.SecureRandom()); } catch (Exception e) { JFLog.log(e); } } public static class TcpReader extends Thread { public InputStream is; public SSLEngine ssl; public boolean client; public ByteBuffer transfer, input; public void log(String msg) { _log("reader", client, msg); } public void run() { try { SSLSession sess = ssl.getSession(); int maxAppSize = sess.getApplicationBufferSize(); int maxPackSize = sess.getPacketBufferSize(); input = ByteBuffer.allocate(maxAppSize + 50); transfer = ByteBuffer.allocateDirect(maxPackSize); int total = 0; while (true) { int avail = is.available(); if (avail > 0) { int maxRead = transfer.remaining(); if (avail > maxRead) avail = maxRead; byte[] tmp = new byte[avail]; int read = is.read(tmp); if (read == -1) break; log("rawread:" + read); transfer.put(tmp); } if (transfer.position() == 0) continue; transfer.flip(); SSLEngineResult res = ssl.unwrap(transfer, input); if (res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { Runnable runnable; while ((runnable = ssl.getDelegatedTask()) != null) { runnable.run(); } } int produced = res.bytesProduced(); if (produced > 0) { byte[] tmp = new byte[produced]; input.flip(); if (input.remaining() != produced) { throw new Exception("input.remaining() != produced"); } input.get(tmp); //TODO : write tmp somewhere (check with client generated data) total += produced; if (total == 1024) break; } transfer.compact(); input.compact(); } log("done"); } catch (Exception e) { JFLog.log(e); } } } public static class TcpWriter extends Thread { public OutputStream os; public SSLEngine ssl; public boolean client; public ByteBuffer output, transfer; public void log(String msg) { _log("writer", client, msg); } public void run() { try { SSLSession sess = ssl.getSession(); byte[] tmp = new byte[1024]; Random r = new Random(); r.nextBytes(tmp); output = ByteBuffer.wrap(tmp); transfer = ByteBuffer.allocateDirect(sess.getPacketBufferSize()); int total = 0; while (true) { SSLEngineResult res = ssl.wrap(output, transfer); if (res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { Runnable runnable; while ((runnable = ssl.getDelegatedTask()) != null) { runnable.run(); } } int consumed = res.bytesConsumed(); int produced = res.bytesProduced(); if (consumed == 0 && produced == 0) { JF.sleep(10); continue; } if (produced > 0) { log("rawwrite:" + produced); byte[] out = new byte[produced]; transfer.flip(); if (transfer.remaining() != produced) { throw new Exception("transfer.remaining() != produced"); } transfer.get(out); os.write(out); } if (consumed > 0) { total += consumed; if (total == 1024) break; } output.flip(); output.compact(); transfer.compact(); } log("done"); } catch (Exception e) { JFLog.log(e); } } } public static class TcpServer extends Thread { public ServerSocket ss; public Socket s; public InputStream is; public OutputStream os; public SSLContext ctx; public SSLSessionContext sessctx; public SSLEngine ssl; public void run() { try { JFLog.log("Server Listening on port 1111"); ss = new ServerSocket(1111); s = ss.accept(); JFLog.log("Server received client"); is = s.getInputStream(); os = s.getOutputStream(); ctx = SSLContext.getInstance("TLSv1.2"); initCtx(ctx); ssl = ctx.createSSLEngine(); ssl.setUseClientMode(false); sessctx = ctx.getServerSessionContext(); TcpReader reader = new TcpReader(); reader.is = is; reader.ssl = ssl; TcpWriter writer = new TcpWriter(); writer.os = os; writer.ssl = ssl; reader.start(); writer.start(); reader.join(); writer.join(); } catch (Exception e) { JFLog.log(e); } } } public static class TcpClient extends Thread { public Socket s; public InputStream is; public OutputStream os; public SSLContext ctx; public SSLSessionContext sessctx; public SSLEngine ssl; public void run() { try { JFLog.log("Client connecting to server"); s = new Socket("localhost", 1111); JFLog.log("Client connected"); is = s.getInputStream(); os = s.getOutputStream(); ctx = SSLContext.getInstance("TLSv1.2"); ctx.init(null, trustAllCerts, new java.security.SecureRandom()); ssl = ctx.createSSLEngine("localhost", 1111); ssl.setUseClientMode(true); sessctx = ctx.getClientSessionContext(); TcpReader reader = new TcpReader(); reader.is = is; reader.ssl = ssl; reader.client = true; TcpWriter writer = new TcpWriter(); writer.os = os; writer.ssl = ssl; writer.client = true; reader.start(); writer.start(); reader.join(); writer.join(); } catch (Exception e) { JFLog.log(e); } } } public static void testTcp() throws Exception { JFLog.log("Starting TCP test"); TcpServer srv = new TcpServer(); srv.start(); JF.sleep(500); TcpClient clt = new TcpClient(); clt.start(); srv.join(); clt.join(); } /*** Udp ***/ public static class UdpHandshake extends Thread { public DatagramSocket ds; public SSLEngine ssl; public boolean client; public ByteBuffer intransfer, outtransfer, input, output; public void log(String msg) { _log("handshake", client, msg); } public void run() { try { SSLSession sess = ssl.getSession(); int maxAppSize = sess.getApplicationBufferSize(); int maxPackSize = sess.getPacketBufferSize(); input = ByteBuffer.allocate(maxAppSize + 50); output = ByteBuffer.allocate(maxAppSize + 50); intransfer = ByteBuffer.allocateDirect(maxPackSize * 2); outtransfer = ByteBuffer.allocateDirect(maxPackSize * 2); DatagramPacket dp; SSLEngineResult res; int consumed; int produced; while (true) { log("status=" + ssl.getHandshakeStatus()); HandshakeStatus status = ssl.getHandshakeStatus(); if (status == HandshakeStatus.NOT_HANDSHAKING) { if (client) status = HandshakeStatus.NEED_WRAP; else status = HandshakeStatus.NEED_UNWRAP; } switch (status) { case NEED_TASK: Runnable runnable; while ((runnable = ssl.getDelegatedTask()) != null) { runnable.run(); } break; case NEED_WRAP: res = ssl.wrap(output, outtransfer); if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) { log("done"); return; } consumed = res.bytesConsumed(); produced = res.bytesProduced(); if (produced > 0) { log("rawwrite:" + produced); byte[] out = new byte[produced]; outtransfer.flip(); if (outtransfer.remaining() != produced) { throw new Exception("transfer.remaining() != produced"); } outtransfer.get(out); dp = new DatagramPacket(out, out.length); dp.setSocketAddress(new InetSocketAddress(InetAddress.getByName("localhost"), client ? 1111 : 2222)); ds.send(dp); } outtransfer.compact(); output.compact(); break; case NEED_UNWRAP: dp = new DatagramPacket(new byte[maxPackSize], maxPackSize); ds.receive(dp); int length = dp.getLength(); if (length > 0) { log("rawread:" + length); intransfer.put(dp.getData(), 0, length); } intransfer.flip(); res = ssl.unwrap(intransfer, input); if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) { log("done"); return; } consumed = res.bytesConsumed(); produced = res.bytesProduced(); intransfer.compact(); input.compact(); break; case NEED_UNWRAP_AGAIN: intransfer.limit(0); //intransfer must be empty res = ssl.unwrap(intransfer, input); if (res.getHandshakeStatus() == HandshakeStatus.FINISHED) { log("done"); return; } consumed = res.bytesConsumed(); produced = res.bytesProduced(); intransfer.compact(); input.compact(); break; } } } catch (Exception e) { JFLog.log(e); } } } public static class UdpReader extends Thread { public DatagramSocket ds; public SSLEngine ssl; public boolean client; public ByteBuffer transfer, input; public void log(String msg) { _log("reader", client, msg); } public void run() { try { SSLSession sess = ssl.getSession(); int maxAppSize = sess.getApplicationBufferSize(); int maxPackSize = sess.getPacketBufferSize(); input = ByteBuffer.allocate(maxAppSize + 50); transfer = ByteBuffer.allocateDirect(maxPackSize); int total = 0; DatagramPacket dp; while (true) { dp = new DatagramPacket(new byte[maxPackSize], maxPackSize); ds.receive(dp); int length = dp.getLength(); if (length > 0) { int maxRead = transfer.remaining(); if (length > maxRead) length = maxRead; log("rawread:" + length); transfer.put(dp.getData(), 0, length); } transfer.flip(); SSLEngineResult res; res = ssl.unwrap(transfer, input); int consumed = res.bytesConsumed(); int produced = res.bytesProduced(); input.flip(); if (produced > 0) { byte[] tmp = new byte[produced]; input.get(tmp); //TODO : write tmp somewhere (check with client generated data) total += produced; if (total == 1024) break; } transfer.compact(); input.compact(); if (total == 1024) break; } log("done"); } catch (Exception e) { JFLog.log(e); } } } public static class UdpWriter extends Thread { public DatagramSocket ds; public SSLEngine ssl; public boolean client; public ByteBuffer output, transfer; public UdpReader reader; public void log(String msg) { _log("writer", client, msg); } public void run() { try { SSLSession sess = ssl.getSession(); byte[] tmp = new byte[1024]; Random r = new Random(); r.nextBytes(tmp); output = ByteBuffer.wrap(tmp); transfer = ByteBuffer.allocateDirect(sess.getPacketBufferSize()); DatagramPacket dp; int total = 0; while (true) { SSLEngineResult res = ssl.wrap(output, transfer); int consumed = res.bytesConsumed(); int produced = res.bytesProduced(); if (consumed == 0 && produced == 0) { JF.sleep(10); continue; } transfer.flip(); if (produced > 0) { byte[] out = new byte[produced]; transfer.get(out); dp = new DatagramPacket(out, out.length); dp.setSocketAddress(new InetSocketAddress(InetAddress.getByName("localhost"), client ? 1111 : 2222)); ds.send(dp); } if (consumed > 0) { total += consumed; if (total == 1024) break; } output.flip(); output.compact(); transfer.compact(); } log("done"); } catch (Exception e) { JFLog.log(e); } } } public static class UdpServer extends Thread { public DatagramSocket ds; public SSLContext ctx; public SSLSessionContext sessctx; public SSLEngine ssl; public void run() { try { JFLog.log("Server binding on port 1111"); ds = new DatagramSocket(1111); ctx = SSLContext.getInstance("DTLS"); initCtx(ctx); ssl = ctx.createSSLEngine(); ssl.setUseClientMode(false); sessctx = ctx.getServerSessionContext(); UdpHandshake handshake = new UdpHandshake(); handshake.ds = ds; handshake.ssl = ssl; handshake.client = false; handshake.start(); handshake.join(); UdpReader reader = new UdpReader(); reader.ds = ds; reader.ssl = ssl; UdpWriter writer = new UdpWriter(); writer.ds = ds; writer.ssl = ssl; writer.reader = reader; reader.start(); writer.start(); reader.join(); writer.join(); } catch (Exception e) { JFLog.log(e); } } } public static class UdpClient extends Thread { public DatagramSocket ds; public SSLContext ctx; public SSLSessionContext sessctx; public SSLEngine ssl; public void run() { try { JFLog.log("Client binding on port 2222"); ds = new DatagramSocket(2222); ctx = SSLContext.getInstance("DTLS"); ctx.init(null, trustAllCerts, new java.security.SecureRandom()); ssl = ctx.createSSLEngine("localhost", 2222); ssl.setUseClientMode(true); sessctx = ctx.getClientSessionContext(); UdpHandshake handshake = new UdpHandshake(); handshake.ds = ds; handshake.ssl = ssl; handshake.client = true; handshake.start(); handshake.join(); UdpReader reader = new UdpReader(); reader.ds = ds; reader.ssl = ssl; reader.client = true; UdpWriter writer = new UdpWriter(); writer.ds = ds; writer.ssl = ssl; writer.client = true; writer.reader = reader; reader.start(); writer.start(); reader.join(); writer.join(); } catch (Exception e) { JFLog.log(e); } } } public static void testUdp() throws Exception { JFLog.log("Starting UDP test"); UdpServer srv = new UdpServer(); srv.start(); JF.sleep(500); UdpClient clt = new UdpClient(); clt.start(); srv.join(); clt.join(); } }