4

I am establishing an SSL connection to a server which has enabled ssl.There is a cacerts file in my hardware's filesystem java keystore and I extracted the certificate from it using keytool & I am giving this certificate file to create an SSLSocketfactory to establish the ssl connection , which works fine with the code snippet below.

I wanted to know how to access the cacerts ( java keystore ) file directly , and pick the certificate and establish the ssl connection. Right now , I am packaging the extracted certicate in the classpath with my jar file , which is not a good practice as I want it to be loaded from the keystore.

Below is the working code snippet of how I create a SSLSocketFactory currently.

private SSLSocketFactory createSSLFactory() {
  KeyStore keyStore = null;
  TrustManagerFactory tmf = null;
  SSLContext ctx = null;

  try {
    keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream is = null;
    is = SSLConnection.class.getResourceAsStream("/" + "my-keystore");
    keyStore.load(is, "changeit".toCharArray());
    tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(keyStore);
    ctx = SSLContext.getInstance("TLSv1");
    ctx.init(null, tmf.getTrustManagers(), null);
    SSLSocketFactory factory = ctx.getSocketFactory();
    return factory;
  } catch (Exception e) {
    // exception handling
  }
  return null;
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Tito
  • 8,894
  • 12
  • 52
  • 86
  • 1
    Why? You don't even need this code, let alone more code. Just set the system properties. – user207421 Jan 08 '14 at 21:50
  • will try and post back , just curious.If the set the keystore path via system properties , Will it iterate through the keystore and pick the right certificate for the server just like that ? – Tito Jan 08 '14 at 22:28
  • You have it back to front. It iterates through the truststore to find *trusted* certificates; sends those `subjectDNs` to the server as trusted CAs in the first message of the SSL handshake; the server sends back a certificate that is supposed to be signed by one of those CAs; then the client checks that in the keystore. There's no question of 'picking the right certificate for the server', unless you're still talking about client authentication. – user207421 Jan 08 '14 at 22:50

3 Answers3

4

It doesn't make any sense to embed a KeyStore into a JAR file in the case of private keys and authenticating certificates. A client certificate is supposed to uniquely identify the client. It is a property of a host, not a JAR file, which can be copied around infinitely. It doesn't make sense to allow the use of the same client certificates for multiple clients. It is a misuse of PKI.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • My mistake , its not client authentication ,there is no unique identification of client to the server.I will edit the question.Its just to establish ssl to the server.The public key of the server is given to connect to it. – Tito Jan 08 '14 at 21:58
  • 3
    It's still poor practice. You should use the truststore that comes with the JDK. If you're doing this because your server is using a self-signed certificate, the correct solution is not to do that. Get it signed. You'll save more money than you are spending here. – user207421 Jan 08 '14 at 23:01
1

You can pass the keystore (and truststore) as system properties to the JVM. See here: https://stackoverflow.com/a/882479/131929

-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

Then you can do

URL url = new URL("https://someurl");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
InputStream inputstream = conn.getInputStream();
Community
  • 1
  • 1
Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • You don't even need to get the `SSLSocketFactory` and set it as default. The default is already the default. And as the OP has now stated he doesn't need client authentication, he doesn't need the `keyStore/keyStorePassword,` just the `trustStore.` – user207421 Jan 08 '14 at 22:48
  • trustStore it is , got confused with trustStore and keystore.Did some learning and good to go. – Tito Jan 14 '14 at 18:16
  • @EJP - uummh, yes of course, sorry I mixed two code samples I had (now fixed). I thought the OP's question strange, too. Went straight from question to answer. That'll lead you nowhere if the question is "wrong"... – Marcel Stör Jan 14 '14 at 19:13
0

You need to add a trust manager :

            SSLSocketFactory factory = null;
        try {
            SSLContext ctx;
            KeyManagerFactory kmf;
            TrustManagerFactory tmf;
            KeyStore ks;
            char[] passphrase = "passphrase".toCharArray();

            ctx = SSLContext.getInstance("TLS");
            kmf = KeyManagerFactory.getInstance("SunX509");
            tmf = TrustManagerFactory.getInstance("SunX509");
            ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream("testkeys"), passphrase);

            kmf.init(ks, passphrase);
            tmf.init(ks);
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

            factory = ctx.getSocketFactory();
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }

        SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
tomk
  • 31
  • 5