import java.net.*; import javax.net.ssl.*; import java.util.*; import java.io.*; /** * This class is a JSSE server that sits and listens for an incoming SSL * connection. Once a connection is made, the server reads a "message" * (defined as a stream terminated by ) and sends back a modified * version of the message to the client before closing the connection. *

The code to perform the SSL stuff is all in "main" - the use of other * methods is limited just to displaying information, so that you should * only need to read the "main" code to see what order things are done. *

Built using JDK1.4 and tested on Windows 2000 * @author Nick Hudson * @version 1.0 */ public class ExampleSSLServer { static Object syncObject = new Object(); /** * Report a message to System.out * @param doTrace true if you want the message to appear, false otherwise * @param message the message to be sent to System.out */ public static void trace(boolean doTrace, String message) { if (doTrace) { synchronized(syncObject) { System.out.println(message); } } } /** * Display usage information */ public static void usage() { trace(true,"\nUsage: java ExampleSSLServer " + " [trace]"); trace(true," port : port number to listen on"); trace(true," ciphers : types of cipher suites to enable :-"); trace(true," 'c' : suites that use server-cert"); trace(true," 'a' : anonymous (no server-cert)"); trace(true," trace : (optional) tracing to enable:-"); trace(true," 'j' : turn on JSSE debug tracing"); trace(true," 't' : turn on program tracing"); } /** * This method looks at the run-time environment in an attempt to check * if things may need setting up for JSSE to work properly. It reports * any areas of concern but does not abort. */ public static void checkEnvironment() { // Check that a keystore has been specified. JSSE doesn't assume a // default value for keystore, so the only way we'll find one is if // the system properties have been set. String keyStoreName = System.getProperty("javax.net.ssl.keyStore"); if (keyStoreName == null) { // Tell them there may be a problem, but we don't abort; there // will be an SSLException if they try and use non-anonymous // ciphers trace(true, "\nYou have not specified a keystore, which means that the program will not"); trace(true, "be able to use cipher suites that require a certificate. To specify a"); trace(true, "keystore, use e.g. :\n"); trace(true, " java -Djavax.net.ssl.keyStore=\"\" ...\n"); } else { // The user has specified a keystore, check that they have supplied // a password if (System.getProperty("javax.net.ssl.keyStorePassword") == null) { trace(true, "\nYou have not specified a keystorePassword, which means that the if your"); trace(true, "keystore has a non-null password, JSSE won't be able to read certificate"); trace(true, "information from it - in this case you may see a \"Cannot recover key\"."); trace(true, "message. To specify a keystore password, use e.g. :\n"); trace(true, " java -Djavax.net.ssl.keyStorePassword=\"\" ...\n"); } } } /** * Display various information out of a HandshakeCompletedEvent object. * @param event HandshakeCompletedEvent object. */ public static void showHandshakeInfo(HandshakeCompletedEvent event) { // This method may be called from a separate thread, so all of // the output here in a synchronized block to make sure it doesn't // get interspersed with other messages. synchronized(syncObject) { trace(true,"Negotiated cipher suite " + event.getCipherSuite()); java.security.cert.Certificate lc[] = event.getLocalCertificates(); if (lc != null) { trace(true,"" + lc.length + " local certificates used :"); for (int i=0; i 2) { String traceOptions = args[2].toLowerCase(); isTracing = (traceOptions.indexOf("t") != -1); if (traceOptions.indexOf("j") != -1) { // Enable JSSE tracing trace(isTracing, "Enabling JSSE debug tracing"); System.setProperty("javax.net.debug","ssl"); } } } catch (Exception e) { trace(true,e.toString()); // They invoked the program with invalid arguments usage(); return; } checkEnvironment(); SSLServerSocketFactory ssf = null; SSLServerSocket listenSocket = null; try { trace(true,"Configuring SSLServerSocketFactory, please wait..."); ssf = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); trace(isTracing,"Creating new ServerSocket"); listenSocket = (SSLServerSocket)ssf.createServerSocket(portNumber); // Look at each of the supported cipher suites, and build a list // of those that we want to use, based on the user's requirements String[] supportedSuites = listenSocket.getSupportedCipherSuites(); HashSet set = new HashSet(); trace(isTracing,"Supported cipher suites are:"); for (int i=0; i" + message + "<--\n"); // And send it back to the client message = "JSSE Server says thank-you for saying : " + message; byte[] reply = message.getBytes(); trace(true,"Send to the client: -->" + message + "<--\n"); outStream.write(reply); } catch (Exception e) { trace(true,"Exception while communicating with client :\n" + e); trace(true,"-- program terminating"); return; } finally { try { // "Socket.close()" requires a catch clause if (clientSocket != null) { trace(isTracing,"Closing client socket"); clientSocket.close(); } if (listenSocket != null) { trace(isTracing,"Closing server socket"); listenSocket.close(); } } catch (Exception e) { trace(true,"Exception when closing sockets:\n" + e.toString()); } } } }