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
keytooldoes not allow importing an existing private key into akeystore - Hence, we first use
opensslto import the private key into aPKCS12formatkeystore
$ openssl pkcs12 –export –inkey <client private key name>.pem –in <client ssl certificate name>.pem –out <client keystore name>.p12
- We then convert the
PKCS12formatkeystoreintoJKSformat 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
keystorewill also be used asTomcat7'struststoreto verify clients’ authenticity
Configure Tomcat7 to use the Client KeyStore as its TrustStore
- Copy the client’s
keystoreto yourTomcat7server - Set the
Connectorto require Client Certificate Authentication - Update the
Connectorin theserver.xmlfile 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 KeyStoreto theAssetsFolder, 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;
}