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