Java client certificates over HTTPS/SSL
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);}
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) {} }}
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