Problem with handshake_failure and SSL connection

Recently I was working on integration with PayPal and I wanted to use certificate based authorization of webservices calls. It was working fine in my integration test (which can be run as standalone Java application), but it was not working when run from real application deployed to Tomcat.

I was getting this exception:

Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1943)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1059)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1294)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1321)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1305)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1087)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1355)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1301)
at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:42)
at org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69)
at org.apache.cxf.io.CacheAndWriteOutputStream.write(CacheAndWriteOutputStream.java:68)
at com.ctc.wstx.io.UTF8Writer.flush(UTF8Writer.java:100)
at com.ctc.wstx.sw.BufferingXmlWriter.flush(BufferingXmlWriter.java:225)
at com.ctc.wstx.sw.BufferingXmlWriter.close(BufferingXmlWriter.java:198)
at com.ctc.wstx.sw.BaseStreamWriter._finishDocument(BaseStreamWriter.java:1400)
... 135 more

So I added debug JVM option to Tomcat startup:

-Djavax.net.debug=ssl

And then I’ve found following message in logs:

http-80-Processor5, READ: SSLv3 Handshake, length = 4
*** ServerHelloDone
[read] MD5 and SHA1 hashes: len = 4
0000: 0E 00 00 00 ....
http-80-Processor5, SEND SSLv3 ALERT: warning, description = no_certificate
http-80-Processor5, WRITE: SSLv3 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 00 00 02 01 29

As we can see here application could not find certificate in keystore. After searching the web for solution I couldn’t find anything helpful. But then I also found out that when Tomcat is starting it is using trustStore from JVM (in my case located in C:\Program Files\Java\jrockit-jdk1.6.0_37-R28.2.5-4.1.0\jre\lib\security\cacerts).

So in my case solution for this problem was simple. I had problem with properties overrides and my keystore was not loaded correctly. In this case default trustStore was taken into consideration and it didn’t have requested certificate. After fixing configuration exception was gone.