Working with Key Managers

} protected void engineInitKeyStore ks, char[] pw { this.ks = ks; this.pw = new char[pw.length]; System.arraycopypw, 0, this.pw, 0, pw.length; } } The key manager factory expects a keystore and a password but not an alias, so weve had to specify the alias via a system property. In general, if you need other initialization fields in your own key manager, this is the way to get them. This engine class requires a security provider, of course; well use the provider from Chapter 8, which contains this mapping: putKeyManagerFactory.XYZ, javasec.samples.ch14.SSLKeyManagerFactory; Finally, heres how we use the key manager within our server: package javasec.samples.ch14; import java.io.; import java.net.; import java.security.; import javax.net.; import javax.net.ssl.; import javax.security.cert.; import com.sun.net.ssl.; import javasec.sample.ch08.XYZProvider; public class SSLServerKeyManager { public static void mainString[] args throws Exception { Security.addProvidernew XYZProvider ; SSLContext sc = SSLContext.getInstanceTLS; KeyStore ks = KeyStore.getInstancejceks; char[] password = args[1].toCharArray ; ks.loadnew FileInputStreamargs[0], null; KeyManagerFactory kmf = KeyManagerFactory.getInstanceXYZ; kmf.initks, password; sc.initkmf.getKeyManagers , null, null; ServerSocketFactory ssf = sc.getServerSocketFactory ; ServerSocket ss = ssf.createServerSocket9096; while true { new SSLSimpleServerss.accept.start ; } } } The only code change here is that weve installed the security provider and used the XYZ algorithm to provide the key manager factory. However, when we run this version of the server, we must remember to set the xyz.aliasName property to an entry in the keystore that were loading: piccolo java −Dxyz.aliasName=sdo javasec.samples.ch14.SSLServerKeyManager \ HOME.keystore

14.4.2 Working with Trust Managers

There is less need to provide a custom trust manager than to provide a custom key manager. Unlike the key manager, the trust manager is never asked to provide a specific alias or single certificate: it is asked to provide all the certificates it can use to validate a peer, and it is asked to validate peers. Hence, you might provide a custom trust manager if you want to limit the certificates from a truststore that you use to validate peers or if you want to do some sort of special validation of a peer such as checking an external certificate−revocation list. Trust managers generally are provided from trust manager factories. The TrustManagerFactory class com.sun.net.ssl.TrustManagerFactory is completely analogous to the KeyManagerFactory class: it contains a static getDefaultAlgorithm method that returns the sun.ssl.trustmanager.type property defined in the JREHOMElibsecurityjava.security file. By default that property is not defined, and the algorithm defaults to SunX509. The static getInstance methods of the TrustManagerFactory class provide specific trust manager factories, and the getTrustManager method returns an array of trust managers that a specific factory defines. Similarity to the KeyManagerFactory interface extends to the definition of the trust manager itself. The TrustManager interface com.sun.net.ssl.TrustManager is an empty interface, and Suns implementation of the SSLContext class requires that the trust manager actually implement the X509TrustManager interface com.sun.net.ssl.X509TrustManager . Well briefly discuss the X509TrustManager interface here. Its a simple enough interface that we wont show a complete example that uses it. The interface contains the following three methods: public boolean isClientTrustedX509Certificate[] chain Check that the chain of certificates provided by the peer can be validated by root certificates in the truststore and that the validation is trusted for client−side SSL that is, your server should trust the connecting client. public boolean isServerTrustedX509Certificate[] chain Check that the chain of certificates provided by the peer can be validated by root certificates in the truststore and that the validation is trusted for server−side SSL that is, whether your client should trust the server to which you are connecting. public X509Certificate[] getAcceptedIssuers Return the list of certificates you will use to validate the peer. This is normally all the root certificates in the truststore.

14.5 Miscellaneous SSL Issues

Finally, there are a number of miscellaneous SSL issues that the SSL socket API is designed to handle, including SSL proxies, client−side authentication, choosing a cipher suite, SSL handshaking, and JSSE permissions. Chapter 14. SSL and HTTPS

14.5.1 SSL Proxies

