Skip to content

Instantly share code, notes, and snippets.

@cpilsworth
Last active May 23, 2018 20:16
Show Gist options
  • Save cpilsworth/ef19bd17ec3c5cb49cbaf0b8be6236c9 to your computer and use it in GitHub Desktop.
Save cpilsworth/ef19bd17ec3c5cb49cbaf0b8be6236c9 to your computer and use it in GitHub Desktop.
A+ SSL using Java 9

Configuring java for an A+ ssllabs.com server rating

It never used to be possible to get an A+ rating, as Java missed a couple of necessary features

Setting up the server

Getting Java 9

wget http://download.java.net/java/GA/jdk9/9/binaries/jdk-9+181_linux-x64_bin.tar.gz

Getting the LetsEncrypt/EFF certbot

wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto

Creating certificate with 4096 bit key

By default a 2048 bit key will be created. A 4096 bit key can be created with a parameter sudo ./certbot-auto certonly --debug --rsa-key-size 4096 see https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide#key-exchange

Create a PKCS12 keystore from the letsencrypt fullchain.pem

openssl pkcs12 -export -in /etc/letsencrypt/live/domain.com/fullchain.pem -inkey privkey.pem -out domain.p12 -name domain

Compile the Java program

./jdk-9/bin/javac Test.java

Run the java program

Sudo required for low numbered ports (e.g. 443)

sudo ./jdk-9/bin/java Test 443 /etc/letsencrypt/live/domain.com/domain.p12 PKCS12 changeme \
  -Djdk.tls.rejectClientInitiatedRenegotiation=true \
  -Dhttps.protocols=TLSv1.1,TLSv1.2 \
  -Djavax.net.debug=all

JRE TLS System Properties

  • jdk.tls.rejectClientInitiatedRenegotiation=true
  • https.protocols=TLSv1.2

Bonus: CAA record

Add a CAA record to the domain for letsencrypt.org e.g.

CAA = 0 issue "letsencrypt.org"

https://letsencrypt.org/docs/caa/

New Java 9 HTTP/TLS features

http://openjdk.java.net/projects/jdk9/

import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.security.Security;
public class Test {
private static final String[] CIPHER_SUITES = new String[] {
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"
// Cipher strength needs to be 256 bits plus for A+
// https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide#cipher-strength
// ,"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
// "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
// "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
};
public static void main(String[] args) throws Exception {
int arg = 0;
int port = Integer.parseInt(args[arg++]);
final String keyStore = args[arg++];
final String keyStoreType = args[arg++];
// args[2] == keystore password
// enable unlimited strength JCA
Security.setProperty("crypto.policy", "unlimited");
final HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 0);
final SSLContext tlsContext = getTLSContext(keyStore, keyStoreType, args[arg++].toCharArray());
server.setHttpsConfigurator(new HttpsConfigurator(tlsContext) {
public void configure(HttpsParameters params) {
final SSLContext c = getSSLContext();
final SSLParameters sslparams = c.getDefaultSSLParameters();
// use cipher suite order provided by the server
sslparams.setUseCipherSuitesOrder(true); //
sslparams.setCipherSuites(Test.CIPHER_SUITES);
params.setSSLParameters(sslparams);
}
});
server.createContext("/", (t) -> {
final String response = "This is the response";
// HSTS headers 6mo+ max-age required
// https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide#changes-in-2009e-21-january-2014
t.getResponseHeaders().add("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); // 1yr
t.sendResponseHeaders(200, response.length());
final OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
});
server.start();
}
private static SSLContext getTLSContext(String keyStoreLocation, String keyStoreType, char[] password) throws Exception {
final KeyStore ks = KeyStore.getInstance(keyStoreType);
ks.load(new FileInputStream(keyStoreLocation), password);
final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
final TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslContext;
}
}
@cpilsworth
Copy link
Author

screencapture-ssllabs-ssltest-analyze-html-1506205244084

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment