Lab / Homework 3

SSL

SSL is a protocol that runs on top of TCP/IP, adding authentication, encryption, and data integrity to TCP connections. SSL was invented by Netscape corporation to add security to application protocols running over TCP, particularly HTTP. HTTPs stands for HTTP over SSL. SSL has since gone through several versions. The current version, SSL v3, has been standardized by IETF (Internet Engineering Task Force) and is also known as TLS (Transport Layer Security). SSL uses X509 Certificates to authenticate the server to the client, and optionally, the client to the server. SSL uses message authentication codes to achieve integrity. SSL is designed to work through the Socket API.

SSL Handshake

SSL begins with a handshake between the client and the server. The handshake allows the client and server to authenticate themselves to each other, negotiate a secret key exchane protocol, and then decide on a secret key to be used as the session key. SSL handshake consists of three steps:

Step 1: Client Hello Message

The client sends a Hello message to the server consisting of
  1. The SSL versions supported by the client
  2. 32 bits of random data selected by the client
  3. A session id made up by the client
  4. A list of supported ciphers
  5. A list of supported compression methods

Step 2: Server Hello Message

The server responds with a server hello message consisting of
  1. The SSL version the server selects from the client's list
  2. 32 bits of random data
  3. The session id
  4. The ciphers chosen from the client list (for example, RSA and RC4)
  5. The compression method selected (typically no compression is used)
  6. The server certificate in X509 form. The certificate contains the server's public key
  7. Optionally, the server may request a certificate from the client.

Step 3

At this point, the client will check the validity of the server's certificate. The client will typically have a keystore containing certificates that it already trusts. The client checks this keystore to see if the server's certificate is already there. If not, the server's certificate is verified by through a certificate authority (CA). Next, the client select 48 bytes (at random) from the pair of 32 bytes of random data previously selected by the client and server. These bytes are sent to the server, encrypted by the server's public key. At this point, the client computes a session key for encryption, as well as a key for a message authentication code. These are computed from the random numbers exchanged by the client and server. Finally, the client sends a Change Cipher message to the server. This is the signal to the server to compute the same keys for the session and for the MAC. From this point on, all communication is encrypted with the session key and is accompanied with a MAC.

Algorithms Supported by SSL

SSL supports different algorithms for key exchange, encryption, and for message authentication codes: Supported key exchange algorithms are
  1. RSA
  2. Fixed Diffie-Hellman
  3. Ephemeral Diffie-Hellman
  4. Anonymous Diffie-Hellman
  5. Fortezza
Supported Ciphers include
  1. RC4
  2. TripleDES
  3. IDEA
  4. Fortezza
  5. DES
  6. RC2
Supported MAC algorithms include.
  1. MD5
  2. SHA-1

Uses for SSL

SSL is typically used for securing web traffic via HTTPS. However, SSL can be used for other application protocols. SSL can be used with POP and IMAP to secure email so it is not exchanged between the mail server and client in clear text. SSL can also be used with telnet and FTP. SSL can also be used with Java protocols such as RMI and JDBC.

Using SSL in Your Applications

SSL is both an API and an implementantion. There is an open source implementation OpenSSL that is written in C, but which has wrappers for other languages. You have to get the OpenSSL for your operating system.

Using SSL in Java

The JDK comes with JSSE, the Java Secure Sockets Extension, which provides a Java implementation of SSL. Using SSL in Java is similar to using regular Java sockets. In fact, Java has two classes
SSLSocket
SSLServerSocket
which respectively extend Socket and ServerSocket. These classes have methods such as
 String[] getEnabledProtocols()
 void setEnabledProtocols(String[] protocols)
 String[] getEnabledCipherSuites()
 void setEnabledCipherSuites(String[] suites)
 String[] getSupportedCipherSuites()
 void setEnabledCipherSuites(String[] suites)
These SSL sockets have protected constructors, and the 6 methods we showed above are abstract. This means that these classes cannot be instantiated. Instead, you have to use factory classes to retrieve appropriate instances of these classes.
javax.net.ssl.SSLSocketFactory
javax.net.ssl.SSLServerSocketFactory

SSLSocketFactory methods

 static SocketFactory getDefault()
this static method returns the default socket factory. The returned object has to be cast to an SSLSocketFactory object before you can use it.
 String[] getSupportedCipherSuites()
Returns the names of the cipher suites which could be enabled for use on an SSL connection. Normally, only a subset of these will actually be enabled by default, since this list may include cipher suites which do not meet quality of service requirements for those defaults. Such cipher suites are useful in specialized applications.
 String[] getDefaultCipherSuites() 
