| /* | |
| * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved. | |
| * | |
| * This program and the accompanying materials are made available under the | |
| * terms of the Eclipse Public License v. 2.0, which is available at | |
| * http://www.eclipse.org/legal/epl-2.0. | |
| * | |
| * This Source Code may also be made available under the following Secondary | |
| * Licenses when the conditions for such availability set forth in the | |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, | |
| * version 2 with the GNU Classpath Exception, which is available at | |
| * https://www.gnu.org/software/classpath/license.html. | |
| * | |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | |
| */ | |
| import javax.net.ssl.SSLSocket; | |
| import javax.net.ssl.SSLSocketFactory; | |
| import javax.net.ssl.SSLServerSocketFactory; | |
| import javax.net.ssl.SSLException; | |
| import javax.net.ssl.SSLHandshakeException; | |
| import javax.net.ServerSocketFactory; | |
| import java.io.InputStreamReader; | |
| import java.io.OutputStreamWriter; | |
| import java.io.BufferedReader; | |
| import java.io.BufferedWriter; | |
| import java.io.IOException; | |
| import com.sun.ejte.ccl.reporter.SimpleReporterAdapter; | |
| public class CipherTest { | |
| private static final String DEFAULT_HOSTNAME = "localhost"; | |
| private static final int DEFAULT_PORT = 8181; | |
| private static final String HTTP_GET_REQUEST = "GET / HTTP/1.0"; | |
| private static String serverHostname = null; | |
| private static int serverPort = -1; | |
| // Default and Supported chipher set | |
| private static String[] DEFAULT_CIPHERS = null; | |
| private static String[] SUPPORTED_CIPHERS = null; | |
| // Flags | |
| private static final String INTERACTIVE_OPTION = "-i"; | |
| private static final String HELP_OPTION = "-h"; | |
| private static final String DEBUG_OPTION = "-d"; | |
| private static final String VERBOSE1_OPTION = "-v"; | |
| private static final String VERBOSE2_OPTION = "-verbose"; | |
| private static final String HOST_OPTION = "-host"; | |
| private static final String PORT_OPTION = "-port"; | |
| private static final String SHOULD_PASS_OPTION = "-shouldPass"; | |
| private static final String SHOULD_FAIL_OPTION = "-shouldFail"; | |
| private static final String ENABLED_CIPHER_OPTION = "-enabledCipher"; | |
| private static boolean VERBOSE_FLAG = false; | |
| private static void usage() { | |
| System.out.println("usage: CipherTest [-i] [-d] [-h] [-host hostname] [-port port#] -shouldPass <comma-spa-ciphers> [-v|-verbose]"); | |
| System.out.println("-i interactive flag"); | |
| System.out.println("-d debug mode"); | |
| System.out.println("-v verbose mode"); | |
| System.out.println("-verbose verbose mode"); | |
| System.out.println("-h help/usage"); | |
| System.out.println("-host hostname - host to connect to"); | |
| System.out.println("-port port# - port to connect to"); | |
| System.out.println("-enabledCiphers - comma separated list of ciphers that should be "); | |
| System.out.println("-shouldPass - comma separated list of ciphers that should pass"); | |
| System.out.println("-shouldFail - comma separated list of ciphers that should fail"); | |
| } | |
| private static void verbose(String msg) { | |
| if( VERBOSE_FLAG) | |
| System.out.println(msg); | |
| } | |
| public static void main(String[] args) throws Exception { | |
| boolean interactive = false; | |
| boolean debug = false; | |
| boolean help = false; | |
| //Set<String> shouldPass = new Set<String>(); | |
| //Set<String> shouldFail = new Set<String>(); | |
| String shouldPass = null; | |
| String shouldFail = null; | |
| String enabledCipherAsString = null; | |
| for(int i=0; i<args.length; i++) { | |
| if( args[i].intern() == INTERACTIVE_OPTION.intern() ) { | |
| interactive = true; | |
| } else if( args[i].intern() == HELP_OPTION.intern() ) { | |
| help = true; | |
| } else if( args[i].intern() == VERBOSE1_OPTION.intern() ) { | |
| VERBOSE_FLAG = true; | |
| } else if( args[i].intern() == VERBOSE2_OPTION.intern() ) { | |
| VERBOSE_FLAG = true; | |
| } else if( args[i].intern() == DEBUG_OPTION.intern() ) { | |
| debug = true; | |
| } else if( args[i].intern() == HOST_OPTION.intern() ) { | |
| serverHostname = args[++i]; | |
| } else if( args[i].intern() == PORT_OPTION.intern() ) { | |
| serverPort = Integer.parseInt(args[++i]); | |
| } else if( args[i].intern() == SHOULD_PASS_OPTION.intern() ) { | |
| shouldPass = args[++i]; | |
| /* | |
| * Workaround for JavaSE bug (6518827) where | |
| * arguments of length 0 are not passed in on Windows. | |
| */ | |
| if (shouldPass.startsWith("-")) { | |
| // a "" param was skipped | |
| shouldPass = ""; | |
| i--; | |
| } | |
| } else if( args[i].intern() == SHOULD_FAIL_OPTION.intern() ) { | |
| shouldFail = args[++i]; | |
| } else if( args[i].intern() == ENABLED_CIPHER_OPTION.intern() ) { | |
| enabledCipherAsString = args[++i]; | |
| } else { | |
| System.out.println("Unrecognized option: " + args[i]); | |
| usage(); | |
| System.exit(10); | |
| } | |
| } | |
| for(int i=0; i<args.length; i++) { | |
| verbose("Arg[" + i + "] " + args[i]); | |
| } | |
| if( help) { | |
| usage(); | |
| System.exit(0); | |
| } | |
| if( debug ) { | |
| System.setProperty("javax.net.debug", "all"); | |
| } | |
| if( shouldPass == null ) { | |
| usage(); | |
| System.exit(11); | |
| } | |
| if( serverHostname == null ) | |
| serverHostname = DEFAULT_HOSTNAME; | |
| if( serverPort == -1 ) | |
| serverPort = DEFAULT_PORT; | |
| initCiphers(); | |
| if( interactive ) { | |
| interactive(); | |
| } else { | |
| nonInteractive(enabledCipherAsString, shouldPass, shouldFail); | |
| } | |
| } | |
| private static void interactive() | |
| throws IOException { | |
| BufferedReader reader = | |
| new BufferedReader(new InputStreamReader(System.in)); | |
| while(true) { | |
| System.out.println(); | |
| System.out.print( | |
| "Enter number of cipher or cipher-name to enable on this client: "); | |
| String s = reader.readLine(); | |
| CipherTest ct = null; | |
| try { | |
| int num = Integer.parseInt(s); | |
| ct = new CipherTest(num, SUPPORTED_CIPHERS[num], null); | |
| } catch(Exception e) { | |
| // try it as a string | |
| ct = new CipherTest(s, s, null); | |
| } | |
| ct.run(); | |
| } | |
| } | |
| private static void nonInteractive(String enabledCipher, | |
| String shouldPass, String shouldFail) { | |
| // if( enabledCipher == null ) { | |
| // for(int i=0; i<SUPPORTED_CIPHERS.length; i++) { | |
| // CipherTest ct = new CipherTest(i, SUPPORTED_CIPHERS[i], shouldFail); | |
| // ct.run(); | |
| // } | |
| // } else { | |
| // CipherTest ct = new CipherTest(enabledCipher, shouldPass, shouldFail); | |
| // ct.run(); | |
| // } | |
| CipherTest ct = new CipherTest(enabledCipher, shouldPass, shouldFail); | |
| ct.run(); | |
| } | |
| private static void nonInteractive(String[] enabledCipher, | |
| String shouldPass, String shouldFail) { | |
| // TODO | |
| } | |
| private static SimpleReporterAdapter stat = | |
| new SimpleReporterAdapter("appserv-tests"); | |
| private int startCipher = -1; | |
| String[] ciphers = null; | |
| String shouldPass; | |
| String shouldFail; | |
| private String testId = null; | |
| public CipherTest(int start, String shouldPass, String shouldFail) { | |
| startCipher = start; | |
| ciphers = new String[1]; | |
| ciphers[0] = SUPPORTED_CIPHERS[startCipher]; | |
| this.shouldPass = shouldPass; | |
| this.shouldFail = shouldFail; | |
| } | |
| public CipherTest(String cipherName, String shouldPass, String shouldFail) { | |
| if( cipherName != null ) { | |
| ciphers = new String[1]; | |
| ciphers[0] = cipherName; | |
| } | |
| this.shouldPass = shouldPass; | |
| this.shouldFail = shouldFail; | |
| } | |
| public void run() { | |
| try { | |
| testId = "SSL cipher test - " + ciphers[0]; | |
| stat.addDescription("Security::SSL cipher test " + ciphers[0]); | |
| doSSLTest(ciphers); | |
| verbose("Supported cipher suite: " + ciphers[0]); | |
| passed(ciphers); | |
| //System.exit(0); | |
| } catch(SSLHandshakeException e) { | |
| failed(ciphers); | |
| verbose("Unsupported (SSLHandshakeException) ciphers: " + ciphers[0] + " ..."); | |
| } catch(SSLException e) { | |
| failed(ciphers); | |
| verbose("SSLException with ciphers: " + ciphers[0] + e.getMessage()); | |
| } catch(IOException e) { | |
| failed(ciphers); | |
| verbose("IOException with ciphers: " + ciphers[0] + " ..."); | |
| } finally { | |
| stat.printSummary(testId); | |
| } | |
| } | |
| private void passed(String[] thatPassed) { | |
| for(int i=0; i<thatPassed.length; i++) { | |
| int index = shouldPass.indexOf(thatPassed[i]); | |
| if( index < 0 ) { | |
| // is not in the should pass, test failed | |
| System.out.println("Cipher - " + thatPassed[i] + | |
| " - pased, but should not have. Test failed"); | |
| stat.addStatus(testId, stat.FAIL); | |
| return; | |
| //System.exit(1); | |
| } | |
| } | |
| System.out.println("Test passed"); | |
| stat.addStatus(testId, stat.PASS); | |
| //System.exit(0); | |
| } | |
| private void failed(String[] thatFailed) { | |
| for(int i=0; i<thatFailed.length; i++) { | |
| int index = shouldPass.indexOf(thatFailed[i]); | |
| if( index >= 0 ) { | |
| // is in the should pass, but did not | |
| System.out.println("Cipher - " + thatFailed[i] + | |
| " - failed, but should have passed. Test failed"); | |
| stat.addStatus(testId, stat.FAIL); | |
| return; | |
| //System.exit(1); | |
| } | |
| } | |
| System.out.println("(Negative) Test passed"); | |
| stat.addStatus(testId, stat.PASS); | |
| //System.exit(0); | |
| } | |
| private void doSSLTest(String[] enableCiphers) throws IOException { | |
| SSLSocketFactory sslSocketFactory = | |
| (SSLSocketFactory)SSLSocketFactory.getDefault(); | |
| SSLSocket secureSocket = (SSLSocket) | |
| sslSocketFactory.createSocket(serverHostname, serverPort); | |
| if( enableCiphers != null ) | |
| secureSocket.setEnabledCipherSuites(enableCiphers); | |
| BufferedWriter buffWriter = new BufferedWriter( | |
| new OutputStreamWriter(secureSocket.getOutputStream())); | |
| buffWriter.write(HTTP_GET_REQUEST); | |
| buffWriter.newLine(); | |
| buffWriter.newLine(); | |
| buffWriter.flush(); | |
| //buffWriter.close(); | |
| //System.out.println("Written request to server: " + HTTP_GET_REQUEST); | |
| BufferedReader buffReader = new BufferedReader( | |
| new InputStreamReader(secureSocket.getInputStream())); | |
| String readin = null; | |
| while( (readin=buffReader.readLine()) != null ) { | |
| //System.out.println(readin); | |
| } | |
| } | |
| private static void initCiphers() { | |
| ServerSocketFactory ssf = SSLServerSocketFactory.getDefault(); | |
| SSLServerSocketFactory sslssf = null; | |
| if( ssf instanceof SSLServerSocketFactory ) { | |
| sslssf = (SSLServerSocketFactory)ssf; | |
| } else { | |
| System.out.println(ssf.getClass().getName()); | |
| System.exit(1); | |
| } | |
| DEFAULT_CIPHERS = sslssf.getDefaultCipherSuites(); | |
| SUPPORTED_CIPHERS = sslssf.getSupportedCipherSuites(); | |
| for(int i=0; i<DEFAULT_CIPHERS.length; i++) { | |
| verbose("Default cipher[" + i + "] "+DEFAULT_CIPHERS[i]); | |
| } | |
| for(int i=0; i<SUPPORTED_CIPHERS.length; i++) { | |
| verbose("Supported cipher[" + i + "] " + SUPPORTED_CIPHERS[i]); | |
| } | |
| } | |
| } |