Using SSL in Java

A simple instruction on how to use SSL in Java.

HTTPS
Key and Trust Store Properties

By default java programs assume the keystore is located in the file ~/.keystore. This can be overridden by setting the relevant system properties either on the command line (using -Dproperty=value) or in code using e.g.:

System.setProperty("javax.net.ssl.keyStore", keyStore);
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
//System.setProperty("javax.net.debug", "ssl");

The "javax.net.debug" property can be used to enable verbose debug output from the SSL handshake and authentication stages. Note that updating the key- or trust stores requires a server restart as they are read on start-up.

The above is for enabling the key and truststore. The below description regards per-thread setup of key and truststore. The key and truststore is quite likely to be the same file, the variables above (keyStore and trustStore) are strings with the path to the key and truststore file.

Set up Key and Trust Store in Code

To programmatically specify key or trust stores the per-thread javax.net.ssl.SSLContext can be used. Just set the wanted stores and/or managers before creating the connection:

    KeyManager[] kms=getKeyManagers(keyStore, keyStorePassword);
    TrustManager[] tms=getTrustManagers(trustStore, trustStorePassword);
    SslContext.setCurrentSslContext(new SslContext(kms, tms, null));

Where getKeyManagers and getTrustManagers come from this post:

    private static TrustManager[] getTrustManagers(String location, String password)
            throws IOException, GeneralSecurityException {
        // First, get the default TrustManagerFactory.
        String alg=TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmFact=TrustManagerFactory.getInstance(alg);

        FileInputStream fis=new FileInputStream(location);
        KeyStore ks=KeyStore.getInstance("jks");
        ks.load(fis, password.toCharArray());
        fis.close();

        tmFact.init(ks);

        // And now get the TrustManagers
        TrustManager[] tms=tmFact.getTrustManagers();
        return tms;
    }

    private static KeyManager[] getKeyManagers(String location, String password)
            throws IOException, GeneralSecurityException {
        // First, get the default KeyManagerFactory.
        String alg=KeyManagerFactory.getDefaultAlgorithm();
        KeyManagerFactory kmFact=KeyManagerFactory.getInstance(alg);

        FileInputStream fis=new FileInputStream(location);
        KeyStore ks=KeyStore.getInstance("jks");
        ks.load(fis, password.toCharArray());
        fis.close();

        // Now we initialise the KeyManagerFactory with this KeyStore
        kmFact.init(ks, password.toCharArray());

        // And now get the KeyManagers
        KeyManager[] kms=kmFact.getKeyManagers();
        return kms;
    }
Getting KeyStore instance from text string
    private static KeyStore keyStoreFromCertificateString(String alias, String certificateString)
            throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
        KeyStore ks=KeyStore.getInstance("jks");
        ks.load(null); // Create empty key store
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate cert = cf.generateCertificate(new ByteArrayInputStream(certificateString.getBytes()));
        ks.setEntry(alias, new KeyStore.TrustedCertificateEntry(cert), null);
        return ks;
    }

Contrast with getting it from a file (as above). Sample usage:

    String certificateString =
        "-----BEGIN CERTIFICATE-----\n" +
        "MIICCzCCAXQCCQCHLeckUtZcJDANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJESzEgMB4GA1UE\n" +
        "ChMXRGV0IEtvbmdlbGlnZSBCaWJsaW90ZWsxDDAKBgNVBAsTA0RJUzELMAkGA1UEAxMCQ0EwHhcN\n" +
        "MTEwOTI4MTExNjQ1WhcNMTMwNDI5MjIyMDEzWjBKMQswCQYDVQQGEwJESzEgMB4GA1UEChMXRGV0\n" +
        "IEtvbmdlbGlnZSBCaWJsaW90ZWsxDDAKBgNVBAsTA0RJUzELMAkGA1UEAxMCQ0EwgZ8wDQYJKoZI\n" +
        "hvcNAQEBBQADgY0AMIGJAoGBAJcGvaV2VjjIhq0NGD1sCDPw/Xvu/G0zzJLStStbvAQZ95CKZ52V\n" +
        "CM7oQ4Ge4Qse+sNNL+DU9ENzFoN/1Xvqip1e0B204arErZaRXc4lThW3vTt7JWx9s/l2TOxnsCuq\n" +
        "uXhe+VnQkMdGu1WeSKIgzhxJ5vjV5mPXkj/RsVnKSp+PAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA\n" +
        "VbQ5VPPDOCW0wuyMLFu8W2W0Tvplv8A458w37qNVo3pvznDSVdEOpPIRznTIM836XSwHWCWhRPN/\n" +
        "Mo2U+CRkSEaN8nPkqxOY46w1AKqhhgLAPr6/sOCjG6k6jxEITYzYO5mv0nAg4yAVvfE4O715pjwO\n" +
        "77h9LapqyJ8S1GSKHr8=\n" +
        "-----END CERTIFICATE-----\n";
    KeyStore ks = keyStoreFromCertificateString("broker", certificateString);
Import client certificate+key to client

$ openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12
$ keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore client.ks -storepass <pass> -file ca.crt

Import server certificate

$ keytool -import -alias broker -keystore client.ks -file ca.crt

Export certificate in text format

$ keytool -export -alias broker -keystore client.ks -rfc

Without the -rfc argument the certificate is exported in binary format.

Misc.

Should a raw SSLSocket be needed, creating a socket that uses specific key and trust stores is described here: http://pa55word.wordpress.com/2007/11/23/secure-sockets-in-java/