Last active
December 20, 2015 23:19
-
-
Save gkhays/6211648 to your computer and use it in GitHub Desktop.
This is a set of classes used to test FIPS 140-2 and SSL communications in general. The OpenSSL s_server and s_client utilities are a great resource to use as partners in the testing process.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.gkh.net; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.InputStreamReader; | |
import java.io.OutputStream; | |
import java.io.PrintWriter; | |
import java.util.logging.Logger; | |
import javax.net.ssl.SSLSocket; | |
public class ClientThread extends Thread { | |
private SSLSocket socket; | |
private InputStream in; | |
private OutputStream out; | |
private Logger logger; | |
public ClientThread(SSLSocket socket) throws IOException { | |
this.socket = socket; | |
this.in = socket.getInputStream(); | |
this.out = socket.getOutputStream(); | |
this.logger = Logger.getLogger(ClientThread.class.getName()); | |
} | |
public void run() { | |
try { | |
String line; | |
int available = 0; | |
BufferedReader cmdInput = new BufferedReader(new InputStreamReader( | |
System.in)); | |
BufferedReader reader = new BufferedReader(new InputStreamReader( | |
this.in)); | |
PrintWriter writer = new PrintWriter(this.out); | |
System.out.println("Type CTRL-Z to exit"); | |
while ((line = cmdInput.readLine()) != null) { | |
logger.info("Received: " + line); | |
writer.println(line); | |
writer.flush(); | |
if ((available = in.available()) > 0) { | |
logger.info("Available bytes: " + available); | |
System.out.println("Server: " + reader.readLine()); | |
} | |
} | |
cmdInput.close(); | |
this.out.close(); | |
this.in.close(); | |
socket.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.gkh.net; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.InputStreamReader; | |
import java.io.OutputStream; | |
import java.io.PrintWriter; | |
import java.net.SocketException; | |
import java.util.logging.Logger; | |
import javax.net.ssl.SSLSocket; | |
public class ServerThread extends Thread { | |
private SSLSocket socket; | |
private InputStream in; | |
private OutputStream out; | |
private Logger logger; | |
private boolean isRunning; | |
public ServerThread(SSLSocket socket) throws IOException { | |
this.socket = socket; | |
this.in = socket.getInputStream(); | |
this.out = socket.getOutputStream(); | |
this.isRunning = true; | |
this.logger = Logger.getLogger(ClientThread.class.getName()); | |
logger.info("Constructing Server Thread..."); | |
} | |
public void run() { | |
try { | |
while (isRunning) { | |
String line = null; | |
BufferedReader reader = new BufferedReader( | |
new InputStreamReader(this.in)); | |
PrintWriter writer = new PrintWriter(this.out); | |
try { | |
line = reader.readLine(); | |
System.out.println("Server read: " + line); | |
writer.println("Input received"); | |
if (line.equals("quit")) { | |
isRunning = false; | |
} | |
} catch (SocketException s) { | |
// Connection reset | |
// Connection closed | |
// Socket write error | |
isRunning = false; | |
logger.info("The client did something we don't like: " | |
+ s.getMessage()); | |
} | |
} | |
this.out.close(); | |
this.in.close(); | |
socket.close(); | |
} catch (IOException e) { | |
logger.info("Unanticipated error, printing stack trace..."); | |
e.printStackTrace(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.gkh.net; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.Provider; | |
import java.security.Security; | |
import java.security.cert.CertPath; | |
import java.security.cert.Certificate; | |
import java.security.cert.CertificateFactory; | |
import java.util.ArrayList; | |
import java.util.List; | |
import javax.net.ssl.TrustManager; | |
import javax.net.ssl.TrustManagerFactory; | |
import javax.net.ssl.X509TrustManager; | |
public class SslSocketUtils { | |
private SslSocketUtils() { | |
} | |
public static void enableCustomTrustManager(KeyStore jks) throws Exception | |
{ | |
X509TrustManager sunX509TrustManager = null; | |
TrustManager[] tms = getTrustManagers(jks); | |
System.out.println("Found " + tms.length + " trust managers."); | |
for (int i = 0; i < tms.length; i++) { | |
if (tms[i] instanceof X509TrustManager) { | |
sunX509TrustManager = (X509TrustManager) tms[i]; | |
break; | |
} | |
} | |
if (sunX509TrustManager == null) | |
throw new Exception("Missing X509 Trust Manager"); | |
TrustManager ctm = new CustomTrustManager(sunX509TrustManager); | |
System.out.println("CutomTrustManager instance of TrustManager: " + (ctm instanceof TrustManager)); | |
//TrustManager[] tms2 = new TrustManager[] { ctm }; | |
} | |
public static TrustManager[] getTrustManagers() | |
throws KeyStoreException, NoSuchAlgorithmException | |
{ | |
return getTrustManagers(null); | |
} | |
public static TrustManager[] getTrustManagers(KeyStore ks) | |
throws KeyStoreException, NoSuchAlgorithmException | |
{ | |
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( | |
TrustManagerFactory.getDefaultAlgorithm()); | |
trustManagerFactory.init(ks); | |
return trustManagerFactory.getTrustManagers(); | |
} | |
public static void insertNssProvider(String configFile) { | |
Provider nss = new sun.security.pkcs11.SunPKCS11(configFile); | |
Security.addProvider(nss); | |
int sunJssePosition = -1; | |
int currentIndex = 0; | |
for (Provider provider : Security.getProviders()) { | |
if ("SunJSSE".equals(provider.getName())) { | |
sunJssePosition = currentIndex + 1; | |
break; | |
} | |
currentIndex++; | |
} | |
Security.removeProvider("SunJSSE"); | |
Provider sunJsse = new com.sun.net.ssl.internal.ssl.Provider(nss); | |
if (sunJssePosition == -1) { | |
Security.addProvider(sunJsse); | |
} else { | |
Security.insertProviderAt(sunJsse, sunJssePosition); | |
} | |
System.out.println(nss.getName()); | |
System.out.println(nss.getInfo()); | |
} | |
public static void printCertificateInformation(KeyStore jks, String alias) | |
throws Exception { | |
java.security.cert.Certificate cert = jks.getCertificate(alias); | |
if (cert == null) { | |
System.out.println("Unable to retrieve certificate for " + alias | |
+ "."); | |
return; | |
} | |
String algo = cert.getPublicKey().getAlgorithm(); | |
System.out.print("Alias '" + alias + "' public key: "); | |
if (algo != null) | |
System.out.println("Certificate public key: " + algo); | |
java.security.cert.Certificate[] cchain = jks | |
.getCertificateChain(alias); | |
if (cchain != null) { | |
List<Certificate> mylist = new ArrayList<Certificate>(); | |
for (int i = 0; i < cchain.length; i++) { | |
mylist.add(cchain[i]); | |
} | |
CertificateFactory cf = CertificateFactory.getInstance("X.509"); | |
CertPath cp = cf.generateCertPath(mylist); | |
System.out.println(cp); | |
} else | |
System.out.println("Certificate chain is null"); | |
} | |
void printDefaultTrustManagers() | |
throws KeyStoreException, NoSuchAlgorithmException | |
{ | |
getTrustManagers(); | |
System.out.println("JVM Default Trust Managers:"); | |
for (TrustManager trustManager : getTrustManagers()) { | |
System.out.println(trustManager); | |
if (trustManager instanceof X509TrustManager) { | |
X509TrustManager x509TrustManager = (X509TrustManager)trustManager; | |
System.out.println("\tAccepted issuers count : " + x509TrustManager.getAcceptedIssuers().length); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.gkh.net; | |
import javax.net.ssl.*; | |
class MyHandshakeListener | |
implements HandshakeCompletedListener | |
{ | |
public void handshakeCompleted(HandshakeCompletedEvent e) | |
{ | |
System.out.println("Handshake succesful!"); | |
System.out.println("Using cipher suite: " + e.getCipherSuite()); | |
} | |
} | |
public class TestClient | |
extends TestSocket | |
{ | |
public TestClient(String host, int port, boolean useNss, String path, | |
String secret, String keypass) throws Exception { | |
initialize(host, port, useNss, path, secret, keypass); | |
} | |
static void usage() | |
{ | |
System.out.println("TestClient <host> <port> <path> <secret> [<useNss>]"); | |
} | |
public static void main(String[] args) | |
{ | |
if (args.length < 4) { | |
usage(); | |
return; | |
} | |
// TODO - How about an XML or JSON configuration file? | |
System.out.println("Starting Java test client..."); | |
String host = args[0]; | |
int port = Integer.parseInt(args[1]); | |
String path = args[2]; | |
String secret = args[3]; | |
boolean useNss = false; | |
if (args.length == 5) | |
useNss = Boolean.parseBoolean(args[4]); | |
String keypass = null; | |
if (args.length == 6) | |
keypass = args[5]; | |
try | |
{ | |
TestClient client = new TestClient(host, port, useNss, path, secret, keypass); | |
SSLSocket socket = client.getSocket(); | |
System.out.println("Supported Cipher Suites: "); | |
for (String s : socket.getSupportedCipherSuites()) { | |
System.out.println(s); | |
} | |
System.out.println("Registering a handshake listener..."); | |
socket.addHandshakeCompletedListener(new MyHandshakeListener()); | |
System.out.println("Supported protocols:"); | |
for (String s : socket.getEnabledProtocols()) | |
System.out.println(s); | |
System.out.println("Starting handshaking..."); | |
socket.setUseClientMode(true); | |
socket.startHandshake(); | |
System.out.println("Just connected to " + socket.getRemoteSocketAddress()); | |
String[] enabled = null; | |
enabled = socket.getEnabledCipherSuites(); | |
printEnabledArray(enabled, "cipher suites"); | |
enabled = socket.getEnabledProtocols(); | |
printEnabledArray(enabled, "protocols"); | |
new ClientThread(socket).start(); | |
} | |
catch (Exception ex) | |
{ | |
ex.printStackTrace(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.gkh.net; | |
import javax.net.*; | |
import javax.net.ssl.*; | |
public class TestServer | |
extends TestSocket | |
{ | |
volatile int serverPort = 0; | |
// List of FIPS cipher suites. | |
// http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html | |
TestServer() | |
{ | |
this.isServer = true; | |
} | |
void doServerSide(int port, boolean useNss, String store, String secret, | |
String keypass) throws Exception { | |
serverPort = port; | |
initialize(null, port, useNss, store, secret, keypass); | |
ServerSocketFactory ssf = ctx.getServerSocketFactory(); | |
SSLServerSocket sslServerSocket = (SSLServerSocket) ssf | |
.createServerSocket(serverPort); | |
sslServerSocket.setEnabledProtocols(new String[] { "TLSv1" }); | |
String[] ciphers = sslServerSocket.getSupportedCipherSuites(); | |
System.out.println("Supported Cipher Suites"); | |
for (int i = 0; i < ciphers.length; i++) { | |
System.out.println(ciphers[i]); | |
} | |
/* | |
* Supported Protocols: SSLv2Hello, SSLv3, TLSv1 | |
*/ | |
String[] protocols = sslServerSocket.getSupportedProtocols(); | |
System.out.println("Supported Protocols"); | |
for (int i = 0; i < protocols.length; i++) { | |
System.out.println(protocols[i]); | |
} | |
String[] enabled = sslServerSocket.getEnabledCipherSuites(); | |
System.out.println("Enabled (Server) Cipher Suites"); | |
for (int i = 0; i < enabled.length; i++) { | |
System.out.println(enabled[i]); | |
} | |
sslServerSocket.setEnabledCipherSuites(ciphers); | |
/* | |
* Configured Protocol: TLSv1 | |
* Provider: | |
* Info: Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1) | |
* Name: SunJSSE | |
*/ | |
System.out.println("Configured Protocol: " + ctx.getProtocol()); | |
System.out.println("Provider: (info) " + ctx.getProvider().getInfo() | |
+ " (name) " + ctx.getProvider().getName()); | |
sslServerSocket.setNeedClientAuth(true); | |
serverPort = sslServerSocket.getLocalPort(); | |
System.out.println("serverPort = " + serverPort); | |
while (true) { | |
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); | |
new ServerThread(sslSocket).start(); | |
} | |
} | |
/** | |
* @param args | |
*/ | |
public static void main(String[] args) throws Exception | |
{ | |
int port = Integer.parseInt(args[0]); | |
String store = ""; | |
String secret = ""; | |
if (args.length >= 3) { | |
store = args[1]; | |
secret = args[2]; | |
} | |
boolean useNss = false; | |
if (args.length == 4) | |
useNss = Boolean.parseBoolean(args[3]); | |
String keypass = null; | |
if (args.length == 5) | |
keypass = args[4]; | |
System.out.println("Starting Java test server..."); | |
TestServer testServer = new TestServer(); | |
testServer.doServerSide(port, useNss, store, secret, keypass); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.gkh.net; | |
import java.io.FileInputStream; | |
import java.io.InputStream; | |
import java.security.KeyStore; | |
import java.security.Provider; | |
import java.security.Security; | |
import javax.net.ssl.KeyManagerFactory; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.SSLSocket; | |
import javax.net.ssl.SSLSocketFactory; | |
import javax.net.ssl.TrustManagerFactory; | |
public class TestSocket | |
{ | |
protected static Provider pkcs11Provider; | |
protected SSLContext ctx = null; | |
protected KeyStore jks = null; | |
protected TrustManagerFactory trustManagerFactory = null; | |
//private static String DIR = System.getProperty("DIR"); | |
protected int port; | |
protected String host; | |
protected boolean isServer = false; | |
protected SSLSocket socket; | |
public void enablePkcsProvider(String configFile) | |
{ | |
pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configFile); | |
Security.insertProviderAt(pkcs11Provider, 1); | |
new com.sun.net.ssl.internal.ssl.Provider(pkcs11Provider); | |
// System.out.println("FIPS Enabled"); | |
// System.out.println(pkcs11Provider.getName()); | |
// System.out.println(pkcs11Provider.getInfo()); | |
} | |
protected void initialize(String host, int port, boolean useNss, | |
String path, String secret, String keypass) throws Exception { | |
if (Utils.isNullOrEmpty(path)) | |
throw new Exception( | |
"Please specify a valid path for NSS or a Java Keystore"); | |
this.host = host; | |
this.port = port; | |
KeyManagerFactory kmf = null; | |
TrustManagerFactory tmf = null; | |
kmf = KeyManagerFactory.getInstance("SunX509"); | |
tmf = TrustManagerFactory.getInstance("SunX509"); | |
char[] passphrase = secret.toCharArray(); | |
if (true == useNss) { | |
// It is possible to update the provider list in java.security, but | |
// we have chosen to do it on-the-fly instead. | |
enablePkcsProvider(path); | |
// Server gets TrustStore from PKCS#11 token. | |
jks = KeyStore.getInstance("PKCS11", "SunPKCS11-NSSFIPS"); | |
jks.load(null, passphrase); | |
} else { | |
// To just use the default Java keystore: | |
// ctx.init(null, null, null); | |
this.jks = KeyStore.getInstance("JKS"); | |
InputStream in = new FileInputStream(path); | |
jks.load(in, passphrase); | |
} | |
if (Utils.isNullOrEmpty(keypass)) | |
kmf.init(jks, passphrase); | |
else | |
kmf.init(jks, keypass.toCharArray()); | |
tmf.init(jks); | |
// SSLContext Algorithms {SSL, SSLv2, SSLv3, TLS, TLSv1, TLSv1.1} | |
// http://download.oracle.com/javase/6/docs/technotes/guides//security/StandardNames.html#SSLContext | |
ctx = SSLContext.getInstance("TLSv1"); | |
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); | |
System.out.println("Configured Protocol: " + ctx.getProtocol()); | |
System.out.println("Provider:\n Info: " + ctx.getProvider().getInfo() | |
+ "\n Name: " + ctx.getProvider().getName()); | |
// SslSocketUtils.printCertificateInformation(alias); | |
System.out.println("Locating socket factory for SSL..."); | |
if (true == isServer) { | |
// System.out.println("Starting server socket on port " + port + "..."); | |
// SSLServerSocketFactory serverFactory = ctx.getServerSocketFactory(); | |
// SSLServerSocket serverSocket = (SSLServerSocket) serverFactory | |
// .createServerSocket(port); | |
// serverSocket.setEnabledProtocols(new String[] { "TLSv1" }); | |
} else { | |
if (host == null) { | |
throw new Exception("The host must not be null"); | |
} | |
SSLSocketFactory factory = ctx.getSocketFactory(); | |
System.out | |
.println("Creating secure socket to " + host + ":" + port); | |
this.socket = (SSLSocket) factory.createSocket(host, port); | |
// this.socket.setEnabledProtocols(new String[] { | |
// "TLSv1", "SSLv3", "SSLv2Hello" }); | |
} | |
} | |
public void setHost(String host) | |
{ | |
this.host = host; | |
} | |
public void setPort(int port) | |
{ | |
this.port = port; | |
} | |
public SSLSocket getSocket() | |
{ | |
return this.socket; | |
} | |
public static void printEnabledArray(String[] enabled, String what) | |
{ | |
System.out.println("Enabled " + what + ":"); | |
for (String s : enabled) | |
{ | |
System.out.println(" " + s); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Good stuff! I need to learn me some Java. :)