JAVA: How to configure a client for using SSL
By design when we open an SSL connection in Java (e.g. through java.net.URL.openConnection(”https://….”)) the JSSE implementation of the SSL protocol performs few validations to ensure the requested host is not fake. This involves validation of the server’s X.509 certificate with the PKIX algorithm and checking the host name agains the certificate subject.
Consider we are trying to download a resource from HTTPS server:
URL url = new URL("https://localhost:8443/");URLConnection con = url.openConnection();Reader reader = new InputStreamReader(con.getInputStream());while (true) {int ch = reader.read();if (ch==-1) {break;}System.out.print((char)ch);}
Exception in thread "main" javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException: PKIX path building failed:sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested targetat com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)...
Exception in thread "main" java.io.IOException: HTTPS hostname wrong: should be <localhost>at sun.net.www.protocol.https.HttpsClient.checkURLSpoofing(Unknown Source)at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
There is a quick and dirty solution: Just tell your client, that you want to accept any certificate, regardless of issuer and host. This can be done by installing a custom TrustManager and a HostnameVerifier. Add the following code to your clients initialization:
import java.io.InputStreamReader;import java.io.Reader;import java.net.URL;import java.net.URLConnection;import javax.net.ssl.HostnameVerifier;import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSession;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;import java.security.cert.X509Certificate;public class Example {public static void main(String[] args) throws Exception {// Create a trust manager that does not validate certificate chainsTrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {public java.security.cert.X509Certificate[] getAcceptedIssuers() {return null;}public void checkClientTrusted(X509Certificate[] certs, String authType) {}public void checkServerTrusted(X509Certificate[] certs, String authType) {}}};// Install the all-trusting trust managerSSLContext sc = SSLContext.getInstance("SSL");sc.init(null, trustAllCerts, new java.security.SecureRandom());HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());// Create all-trusting host name verifierHostnameVerifier allHostsValid = new HostnameVerifier() {public boolean verify(String hostname, SSLSession session) {return true;}};// Install the all-trusting host verifierHttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);URL url = new URL("https://svn.academy.devbg.org:9024/");URLConnection con = url.openConnection();Reader reader = new InputStreamReader(con.getInputStream());while (true) {int ch = reader.read();if (ch==-1) {break;}System.out.print((char)ch);}}}
Needless to say, the quick and dirty solution may is insecure, because it can your requests can be intercepted by a man-in-the-middle attack. Fortunately, there is also a clean solution: Import the servers public key into your truststore.
As a first step, you've got to obtain the servers public key. Assuming, that the key is in your keystore, you may export it by running
keytool -export -alias tomcat -rfc -file tomcat.crt
This example would export the public key named "tomcat" (which is used by Tomcat) into the file "tomcat.crt". The key would be read from your default keystore, which is the file .keystore in your home directory (something like "c:\Documents and Settings\jwi\.keystore" on windows or "/home/jwi/.keystore" on Linux/Unix).
Obviously, this first step must be done on the server. The second step would be to create a truststore on your client by importing the file "tomcat.crt":
keytool -import -alias servercert -file tomcat.crt -keystore truststore
The option "-keystore truststore" specifies a file name. Of course, this may as well be an absolute path.
0 Comments:
Post a Comment
<< Home