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: