JSSE Architecture

  

The Java Secure Socket Extension (JSSE) is an extension of Java Sockets to provide extended functionality for SSL and Transport Layer Security (TLS). Sockets derive their name from wall sockets, where electricity is provided through a connection from the wall into an electric device. Like the connection of electricity, a socket provides a connection of data.

Just as the session of electricity has a beginning and ending of electric current that it provides to the electric device, there is a session of connectivity from the client to the server and back. During this session, encryptions are passed along with other information that changes state between the connections. The state and information that is exchanged between the client and server are based on the protocol, in this case SSL version 3.0 or TLS version 1.0, and so it is critical to understand the different protocols.

The TLS and SSL protocols provide functionality for data encryption, server authentication, message integrity, and client authentication. The JSSE interface, just like the socket interface, works on the Session Layer. The parent applications that operate at the application level, such as HTTPS , FTP, and Telnet, are meant to use sockets to handle the TCP (or UDP) communications and handshaking.

These applications deal with the support of application protocols that require multiple connections and sessions. Some of the applications that use HTTPS require JSSE for some connections and Java Sockets for other connections, depending on whether the application requires a secure or non-secure connection during an implementation of the current process. Just as Java Sockets hide the Ethernet implementations of session and connection, the JSSE protocol hides those layers as well as the handshaking of keys and implementations of the cipher suites. The connection is the general transport mechanism, and session is state-specific information shared between the peers.

The socket connection provides a transport between the two peers, client and server, just as a power cord provides a connection between an appliance and the power source. The OSI layering model provides the definitions of the packets.

The socket session is the instance and state between a specific client and server. It includes the handshake protocol, keys, security parameters, and any specific information between the client and server. The JSSE encapsulates socket implementation, encryption, and the TCP/IP stack, as shown in Figure 23-1.

click to expand
Figure 23-1: JSSE encapsulates sockets and TCP/IP layers
Cross-Reference  

Chapter 21 describes the OSI model.

In addition to the JSSE being a standard API for SSL and TLS, it also supports an API to the Transport Layer Security (TLS) secure socket protocol. The JSSE supports SSL versions 2 and 3 and TLS version 1. The JSSE v1 is available from http://java.sun.com/products/jsse . A close look at the API shows that, just like the Java Sockets, the JSSE forms wrappers around the regular socket layers around Java; it is just an extension of Java Sockets.

The following packages comprise the JSSE v1.0 architecture:

  • java.net.ssl : This package contains the core classes and the interfaces for the JSSE API.

  • javax.net : This package is the socket support needed for client and server socket factory functionality.

  • javax.security.cert : This package is needed to support basic certificate management functionality.

The JSSE architecture is primarily useful for its encapsulation of SSL Sockets, SSL server socket objects, and factories. SSL session handles can also be useful. Finally, the SSL binding and handshake event and listener APIs are also provided. The following list describes the role of each major API class or interface in the JSSE architecture:

  • SSLSocket : A socket that supports SSL, TLS, and WTLS secure socket protocols.

  • SocketFactory : A factory for socket objects. Factories create the instance of the class for the socket. The factory object can be re-used for new sockets.

  • SSLSocketFactory : A factory of SSLSocket objects.

  • SSLServerSocket : A server socket that supports the SSL, TLS, and WTLS secure socket protocols.

  • ServerSocketFactory : A factory for ServerSocket objects.

  • SSLServerSocketFactory : A factory for SSLServerSocket objects.

  • SSLSession : An interface to an object encapsulating an SSL session (exposing standard session attributes, peer identity, peer host, and cipher suit name).

    Note  

    Recall that a session shows information on a relationship between endpoints (such as a server and client).

  • SSLSessionContext : An interface to an object encapsulating a collection of SSL sessions identified with a session ID.

  • SSLBindingEvent : An event class encapsulating SSL session binding and unbinding events.

    Note  

    Listener objects can be bound and unbound to an SSL session, and objects that implement SSLBindingListener receive SSLBindingEvents.

  • SSLBindingListener : A listener interface. Objects wanting to be made aware of SSL session binding and unbinding events implement this interface.

  • HandshakeCompletedEvent : An event class encapsulating the fact that an SSL handshake has completed.

  • HandshakeCompletedListener : A listener interface. Objects wanting to be made aware of SSL handshake completion events implement this interface.

The basic JSSE architecture is rather simple, yet it provides a core suite of API abstractions necessary for tapping the functionality of SSL from within the Java applications. Figure 23-2 describes how a client and server communicate using the JSSE API; the client and server communicate through sockets. The server has an instance of an SSLServerSocket from an SSLServerSocketFactory, and the SSLSession (used to access all state information) is created in the SSLServerSocket . Likewise, the client has an instance of an SSLSocket acquired from the SSLSocketFactory and contains an SSLSession .

click to expand
Figure 23-2: Client/server communication using the JSSE API

For a connection to be completed, two peers must establish an acceptance of each other at both ends. One end is normally called a client , characterized because it initiates the request, and the other end is a receiver, the server, that listens for the initiating request for connection. In normal Java Sockets, the server has a listening socket called the ServerSocket that is generated in ServerSocketFactory .

