Secure Internet
Applications using Java
Art Gittleman
The Java Secure Socket Extension
(JSSE), included with the J2SE version 1.4 and above,
enables secure Internet communications.
It implements the Secure Sockets Layer (SSL) protocol for implementing cryptography
on the Web. We start with an
introduction to HTTP in order to understand how a Web server and client
communicate.
Objectives:
Introduce HTTP
Introduce the Secure Sockets Layer
(SSL) protocol
Develop a simple web server and
client
Use JSSE to make the web server and
client secure
Use JSSE with other network
applications.
1. The
Hypertext Transfer Protocol (HTTP)
The Hypertext Transfer Protocol allows
a formal exchange of messages using well-specified formats. Before going further with networking we
describe HTTP, which we will use when writing our own HTTP client and server.
An HTTP client sends a request to the
server in which the first line has the form
Method
used Identifier for the resource Protocol version
The
following lines of the request are various request headers which provide
information about the capabilities of the client. After the request headers comes the data (if
any) to be sent to the server. For
example the request sent by the Safari browser to the server of Example 1 when
we enter the URL
http://localhost:1234/Users/artg/Documents/nsf/jsse/VerySimpleBrowser.java
is
GET
/Users/artg/Documents/saying.txt HTTP/1.1
Accept:
*/*
Accept-Language:
en
Accept-Encoding:
gzip, deflate
User-Agent:
Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)
AppleWebKit/416.11 (KHTML, like
Gecko) Safari/416.12
Connection:
keep-alive
Host:
localhost:1234
In the first line of the request, GET
is the method used; we are asking the server to get us a file. The path to that file is the second part of
that first line, while the protocol, HTTP/1.1, is the third. The remaining lines after the
request are request headers of the form
name: value
They
are:
Field Description
Accept Specifies the types of files that the client
is prepared to accept.
*/*
includes any file type, because * matches anything.
Accept-Language en denotes English.
Accept-Encoding The client will
accept zipped files.
User-Agent Identifies the client, the
Safari browser.
Connection Specifies the type of
connection.
keep-alive expresses
the client's wish to keep the connection alive
for multiple
requests.
Host Identifies the
address and port of the server.
Our client has sent a request followed
by six request headers selected from various header types available. Other clients may choose a different
selection of request headers.
An HTTP server responds to a request
with a status line followed by various response headers. The status line has the form
HTTP
Version Status Code Reason
The
response headers help the client to interpret and display the response. Our
very simple web server sends the status line and only one response header. In response to the above request it sends
HTTP/1.1
200 OK
Content-type:
text/plain
The server sends a status line showing
the HTTP version, 1.1 in this example, a code, 200,
and a brief description of the code, OK.
Other servers respond with a different selection of response
headers. Status codes have five types,
distinguished by their first digit. Some
are:
Success 200 OK
Redirection 301
Moved Permanently
Client Error 400 Bad Request
404 Not Found
406 Not Acceptable
Server Error 501
Not Implemented
2. Secure
Sockets Layer (SSL)
Netscape developed SSL in 1994. The
International Engineering Task Force standards body renamed it Transport Layer
Security (TLS). TLS 1.0 is similar to
SSL 3.0. SSL allows each party to
authenticate the other to ensure that the communicating parties are who they
say they are. SSL allows for encryption
so the messages can not be read by unauthorized third parties. SSL is also able to ensure that data has not
been modified.
Secret key cryptography is the most
efficient way to encrypt and decrypt information, but it requires that both
parties know the key. Public key
cryptography can be used to transmit the secret key. Public key cryptography use private and
public keys. The creator keeps the
private key secret and publishes the public key.
The server and client use public key
cryptography to transmit the secret key.
The server sends the client its public key, and then the client uses it
to encode the secret key and transmit it to the server. The server decodes the secret key with its
private key.
One problem involves the sending of
the server's public key. How can the
client know that it is really the server's key and not one sent by an impostor? To provide verification the server sends a
certificate issued by a trusted organization. The certificate authority
digitally signs the certificate using its private key. The trusted certificate authority's public
key is well known.
To ensure that the data is not
changed during transmission a hash message authentication code (HMAC) may be
used. A hash function computes a hash
code from the data to be transmitted.
This hash code is then encoded with the secret key and transmitted along
with the data. The receiver decodes this
message digest and hashes the data received.
If the decoded message digest is the same as the computed hash value of
the transmitted data, then the receiver knows that the message was unchanged
during transmission. Changing the
message would have cause the hash code to change It is
not practical to figure out how to change the message to produce the same hash
code.
The SSL Protocol
1. (Client) Sends information about the SSL
version it supports and the
types
of ciphers it supports.
2. (Server) Chooses an SSL version and a cipher
that both the client of
the server support.
3. (Server) Optionally
sends the client a certificate. It is used
whenever
server authentication is required.
4.
(Server) Optionally
requests a certificate from the client.
5.
(Server) Optional and is used if more is
needed to exchange keys.
6.
(Server) The server is finished with the
setup.
7.
(Client) Sends a certificate if it was
requested.
8.
(Client) The client creates a secret
key, encodes it using the
server's public
key and transmits it to the server.
9. (Client) Optionally
helps the server authenticate the client.
10.
(Client) Tells the server to change to encrypted
mode.
11.
(Client) Tells the server that it is ready for secure
communications.
12.
(Server) Tells the client to change to encrypted mode.
13.
(Server) Tells the client that it is ready for secure
communications.
Now the client and the server can
communicate using the agreed upon secret key algorithm and the agreed upon
cryptographic hash function.
3. A Client and
Server without SSL
Before coding a secure server and
client, we present a simple example which does not use SSL. The server is very simple. We pass a port number on the command line. The standard ports use numbers below 1024 so
we will choose port number 1234. The java.net
package contains the network interface that abstracts the details of the
network connection.
The ServerSocket class represents the server. Its accept method allows the server to wait for a client to
connect. To handle multiple clients
concurrently the server would ordinarily create a thread for each client, but
we omit this step in this simple example.
Our server quits after handling one client. It would be easy to add a loop so the server
returns to the accept statement to accept another connection after the
current client is finished.
Once the client connects we create a
BufferedReader to read from the client and a PrintWriter to write to the client. This simple server reads the first line from
the client and rejects any request that does not start with GET. It gets the next part of that first line read
and saves it as the filename to be served.
The server then reads from the client until it encounters a blank line. These are the request headers which it echoes
back to the client. This step is not
necessary but we do it here just to see what the headers are.
Next
the server creates a BufferedReader to read from the requested file. If that file cannot be found it will throw an
exception and abort. Otherwise the file
has been found and the server will send the status line, a request header, and
the contents of the requested file.
Example 1 VerySimpleWebServer.java
/*
Serves a text file to an HTTP client submitting a GET request.
*/
import java.net.*;
import java.io.*;
import java.util.StringTokenizer;
public class VerySimpleWebServer {
public static void
main(String [] args) {
String s;
try {
ServerSocket
server = new ServerSocket(Integer.parseInt(args[0]));
Socket client = server.accept();
System.out.println("VerySimpleWebServer
Connected on port "
+ args[0]);
BufferedReader
fromClient = new BufferedReader
(new InputStreamReader(client.getInputStream()));
PrintWriter toClient = new PrintWriter
(client.getOutputStream(),
true);
s=fromClient.readLine();
toClient.println(s);
StringTokenizer
tokens = new StringTokenizer(s);
if (!(tokens.nextToken()).equals("GET")) {
toClient.println("HTTP/1.0
501 Not Implemented");
toClient.println();
}
else {
String filename = tokens.nextToken();
while (!(s=fromClient.readLine()).equals(""))
toClient.println(s);
BufferedReader
file
= new BufferedReader(new FileReader(filename));
toClient.println("HTTP/1.1 200 OK");
toClient.println("Content-type: text/plain");
toClient.println();
while ((s=file.readLine()) != null)
toClient.println(s);
file.close();
}
fromClient.close();
toClient.close();
client.close();
}catch(Exception
e) {
e.printStackTrace();
}
}
}
To
start the server we use the command
java VerySimpleWebServer 1234
It
will wait for a client to connect. We
connect by entering
http://localhost:1234/Users/artg/Documents/sayings.txt
in
the Safari browser. The result is
GET
/Users/artg/Documents/sayings.txt HTTP/1.1
Accept:
*/*
Accept-Language:
en
Accept-Encoding:
gzip, deflate
User-Agent:
Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)
AppleWebKit/416.11 (KHTML, like
Gecko) Safari/416.12
Connection:
keep-alive
Host:
localhost:1234
HTTP/1.0
200 OK
Content-type:
text/plain
the three did feed the deer
happy days are here again
peter piper picked a peck of pickled peppers
Next we write our own client, a very
simple browser. To request the same file
we enter the command
java VerySimpleBrowser localhost
1234 /User/artg/Documents/sayings.txt
The
browser checks that the user entered three command-line arguments. If so it
creates a Socket to connect to the server, a BufferedReader to read from the server and a PrintWriter to write to the server. It sends the GET request, one
request header and the blank line that the protocol requires. It reads the status line and response headers
from the server and displays them. In
the case of VerySimpleWebServer the status line and response headers will be
preceded by the request and the request headers. After the client finds the
blank line from the server, it reads the file requested and displays it in the
console.
Example 2 VerySimpleBrowser.java
/*
Connects to a web server to download a text file.
*/
import java.net.*;
import java.io.*;
public class VerySimpleBrowser {
public static void
main(String [] args) {
String s;
if (args.length != 3){
System.out.println("Usage: java VerySimpleBrowser
host port file");
System.exit(1);
}
try {
int
port = Integer.parseInt(args[1]);
Socket server = new Socket(args[0],port);
System.out.println("Connected to host "
+ server.getInetAddress());
BufferedReader
fromServer = new BufferedReader
(new InputStreamReader(server.getInputStream()));
PrintWriter toServer = new PrintWriter
(server.getOutputStream(),true);
toServer.println("GET " + args[2] +
" HTTP/1.1");
toServer.println("Host:
" + args[0]+ ':' + args[1]);
toServer.println();
while (!(s=fromServer.readLine()).equals(""))
System.out.println(s);
while ((s=fromServer.readLine()) != null)
System.out.println(s);
fromServer.close();
toServer.close();
server.close();
}catch(Exception
e) {
e.printStackTrace();
}
}
}
The
result from the request
java VerySimpleBrowser localhost
1234 /User/artg/Documents/sayings.txt
is
Connected
to host localhost/127.0.0.1
GET
/Users/artg/Documents/sayings.txt HTTP/1.0
Host:
localhost:1234
HTTP/1.0
200 OK
Content-type:
text/plain
the three did feed the deer
happy days are here again
peter piper picked a peck of pickled peppers
Of
course we can use our client with other Web servers. For example the command
java VerySimpleBrowser www.cecs.csulb.edu
80 /~artg/TryURL.java
produces
Connected
to host www.cecs.csulb.edu/134.139.249.82
HTTP/1.1
200 OK
Date:
Tue, 15 Nov 2005 17:03:24 GMT
Server:
Apache/1.3.23 (Unix) (Red-Hat/Linux)
PHP/4.2.2 mod_perl/1.26
Last-Modified:
Wed, 11 Feb 1998 19:19:01 GMT
ETag: "e3962-1b7-34e1f9a5"
Accept-Ranges:
bytes
Content-Length:
439
Connection:
close
Content-Type:
text/plain
import java.net.*;
import java.io.*;
public class TryURL {
public static void
main(String [] args) {
BufferedReader
input;
try {
URL url = new URL(args[0]);
input = new BufferedReader(new InputStreamReader(url.openStream()));
String s;
while ((s=input.readLine())!= null)
System.out.println(s);
}catch(Exception
e) {
e.printStackTrace();
}
}
}
4. An SSL Client and Server
An SSL Client
The javax.net.ssl provides classes for the secure socket
package. It is included with the Java 2
Standard Edition versions 1.4 and up. We
use an SSLSocketFactory to create the secure socket. In general this enables us to configure the
socket without coupling to the specific implementation class. However we just use the getDefault method to accept the default configuration. This returns a subclass of the abstract SocketFactory class so we need to cast it to an SSLSocketFactory. The code
is
SSLSocketFactory factory =
(SSLSocketFactory)SSLSocketFactory.getDefault();
Once we have the factory we use its createSocket method to create an SSLSocket. The createSocket method in general returns a Socket
so we cast it to an SSLSocket. The code
is
SSLSocket server = (SSLSocket)factory.createSocket(args[0],port);
where
args[0]
is the host.
We add an optional callback to be
informed when the SSL handshaking has completed. The HandshakeCompletedListener interface contains the handshakeCompleted method which we implement to be notified upon
completion. We use the addHandshakeCompletedListener method to register a listener with the socket.
Example 3 VerySimpleJSSEBrowser.java
/*
Connects to a web server to download a text file. Uses SSL.
*/
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
public class VerySimpleJSSEBrowser {
public static void
main(String [] args) {
String s;
if (args.length != 3){
System.out.println("Usage: java VerySimpleBrowser
host port file");
System.exit(1);
}
try {
int
port = Integer.parseInt(args[1]);
SSLSocketFactory
factory
= (SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket
server = (SSLSocket)factory.createSocket(args[0],port);
server.addHandshakeCompletedListener(new Hand());
System.out.println("Connected to host "
+ server.getInetAddress());
BufferedReader
fromServer = new BufferedReader
(new InputStreamReader(server.getInputStream()));
PrintWriter toServer = new PrintWriter
(server.getOutputStream(),true);
toServer.println("GET " + args[2] +
" HTTP/1.1");
toServer.println("Host: " + args[0]+ ':'
+ args[1]);
toServer.println();
while (!(s=fromServer.readLine()).equals(""))
System.out.println(s);
while ((s=fromServer.readLine()) != null)
System.out.println(s);
fromServer.close();
toServer.close();
server.close();
}catch(Exception
e) {
e.printStackTrace();
}
}
}
class Hand implements HandshakeCompletedListener
{
public void handshakeCompleted(HandshakeCompletedEvent
e) {
System.out.println(e);
}
}
To connect to a secure server we use
port 443, the standard port for secure HTTP connections. Executing the command
java VerySimpleJSSEBrowser java.sun.com
443 /
results in
Connected
to host java.sun.com/209.249.116.141
javax.net.ssl.HandshakeCompletedEvent[source=704baa[SSL_RSA_WITH_RC4_128_MD5:
Socket[addr=java.sun.com/209.249.116.141,port=443,localport=54818]]]
HTTP/1.1
200 OK
Server:
Sun-Java-System-Web-Server/6.1
Date:
Tue, 15 Nov 2005 18:11:35 GMT
Content-type:
text/html;charset=ISO-8859-1
Set-Cookie:
SUN_ID=71.116.236.191:174411132078295; EXPIRES=Wednesday, 31-Dec-2025 23:59:59
GMT; DOMAIN=.sun.com; PATH=/
Set-cookie:
JSESSIONID=25F548B08059961839B64DFC582C8816;Path=/
Connection:
close
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN">
<html>
<head>
<title>Java Technology</title>
..... Remainder of the file omitted.
Executing the command
java VerySimpleJSSEBrowser
www.microsoft.com 443 /
returns
Connected
to host www.microsoft.com/207.46.198.30
javax.net.ssl.HandshakeCompletedEvent[source=39eeda[SSL_RSA_WITH_RC4_128_MD5:
Socket[addr=www.microsoft.com/207.46.198.30,port=443,localport=54868]]]
HTTP/1.1
200 OK
Connection:
close
Date:
Tue, 15 Nov 2005 18:25:47 GMT
Server:
Microsoft-IIS/6.0
P3P:
CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo
PSA PSD TAI TELo OUR SAMo
CNT COM INT NAV ONL PHY PRE PUR UNI"
X-Powered-By:
ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control:
private
Content-Type:
text/html; charset=utf-8
Content-Length:
22272
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0
Transitional//EN" >
<html
dir="ltr" lang="en">
....
Remainder of file omitted
During the handshake protocol
between the client and the server, the server sends a certificate. The java.sun.com and www.microsoft.com servers send certificates that have been
obtained from a certificate authority such as VeriSign. By default Java includes a cacerts (certificate authority certificates) file that
includes trusted authorities. When our
client receives a certificate it checks in the cacerts file for the signer of the certificate. If it is a trusted signer such as VeriSign it will be found and the certificate will be
validated. The secure client will then
accept the server as authentic and proceed.
Otherwise it will throw an exception.
When we create our own server we will have to provide a certificate for
clients.
For an even simpler client we can use
the Java URL class which supports various protocols including HTTP and HTTPS,
the secure HTTP. HTTPS is the same as
HTTP but it is implemented over a secure socket layer. The URL object hides the
details of the protocol so we do not explicitly create or read headers. We simply use the openStream method to read from the remote site.
Example 4 TryURL.java
import java.net.*;
import java.io.*;
public class TryURL {
public static void
main(String [] args) {
BufferedReader
input;
try {
URL
url = new URL(args[0]);
input = new BufferedReader(new InputStreamReader(url.openStream()));
String s;
while ((s=input.readLine())!= null)
System.out.println(s);
}catch(Exception
e) {
e.printStackTrace();
}
}
}
Executing
Example 4 with the command
java TryURL https://java.sun.com
will
return the home page of Sun's Java site via a secure server running on port
443. We could enter the same URL in a
browser to connect securely.
Next we build a very simple secure
server.
An SSL Server
We augment our very simple web
server of Example 1 to a secure server.
First we need to create a certificate for authentication. Java provides the keytool program to generate keys and jarsigner to create digital signatures. The generated keys go into the keystore, a file protected by a password. We use the command
keytool -genkey -keystore profstore
which
specifies the genkey option to generate public and private keys, and
the keystore option to name the keystore
file as profstore. keytool then prompts for the remaining information it needs.
Enter
keystore password:
abc123
What
is your first and last name?
[Unknown]:
Art Gittleman
What
is the name of your organizational unit?
[Unknown]:
Computer Science
What
is the name of your organization?
[Unknown]:
CSULB
What
is the name of your City or Locality?
[Unknown]:
Long Beach
What
is the name of your State or Province?
[Unknown]:
CA
What
is the two-letter country code for this unit?
[Unknown]:
US
Is
<CN=Art Gittleman, OU=Computer Science, O=CSULB, L=Long Beach, ST=CA,
C=US> correct?
[no]: y
The last question asks for verification
of the previously entered data. Once
that is verified, keytool prompts for a password for the private key. Each entry in the keystore
has an alias by which we refer to it.
Because we did not use the alias option on the command line, keytool gave us the default alias mykey.
Enter
key password for <mykey>
(RETURN if same as keystore
password): def456
This keytool command creates the profstore file which contains the generated keys. The public key is in a self-signed
certificate, meaning that it is signed with our private key. The default validity for the certificate is
six months. To authenticate our public key we would need to contact a
certificate authority, such as VeriSign,Inc.,
but we omit this step in this example.
Having created a certificate we
continue with the secure server. The SSLContext class holds the state information shared by
sockets created under this context. We configure it with key and trust
managers. The getInstance method passes a specific secure socket protocol
to be implemented. For example
SSLContext.getInstance("SSLv3")
specifies Secure Socket Layer version 3.
Alternatively we could specify SSL, TLS, or TLSv1.
A KeyManagerFactory implements a specified key management
algorithm. We use the default
authentication based on X.509 certificates and create the key manager factory
using
KeyManagerFactory.getInstance("SunX509")
The
X.509 standard defines what can go into a certificate and the format.
A KeyStore provides storage for keys and certificates. JKS is the name of the keystore
implementation provided by Sun, so we use
KeyStore keystore = KeyStore.getInstance("JKS");
to
create the key store, and the load method to load the keystore
keystore.load(new FileInputStream("profstore"), args[1].toCharArray());
We initialize the KeyManagerFactory with the keystore and its
password
f.init(keystore, args[2].toCharArray());
The
getKeyManagers method returns the KeyManager which we use to initialize the SSLContext
context.init(f.getKeyManagers(), null, null);
The
second argument represents a TrustManager, and
the third represents a SecureRandom secure random number generator. Both are null as we will use the
default settings.
To
run the server we use the command
java VerySimpleJSSEWebServer 4433 abc123
def456
To
run the client we use the command
java -Djavax.net.ssl.trustStore=profstore
-Djavax.net.ssl.trustPassword=abc123
VerySimpleJSSEBrowser
localhost 4433 VerySimpleBrowser.java
Which produces the output
Connected
to host localhost/127.0.0.1
javax.net.ssl.HandshakeCompletedEvent[source=1050169[TLS_DHE_DSS_WITH_AES_128_CB
C_SHA:
Socket[addr=localhost/127.0.0.1,port=4433,localport=1491]]]
HTTP/1.0
200 OK
Content-type:
text/plain
// Code for VerySimpleWebBrowser.java
displayed here
The
client specifies the trustStore property to add the certificate in profstore to the trusted store. This is necessary because our certificate is
self-signed. We did not get a
certificate from a known signing authority such as VeriSign
that is already known to the Java certificate store. At the end of this section we will use a
browser client that will allow the server to present its certificate for the
user to inspect and decide if it should be trusted.
Example 5 VerySimpleJSSEWebServer.java
/*
Serves a text file to an HTTPS client submitting a GET. Uses JSSE.
*/
import java.io.*;
import java.security.*;
import java.util.StringTokenizer;
import javax.net.ssl.*;
public class VerySimpleJSSEWebServer {
public static void
main(String [] args) {
String s;
try {
SSLContext
context = SSLContext.getInstance("SSLv3");
KeyManagerFactory
f
= KeyManagerFactory.getInstance("SunX509");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("profstore"),
args[1].toCharArray());
f.init(keystore, args[2].toCharArray());
context.init(f.getKeyManagers(), null, null);
SSLServerSocketFactory
factory
= context.getServerSocketFactory();
SSLServerSocket
server
= (SSLServerSocket)factory.createServerSocket
(Integer.parseInt(args[0]));
SSLSocket
client = (SSLSocket)server.accept();
System.out.println("VerySimpleJSSEWebServer
Connected on port "
+ args[0]);
BufferedReader
fromClient = new BufferedReader
(new InputStreamReader(client.getInputStream()));
PrintWriter toClient = new PrintWriter
(client.getOutputStream(),
true);
s=fromClient.readLine();
StringTokenizer
tokens = new StringTokenizer(s);
if (!(tokens.nextToken()).equals("GET")) {
toClient.println("HTTP/1.0
501 Not Implemented");
toClient.println();
}
else {
String filename = tokens.nextToken();
while (!(s=fromClient.readLine()).equals(""));
BufferedReader
file
= new BufferedReader(new FileReader(filename));
toClient.println("HTTP/1.0 200 OK");
toClient.println("Content-type: text/plain");
toClient.println();
while ((s=file.readLine()) != null)
toClient.println(s);
file.close();
}
fromClient.close();
toClient.close();
client.close();
}catch(Exception
e) {
e.printStackTrace();
}
}
}
Adding a Certificate to the Store
Our VerySimpleJSSEWebServer
has a self-signed certificate so we cannot securely connect to it without
consulting the user to see if this site is to be trusted. If we start VerySimpleJSSEWebServer as above and browse
https://localhost:4433/c:/471/nsf/jsse/VerySimpleBrowser.java
in
InternetExplorer a window
which
allows the user to view the certificate and choose whether or not to trust the
server. Viewing the certificate brings
up the screen
where
the user can view the details and choose to install the certificate if it is
determined to be trustworthy. If the
user decides to install the certificate, the Certificate Import Wizard pops up.
Clicking
Next
produces the screen
Clicking
Next produces
the screen
Finally
we verify that we really do want to trust this certificate
Clicking
Yes will import the certificate into the trusted
store, while clicking No will reject
it.
5. JSSE with Other
Protocols
Our examples so far have the Hypertext
Transfer Protocol (HTTP) but we can use JSSE with any network protocol. To illustrate we create a server that
reverses whatever text is sent to it, and a client that communicates with this
server.
We call ReverseServer with the command
java ReverseJSSEServer 5678 abc123 def456
Example 6 ReverseJSSEServer.java
/*
Listens on port 5678. When a client
connects, the server
* reverses whatever the client sends, and
sends it back.
*/
import javax.net.ssl.*;
import javax.net.*;
import java.net.*;
import java.io.*;
import java.security.*;
public class ReverseJSSEServer {
public static void
main(String [] args) {
String s; // the string to reverse
int
size; // the length of the string
char [] c; // the
reversed characters
try {
SSLContext
context = SSLContext.getInstance("SSLv3");
KeyManagerFactory
f
= KeyManagerFactory.getInstance("SunX509");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("profstore"),
args[1].toCharArray());
f.init(keystore, args[2].toCharArray());
context.init(f.getKeyManagers(), null, null);
ServerSocketFactory
factory
= context.getServerSocketFactory();
SSLServerSocket server
= (SSLServerSocket)factory.createServerSocket
(Integer.parseInt(args[0]));
SSLSocket
client = (SSLSocket)server.accept();
System.out.println("Reverse Server Connected on port 5678");
BufferedReader
input = new BufferedReader
(new InputStreamReader(client.getInputStream()));
PrintWriter
output = new PrintWriter
(client.getOutputStream(),true);
while ((s = input.readLine()) != null){
size = s.length();
c = new char[size];
for (int i=0; i<size;
i++)
c[i] = s.charAt(size-1-i);
output.println(c);
}
input.close();
output.close();
client.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
Output (when a client connects)
Reverse
Server Connected on port 5678
We run the client with the command
java -Djavax.net.ssl.trustStore=profstore -Djavax.net.ssl.trustStorePassword=abc123
ReverseJSSEClient localhost
Example 7 ReverseJSSEClient.java
/*
Connect to a server which reverses whatever
* the user
inputs. Specifies the host of the
* server on the
command line.
*/
import javax.net.ssl.*;
import javax.net.*;
import java.net.*;
import java.io.*;
public class ReverseJSSEClient {
public static void
main(String [] args) {
String s; // the string to reverse
if (args.length != 1){
System.out.println("Usage: java ReverseClient
host");
System.exit(1);
}
SocketFactory sf =
SSLSocketFactory.getDefault();
try {
Socket server = sf.createSocket(args[0],5678);
System.out.println("Connected to ReverseSever
host "
+ server.getInetAddress());
BufferedReader
fromServer = new BufferedReader
(new InputStreamReader(server.getInputStream()));
PrintWriter toServer = new PrintWriter
(server.getOutputStream(),true);
BufferedReader
input = new BufferedReader(
new
InputStreamReader(System.in));
while (true) {
System.out.print("# ");
System.out.flush();
if ((s=input.readLine()) == null)break;
toServer.println(s);
System.out.println(fromServer.readLine());
}
fromServer.close();
toServer.close();
input.close();
server.close();
}catch(Exception
e) {
e.printStackTrace();
}
}
}
Output
Connected
to ReverseSever host localhost/127.0.0.1
#
1234
4321
#
hi there
ereht ih
#
^Z