Using SSL in Java
A simple instruction on how to use SSL in Java.
HTTPS
- Attach key and trust stores to the applicable SslContext, i.e. either the threads local SSLContext (get/setCurrentSslContext) or an explicit one, as described below.
- Something like bitrepository-protocol/src/main/java/org/bitrepository/protocol/http/HTTPSFileExchange.java should now work.
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/