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
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
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
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.
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" />
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);
<x509 subject-principal-regex="CN=(.*)"/>
optionally user-service-ref="userDetailsService"
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);
factory.getSslContextFactory().setTrustAll(false);
factory.getSslContextFactory().setTrustStore(truststore);
factory.getSslContextFactory().setKeyStore(keystore);
factory.getSslContextFactory().setKeyManagerPassword("password");
Thanks, this saved me a lot of time :)