SSL clients often need to make connections through a proxy server; this enables them to make requests through a firewall. If you need to make a connection through a proxy server, use this method of the SSLSocketFactory class: public abstract Socket createSocketSocket s, String host, int port, boolean autoClose Create an SSL socket to the given host and port that uses the existing socket as its proxy. The existing socket is a standard plain socket that has been connected to the appropriate proxy host and proxy port. If autoClose is true , the underlying socket will be closed when this socket is closed. If the socket cannot be created, an IOException is thrown. If youre using your own protocol, its up to you to define what data should flow between your program and the proxy server before layering the sockets with this call. If youre using HTTPS, you must send a connect string and read the headers from the proxy server on the underlying socket before you create the SSL socket. JSSE comes with a set of sample code that shows how this can be accomplished. However, if youre using HTTPS as your protocol, its far easier to use the HTTPS protocol handler, which handles all these details for you see Section 14.6 later in this chapter.

14.5.2 Client−Side Authentication

As weve mentioned, in most SSL conversations the server presents credentials to the client and the client verifies those credentials; the client is then assured of the servers identity. The client does not normally present its certificate credentials to the server; in fact, the client is not even required to possess such credentials. SSL servers can require the client authenticate itself as well, however. To do this, the server uses the setNeedClientAuth method on its server socket as follows: SSLContext sc = ... set up context as before ... SSLServerSocketFactory sssf = SSLServerSocketFactory sc.getServerSocketFactory ; SSLServerSocket sss = SSLServerSocket sssf.createServerSocket9096; sss.setNeedClientAuthtrue; Note that this leads us further from the path of protocol−independent socket factories. Although the createServerSocket method returns an instance of the ServerSocket class, we must cast that object to an SSLServerSocket in order to call the setNeedClientAuth method. Remember that if you put this code into your server, your server will need a valid truststore that contains the root certificate of the clients certificate chain. Be sure to set the appropriate trustStore property when you run a server with this code.

14.5.3 Choosing an SSL Cipher Suite

When an SSL conversation begins, the client and server negotiate between themselves as to which SSL cipher suite they will use. The suite is chosen based upon the credentials that each side possesses and the suites that each side supports. For example, a server cant support an RSA cipher suite unless it has an available RSA private key. The client and server must support at least one common cipher suite in order to communicate; if they both support multiple ciphers, the strongest available suite will be chosen. SSL sockets in Suns implementation of JSSE support 15 different cipher suites, as listed in Table 14−1. These strings are part of the SSL specification and are defined as SSL_key exchange 282 algorithm_WITH_encryption algorithm_hash algorithm . When a number appears in the encryption algorithm, it refers to the key strength of the encryption: higher numbers are more secure though the highest numbers used to be subject to export control, and many other SSL implementations may not support them. Table 14−1. SSL Cipher Suites Supported by Suns JSSE Implementation Prefix Key Exchange Encryption Hash SSL_ DH_anon_EXPORT_ WITH_DES40_CBC_ SHA SSL_ DH_anon_EXPORT_ WITH_RC4_40_ MD5 SSL_ DH_anon_ WITH_3DES_EDE_CBC_ SHA SSL_ DH_anon_ WITH_DES_CBC_ SHA SSL_ DH_anon_ WITH_RC4_128_ MD5 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_NULL_ MD5 SSL_ RSA_ WITH_NULL_ SHA SSL_ RSA_ WITH_RC4_128_ MD5 SSL_ RSA_ WITH_RC4_128_ SHA Even though these 15 suites are all supported, by default just 8 of them are enabled; those suites are listed in bold in the table. The other suites will not be used unless you enable them explicitly. To see and modify the suites that an SSL socket is using, use the following methods which are defined for both the SSLSocket and SSLServerSocket classes: public abstract String[] getEnabledCipherSuites Return an array containing all the cipher suites that are enabled on the socket. Unless different suites have been enabled, this will return an array containing the eight bold items in Table 14−1. public abstract void setEnabledCipherSuitesString[] suites Set which cipher suites are enabled on the particular socket. The list completely overwrites the old set of enabled suites; if you want to add support for a new suite, you must construct an array containing all the presently enabled suites plus the new suite you want to support. Each string in the given array must have been listed in the array returned by the getSupportedCipherSuites method. public abstract String[] getSupportedCipherSuites Return an array containing all the cipher suites that this implementation supports. To add support for anonymous, exportable Diffie−Hellman key exchange using 40−bit DES encryption and an Chapter 14. SSL and HTTPS SHA hash to a server socket, execute this code: SSLServerSocket sss = ... initialize from socket factory ...; String[] enabled = sss.getEnabledCipherSuites ; String[] newEnabled = new String[enabled.length + 1]; System.arraycopyenabled, 0, newEnabled, 0, enabled.length; newEnabled[enabled.length] = SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA; sss.setEnabledCipherSuitesnewEnabled; If youre writing the client, you must supply similar code for the SSLSocket .

