Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTTPS Connections with Proxy cause SSLHandshakeException

Tags:

java

proxy

ssl

I have been struggling with this issue for some days now and I can't seem to find a useful answer...

I have some Software that causes SSLHandshakeExceptions each time I want to use it with a Proxy server. I have been able to replicate the issue with the following code (that is way simpler than the real application):

    HttpsURLConnection con = (HttpsURLConnection) new URL("https://www.google.com").openConnection();
    try {
        con.connect();
    } catch(Exception e) {
        e.printStackTrace();
    }

If I run this code connected to a WiFi Hotspot (no proxy server needed), I get the connection and everything works just as expected:

java -cp . SampleJavaURLTest

However, If I run the same Java command with a Proxy Server:

java -cp . -DproxySet=true -DproxyHost={myProxyHost} -DproxyPort={myProxyPort} SampleJavaURLTest

I get this Exception (printed with the e.printStackTrace() that is in the code snipplet to make line numbers irrelevant:

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 target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at SampleJavaURLTest.main(SampleJavaURLTest.java:116)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:323)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
... 11 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
... 17 more

So, first logical advice would be "Use the InstallCert program and add google´s certificate". However that's not the issue, somehow Java is not liking the way certificates are handled through the proxy server.

I am running both samples with exact the same JVM, no further configuration changes other than the proxy settings in the command line. In fact, both tests were done with the same Console Window, only seconds between both tests needed to switch networks... Here's a java -v printout:

java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) Client VM (build 20.5-b03, mixed mode, sharing)

And, to be 100% sure, I also tested with a newer JVM:

java version "1.7.0_10"
Java(TM) SE Runtime Environment (build 1.7.0_10-b18)
Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode)

As a workaround, I disabled all Certificate validation by using this approach:

http://code.google.com/p/misc-utils/wiki/JavaHttpsUrl

Although it doesn't really affect me and I can live with this workaround (not so critical if someone hacks in the communication with a false certificate), I would really like to know how to properly get the certificates to work as they should. What am I missing?

like image 933
Martin Avatar asked Feb 26 '14 14:02

Martin


1 Answers

If I understand you right your SSL connection succeeds without proxy, also succeeds with a proxy if you disable certificate validation but fails with a proxy if you enable certificate validation. In this case the proxy is tampering with the SSL, e.g. it does a man-in-the-middle attack (also called SSL interception in some firewalls or SSL bump in squid). If this is not an attack but a known feature of this proxy (e.g. to scan SSL connections for viruses etc) you need to import the proxies interception CA, because due to the man-in-the-middle you don't talk any longer SSL to the web server but to the proxy and the proxy then talks SSL to the server.

like image 188
Steffen Ullrich Avatar answered Nov 02 '22 23:11

Steffen Ullrich