Skip to content

Instantly share code, notes, and snippets.

@jankronquist
Last active January 24, 2021 13:49
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save jankronquist/6412839 to your computer and use it in GitHub Desktop.
Save jankronquist/6412839 to your computer and use it in GitHub Desktop.
Java certificate authentication for both server and client using shared trusted CA.

Certificates

CA and trust keystore

keytool -genkeypair -keyalg RSA -keysize 2048 -validity 365 -alias ca -dname "CN=ca,O=HMS,S=SE" -keystore ca.jks -storepass password
keytool -exportcert -rfc -alias ca -keystore ca.jks -storepass password > ca.pem
cat ca.pem | keytool -importcert -alias ca -noprompt -keystore trust.jks -storepass password

server cert

Notice that the CN must be equal to the DNS hostname!

keytool -genkeypair -keyalg RSA -keysize 2048 -validity 365 -alias server -dname "CN=localhost.com,O=HMS,S=SE" -keystore server.jks -storepass password
keytool -certreq -alias server -storepass password -keystore server.jks | keytool  -gencert -alias ca -rfc -keystore ca.jks -storepass password > server.pem
cat ca.pem | keytool -importcert -alias ca -noprompt -keystore server.jks -storepass password
cat ca.pem server.pem | keytool -importcert -alias server -keystore server.jks -storepass password

client cert

The username of the client is the value of CN!

keytool -genkeypair -keyalg RSA -keysize 2048 -validity 365 -alias client -dname "CN=client,O=HMS,S=SE" -keystore client.jks -storepass password
keytool -certreq -alias client -keystore client.jks -storepass password | keytool -gencert -alias ca -rfc -keystore ca.jks -storepass password> client.pem
cat ca.pem | keytool -importcert -alias ca -noprompt -keystore client.jks -storepass password
cat ca.pem client.pem | keytool -importcert -alias client -keystore client.jks -storepass password

Server authentication and authorization

Tomcat and Jetty authenticates the client if the certificate if signed by a trusted CA. However, standard Java Web security is a mess to configure and I decided to use Spring Security to provide authorization.

tomcat

In server.xml:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"
           maxThreads="150" scheme="https" secure="true"
           keystoreFile="server.jks" keystorePass="password"
           truststoreFile="trust.jks" truststorePass="password"
           clientAuth="want" sslProtocol="TLS" />

Jetty

SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreInputStream(new FileInputStream("server.jks"));
sslContextFactory.setKeyStorePassword("password");
sslContextFactory.setKeyManagerPassword("password");
sslContextFactory.setTrustStoreInputStream(new FileInputStream("trust.jks"));
sslContextFactory.setTrustStorePassword("password");
sslContextFactory.setWantClientAuth(true);
_connector = new SslSelectChannelConnector(sslContextFactory);

Spring Security - authorization

<x509 subject-principal-regex="CN=(.*)"/>

optionally user-service-ref="userDetailsService"

Client code

HttpClient

final KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
truststore.load(new FileInputStream("trust.jks"), "password".toCharArray());

final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(new FileInputStream("client.jks"), "password".toCharArray());

Scheme httpsScheme = new Scheme("https", 443, new SSLSocketFactory(keystore, "password", truststore));

SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);

ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
return new DefaultHttpClient(cm);

Jetty WebSocketClient

factory.getSslContextFactory().setTrustAll(false);
factory.getSslContextFactory().setTrustStore(truststore);
factory.getSslContextFactory().setKeyStore(keystore);
factory.getSslContextFactory().setKeyManagerPassword("password");
@fatbatman
Copy link

Thanks, this saved me a lot of time :)

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