NOTE
This post builds upon my previous post HTTPS Communication between an Android App and Tomcat7 using Self-Signed Certificates. Please see that post for the fundamentals of HTTPS
communication and how Android Apps
can authenticate the server.
Configuring Tomcat7
to do Client Certificate Authentication
Create the Client App’s Private Key in PEM
format
$ openssl genrsa -des3 -out <client private key name>.pem 2048
Create the Client App’s Self-Signed Digital Certificate in PEM
format
$ openssl req -new -x509 -key <client private key name>.pem -out <client ssl certificate name>.pem -days 7300
Create the Client’s KeyStore
containing its Self-Signed Digital Certificate
- Java’s
keytool
does not allow importing an existing private key into akeystore
- Hence, we first use
openssl
to import the private key into aPKCS12
formatkeystore
$ openssl pkcs12 –export –inkey <client private key name>.pem –in <client ssl certificate name>.pem –out <client keystore name>.p12
- We then convert the
PKCS12
formatkeystore
intoJKS
format so that it can also be used byTomcat7
$ keytool –importkeystore –srckeystore <client keystore name>.p12 –srcstoretype pkcs12 –destkeystore <client keystore name>.jks –deststoretype jks
- The client’s
keystore
will also be used asTomcat7's
truststore
to verify clients’ authenticity
Configure Tomcat7
to use the Client KeyStore
as its TrustStore
- Copy the client’s
keystore
to yourTomcat7
server - Set the
Connector
to require Client Certificate Authentication - Update the
Connector
in theserver.xml
file in/etc/tomcat7/
- Set
clientAuth="true", truststoreFile="<Full Path to the TrustStore File>", trustStorePass="<TrustStore Password>"
<Connector port="443" protocol="HTTP/1.1"
SSLEnabled="true" maxThreads="150" scheme="https"
secure="true" clientAuth="true"
sslProtocol="TLS"
keystoreFile="<Full Path to the Server's Keystore File>"
keystorePass="<Keystore Password>"
truststoreFile="<Full Path to the Client's Keystore File that you just copied to the Server>"
truststorePass="<Client's Keystore Password>" />
Update the Android App to use the Client KeyStore
- Copy the Client’s
PKCS12 KeyStore
to theAssets
Folder, e.g.,/assets/<client keystore name>.p12
Load the KeyStore
private KeyStore loadKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
String KEY_STORE_FORMAT = "PKCS12";
String KEY_STORE_FILENAME = "<client keystore name>.p12";
String KEY_STORE_PASSWORD = "<Client's Keystore Password>";
KeyStore keyStore = null;
// Create a new keyStore object
try {
keyStore = KeyStore.getInstance(KEY_STORE_FORMAT);
} catch (KeyStoreException e) {
throw e;
}
// Open the keyStore file for reading AssetManager
assetManager = this.getContext().getAssets();
InputStream inputStream = null;
try {
inputStream = assetManager.open(KEY_STORE_FILENAME, AssetManager.ACCESS_UNKNOWN);
} catch (IOException e) {
throw e;
}
// Load the keyStore
try {
keyStore.load(inputStream, KEY_STORE_PASSWORD.toCharArray());
} catch (NoSuchAlgorithmException | CertificateException e) {
throw e;
}
inputStream.close();
return keyStore;
}
Create a KeyManagerFactory
based on the KeyStore
private KeyManagerFactory initializeKeyManagerFactory(KeyStore keyStore, String keyStorePassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
return keyManagerFactory;
}
Update the creation of the SSLContext
to include the KeyManagerFactory
private SSLContext initializeSSLContext(KeyManagerFactory keyManagerFactory, TrustManagerFactory trustManagerFactory) throws NoSuchAlgorithmException, KeyManagementException {
String CRYPTO_PROTOCOL = "TLS";
SSLContext sslContext = SSLContext.getInstance(CRYPTO_PROTOCOL);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
return sslContext;
}