Secure Internet Programming We demonstrate how to build secure Internet applications based on. The first part is concerned with the server-side and the next part will be concerned with the client-side. Table of contents 1. Introduction .............................................................................................................3 2. Overview of SSL .......................................................................................................4 2.1. SSL and the TCP/IP Protocol Stack ..........................................................................4 2.2. Negotiable Encryption............................................................................................5 3. JSSE........................................................................................................................8 3.1. Programming with JSSE .........................................................................................8 4. 3.1.1. SSLSocket and SSLServerSocket ......................................................................8 3.1.2. SSLSocketFactory and SSLServerSocketFactory .................................................9 3.1.3. Making Existing Client/Server Applications Secure ..............................................9 Example: HTTP Server ............................................................................................. 12 4.1. Overview of HTTP ............................................................................................... 12 4.2. Insecure HTTP Server .......................................................................................... 13 Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 1/26 4.3. Extending HttpServer to Handle https:// URLs ........................................................ 20 4.4. Links ................................................................................................................. 26 Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 2/26 1. Introduction Any information transmitted over computer networks, or the Internet, is subject to interception. Some of that information could be sensitive, such as credit card numbers and other personal data. To make the Internet more useful in an enterprise setting and for e-commerce, applications must protect their users' information, using encryption, authentication, and secure communications protocols. The secure Hypertext Transfer Protocol (HTTPS), which is HTTP over the Secure Sockets Layer (SSL), is already being used successfully for e-commerce applications. The Java Secure Socket Extension (JSSE), which is a set of Java packages that enable secure Internet communications, is a framework and 100% Pure Java implementation of the Secure Socket Layer (SSL). These packages enable a Java developer to develop secure network applications that feature the secure passage of data between a client and a server running any application protocol, such as HTTP, FTP, Telnet, or NTTP, over TCP/IP. TM JSSE has been integrated into the Java 2 SDK, Standard Edition, version 1.4 (J2SE 1.4). Here we start by presenting a detailed overview of SSL, then shows you how to: TM Use the JSSE APIs Integrate SSL into your existing client-server applications Develop a simple HTTP server Revise the HTTP server to handle HTTPS requests Generate your own certificates using the keytool delivered with J2SE Develop, configure, and run a secure HTTP server Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 3/26 2. Overview of SSL The SSL protocol, which was developed by Netscape in 1994, allows clients (Web browsers, typically) and HTTP servers to communicate over a secure connection. It offers encryption, source authentication, and data integrity as means to protect information exchanged over insecure, public networks. There are several versions of SSL: SSL 2.0 has security weaknesses and is hardly used today; SSL 3.0 is universally supported; and finally the Transport Layer Security (TLS), which is an improvement on SSL 3.0, has been adopted as an Internet standard and is supported by almost all recent software. Encryption protects data from unauthorized use by converting it to an apparently meaningless form before transmission. The data is encrypted by one side (the client or the server), transmitted, decrypted by the other side, then processed. Source authentication is a method of verifying the data sender's identity. The first time a browser or other client attempts to communicate with a Web server over a secure connection, the server presents the client with a set of credentials in the form of a certificate. Certificates are issued and validated by trusted authorities known as certification authorities (CAs). A certificate represents the public-key identity of a person. It is a signed document that says: I certify that the public key in this document belongs to the entity named in this document. Well-known CAs include Verisign, Entrust, and Thawte. Data integrity refers to means of ensuring that data has not been modified in transit. 2.1. SSL and the TCP/IP Protocol Stack As the name Secure Sockets Layer indicates, SSL connections act like sockets connected by TCP. Therefore, you can think of SSL connections as secure TCP connections since the place for Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 4/26 SSL in the protocol stack is right above TCP and below the application layer as shown in Figure 1. It is important to note, however, that SSL doesn't support some of the TCP features such as out-of-band data. Figure 1: SSL and the TCP/IP protocol stack 2.2. Negotiable Encryption Among the features of SSL that have made it the de facto standard vehicle for secure ecommerce transactions is its support for negotiable encryption and authentication algorithms. The designers of SSL realized that not all parties will use the same client software and consequently not all clients will include any particular encryption algorithm. The same is true for servers. The client and server at the two ends of a connection negotiate the encryption and decryption algorithms (cipher suites) during their initial handshake. It may turn out that they do not have sufficient algorithms in common, in which case the connection attempt will fail. Note that while SSL allows both the client and the server to authenticate each other, typically only the server is authenticated in the SSL layer. Clients are customarily authenticated in the application layer, through the use of passwords sent over an SSL-protected channel. This pattern is common in banking, stock trading, and other secure Web applications. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 5/26 The SSL full handshake protocol is illustrated next. It shows the sequences of messages exchanged during the SSL handshake. 1. ClientHello: The client sends the server infor- mation such as SSL protocol version, session id, and cipher suites information such cryptographic algorithms and key sizes supported. 2. ServerHello: The server chooses the best cipher suite that both the client and server support and sends this information to the client. 3. Certificate: The server sends the client its cer- tificate which contains the server's public key. While this message is optional, it is used when server authentication is required. In other words, it is used to confirm the server's identity to the client. 4. Certificate Request: This message is sent only if the server requires the client to authenticate itself. Most e-commerce applications do not require the client to authenticate itself. 5. Server Key Exchange: This message is sent if the certificate, which contains the server's public key, is not sufficient for key exchange. 6. ServerHelloDone: This message informs the cli- ent that the server finished the initial negotia- tion process. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 6/26 7. Certificate: This message is sent only if the server requested the client to authenticate itself. 8. Client Key Exchange: The client generates a secret key to be shared between the client and server. If the Rivest-Shamir-Adelman (RSA) encryption algorithm is used, the client encrypts the key using the server's public key and sends it to the server. The server uses its private or secret key to decrypt the message and retrieves the shared secret key. Now, client and server share a secret key that has been distributed securely. 9. Certificate Verify: If the server requested to authen- ticate the client, this message allows the server to complete the authentication process. Change Cipher Spec: The client asks the server to change to encrypted mode. 10. Finished: The client tells the server it is ready for secure communication. 11. Change Cipher Spec: The server asks the client to change to encrypted mode. 12. Finished: The server tells the client it is ready for secure communication. This marks the end of the SSL handshake. 13. Encrypted Data: The client and server can now start exchanging encrypted messages over a secure communication channel. 14. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 7/26 3. JSSE The Java Secure Socket Extension (JSSE) provides a framework and a 100% Pure Java implementation of the SSL and TLS protocols. It provides mechanisms for data encryption, server authentication, message integrity, and optional client authentication. The JSSE framework is capable of supporting many different secure communication protocols such as SSL 2.0 and 3.0 and TLS 1.0, but the J2SE v1.4.1 implements SSL 3.0 and TLS 1.0. 3.1. Programming with JSSE The JSSE APIs supplement the java.security and java.net packages by providing extended networking socket classes, trust and key managers, and a socket factory framework for encapsulating socket creation behaviour. These classes are included in the packages javax.net and javax.net.ssl. 3.1.1. SSLSocket and SSLServerSocket The javax.net.ssl.SSLSocket is a subclass of the java.net.Socket class. Therefore, it supports all the standard Socket methods and adds additional methods specific to secure sockets. The javax.net.ssl.SSLServerSocket class is analogous to the SSLSocket class except that it is used to create server sockets. Creating an instance of SSLSocket can be done in two ways: As an instance of SSLSocketFactory by invoking one of the createSocket methods on that class. Through the accept method on the SSLServerSocket. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 8/26 3.1.2. SSLSocketFactory and SSLServerSocketFactory The javax.net.ssl.SSLSocketFactory class is an object factory for creating secure sockets, and the javax.net.ssl.SSLServerSocketFactory is an object factory for creating server sockets. An SSLSocketFactory instance can be obtained in two ways: Get the default factory by calling SSLSocketFactory.getDefault. Construct a new factory with specified configured behavior. Note that the default factory is configured to enable server authentication only. 3.1.3. Making Existing Client/Server Applications Secure Incorporating SSL into existing client/server applications to make them secure can be easily done using a few lines of JSSE code. The lines highlighted in yellow in the following example show the code necessary to make a server secure: Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 9/26 import java.io.*; import javax.net.ssl.*; public class Server { int port = portNumber; SSLServerSocket server; try { SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); server = (SSLServerSocket) factory.createServerSocket(portNumber); SSLSocket client = (SSLSocket) server.accept(); // Create input and output streams as usual // send secure messages to client through the // output stream // receive secure messages from client through // the input stream } catch(Exception e) { } } Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 10/26 The lines highlighted in yellow in the following example show the code necessary to make a client secure: import java.io.*; import javax.net.ssl.*; public class Client { ... try { SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket client = (SSLSOcket) factory.createSocket(serverHost, port); // Create input and output streams as usual // send secure messages to server through the // output stream receive secure // messages from server through the input stream } catch(Exception e) { } } … Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 11/26 4. Example: HTTP Server We demonstrate how to develop, configure, and run a complete HTTP server application that supports the GET request method. First, we build a HTTP server, next we make it secure, implementing SSL capabilities. 4.1. Overview of HTTP The Hypertext Transfer Protocol (HTTP) is a request-reply application protocol. This protocol supports a fixed set of methods such as GET, POST, PUT, DELETE, etc. The GET method is commonly used to request resources from a Web server. Here are two sample GET requests: GET / HTTP/1.0 <empty-line> GET /names.html HTTP/1.0 <empty-line> The server we consider is simple since it only supports the GET request method. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 12/26 GET /index.html HTTP/1.1 client HTTP/1.0 200 OK … server <HTML> … 4.2. Insecure HTTP Server Our implementation is a multi-threaded HTTP server where the ProcessConnection class is used to run each new request in a different thread. When the server receives a request from the client, it parses the request to find out which document is being requested. If the requested document is available on the server, the shipDocument method is used to send the requested document to the server. If the document is not found, an error message is sent to the server. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 13/26 $ cat HttpServer.java import java.io.*; import java.net.*; import java.util.StringTokenizer; /** * This class implements a multithreaded simple HTTP * server that supports the GET request method. * It listens on port 9999, waits client requests, and * serves documents. */ public class HttpServer { // The port number which the server will be listening on public static final int HTTP_PORT = 9999; public ServerSocket getServer() throws Exception { return new ServerSocket(HTTP_PORT); } Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 14/26 // multi-threading -- create a new connection for each request public void run() { ServerSocket listen; try { listen = getServer(); while(true) { Socket client = listen.accept(); ProcessConnection cc = new ProcessConnection(client); } } catch(Exception e) { System.out.println("Exception:"+e.getMessage()); } } // main program public static void main(String argv[]) throws Exception { HttpServer httpserver = new HttpServer(); httpserver.run(); } } Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 15/26 class ProcessConnection extends Thread { Socket client; BufferedReader is; DataOutputStream os; public ProcessConnection(Socket s) { // constructor client = s; try { is = new BufferedReader(new InputStreamReader (client.getInputStream())); os = new DataOutputStream(client.getOutputStream()); } catch (IOException e) { System.out.println("Exception: "+e.getMessage()); } this.start(); // Thread starts here...this start() will call run() } Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 16/26 public void run() { try { // get a request and parse it. String request = is.readLine(); System.out.println( "Request: "+request ); StringTokenizer st = new StringTokenizer( request ); if ( (st.countTokens() >= 2) && st.nextToken().equals("GET") ) { if ( (request = st.nextToken()).startsWith("/") ) request = request.substring( 1 ); if ( request.equals("") ) request = request + "index.html"; File f = new File(request); shipDocument(os, f); } else { os.writeBytes( "400 Bad Request" ); } client.close(); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); } } Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 17/26 // Read the requested file and ships it to the browser if found. public static void shipDocument(DataOutputStream out, File f) throws Exception { try { DataInputStream in = new DataInputStream(new FileInputStream(f)); int len = (int) f.length(); byte[] buf = new byte[len]; in.readFully(buf); in.close(); out.writeBytes("HTTP/1.0 200 OK\r\n"); out.writeBytes("Content-Length: " + f.length() +"\r\n"); out.writeBytes("Content-Type:text/html\r\n\r\n"); out.write(buf); out.flush(); } catch (Exception e) { out.writeBytes( "<html><head><title>error</title></head><body>\r\n\r\n"); out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n"); out.writeBytes("Content-Type: text/html\r\n\r\n"); out.writeBytes("</body></html>"); out.flush(); } finally { out.close(); } } } // ProcessConnection $ Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 18/26 The server listens on port 9999, thus we have to use the following URL in a browser: http://localhost:9999/index.html To visualise the data, transferred between client and server, we use the TCP/IP monitor tcpmon out of the Axis project. $ java org.apache.axis.utils.tcpmon 9998 localhost 9999 tcpmon listens to port 9998, tunnelling the data further to port 9999 on localhost. Therefore, we use the URL http://localhost:9998/index.html and see that we have readable text. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 19/26 4.3. Extending HttpServer to Handle https:// URLs Now, let's modify the HttpServer class, making it secure. As mentioned earlier, SSL uses certificates for authentication. Certificates must be created for clients and servers that need to communicate securely using SSL. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 20/26 JSSE uses certificates created using the Java keytool shipped with J2SE. We used the following command to create an RSA certificate for the HTTP server. $ keytool -genkey -keystore serverkeys -keyalg rsa -alias as Geben Sie das Keystore-Passwort ein: pwd123 Wie lautet Ihr Vor- und Nachname? [Unknown]: Alois Schuette Wie lautet der Name Ihrer organisatorischen Einheit? [Unknown]: FHD Wie lautet der Name Ihrer Organisation? [Unknown]: Informatik Wie lautet der Name Ihrer Stadt oder Gemeinde? [Unknown]: Darmstadt Wie lautet der Name Ihres Bundeslandes oder Ihrer Provinz? [Unknown]: Hessen Wie lautet der Landescode (zwei Buchstaben) für diese Einheit? [Unknown]: de Ist CN=Alois Schuette, OU=FHD, O=Informatik, L=Darmstadt, ST=Hessen, C=de richtig? [Nein]: ja Geben Sie das Passwort für <as> ein. (EINGABETASTE, wenn Passwort dasselbe wie für Keystore): $ Now, we have a file „serverkeys“ holding our certificate for the server. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 21/26 Once a certificate for the server has been generated, we can revise my HttpServer to make it secure. If you examine the HttpServer class, you'll notice that the getServer method is used to return a server socket. This means, the only method I need to modify is the getServer method so that it returns a secure server socket. The changes are highlighted in yellow. The lines: String keystore = "serverkeys"; char keystorepass[] = "pwd123".toCharArray(); char keypassword[] = "pwd123".toCharArray(); specify the name of the keystore, its password, and the key password. Hardcoding the passwords into the code is not a good idea for production code, however. They can be specified on the command line when running the server. The rest of the JSSE related code is in the getServer method: It access the serverkeys keystore. The JKS is the Java KeyStore (a type of keystore created by keytool). The KeyManagerFactory is used to create an X.509 key manager for the keystore. An SSLContext is an environment for implementing JSSE. It is used to create a ServerSocketFactory that in turn used to create a SSLServerSocket. Although we specify SSL 3.0, the implementation that is returned will often support other protocol versions, such as TLS 1.0. Older browsers, however, use SSL 3.0 more widely. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 22/26 Note that by default client authentication is not required. For if you wish for your server to require client authentication, use: serversocket.setNeedClientAuth(true). $ cat HttpsServer.java import java.io.*; import java.net.*; import javax.net.*; import javax.net.ssl.*; import java.security.*; import java.util.StringTokenizer; /** * This class implements a multithreaded simple HTTPS * server that supports the GET request method. * It listens on port 44, waits client requests * and serves documents. */ Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 23/26 public class HttpsServer { String keystore = "serverkeys"; char keystorepass[] = "pwd123".toCharArray(); char keypassword[] = "pwd123".toCharArray(); // The port number which the server will be listening on public static final int HTTPS_PORT = 9999; public ServerSocket getServer() throws Exception { KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream(keystore), keystorepass); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, keypassword); SSLContext sslcontext = SSLContext.getInstance("SSLv3"); sslcontext.init(kmf.getKeyManagers(), null, null); ServerSocketFactory ssf = sslcontext.getServerSocketFactory(); SSLServerSocket serversocket = (SSLServerSocket) ssf.createServerSocket(HTTPS_PORT); return serversocket; } Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 24/26 // multi-threading -- create a new connection for each request public void run() { … } // main program public static void main(String argv[]) throws Exception { HttpsServer https = new HttpsServer(); https.run(); } } class ProcessConnection extends Thread { … } // ProcessConnection $ When you enter an https:// URL in the browser, you get a security alert popup window. This is because the HTTP server certificate was self-generated. In other words, it was generated by an unknown certification authority, one that was not found among the certification authorities your browser keeps in its store. You have the option to view the certificate (check whether it is a proper certificate and discover who signed it) and then install it, reject the certificate, or accept the certificate. Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 25/26 Generating your own certificate is fine for internal private systems. For public systems, however, it is a good idea to get a certificate from a well known Certification Authority in order to avoid the browser security alert. If you accept the certificate you will be able to see the page behind the secure connection, and future access to the same Web site will not cause the browser to issue a security alert. When you accept the certificate, it is only for that session. Using tcpmon with proxy enabled demonstrate that we have ciphered data over our connection. 4.4. Links SSL 3.0 Java Secure Socket Extension (JSSE) JSSE Reference Guide tcpmon keytool Distributed Programming in Java: 106744054 Prof. Dr. Alois Schütte 26/26