Returns the list of cipher suites which are enabled by default. Unless a different list is enabled, handshaking on an SSL connection will use one of these cipher suites. The minimum quality of service for these defaults requires confidentiality protection and server authentication (that is, no anonymous cipher suites).
Socket createSocket(Socket s,  String host,  int port, boolean autoClose)  
Returns a socket layered over an existing socket connected to the named host, at the given port. This constructor can be used when tunneling SSL through a proxy or when negotiating the use of SSL over an existing socket. The host and port refer to the logical peer destination. This socket is configured using the socket options established for this factory. The host and port parameters refer to the server machine. The method returns a socket connected to the remote server at the given port.

SSLServerSocketFactory

static ServerSocketFactory getDefault()
String[] getDefaultCipherSuites()
String[] getSupportedCipherSuites()
In addition to the above methods, SSLServerSocketFactory inherits from ServerSocketFactory the following method
ServerSocket createServerSocket(int port)                                         
This methods creates a server socket bound to a specific port. There are other overloads of this method which we do not go into. Here is an example that creates an SSLServerSocketFactory and prints out the set of default ciphers as well as the set of supported ciphers.
package sslexample;
import javax.net.*;
import javax.net.ssl.*;

public class Main
{
    public static void main(String[] args)
    {
        SSLServerSocketFactory sslssf =
                (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
        String [] supportedCiphers = sslssf.getSupportedCipherSuites();
        String [] defaultCiphers = sslssf.getDefaultCipherSuites();
        // print the default and supported ciphers
        System.out.println("Supported Ciphers: ");
        for (String s : supportedCiphers)
        {
            System.out.println(s);
        }
        System.out.println("Default Ciphers: ");
        for (String s : defaultCiphers)
        {
            System.out.println(s);
        }
    }
}
The output looks like this
Supported Ciphers: 
SSL_RSA_WITH_RC4_128_MD5
SSL_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_DES_CBC_SHA
SSL_DHE_RSA_WITH_DES_CBC_SHA
SSL_DHE_DSS_WITH_DES_CBC_SHA
SSL_RSA_EXPORT_WITH_RC4_40_MD5
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
SSL_RSA_WITH_NULL_MD5
SSL_RSA_WITH_NULL_SHA
SSL_DH_anon_WITH_RC4_128_MD5
TLS_DH_anon_WITH_AES_128_CBC_SHA
SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
SSL_DH_anon_WITH_DES_CBC_SHA
SSL_DH_anon_EXPORT_WITH_RC4_40_MD5
SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA
TLS_KRB5_WITH_RC4_128_SHA
TLS_KRB5_WITH_RC4_128_MD5
TLS_KRB5_WITH_3DES_EDE_CBC_SHA
TLS_KRB5_WITH_3DES_EDE_CBC_MD5
TLS_KRB5_WITH_DES_CBC_SHA
TLS_KRB5_WITH_DES_CBC_MD5
TLS_KRB5_EXPORT_WITH_RC4_40_SHA
TLS_KRB5_EXPORT_WITH_RC4_40_MD5
TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA
TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5

Default Ciphers: 
SSL_RSA_WITH_RC4_128_MD5
SSL_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_DES_CBC_SHA
SSL_DHE_RSA_WITH_DES_CBC_SHA
SSL_DHE_DSS_WITH_DES_CBC_SHA
SSL_RSA_EXPORT_WITH_RC4_40_MD5
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
The cipher suite show the key agreement algorithm (RSA or DHE), Session encryption algorithm and optionally, the key size (RC4-128); and a MAC algorithm.

Simple Example Server

We now give an example of a server.
package sslserver;
import java.io.*;
import java.net.*;
import javax.net.ssl.*;

public class Main
{
    public static void main(String[] args) throws IOException
    {
       SSLServerSocketFactory ssf =
           (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
       ServerSocket sslServerSocket = ssf.createServerSocket(50000);

       //Wait for a connection
       System.out.println("Waiting for a connection");
       Socket sock = sslServerSocket.accept();
       System.out.println("Got a connection");
       // Get the input stream. This will be automatically decrypted
       BufferedReader bR =
               new BufferedReader(new InputStreamReader(sock.getInputStream()));
       String line = bR.readLine();
       while (line != null)
       {
           System.out.println(line);
           line = bR.readLine();
       }
       // Close the buffered reader and underlying input stream
       bR.close();
       // close the socket
       sock.close();
    }
}
Here is a client
package sslclient;
import java.io.*;
import java.net.*;
import javax.net.ssl.*;

public class Main
{
    public static void main(String[] args) throws IOException
    {
       SSLSocketFactory ssf =
           (SSLSocketFactory)SSLSocketFactory.getDefault();
       Socket sslSocket = ssf.createSocket("localhost", 50000);

       PrintWriter pR = new PrintWriter(sslSocket.getOutputStream(), true);
       pR.println("Hello Secure Sockets!");
       pR.println("I Love security!");
       pR.close();
       sslSocket.close();
    }
}

Creating a Server Certificate

Now create a certificate in a keystore, specifying the RSA algorithm
keytool -genkey -v -keyalg RSA -alias mytestcert
This will create a keystore in the default keystore location. (If you already have a keystore there, you may want to delete it.)

Running the Server

When you run the server, you will need to tell it where its certificate is. First do a Clean and Build operation on the project in Netbeans. This will place an executable jar file in the dist folder of the project. Then, Copy the .keystore file to the dist directory of the server project. Next, run the server with the following command line:
java -jar -Djavax.net.ssl.keyStore=.keystore
          -Djavax.net.ssl.keyStorePassword=csccsc SSLServer.jar
Here you are simply specifying the password you used to create the keystore. (This assumes you are using the keystore password to access the certificate.)

Running the Client

The client needs a truststore, which is a database of trusted certificates. We will copy the keystore and place it into the dist directory of the SSL client and use it for the truststore. Use the following command:
java -jar -Djavax.net.ssl.trustStore=.keystore SSLClient.jar

Homework 3: Secure File Transfer

Write a client-server application that allows users to register, log in, save files, and retrieve files. The server will create a separate folder for each user, with the name of the folder being the username. This folder will be used to store the user's files.

The client should work as follows. When executed, it asks the user for the IP address of the secure file server. IP addresses will be entered in as strings in dotted decimal notation. The client will then establish a connection to server. Next, the client will ask the user to register or log in. At this point, the user should respond with one of the commands:

login username
register username

Where username is a the user's name. The client will then ask the user to enter a password.

If the user is registering, the client will require the user to enter the same password twice, reprompting for the password as necessary until the user enters the same password twice. At that point, the client will automatically log the user in and allow the user to execute commands to transfer files. An attempt to register a user name that is already in use will be flagged as an error, and the user will be asked to select a different user name.

If the user is logging in, the client will ask the server to authenticate the user using the password supplied by the user. If a user enters an incorrect password for an existing user name, the client gives him or her two more attempts to get the password right before exiting. If a user tries to log in with an unknown user name, the client prints an error message and allows the user to enter the user name again. A user gets 3 tries to get the user name right: after that, the client exits.

Next the client will go into a loop, allowing the user to enter any of the following commands:

list
put 
get filename
bye

The list command will display a list of all files currently stored in the user's account on the server machine.

The put command causes the client to bring up a choose file dialog. The file selected by the user on the local machine will be transmitted to the server and stored there in the user's folder on the server machine. The file stored on the remote server must have the same name as the local file. If a file of the same name already exists on the server is the user's folder, it is overwritten with the new file.

The get filename command causes the client to fetch the file with the given name from the user's folder on the remote server. The client then will pop up a save file dialog and allow the user to store the retrieved file on the local machine (in a directory of the user's choosing).

The quit command will close the connection to the remote server and exit the client program.

The server machine should run on TCP port 50000. Once started, the server will run forever. It will wait for a connection request from the user. The server will then process commands from this connection until the connection terminates (This can be done by the client sending a special "bye" command when it is done.) At this point, the server will go back to waiting for the next connection request. You may make the server multi-threaded if you know how.

You will need to devise an application protocol to make this work. A natural way to devise the protocol is to base it around the commands that the user types to the client.

Finally, make sure your client does not echo passwords to the screen as they are being entered. To do this, you should use the readPassword() method of the Consol class.

What to hand in:

  1. A word file or text file: this file will lay out the application protocol that the client uses to communicate with the server. This is just the structure or format of the messages that the client sends to the server in response to user commands, and the format of the messages sent back by the server in reply.
  2. A Netbeans folder for the client program
  3. A Netbeans folder for the server program

Important: Your application needs to be secure. It must take adequate measures to protect user passwords while they are being typed in. It should also provide confidentiality for the network exchanges between the client and the server, so that any person monitoring the transmissions will not be able to decipher the contents of the messages exchanged. Furthermore, the application should be resistant to data tampering: that is, it must ensure data integrity. Note that SSL already provides confidentiality and integrity. The server should save a password file on disk in encrypted form.

You should assume that both programs will be executed on the commandline, and that the keystore required by the server will be in the same directory in which the server jar file is being run. Likewise, assume that the truststore required by the client will also be in the same directory in which the client jar file is being run.

This is due Monday of Week 8.