I am using Java 6 and am trying to create an HttpsURLConnection
against a remote server, using a client certificate.
The server is using an selfsigned root certificate, and requires that a password-protected client certificate is presented. I've added the server root certificate and the client certificate to a default java keystore which I found in /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/security/cacerts
(OSX 10.5).
The name of the keystore file seems to suggest that the client certificate is not supposed to go in there?
Anyway, adding the root certificate to this store solved the infamous javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed' problem.
However, I'm now stuck on how to use the client certificate. I've tried two approaches and neither gets me anywhere.
First, and preferred, try:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://somehost.dk:3049");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
// The last line fails, and gives:
// javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
I've tried skipping the HttpsURLConnection class (not ideal since I want to talk HTTP with the server), and do this instead:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("somehost.dk", 3049);
InputStream inputstream = sslsocket.getInputStream();
// do anything with the inputstream results in:
// java.net.SocketTimeoutException: Read timed out
I am not even sure that the client certificate is the problem here.
Finally solved it ;). Got a strong hint here (Gandalfs answer touched a bit on it as well). The missing links was (mostly) the first of the parameters below, and to some extent that I overlooked the difference between keystores and truststores.
The self-signed server certificate must be imported into a truststore:
These properties need to be set (either on the commandline, or in code):
Working example code:
While not recommended, you can also disable SSL cert validation alltogether:
For me, this is what worked using Apache HttpComponents ~ HttpClient 4.x:
The P12 file contains the client certificate and client private key, created with BouncyCastle:
I think you have an issue with your server certificate, is not a valid certificate (I think this is what "handshake_failure" means in this case):
Import your server certificate into your trustcacerts keystore on client's JRE. This is easily done with keytool:
If you are dealing with a web service call using the Axis framework, there is a much simpler answer. If all want is for your client to be able to call the SSL web service and ignore SSL certificate errors, just put this statement before you invoke any web services:
System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory");
The usual disclaimers about this being a Very Bad Thing to do in a production environment apply.
I found this at the Axis wiki.
Have you set the KeyStore and/or TrustStore System properties?
or from with the code
Same with javax.net.ssl.trustStore