In the JSSE API the interaction is similar; however, SSLServerSocketFactory initiates the SSLServerSocket, and the SSLSocketFactory generates the client's SSLSocket . You use the getDefault() method, which uses the default SSLContext , to retrieve these factories. The property provider defined in the JRE_HOME\lib\security\java.security file during runtime defines the SSL factories as the following lines of code show:

 ssl.ServerSocketFactory.provider = com.richware.ssl.ServerSocketFactory ssl.SocketFactory.provider = com.richware.ssl.SocketFactory 

Additionally, there are vendor-specific ways to obtain the handles for the SSLServerSocketFactory by using the SSLContext . The JSSE reference implementation provides a reference implementation of the com.net.ssl.SSLContext class to handle concrete implementations and proper initialization of the SSLServerSocketFactory . To initialize the SSLContext , at least a KeyManager or TrustManager must be used to retrieve the collection of the server certificates and keys.

Cross-Reference  

Chapter 8 describes KeyManager s and TrustManager s.

After a JSSE-specific collection of key managers is created, using the JCA Keystore object, the key managers are initialized in the SSLContext as the set of keys that are used during the SSL authentication process.

After an SSL server socket has been created, the SSL server listens for the client connection similar to the way the Java Sockets listen to the client connection. This is done by explicitly calling the ServerSocket 's accept method, or by implicitly calling the createServerSocket() function. If the server needs the SSLSocket class for interaction, a cast can be done to accept the socket. Listing 23-1 illustrates how these calls are used.

Listing 23-1: Server socket creation
start example
 try {  /*   * Get the server socket factory   */   SSLServerSocketFactory ssf =     (SSLServerSocketFactory)     SSLServerSocketFactory.getDefault();  /*   * Get the server socket   */   SSLServerSocket server  =(SSLServerSocket)ssf.createServerSocket("25001");  /*   * Get the client socket   */   SSLSocket sock = (SSLSocket)server.accept();  /*   * Get the stream   */   OutputStream out = sock.getOutputStream();   InputStream in = sock.getInputStream();  /*   * Do the protocol here through the streams   */ } catch(IOException e) {  e.printStackTrace(); } 
end example
 

You can expose special SSL- related socket manipulation operations to the SSL server socket by casting the javax.net.ssl.SSLSocket subclass of Socket . The need for clients to authenticate themselves to SSL servers can also be established on the server side. SSL servers use the SSLServerSocket.setNeedClientAuth(boolean flag) method call to indicate whether clients must supply certificates during the creation of new connections to the server. The SSLServerSocket.getNeedClientAuth() call returns a boolean value indicating whether client authentication is required after such a value has been set.

If the client authentication is required, the SSL client has to provide certificate information to the SSL server. When using JSSE on the client side, the client authentication steps are accomplished primarily using vendor-specific means. This is similar to the SSL server obtaining the socket handles.

After a client obtains an SSLSocketFactory , it can then use one of the few simple means for creating a handle to a javax.net.ssl.SSLSocket object; a javax.net.Socket object is returned using one of four calls defined at the base SocketFactory level, as described in the following list:

  • createSocket (String host, int port) is used for creating a remote host and port number.

  • createSocket (InetAddress host, int port) is used for creating a remote host and port number.

  • createSocket (String host, int port, InetAddress clientHost, int clientPort) is used for creating a remote host and port number in addition to a client-side host and port number.

  • createSocket (InetAddress host, int port, InetAddress clientHost, int clientPort) is used for creating a remote host and port number in addition to a client-side host and port number.

An SSL session represents a communications session between two endpoints. Data communicated between such entities engaged in an SSL session can be exchanged over different physical connections during the lifetime of the session. Likewise, an SSL connection might allow more than one session to utilize the established SSL connection.

Note  

Due to import control restrictions, the JSSE implementation provided in JDK 1.4 release includes the strong cipher suites, but does not allow the default SSLSocketFactory and SSLServerSocketFactory to be replaced .

JSSE providers

The JSSE uses standard JCA mechanisms for configuring the JDK when running a JVM instance. That is, a JSSE provider can be configured for use with a JVM instance through an entry in the [ JRE_HOME]\lib\security\java.security file; the entry security.provider.x can be modified or added to reference a particular security provider. For example, you might have the following line:

 Security.provider.1 = com.richware.security.SSLProvider 

Similarly, a security provider might also be configured for use with a JVM instance from within a static method call to the java.security.Security class as exemplified in the following lines:

 //Add new instance of JSSE Provider java.security.Provider provider = new  com.sun.net.ssl.internal.ssl.Provider(); java.security.Security.addProvider(provider); 

The provider class name used for this example is simply the default SSL provider that comes equipped with the downloaded JSSE reference implementation. The end-to-end SSL client and server example that is built up throughout this chapter, in fact, assumes that your SSL client and SSL server have established the default security provider during startup as shown in the preceding code.

The default provider implementation packaged with the JSSE reference implementation provides support for SSL v3 and TLS v1. The default implementation also provides support for RSA encryption used in generating signatures, support for PKCS 12 key store, X.509 key management functionality for loading authentication keys from a key store, and X.509 trust management functionality for chaining of certificates.

SSLContext

The first piece that makes up the SSL API is the TrustManager and KeyManager that maintain the keys. These interfaces are discussed in other chapters. The interface into the SSL from the keys and managers consists of the SSLContext .