14.5.4 SSL Handshaking

When the SSL client and server negotiate which cipher suite to use, they engage in an SSL handshake. If you want to keep track of the handshake, you can use various handshaking event classes. A handshake event is like any other event. To receive a handshake event, register a class that implements the HandshakeCompletedListener interface javax.net.ssl.HandshakeCompletedListener by calling the addHandshake−CompletedListener method of the SSL socket. For SSL servers, call this method on the socket returned from the accept method of the SSL server socket; it is defined only in the SSLSocket class. The listener can be removed with the removeHandshakeCompletedListener method. When the handshake is complete, the handshakeCompleted method of the handshake listener is called and it is passed a HandshakeCompletedEvent object javax.net.ssl.HandshakeCompletedEvent . This event allows you to retrieve the cipher suite that was negotiated, the certificate chain the peer presented for authentication if applicable, the SSL session that is in use, and the socket on which the event occurred. Note that all of this information is available directly from the SSL socket as well.

14.5.5 JSSE Permissions

To use some features of JSSE in an environment in which a security manager has been installed, untrusted code will need the following permissions: permission com.sun.net.ssl.SSLPermission setHostnameVerifier; permission com.sun.net.ssl.SSLPermission setDefaultAuthenticator; permission com.sun.net.ssl.SSLPermission getSSLSessionContext; The setHostnameVerifier permission is needed to call the setDefault−HostnameVerifier method of the HttpsURLConnection class. It is not needed to call the setHostnameVerifier method of that class; setting the global verifier is the only option considered unsafe. The setDefaultAuthenticator permission is needed to call the setDefaultAuthenticator method of the HttpsURLConnection class. The getSSLSessionContext permission is needed to call the getSessionContext method of the SSLSession class.

14.6 The HTTPS Protocol Handler

SSL is often used as the underlying communication protocol of HTTPS. If youre talking to an HTTPS server you can write the SSL−level code yourself, but its generally easier to use the standard URL class to talk to the server and install a protocol handler that implements the HTTPS protocol. JSSE comes with such a protocol handler. As an example, heres a simple URL−based client that can retrieve arbitrary URLs: package javasec.samples.ch14; import java.io.; import java.net.; public class URLClient { public static void mainString[] args throws Exception { URL u = new URLargs[0]; URLConnection uc = u.openConnection ; BufferedReader br = new BufferedReader new InputStreamReaderuc.getInputStream ; String s = br.readLine ; while s = null { System.out.printlns; s = br.readLine ; } } } You can run this code with an HTTP−based URL as follows: piccolo java javasec.samples.ch14.URLClient http:www.sun.com ... lots of output from sun.com ... Similarly, by specifying the appropriate property for the HTTPS protocol handler, you can connect to an HTTPS−based URL: piccolo java \ −Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol \ javasec.samples.ch14.URLClient https:www.sun.com As always, the server sun.com in this case will present its certificate to the client, which must verify it using its truststore. In this case, weve used the default truststore JREHOMElibsecuritycacerts, which contains the root certificate of many CAs including the one used by Sun. If you connect to your own server, you may need to specify the appropriate trustStore property.

14.6.1 Verifying HTTPS Hosts

When we wrote our own SSL client socket code, we had to extract the name from the servers certificate and make sure that it represented the host to which we expected to connect. The HTTPS protocol handler will do that for us automatically, and if the hostnames dont match, an IOException will be thrown when you attempt to get the input or output stream. There are times when this verification is insufficient. If you connect to https:192.18.297.41, the default verification will fail. The certificate presented by that site has an embedded name of www.sun.com, and even though 192.18.297.41 is the correct IP address, the protocol handler will do a string comparison of 192.18.297.41 and www.sun.com and will fail. In cases such as this you may want to look up the IP address of the name in the certificate and see if it matches your target. You may also want to ask the user if its okay to proceed regardless of whether the names match. To handle such situations, you can implement a hostname verifier in order to perform extended hostname verification. Extended hostname verification is used only if the name in the certificate and the hostname in the URL dont match; if the names match, the HTTPS protocol handler does not call the hostname verifier. Hence, a hostname verifier cannot be used to prevent any arbitrary connection.