CS 5523 Operating Systems
Using Secure Sockets in Java

In the example discussed in this handout, a client ( TCPSecureClientNoAuth) uses a secure socket to send a message to a server (TCPSecureServer) which in turn sends a response back that includes the portion of the original message that it read. The communication uses an authenticated server but no client authentication. Because the server authenticates itself, it must have a key store with both a public/private key and a certificate. The key store used in this example is cs5523keys, which the server assumes to be in the same directory as its class files. This key store contains a single entry called kay that is used when the server authenticates itself to the client. The password for both cs5523keys and kay is cs5523. In this example the location, name and password of the key store are specified within the TCPSecureServer.java code. Alternatively you can pass this information in as parameters on the java run line.

Both the client and the server must have trust stores that contain a trusted certificate for kay. (Alternatively the client's trust store could contain a certificate representing kay that has been signed by a trusted certificate authority such as Verisign. Of course this costs money and since we are cheap, we will just trust kay.) The trust store used by the client and server in this example is cs5523certs. The password for cs5523certs is trustme. You can specify the location, name and password for the trust store within the program. In the example here, we pass the information in as parameters on the java run line.

The certificates.html file describes how to generate a key store such as cs5523keys and a trust store such as cs5523certs.

The Client

The TCPSecureClientNoAuth shown here establishes a secure socket to a server whose name and port are passed on the command line. The TCPSecureClientNoAuth program has a third command line argument, a message to be sent. The TCPSecureClientNoAuth sends the message over the secure socket and reads a response. The implementation does not guarantee that TCPSecureClientNoAuth reads everything that the server sends, since it only does one read.

import java.net.*;
import java.io.*;
import javax.net.ssl.*;


public class TCPSecureClientNoAuth {
    private static final int DEFAULT_SIZE = 1024;

    public static void main(String[] args) throws Exception {

        // Processing the command line arguments
        if (args.length < 3) {
            System.err.println("Too few arguments...need 3");
            System.err.println("USAGE: java TCPSecureClientNoAuth host port msg");
            System.exit(-1);
        }
        String serverName = args[0];
        String msg = args[2];
        int portNumber = -1;
        try {
            portNumber = Integer.parseInt(args[1]);
        } catch (IllegalArgumentException e) {
             System.err.println("Error converting port number " + portNumber);
             System.err.println("USAGE: java TCPSecureClientNoAuth host port msg");
             System.exit(-1);
        }


        // Setting up the secure socket with no client authentication
        SSLSocket socket = null;
        try {
            SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
            socket = (SSLSocket)factory.createSocket(serverName, portNumber);
            socket.startHandshake();   // Isn't necessary depending on how data is written
        } catch (Exception e) {
            System.err.println("Failed to set up unauthenticated SSL on port " + portNumber
                                + " to server " + serverName);
            e.printStackTrace();
            System.exit(-1);
        }
 
        // Sending a message on the secure socket and reading a reply
        try {
           DataOutputStream out = new DataOutputStream(socket.getOutputStream());
           String sendingString = "Sending:" + msg;
           out.write(sendingString.getBytes());
           out.flush();
           DataInputStream in = new DataInputStream(socket.getInputStream());
           byte [] buf = new byte[DEFAULT_SIZE];
           int bytesRead = in.read(buf);  // no guarantee here we have all, just some
           if (bytesRead > 0)
               System.out.println("Received: {" + new String(buf, 0, bytesRead) + "}");
           else
               System.out.println("Warning...did not receive any bytes");
         } catch (Exception e) {
            System.err.println("Error in sending or receiving the data...");
            e.printStackTrace();
            System.exit(-1);
         }
    }
}
Suppose that the server was listening for connections on port 16001 of host ten22.cs.utsa.edu. If the cs5523certs file is located at /home/krobbins/securityTest/jssesamples/cs5523certs, you can start the client with the following command to send the phrase HelloWorld! to the server.
java -Djavax.net.ssl.trustStore=/home/krobbins/securityTest/jssesamples/cs5523certs \
     -Djavax.net.ssl.trustStorePasword=trustme \
      TCPSecureClientNoAuth ten22.cs.utsa.edu 16001 HelloWorld! 

The Server

The TCPSecureServer.java takes one or two command line arguments. The first command line argument is the listening port. If a second command line argument is present, the server asks the client to authenticate itself. After establishing a connection, the server reads a phrase from the client (not guaranteed to be everything that was sent) and sends a response. The TCPSecureServer program might be run with the following:

java -Djavax.net.ssl.trustStore=/home/krobbins/securityTest/jssesamples/cs5523certs \
     -Djavax.net.ssl.trustStorePasword=trustme \
      TCPSecureServer 16001
The TCPSecureServer is:
import java.io.*;
import java.net.*;
import java.security.KeyStore;
import javax.net.*;
import javax.net.ssl.*;
import javax.security.cert.X509Certificate;


public class TCPSecureServer {

    public static void main(String args[])
    {
        // Processing the command line arguments
        if (args.length < 1) {
            System.err.println("Too few arguments...need 1 or 2");
            System.err.println("USAGE: java TCPSecureServer port [true]");
            System.exit(-1);
        }
        int portNumber = -1;
        try {
            portNumber = Integer.parseInt(args[0]);
        } catch (IllegalArgumentException e) {
            System.err.println("Error converting port number " + portNumber);
            System.err.println("USAGE: java TCPSecureServer port [true]");
            System.exit(-1);
        }


        // Set up the secure listening socket
        ServerSocket listenSocket = null;
        try {
            ServerSocketFactory theFactory = TCPSecureServer.getServerSocketFactory();
            listenSocket = theFactory.createServerSocket(portNumber);
            if (args.length >= 2) { // if two commmand line args, require client auth.
                ((SSLServerSocket)listenSocket).setNeedClientAuth(true);
            }
        } catch (Exception e) {
            System.err.println("Server died setting up SSL: " + e.getMessage());
            e.printStackTrace();
            System.exit(-1);
        }

        while (true) {
            Socket clientSocket = null;
            try {
                clientSocket = listenSocket.accept();
                Connection c = new Connection(clientSocket);
            } catch (IOException e) {
               System.err.println("Client connection failed Server died: " + e.getMessage());
               e.printStackTrace();
               try {
                  if (clientSocket != null)
                     clientSocket.close();
               } catch (Exception eclose) {
                 System.err.println("Failed closing client socket: " + eclose.getMessage());
                 eclose.printStackTrace();
               }
            }   
        }    
    }    


    private static ServerSocketFactory getServerSocketFactory() {
       SSLServerSocketFactory theFactory = null;
       try {
        // set up key manager to do server authentication
          SSLContext theContext;
          KeyManagerFactory theKeyManagerFactory;
          KeyStore theKeyStore;
          char[] thePassword = "cs5523".toCharArray();

          theContext = SSLContext.getInstance("TLS");
          theKeyManagerFactory = KeyManagerFactory.getInstance("SunX509");
          theKeyStore = KeyStore.getInstance("JKS");

          theKeyStore.load(new FileInputStream("cs5523keys"), thePassword);
          theKeyManagerFactory.init(theKeyStore, thePassword);
          theContext.init(theKeyManagerFactory.getKeyManagers(), null, null);

          theFactory = theContext.getServerSocketFactory();
          return theFactory;
       } catch (Exception e) {
          System.err.println("Failed to create a server socket factory...");
          e.printStackTrace();
       }
     return null;
   }
}



class Connection extends Thread {
    private static final int DEFAULT_SIZE = 1024;
    private Socket clientSocket;

    public Connection (Socket aClientSocket) {
       clientSocket = aClientSocket;
       this.start();
    }

    public void run()
    {
       try {
          DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
          DataInputStream in = new DataInputStream(clientSocket.getInputStream());
          System.out.println("Waiting for client message...");
          byte [] buf = new byte[DEFAULT_SIZE];
          int bytesRead = in.read(buf);
          String sendBack = "(Server Received [" + new String(buf, 0, bytesRead) + "]" +")";
          System.out.println("Echo..." + sendBack);
          out.write(sendBack.getBytes());
          out.flush();
        } catch (IOException e) {
          System.err.println("Server error processing response: " + e.getMessage());
          e.printStackTrace();
        } finally {
          try {
             clientSocket.close();
          } catch (IOException e) {
          }
        }  
    }    
}

Additional Documentation and Examples:

A more complete discussion can be found in the JavaTM Secure Socket Extenstion (JSSE) Reference Guide (found locally at JavaTM Secure Socket Extension (JSSE). Here are some code examples from that document:


Last revision: April 18, 2002 at 4:30 am by Kay A. Robbins