JSSE Certificates An Overview of SSL and JSSE

14.2.2 SSL Sockets

SSL client sockets are obtained from the SSLSocketFactory class javax.net.ssl.SSLSocketFactory , which extends the SocketFactory class javax.net.SocketFactory . The SSLSocketFactory class overrides the getDefault method to provide a factory that produces SSL sockets: public static SocketFactory getDefault Obtain the default SSL socket factory for this implementation. That factory can be used to obtain SSL sockets. The default implementation is defined in the JREHOMElibsecurityjava.security file by the property ssl.SocketFactory.provider . If this is not set by default, it is not, a hardwired, internal implementation is used. Like its server analogue, the ssl.SocketFactory.provider property is ignored in the exportable version of JSSE. The default socket factory will handle both SSL 3.0 and TLS 1.0 protocols. Heres how we can write a simple client: package javasec.samples.ch14; import java.io.; import java.net.; import javax.net.; import javax.net.ssl.; public class SSLSimpleClient { public static void mainString[] args throws Exception { SocketFactory sf = SSLSocketFactory.getDefault ; Socket s = sf.createSocketargs[0], Integer.parseIntargs[1]; BufferedReader br = new BufferedReader new InputStreamReader s.getInputStream ; PrintWriter pw = new PrintWriters.getOutputStream ; System.out.printlnWho is Sylvia?; pw.printlnWho is Sylvia?; pw.flush ; System.out.printlnbr.readLine ; s.close ; } } Note again that we used the SSLSocketFactory class to obtain the socket factory; to use this client to connect to a non−SSL server, wed change the first line of the main method to use the SocketFactory class instead. The socket returned from the SSL socket factory will be an instance of the SSLSocket class javax.net.ssl.SSLSocket , which extends the Socket class. For the most part you can treat it like any other socket, but we will look at some advanced ways of handling the SSL socket a little later. To run this program, we must supply the host and port that we want to contact. More importantly, the server will present its certificate to us, and we must have the root certificate of the servers CA in our truststore. Using the truststore we created earlier, we can run the client with this command: piccolo java −Djavax.net.ssl.trustStore=HOME.truststore \ javasec.samples.ch14.SSLSimpleClient localhost 9096 Who is Sylvia? What is she? The first line of output is the string we sent to the server; the second line is the string returned by the server. At this point, weve developed a very simple server and client that communicate via SSL. Weve relied on the SSL implementation to provide many of the details of this communication for us: the certificates used for verification, the cipher suites used, and so on. In the next few sections, well look at the SSL support classes that allow us to modify these things.

14.3 SSL Sessions

When an SSL socket is connected, it joins an SSL session. Every SSL socket belongs to one SSL session. If there are many connections between a client and server they may share an SSL session, but there is no programmatic way to determine which sockets are attached to which sessions. From our perspective, the SSL session is just an object that allows us to retrieve certain information about a particular SSL connection. Specifically, the SSL session allows us to perform a necessary but often ignored step in the verification of an SSL peer. In our first example, the server has sent its certificate to the client. If the client recognized the CA that issued the servers certificate, we allowed communication to proceed. However, as weve mentioned before, just because someone has a valid certificate does not necessarily mean that they can be trusted. I can get a valid certificate for www.myevilenterprise.com and then spoof your DNS server so that when you attempt to connect to shopping.oreilly.com, you get connected to me. Just because I present a certificate to you is no assurance that I am authorized to take your credit card information. So when you make an SSL connection, you should verify that the server certificate contains the information you expect. Typically, this means that the name within the certificate should be the domain name of the machine to which youre connecting. If your server requires clients to authenticate themselves, the server should follow this procedure with the clients certificate as well. To verify this, you must use an object that implements the SSLSession interface javax.net.ssl.SSLSession . SSL session objects are retrieved from the SSLSocket class using this method: public SSLSession getSession Retrieve the SSL session associated with this SSL socket. Because this method operates on an SSL socket and not a generic socket, well have to modify the protocol−independent technique we used in our first client in order to use it. Now when we get a socket back from the SSLSocketFactory , well have to cast it to an SSLSocket object. Nonetheless, verifying the name in the servers certificate is important enough to warrant the protocol−specific code. The SSLSession interface contains the following methods: public byte[] getId Return the arbitrary identifier assigned to this session. Chapter 14. SSL and HTTPS public SSLSessionContext getSessionContext Return the session context associated with this session. The session context simply groups together multiple SSL sessions; we wont use it in our examples. public long getCreationTime Return the time at which this SSL session was created. public long getLastAccessedTime Return the time at which this SSL session was last accessed i.e., when a new connection was last added to the session. public void invalidate Invalidate this session. Existing connections will not be affected by this call; new connections will need to join a new session. public void putValueString name, Object value Bind an object into this session, associated with the given name. public Object getValueString name Return the bound object associated with the given name. public void removeValueString name Remove the bound object associated with the given name. public String[] getValueNames Retrieve the names of all bound objects. public javax.security.cert.X509Certificate[] getPeerCertificateChain Retrieve the certificate chain that the peer sent in order to verify itself to us. This method throws an SSLPeerUnverifiedException in two cases: if the server executes this method but does not require the client to authenticate itself, and if the certificates presented by the peer are not recognized that is, if the root certificate does not correspond to a certificate held in the truststore. public String getCipherSuite Return the name of the cipher suite that the peers negotiated. public String getPeerHost Return the name of the host to which this socket is connected. Unless youre writing your own implementation of JSSE, the last three methods are really the only ones that are useful. The SSL protocol defines a technique by which SSL connections can be reestablished without a full time−consuming handshake, and SSL sessions can be used to provide that. However, that detail is 272 dependent on the JSSE implementation and is not something we can change programatically. We will use the last three methods to modify our original client. We can use the relevant methods of the SSL session to retrieve information and complete the verification of the server. Changes to our original client are shown in bold: package javasec.samples.ch14; import java.io.; import java.net.; import javax.net.; import javax.net.ssl.; import javax.security.cert.; public class SSLClientVerifier { public static void mainString[] args throws Exception { SocketFactory sf = SSLSocketFactory.getDefault ; SSLSocket s = SSLSocket sf.createSocket args[0], Integer.parseIntargs[1]; SSLSession sess = s.getSession ; String host = sess.getPeerHost ; X509Certificate[] certs = sess.getPeerCertificateChain ; String dn = certs[0].getSubjectDN.getName ; X500Name name = new X500Namedn; if host.equalsname.getCN System.err.printlnWarning: Expected + host + and got + name.getCN ; BufferedReader br = new BufferedReader new InputStreamReader s.getInputStream ; PrintWriter pw = new PrintWriters.getOutputStream ; System.out.printlnWho is Sylvia?; pw.printlnWho is Sylvia?; pw.flush ; System.out.printlnbr.readLine ; s.close ; } } We use the session object to retrieve the servers certificate. If the common name in the servers certificate is not equal to its hostname, we print out a warning message. It is conceivable that the name we used to construct the socket may not exactly match the name embedded within the certificate, so we should obtain the IP addresses of both and ensure that they are the same. Thats the technique well use a little later when we perform HTTP client verification. Note that this is the same thing a browser does when the name within a site certificate does not match the name within the URL. If you run this with the test keystore created earlier youll see the warning message, but if you create another keystore with the common name equal to the hostname of your server, this code will execute without the warning.

14.4 SSL Contexts and Key Managers