Example: JSSE client servlet

/* 
 * 
 *  This material contains programming source code for your 
 *  consideration.  These examples have not been thoroughly 
 *  tested under all conditions.  IBM, therefore, cannot 
 *  guarantee or imply reliability, serviceability, or function 
 *  of these program.  All programs contained herein are 
 *  provided to you "AS IS".  THE IMPLIED WARRANTIES OF 
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 *  ARE EXPRESSLY DISCLAIMED.  IBM provides no program services for 
 *  these programs and files. 
 * 
 */ 
import java.io.*; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.security.Security; 
import java.security.KeyStore; 
import javax.net.ssl.SSLServerSocketFactory; 
import javax.net.ssl.SSLSocketFactory; 
import javax.net.ssl.SSLServerSocket; 
import javax.net.ssl.SSLSocket; 
import javax.net.ssl.SSLSession; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import com.ibm.net.ssl.SSLContext; 
import com.ibm.net.ssl.TrustManagerFactory; 
import com.ibm.net.ssl.TrustManager; 
import com.ibm.net.ssl.KeyManagerFactory; 

/* 
 * ServerJsse and ClientJsse 
 * 
 * Sample applications to demonstrate a simple client/server interaction using JSSE.
 * They communicate using all enabled cipher suites. 
 * 
 * The ServerJsse and ClientJsse use different KeyStore files called
 * "clientAppKeys.jks" and "serverAppKeys.jks" protected by a password and assumed
 * to be in the current working directory. In a real application, the client and
 * server should also have their own KeyStore files. 
 * 
 * You can build these sample program classes by issuing the following command but
 * first make sure that the ibmjsse.jar file shipped in the 
 * "WAS_PRODUCT_ROOT/java/ext" is in your CLASSPATH or extensions directory.
 * This is a servlet, so you also need "WAS_PRODUCT_ROOT/lib/j2ee.jar to compile.
 * 
 *     javac ServerJsse.java 
 *     javac ClientJsse.java 
 * 
 * 
 * Running the client/server application requires that the Server is started first
 * and then the Client application. 
 * 
 * To start the ServerJsse, run the following command: 
 * 
 *     java ServerJsse
 * 
 * The ServerJsse uses port 8050 by default. Once ServerJsse has started it waits
 * for the ClientJsse connection. 
 * 
 * To start the client, issue the following command: 
 * 
 *     java ClientJsse hostname:port
 * 
 * where hostname:port is the optional host:port running SeverJsse. 
 * The default is localhost:8050. 
 * 
 */ 

public class ClientJsse extends HttpServlet { 
  static int N = 50, L = 100, R = 2; 
  static PrintWriter out = new PrintWriter(System.out); 
  static SSLContext sslContext; 
  

  // Open the KeyStore to obtain the Trusted Certificates. 
  // KeyStore is of type "JKS". Filename is "clientAppKeys.jks"
  // and password is "myKeys". 
  public static void initContext() { 
    try { 
      Security.addProvider(new com.ibm.jsse.JSSEProvider()); 

      KeyStore ks = KeyStore.getInstance("JKS"); 
      ks.load(new FileInputStream("clientAppKeys.jks"), "myKeys".toCharArray()); 
      KeyManagerFactory kmf = KeyManagerFactory.getInstance("IbmX509"); 
      kmf.init(ks, "myKeys".toCharArray()); 

      TrustManager[] tm; 
      TrustManagerFactory tmf = TrustManagerFactory.getInstance("IbmX509"); 
      tmf.init(ks); 
      tm = tmf.getTrustManagers(); 

      sslContext = SSLContext.getInstance("SSL"); 
      sslContext.init(kmf.getKeyManagers(), tm, null); 
    }
    catch (Throwable t) { 
      out.println("Failed to read clientAppKeys.jks file."); 
      t.printStackTrace(); 
    } 
  } 
  
  public void doGet(HttpServletRequest q, HttpServletResponse r) { 
    r.setContentType("text/html"); 
    String[] args = new String[1]; 
    args[0] = getInitParameter("hostname"); 

    // send result to the caller 
    try { 
      out = r.getWriter(); 
      out.println("<html>"); 
      out.println("<head>title>Client JSSE Session</title></head>"); 
      out.println("<body>"); 
      out.println("<h1>Client JSSE Session (starting)</h1>"); 
      out.flush(); 
      out.println("<pre>"); 

      main(args); 

      out.println("</pre>"); 
      out.println("</body></html>"); 
      out.flush(); 
      out.close(); 

    }
    catch (Exception e) { 
      out.println("Exception in ClientJsse Servlet: " + e.getMessage()); 
      e.printStackTrace(); 
    } 
  }//end  public void doGet(...) 
  
  

 /** Starts the ClientJsse application as stand alone application. 
   * @param args the name of the host the ClientJsse should connect to 
   */ 
  public static void main(String args[]) throws Exception { 

    int i, j, len, ci_nonanon; 

    String host = "127.0.0.1"; 
    int port = 8050; 

    if ((args != null) && (args.length > 0)) { 
      host = args[0]; 
      i = host.indexOf(':'); 
      if (i != -1) { 
        try { 
          port = Integer.parseInt(host.substring(i+1)); 
          host = host.substring(0,i); 
        }
        catch (Exception e) { 
          System.err.println("ClientJsse: wrong address format"); 
          e.printStackTrace(); 
          throw e; 
        } 
      } 
    } 

    if (args.length > 1) 
      N = Integer.parseInt(args[1]); 
    if (args.length > 2) 
      L = Integer.parseInt(args[2]); 
    byte buffer[] = new byte[L]; 

    out.println("ClientJsse: started."); 

    initContext(); 

    try { 
      if (sslContext == null) { 
        out.println ("ClientJsse:  SSL client context NOT created."); 
        return; 
      } 

      out.println("ClientJsse: SSL client context created."); 
      SSLSocketFactory factory = sslContext.getSocketFactory(); 
      String[] cipher_suites =
         sslContext.getSocketFactory().getSupportedCipherSuites(); 

      out.println("ClientJsse: enabled cipher suites"); 
      for (i=0, ci_nonanon=0; i < cipher_suites.length; i++) { 
        if (cipher_suites[i].indexOf("_anon_") < 0) { 
          ci_nonanon++; 
        } 
        out.println("   " + cipher_suites[i]); 
      } 
      out.flush(); 
      SSLSocket ssl_sock; 
      OutputStream ostr; 
      InputStream istr; 
      long t; 
      String[] ecs = new String[1]; 

      out.println("\n "); 
      for (int csi = 0; csi < ci_nonanon; csi++) { 
        // Remove anonymous cipher suites.
        // TrustManager requires a personal certificate. 
        ecs[0] = cipher_suites[csi]; 
        if (ecs[0].indexOf("_anon_") >= 0) { 
          continue; 
        } 
        for (int n = 0; n < R; n++) { 
          t = System.currentTimeMillis(); 
          try { 
            ssl_sock = (SSLSocket) factory.createSocket(host, port); 
            ssl_sock.setEnabledCipherSuites(ecs); 

            ssl_sock.startHandshake(); 
            SSLSession session = ssl_sock.getSession(); 
            out.println(" "); 
            out.println("\nClientJsse: SSL connection established"); 
            out.println("   cipher suite:       " + session.getCipherSuite()); 
          }
          catch (Exception se) { 
            out.println(" "); 
            out.println("\nClientJsse: can't connect using: " + 
                        cipher_suites[csi] + "\n" + se); 
            break; 
          } 

          if (L > 0) { 
            istr = ssl_sock.getInputStream(); 
            ostr = ssl_sock.getOutputStream(); 

            for (j=0; j < N; j++) { 
              if ((j==N-1) && (n == R-1) && (csi == ci_nonanon - 1)) 
                buffer[0] = (byte)-1; 
              ostr.write(buffer, 0, L); 
              for (len = 0;;) { 
                try { 
                  if ((i = istr.read(buffer, len, L-len)) == -1) { 
                    out.println("ClientJsse: SSL connection dropped by partner."); 
                    istr.close(); 
                    return; 
                  } 
                  // out.println("ClientJsse: " + i + " bytes received."); 
                  if ((len+=i) == L) break; 
                }
                catch (InterruptedIOException e) { 
                  // out.println("ClientJsse: timeout.\n"); 
                } 
              } 
            } 
          } 
          out.println("Messages = " + N*2 + "; Time = " + 
                     (System.currentTimeMillis() - t)); 
          ssl_sock.close(); 
          out.println("ClientJsse: SSL connection closed."); 
          out.flush(); 
        } 
      } 

      Thread.sleep(1500); 

      // Example using plain sockets 
      if (L > 0) { 
        Socket sock = new Socket(host, port); 
        out.println(" "); 
        out.println("\nClientJsse: Plain Socket connection established."); 
        istr = sock.getInputStream(); 
        ostr = sock.getOutputStream(); 
        t = System.currentTimeMillis(); 
        for (j=0; j < N; j++) { 
          ostr.write(buffer, 0, L); 
          for (len = 0;;) { 
            if ((i = istr.read(buffer, len, L-len)) == -1) { 
              out.println("ClientJsse: connection dropped by partner."); 
              return; 
            } 
            if ((len+=i) == L) break; 
          } 
        } 
        out.println("Messages = " + N*2 + "; Time = " + 
                   (System.currentTimeMillis() - t)); 
        sock.close(); 
        out.println("ClientJsse: Plain Socket connection closed."); 
        Thread.sleep(1500); 
      } 
    }
    catch (Exception e) { 
      out.println(e); 
    } 
    out.println(" "); 
    out.println("ClientJsse: terminated."); 
    out.flush(); 
  }//end main(...) 
}//end class