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
While not recommended, you can also disable SSL cert validation alltogether:
import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class SSLTool {
public static void disableCertificateValidation() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}};
// Ignore differences between given hostname and certificate hostname
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) { return true; }
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (Exception e) {}
}
}
I use the Apache commons HTTP Client package to do this in my current project and it works fine with SSL and a self-signed cert (after installing it into cacerts like you mentioned). Please take a look at it here:
http://hc.apache.org/httpclient-3.x/tutorial.html
http://hc.apache.org/httpclient-3.x/sslguide.html
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.
Using below code
-Djavax.net.ssl.keyStoreType=pkcs12
or
System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);
is not at all required. Also there is no need to create your own custom SSL factory.
I also encountered the same issue, in my case there was a issue that complete certificate chain was not imported into truststores. Import certificates using keytool utility right fom root certificate, also you can open cacerts file in notepad and see if the complete certificate chain is imported or not. Check against the alias name you have provided while importing certificates, open the certificates and see how many does it contains, same number of certificates should be there in cacerts file.
Also cacerts file should be configured in the server you are running your application, the two servers will authenticate each other with public/private keys.
Have you set the KeyStore and/or TrustStore System properties?
java -Djavax.net.ssl.keyStore=pathToKeystore -Djavax.net.ssl.keyStorePassword=123456
or from with the code
System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);
Same with javax.net.ssl.trustStore
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:
keytool -import -alias gridserver -file gridserver.crt -storepass $PASS -keystore gridserver.keystore
These properties need to be set (either on the commandline, or in code):
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=gridserver.keystore
-Djavax.net.debug=ssl # very verbose debug
-Djavax.net.ssl.keyStorePassword=$PASS
-Djavax.net.ssl.trustStorePassword=$PASS
Working example code:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://gridserver:3049/cgi-bin/ls.py");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
System.out.println("Received " + string);
}