Interactions

The SSLContext interacts with TrustManager and KeyManager to use the keys and certificates when the default implementation of the SSLContext is not supplied. By default, the JSSE can utilize default TrustManager s and KeyManager s. However, if any customization is involved, or any default options are changed, the new instance of an SSLContext must be used.

The class that defines the SSLContext in JSSE is the com.sun.net.ssl.SSLContext class. The SSLContext provides a context for communicating with the SecureRandom algorithm, KeyManager s, and TrustManager s. Without the SSLContext , only default settings may be applied to these algorithms. This means that any access to a non-defaulted KeyStore , keying mechanism, TrustStore , or SecureRandom and their accompanying managers will be denied . The SSLContext is the interface for these mechanisms, as shown in Figure 23-3.

click to expand
Figure 23-3: The SSLContext interface

The SSLContext

The SSLContext holds the state information across sockets. An instance of this class acts as a context factory for the SocketFactory . The session state is used for the handshaking of the client and server SSLSocket. SSLSocket s that are created under the same context can share and re-use the cache sessions. The SSLContext initializes the managers. These managers provide the support for key agreement and authentication. The following protocols are supported in the SSLContext :

  • SSL: For support of other versions of SSL

  • SSLv2: Supports version 2 or higher

  • SSLv3: Supports version 3

  • TLS: For support of other versions of TLS

  • TLSv1: Supports version 1

The purpose of SSLContext is to set up the KeyManager , TrustManager, and SecureRandom to the factories of the server and client sockets on what key mechanisms to use for the handshaking. Listing 23-2 displays the server setup for a KeyManager; it is an example of X509-based key managers using the com.sun.net.ssl.KeyManager class. A TrustManager uses the com.sun.ssl.TrustManager package to implement the trusted remote process decisions used during the SSL authentication.

The standard JCA java.security.SecureRandom class is used for generating a random seed value that is used for the SSLContext . After getting the handle to the KeyManager objects, the TrustManager objects, and the SecureRandom object, the SSLContext object can be created and initialized. These objects are used during the initialization of the SSLContext object that will be used subsequently to initialize the security and operational qualities of the SSLServerSocketFactory .

Listing 23-2: X509-based key manager
start example
 /**  * Method getServerSocketFactory  * @param type is the support of TLS.  * @return the ServerSocketfactory created with the context.  */  public static ServerSocketFactory getServerSocketFactory(String type) {   if (type.equals("TLS")) {  SSLServerSocketFactory ssf = null;  try {   /*    * set up key manager to do server authentication    */    SSLContext    ctx;    KeyManagerFactory kmf;    KeyStore    ks;   /*    *  passphrase is the password for the store    */    char[] passphrase = "passphrase".toCharArray();   /*    *  Use TLS    */    ctx = SSLContext.getInstance("TLS");   /*    *  Get an instance of the X509    */    kmf = KeyManagerFactory.getInstance("SunX509");   /*    *  Get the default Java KeyStore    */    ks = KeyStore.getInstance("JKS");   /*    *  Open the keystore that is a file called testkeys and the password    */    ks.load(new FileInputStream("testkeys"), passphrase);   /*    *  Initialize the KeyManager with the KeyStore    */    kmf.init(ks, passphrase);   /*    *  Initialize the SSLContext with the keyManager    */    ctx.init(kmf.getKeyManagers(), null, null);   /*    *  Initialize the ServerSocketFactory with the SSLContext    */    ssf = ctx.getServerSocketFactory();    return ssf;    } catch (Exception e) {    e.printStackTrace();    }  } else {    return ServerSocketFactory.getDefault();  }  return null;  } 
end example
 

Another way to look at the calling of these methods is in a UML sequence diagram, as shown in Figure 23-4.

click to expand
Figure 23-4: SSLServer, SSLContext, KeyManager,and KeyStore UML sequence

SSLSession

A javax.net.ssl.SSLSession represents a security context negotiated between the client and the server. Once a session is created, it is used between the same connections of the client and server. The session contains the cipher suite, connection information, and management information that will be used over the secure socket connection. The session also can be seen as means to retrieve key information from a socket connection. One of the items that can be retrieved is the session ID that identifies a particular session. Other items include the creation time of the session, the certificates, the cipher suite name, and the SSLSessionContext, as shown in Listing 23-3.

Listing 23-3: Getting the SSLSession
start example
 /*  * Get the SSLSession and print some of the session info  */  SSLSession session = socket.getSession();  System.out.println("Peer Host :" + session.getPeerHost());  System.out.println("Name of the cipher suite :" +  1session.getCipherSuite()); /*  *  Get the certificate Chain  */  X509Certificate[] certificates = session.getPeerCertificateChain(); /*  * Print the distinguished Principal's name   */  System.out.println("DN :" + certificates[0].getSubjectDN().getName(); 
end example
 

An SSLSession is associated with getting information from a given connection. However, a client and server can contain many connections and peers to those connections. To encapsulate a set of SSLSessions , an SSLSessionContext is used that contains the server's or client's set of SSLSessions that are associated with the connection. An individual SSLSession can be retrieved by the getSession() on a particular client socket. Also, the SSLSessionContext that is retrieved from the SSLSession contains a set of more SSLSessions that may be part of the socket entity.

For example, when a ServerSocket has many client sessions, the ServerSocket can retrieve the SSLSessionContext that contains all the sets of SSLSession s related to all of the client sessions. The SSLSessionContext is a set of SSLSessions that belong to either client or a server that maintains many connections, and correspondingly many SSLSessions . The set is stored in an enumeration data type that is looked up by the SSLSession 's identification. The SSLSessionBindingEvent handles any notification of events to the SSLSession . Attackers can easily intercept data that is open across a network.

When the data includes private information, such as passwords and credit card numbers , steps must be taken to hide the data to make the data unintelligible except to the intended parties. You must ensure these parties are authentic , that they are who they say they are; and ensure that the data has not been modified during transport; therefore, a form of data integrity must be enforced. TLS and SSL were designed to protect the privacy and integrity of data during transport. Each instance creates a trust and key manager, if any are needed for the authentication in the SSLSession .

JSSE SSLServerSockets

Creating SSL server sockets can be as simple as creating regular Java TCP/IP server sockets. SSL server socket abstractions provide additional hooks, however, to manipulate the security and SSL-related operation characteristics of SSL socket connections. SSL cipher parameters, authentication properties, and handshaking management are also exposed by the SSL abstractions.

Although standard APIs exist for creating SSL server sockets using standard SSL server socket factories, the means by which handles to SSL server socket factories are obtained can be JSSE provider-specific. The SSLServerSocket is obtained through the SSLServerSocketFactory that creates the instance of the SSLServerSocket . The javax.net.ssl.SSLServerSocketFactory extends the javax.net.ServerSocketFactory class. Once the SSLContext of the SSLServerSocketFactory is defined, an unlimited supply, depending on resources, of ServerSockets can be created containing the same SSLContext information. The factory provides the capability to create instances depending on the SSLContext specified for the factory.

Obtaining an SSL server socket factory

The JSSE uses the concept of socket factories to create handles to SSL sockets. The javax.net.ServerSocketFactory class is an abstract class used to create generic server sockets. The javax.net.ssl.SSLServerSocketFactory abstract class is used to create SSL server socket handles and subclasses javax.net.ServerSocketFactory . The default server socket factory class name is identified in the [ JRE_HOME]\lib\security\java.security file for your Java runtime environment using ssl.ServerSocketFactory.provider property name. Additionally, JSSE providers often provide vendor-specific ways to obtain handles to SSLServerSocketFactory objects so that server authentication information can be provided.

For example, the JSSE reference implementation provides a com.sun.net.ssl.SSLContext class that can be used to obtain handles to concrete SSLServerSocketFactory implementation objects after proper initialization. Before you can use the reference implementation's SSLContext object to obtain such an SSL server socket factory, you must first take a number of steps to configure the SSL server socket with particular security and operational properties.

The standard JCA java.security.KeyStore object is first used to obtain a handle to a stored collection of server certificates and keys. For example, you first obtain a handle to a stored collection of server certificates and keys via a KeyStore object. Also, you create a KeyStore object using the JCA-provided LKS keystore type with a testKeys keystore file name; it is loaded using a passphrase password.

A special JSSE reference implementation-specific collection of key managers is then created using the JCA KeyStore object. This object is used to manage the keys employed during the SSL authentication process. For example, you create a collection of X509-based key managers using the com.sun.net.ssl.KeyManager . TrustManagers and SecureRandom can also be initialized with non-default implementations and passed inside the SSLContext .

Now that you have handles to KeyManager objects, TrustManager objects, and a SecureRandom object, you can create and initialize the SSLContext object. Such objects used during initialization of the SSLContext object are also used subsequently to initialize the security and operational qualities of the SSLServerSocketFactory . The creation and initialization of the JSSE reference implementation-specific SSLContext .

Creating SSL server sockets

You can create handles to SSL server sockets using the SSLServerSocketFactory object in one of three ways. The SSLServerSocketFactory object's base ServerSocketFactory class has three standard createServerSocket() methods defined. These return handles to java.net.ServerSocket objects. When you are using a SSLServerSocket subclass, the returned server sockets will actually be subclasses of the abstract javax.net.ssl.SSLServerSocket class. Listing 23-4 shows an example that creates an SSL server socket.

Listing 23-4: The SSLServer class: An example for creating SSL server sockets
start example
 package com.richware.chap23;     import java.io.*; import java.net.*; import java.security.*; import javax.net.*; import javax.net.ssl.*; import javax.security.cert.*;     /**  * Class SSLServer  * This example demonstrates a JSSE server with context creation.  *  * Copyright:    Copyright (c) 2002 Wiley Publishing, Inc.  * @author Rich Helton <rhelton@richware.com>  * @version 1.0   * DISCLAIMER: Please refer to the disclaimer at the beginning of this book.  */ public class SSLServer extends Thread  {   private final static int port = 25001;   Socket                   sock;   String                   docroot = "C:\";   final static String      debug   = "none";       /**    * Method main    * The main driver for the server.    *    * @param args none needed    *    * @throws Exception if there is an issue.    *    */   public static void main(String[] args) throws Exception    {     try      {       System.out.println("Starting SSLServer....");           /*        * Pass in the argument of the keystore file        * It will be opened in the same directory as the application        */       if (args[0] == null)         {         System.out.println(           "This application requires an input file for the location of  the keystore");       }           String localDirectory = System.getProperty("user.dir");       System.out.println("Changing directory to Chapter 23");       System.setProperty("user.dir",                          localDirectory                          + "\com\richware\chap23\");       localDirectory = System.getProperty("user.dir");           /*        * Get the local keystore that contains a trusted certificate        */       String localInputFile = localDirectory + args[0];           System.out.println(         "Openining Chapter 23 plus the input file as an argument: " +  localInputFile);           /*        * Set the SSL internal debugger to none        * Set it to all for all connections        */       System.out.println("Setting SSL debugging to :" + debug);       System.setProperty("javax.net.debug", debug);           ServerSocketFactory ssf =         SSLServer.getServerSocketFactory("TLS",                                          localInputFile);       ServerSocket        ss  = ssf.createServerSocket(port);       ((SSLServerSocket) ss).setNeedClientAuth(true);           /*        * Keep accepting Socket Connections and starting them on a thread        */       while (true)        {         System.out           .println("Waiting for client connection....");         new SSLServer(ss.accept()).start();       }     }     catch (Exception e)      {       e.printStackTrace();     }   }       /**    * Method getServerSocketFactory    *    *    * @param type is the support of TLS.    * @param filename    *    * @return the ServerSocketfactory created wuth the context.    *    */   public static ServerSocketFactory getServerSocketFactory(           String type, String filename)    {     if (type.equals("TLS"))      {       SSLServerSocketFactory ssf = null;       System.out.println("Starting TLS Exchange....");       try        {         /*          * set up key manager to do server authentication          */         SSLContext          ctx;         KeyManagerFactory   kmf;         TrustManagerFactory tmf;         KeyStore            ks;             /*          *  passphrase is the password for the store          */         char[] passphrase = "passphrase".toCharArray();             /*          *  Use TLS          */         ctx = SSLContext.getInstance("TLS");             /*          *  Get an instance of the X509          */         kmf = KeyManagerFactory.getInstance("SunX509");             /*          *  Get an instance of the X509          */         tmf = TrustManagerFactory.getInstance("SunX509");             /*          *  Get the default Java KeyStore          */         ks = KeyStore.getInstance("JKS");             /*          *  Open the keystore that is a file called testkeys and the  password          */         ks.load(new FileInputStream(filename), passphrase);             /*          *  Initialize the KeyManager with the KeyStore          */         kmf.init(ks, passphrase);         tmf.init(ks);         System.out.println("Opened KeyStore");             /*          *  Initialize the SSLContext with the keyManager          */         ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(),                  null);         /*          *  Initialize the ServerSocketFactory with the SSLContext          */         ssf = ctx.getServerSocketFactory();         return ssf;       }       catch (Exception e)        {         e.printStackTrace();       }     }     else      {       return ServerSocketFactory.getDefault();     }     return null;   }       /**    * Constructor SSLServer    * Initializes the client socket when acceptance.    *    * @param s the client socket.    *    */   public SSLServer(Socket s)    {     sock = s;   }       /**    * Method run    * This method is a thread that is accepting an input socket    *    */   public void run()    {     try      {       System.out.println("Received client connection....");       /*        *  Get the Input and Output Socket Streams        */       PrintWriter    out = new PrintWriter(         new BufferedWriter(           new OutputStreamWriter(sock.getOutputStream())));       BufferedReader in  =         new BufferedReader(new InputStreamReader(sock           .getInputStream()));       String         inputLine;           /*        * Read until all input is read        */       if ((inputLine = in.readLine()) != null)        {         System.out.println(inputLine);       }           out.println("Post HTTP/1.1");       out.flush();           /*        * Close the stream and connection        */       in.close();       out.close();     }     /*      * Print any errors      */     catch (IOException ex)      {       System.out.println("Error: " + ex.getMessage());       ex.printStackTrace();     }     finally      {       try        {         System.out.println("Closing Client Socket......");             /*          * Close the Socket Connection          */         sock.close();       }       catch (IOException e) {}     }   } } 
end example
 

SSL server socket listener

After an SSL server socket has been created, the SSLServerSocket listens for the SSL client requests in the same way that regular server sockets listen for socket client requests . That is, the SSLServerSocket class's accept() method is used to block for client requests and returns an instance of a java.net.Socket object representing the socket connection with the requesting client. By casting this object to the java.net.ssl.SSLSocket abstract subclass of Socket , special SSL-related socket manipulation operations are exposed to the SSL server socket.

Then the thread handler may handle client requests using socket calls from the java.net package and I/O stream handling from the java.io package as usual without any cognizance of SSL specifics.

Client authorization

The need for clients to authenticate themselves to SSL servers can also be established on the server side. SSL servers use the SSLServerSocket.setNeedClientAuth(boolean flag) method call to indicate whether clients must supply certificates during the creation of new connections with the server. The SSLServerSocket.getNeedClientAuth() call returns a boolean value indicating whether client authentication is required after such a value has been set. If client authentication is required, the SSL client has to provide certificate information to the SSL server.

Note  

When using JSSE on the client side, the client authentication steps are accomplished primarily using vendor-specific means. The vendor-specific means for providing such information will most likely be similar to the means that JSSE SSL servers use to obtain handles to JSSE SSL server socket factories.

JSSE SSL client sockets

The creation of SSL sockets from client to server is also a very simple task using JSSE. Clients must first obtain handles from the SSL socket factories. The handles, which are obtained in the same manner as SSL servers, obtain handles to the SSL socket factories. Creation of SSL client sockets is then accomplished using one of a few very simple creation calls. SSL sockets are then used much as regular Java Socket objects are used to communicate with a remote server. This section describes how to obtain SSL socket factory objects and how to create SSL socket objects using JSSE.

Obtaining an SSL socket factory

Akin to the way in which SSL servers obtain handles to SSL server socket factories, SSL clients obtain handles to SSL socket factories. The abstract javax.net.ssl.SSLSocketFactory class extends the javax.net.SocketFactory class to return SSL socket handles for clients. JSSE providers might provide vendor-specific mechanisms for obtaining SSLSocketFactory handles, or a client might obtain a handle to the default SSLSocketFactory configured for that client's environment.

The vendor-specific way for obtaining an SSLSocketFactory handle using the JSSE reference implementation is nearly identical to the creation of SSLServerSocketFactory handles. The only key difference is that the client initiates the request and doesn't have to listen and wait for the request to be initiated. Listing 23-5 demonstrates this process.

Listing 23-5: The SSLClient class: An example usage of SSLSocketFactory
start example
 package com.richware.chap23;     import java.io.*; import java.net.*; import java.security.*; import javax.net.*; import javax.net.ssl.*; import javax.security.cert.*;      /**  * Class SSLClient  * This example demonstrates a JSSE client with context creation.  *  * Copyright:    Copyright (c) 2002 Wiley Publishing, Inc.  * @author Rich Helton <rhelton@richware.com>  * @version 1.0    * DISCLAIMER: Please refer to the disclaimer at the beginning of this book.  */ public class SSLClient  {   private final static int    port  = 25001;   private final static String host  = "127.0.0.1";   final static String         debug = "none";       /**    * Method main    * This method is the main driver for the client.    *    * @param args none needed, later can put in host and port.    *    * @throws Exception if there is an issue.    *    */   public static void main(String[] args) throws Exception    {     try      {       System.out.println("Starting SSLClient....");       /*        * Pass in the argument of the keystore file        * It will be opened in the same directory as the application        */       if (args[0] == null)         {         System.out.println(           "This application requires an input file for the location of  the keystore");       }           String localDirectory = System.getProperty("user.dir");       System.out.println("Changing directory to Chapter 23");       System.setProperty("user.dir",                          localDirectory                          + "\com\richware\chap23\");       localDirectory = System.getProperty("user.dir");           /*        * Get the local keystore that contains a trusted certificate        */       String localInputFile = localDirectory + args[0];       System.out.println(         "Openining Chapter 23 plus the input file as an argument: " +  localInputFile);           /*        * Set the SSL internal debugger to all        */       System.out.println("Setting SSL debugging to :" + debug);       System.setProperty("javax.net.debug", debug);           /*        * Get a TLS socket factory        */       SSLSocketFactory socketFactory =         SSLClient.getClientSocketFactory("TLS",                                          localInputFile);           /*        * Get the client socket instance        */           //    SSLSocket    socket    =       //      (SSLSocket) socketFactory.createSocket("www.richware.com",       //                   25001);       SSLSocket sock =         (SSLSocket) socketFactory.createSocket(host, port);           /*        * send http request        *        * Before any application data is sent or received, the        * SSL socket will do SSL handshaking first to set up        * the security attributes.        *        * The only way to tell there was an error is to call        * PrintWriter.checkError().        */       System.out.println("Socket : " + sock);       sock.startHandshake();       System.out.println("Handshake finished");           /*        * Get the SSLSession and print some of the session info        */       SSLSession session = sock.getSession();       System.out.println("Peer Host :"                          + session.getPeerHost());       System.out.println("Name of the cipher suite :"                          + session.getCipherSuite());           /*        *  Get the certificate Chain        */       X509Certificate[] certificates =         session.getPeerCertificateChain();         /*      * Print the distinguished Principal's name      */       System.out         .println("DN :"                  + certificates[0].getSubjectDN().getName());           /*        * Get the output stream        */       PrintWriter out = new PrintWriter(         new BufferedWriter(           new OutputStreamWriter(sock.getOutputStream())));           /*        * Send the Get method        */       out.println("GET HTTP/1.1");       out.println();       out.flush();           /*        * Make sure there were no issues        */       if (out.checkError())        {         System.out           .println("SSLClient:  java.io.PrintWriter error");       }           /*        * Read any responses        */       BufferedReader in =         new BufferedReader(new InputStreamReader(sock           .getInputStream()));       String         inputLine;           /*        * Read until all input is read        */       while ((inputLine = in.readLine()) != null)        {         System.out.println(inputLine);       }           /*        * Close the stream and connection        */       in.close();       out.close();       sock.close();     }     catch (Exception e)      {       e.printStackTrace();     }   }       /**    * Method getClientSocketFactory    *    *    * @param type is the supported TLS type.    * @param filename    *    * @return the SocketFactory created with the context.    *    */   public static SSLSocketFactory getClientSocketFactory(           String type, String filename)    {     if (type.equals("TLS"))      {       SSLSocketFactory factory = null;       System.out.println("Starting TLS Exchange....");       try        {         /*          * set up key manager to do server authentication          */         SSLContext          ctx;         KeyManagerFactory   kmf;         TrustManagerFactory tmf;         KeyStore            ks;              /*          *  passphrase is the password for the store          */         char[] passphrase = "passphrase".toCharArray();             /*          *  Use TLS          */         ctx = SSLContext.getInstance("TLS");             /*          *  Get an instance of the X509          */         kmf = KeyManagerFactory.getInstance("SunX509");             /*          *  Get an instance of the X509          */         tmf = TrustManagerFactory.getInstance("SunX509");             /*          *  Get the default Java KeyStore          */         ks = KeyStore.getInstance("JKS");             /*          *  Open the keystore that is a file called testkeys and the  password          */         ks.load(new FileInputStream(filename), passphrase);             /*          *  Initialize the KeyManager with the KeyStore          */         kmf.init(ks, passphrase);         tmf.init(ks);         System.out.println("Opened KeyStore");             /*          *  Initialize the SSLContext with the keyManager          */         ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(),                  null);             /*          *  Initialize the SocketFactory with the SSLContext          */         factory = ctx.getSocketFactory();         return factory;       }       catch (Exception e)        {         e.printStackTrace();       }     }     else      {       return (SSLSocketFactory) SSLSocketFactory.getDefault();     }         return null;   } } 
end example
 

Alternatively, a default SSLSocketFactory, which can be configured for the client's environment, is the [ JRE_HOME]\lib\security\java.security file's ssl.SocketFactory.provider property as follows :

 ssl.SocketFactory.provider=com.assuredtech.ssl.SocketFactory 

The output for the client looks like the following:

 >java com.richware.chap23.SSLClient testkeys Starting SSLClient.... Changing directory to Chapter 23 Openining Chapter 23 plus the input file as an argument: C:\  \com\richware\chap23\testkeys Setting SSL debugging to :none Starting TLS Exchange.... Opened KeyStore Socket : ac2f9c[SSL_NULL_WITH_NULL_NULL:  Socket[addr=127.0.0.1/127.0.0.1,port=25 001,localport=1244]] Handshake finished Peer Host :127.0.0.1 Name of the cipher suite :SSL_RSA_WITH_RC4_128_SHA DN :CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Cupertino,  ST=CA, C=US HTTP/1.0 200 OK Post HTTP/1.1 

and the corresponding server output is as follows:

 >java com.richware.chap23.SSLServer testkeys Starting SSLServer.... Changing directory to Chapter 23 Openining Chapter 23 plus the input file as an argument: C:\  com\richware\chap23\testkeys Setting SSL debugging to :none Starting TLS Exchange.... Opened KeyStore Waiting for client connection.... Waiting for client connection.... Received client connection.... Wait for input Received input GET HTTP/1.1 Closing Client Socket...... 

Creating SSL client sockets

After an SSLSocketFactory is obtained, a client can then use one of the few simple means for creating a handle to a javax.net.ssl.SSLSocket object. A java.net.Socket.object is returned using one of four calls defined in the base SocketFactory level as follows:

  • createSocket( String host, int port) : Creates a socket given a remote host and port number.

  • createSocket( InetAddress host, int port ) : Creates a socket given a remote host and port number.

  • createSocket ( String host, int port, InetAddress clientHost, int clientPort) : Creates a socket given a remote host and port number in addition to a client-side host and port number.

  • createSocket( InetAddress host, int port, InetAddress clientHost, int clientPort) : Creates a socket given a remote host and port number in addition to a client-side host and port number.

Additionally, the SSLSocketFactory subclass of SocketFactory defines another createSocket() method that creates a socket wrapped around an existing socket. In addition to an existing socket handle, a remote server host String , a remote port number, and a boolean value are provided to indicate whether to close the wrapped socket when the newly created socket is closed. The signature of this method is createSocket( Socket wrappedSocket, String host, int portNumber, boolean autoClose) .

Note  

When you are creating SSLSocket objects, they must be cast from the signature java.net.Socket type.

Here is an example of how to create an SSLSocket object:

 // Set remote host and port number String host = "111.111.111.111"; String portNumber = 9000; // Create an SSLSocket to a remote server SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(host,  portNumber); 

Then the use of the SSLSocket objects on the client side proceeds as usual with the base Socket class. All encryption and decryption via SSL occur transparently to the client when InputStream and OutputStream objects are used to receive and send data, respectively.

An SSL session represents a communications session between two endpoints. Data communicated between such entities engaged in an SSL session can be exchanged over different physical connections during the lifetime of the session. Likewise, an SSL connection might allow more than one session to utilize the established SSL connection. To get the different SSLSessions , the SSLSessionContext class is used to retrieve the set of SSLSessions .

In the server side, the capability to create SSL sessions associated with an SSL server socket can be established using the SSLServerSocket.setEnabledSessionCreation( boolean flag) method. The boolean value passed into such a method, of course, indicates true if SSL sessions are allowed to be created on the server socket connection. The SSLServerSocket.getEnabledSessionCreation() method call returns a boolean value to determine whether the SSL server socket enables session creation.

The same two methods exist on the SSLSocket object as well. In addition to such methods, the SSLSocket object also provides a getSession() method to return an SSLSession object used by the current connection. The SSLSession.invalidate() method is used to invalidate sessions and, thus, prevent other connections from using the current SSL session.

The javax.net.ssl.SSLSession interface provides a means by which objects can be bound to a session; this interface uses a String name for removing and retrieving such objects via the following methods:

  • void putValue( String name, Object value) : Binds the named object to the session.

  • void removeValue ( String name ) : Removes the bound named object from the session.

  • Object getValue ( String name) : Returns a handle to an object bound with an associated name to this session.

  • String [] getValueNames( ) : Returns a collection of String names for those objects bound to this session.

Additionally, SSLSession defines a number of other getters related to attributes of the SSL session; here is a list of these methods:

  • byte [ ] getID ( ) : Returns the session ID.

  • String getPeerHost ( ) : Returns the host name for the remote session peer.

  • X509Certificate [ ] getPeerCertificateChain ( ) : Returns a chain of certificates associated with the remote peer of this session.

  • String getCipherSuite ( ) : Returns a name for the SSL cipher suite used by this session.

  • long getCreationTime ( ) : Returns a long value representation of when the session was created, measured in milliseconds since January 1, 1970.

  • long getLastAcessedTime ( ) : Returns a long value representation of when the session was last used, measured in milliseconds since January 1, 1970.

  • SSLSessionContext getSessionContext ( ) : Returns a handle to the context for the session.

The javax.net.ssl.SSLSessionContext interface simply serves as a collection of SSLSession objects that are associated with a particular entity. The SSLSessionContext interface defines the getIDs ( ) method to return an enumeration of all session IDs associated with the SSL context. The SSLSessionContext interface also defines a getSession (byte [ ] sessonID) method to return an SSLSession identified by the session ID byte array.

The client and server

To establish the two peer sessions of both the client and the server, a server must be listening for the client to request upon. The server must be using a KeyManager or TrustManager that the client can accept. The client initiates the request to the server for an SSL connection. The client tells the server which cipher suites it can accept. The server responds with which SSL cipher suites it supports. By default, SSL supports eight cipher suites based on key exchange, encryption, and one-way hash. These are:

  • SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA

  • SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA

  • SSL_DHE_DSS_WITH_DES_CBC_SHA

  • SSL_RSA_EXPORT_WITH_RC4_40_MD5

  • SSL_RSA_WITH_3DES_EDE_CBC_SHA

  • SSL_RSA_WITH_DES_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5

  • SSL_RSA_WITH_RC4_128_SHA

Here is an example of how to read this: SSL_RSA_WITH_RC4_128_SHA means that the keys are using an RSA key exchange using the RC4 algorithm at 128 bits and the SHA one-way hash.

After the client and the server negotiate which algorithm suite to use, the server responds with a certificate to verify the server identity. This initiates a key exchange by the keys that are contained in the X.509 certificate. The client completes the key exchange of public and private keys to the server after verifying the certificate, which includes checking the validity of the keys with the message digest of SHA or MD5. Based on the type of key exchange, RSA or Diffie-Helman, the client makes a final recommendation on the rest of the cipher suite. The server may accept the recommendation and accept the exchange.

The SSL protocol handles most of the interaction. The developer in JSSE selects the keys, can set the type of cipher suite to use, and establishes the manager of the keys or trust. The developer initiates the entries that are needed for the SSL and TLS protocol, but does not need to worry about most of the internal exchanges. The developer does have access to look at any part that is going on in the session by the SSLSession class.

HTTPSURLConnection

Because SSL became popular because of its use on the Internet over HTTP, it is natural to think about how JSSE can be used with Web-enabled applications. On the Web-client side, the built-in SSL functionality of your Web browser will most likely be utilized when the need for a Web-enabled SSL client arises. However, signed Java applets may also take advantage of JSSE. Homegrown Web clients may also utilize the standard Java URL, java.net , and java.io libraries to implement Web-based clients over HTTPS.

However, if the developer uses the standard Java URL libraries, a vendor must provide a java.net.URLStreamHandler implementation, and you must configure such an implementation with the JVM using the java.protocol.handler.pkgs system property. Additional arguments that can be defined in this system property are the https proxy host, proxy port, and cipher suite.

The HttpsUrlConnection encapsulates both the SSLSocketFactory class and the HostnameVerifier class. These are the classes that are needed to complete an HTTPS connection. HTTPS (Secure HTTP) is one of the primary uses of SSL and TLS. The HttpsUrlConnection supports the HTTP protocol and using SSL or TLS as the underlying layers that handle the handshaking, confidentiality, and integrity. The HostnameVerifier is used to ensure that the host name in the certificate matches the URL that the HTTPS is requesting the connection from.

If the two host names do not match, then a false is returned and the connection should not be allowed. Encapsulating these classes gives a developer and architect the ability to build a HTTPS client while using many of the defaults of SSL and TLS without having to explicitly set up the socket interfaces. Specifying the URL and not explicitly assigning a port and host establishes the connection.

  


Java Security Solutions
Java Security Solutions
ISBN: 0764549286
EAN: 2147483647
Year: 2001
Pages: 222

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net