Unifying Key Store Access in ICS
March 13th, 2012 | Published in Google Android
[This post is a group effort by Tony Chan, Fred Chung, Brian Carlstrom, and Kenny Root. — Tim Bray]
Android 4.0 (ICS) comes with a number of enhancements that make it easier for people to bring their personal Android devices to work. In this post, we’re going to have a look at the key store functionality.
Back in Android 1.6 (Donut), a system key store was added for use by VPN. Although this was later expanded to support WiFi authentication, applications weren’t able to access it.
In the past, it was common practice for apps to maintain their own key store if they needed to authenticate a secure SSL web server, or authenticate the user to a server via a client certificate. While this works, it can present manageability issues in an enterprise environment where multiple certificates may be shared across a number of apps such as Email and Browser.
New in ICS: KeyChain
To bridge the gap in ICS, there’s a new API named KeyChain that regulates application access to the system key store and allows users to grant application access to the credentials stored there. Additionally, this API enables applications to initiate installation of credentials from X.509 certificates and PKCS#12 key stores.
The KeyChain API is rather simple. To install a key store or a certificate, you retrieve an install intent, supply the raw bytes of the credentials, and use the intent to launch a system installation dialog. If it’s a keystore, as in the example below, you’ll need provide the data in PKCS#12 format, and the user will have to know the PKCS#12 password.
byte[] keystore = . . (read from a PKCS#12 keystore)
Intent installIntent = KeyChain.createInstallIntent();
installIntent.putExtra(KeyChain.EXTRA_PKCS12, keystore);
startActivityForResult(installIntent, INSTALL_KEYSTORE_CODE);
The install intent launches a system dialog that prompts the user to enter the password for the keystore.
This can also be used for installing organizational CA certificates which will then be trusted by all applications to authenticate to non-public servers with certificates issued by the same CA.
In ICS, Android no longer requires a separate password to protect the system credential storage. Rather, it uses the screen lock password for this purpose, and the Android Device Administration API can be used for central policy enforcement. This means, for example, that the screen lock password can’t be removed as long as the secured credentials remain on the device.
Accessing System Key Store Credentials
Once the system key store is configured, the KeyChain API offers functions such as requesting a client certificate for authenticating with an SSL server. The first time an application requests access, the user is prompted with a list of available certificates and can select one to grant access to that certificate to the application. If the user chooses to allow access to a certificate, a string alias name for the certificate is returned to the application. The application can then use the alias to access the certificate in the future without further user involvement.
The code below illustrates how an application can prompt the user to select a credential alias and grant access to the application. KeyChain will remember this selection such that the same application can save the credential alias selection and have access to the same certificate in future. For example, the Email application for ICS has implemented this feature in its Server Settings screen.
KeyChain.choosePrivateKeyAlias(this,
new KeyChainAliasCallback() {
public void alias(String alias) {
// Credential alias selected. Remember the alias selection for future use.
if (alias != null) saveAlias(alias);
}
},
new String[] {"RSA", "DSA"}, // List of acceptable key types. null for any
null, // issuer, null for any
"internal.example.com", // host name of server requesting the cert, null if unavailable
443, // port of server requesting the cert, -1 if unavailable
null); // alias to preselect, null if unavailable
Once an application has been granted access to the certificate, it can access the private key through the getPrivateKey() method. It is worth noting that as with any PrivateKey objects, the application should not make assumptions about the encoding. For example, on some implementations the PrivateKey object may just be an opaque representation of a key stored in a hardware key store.
Here’s a sample code snippet that demonstrates the use of private key retrieved from the key store for signing:
PrivateKey privateKey = KeyChain.getPrivateKey(context, savedAlias);
if (privateKey != null) {
...
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
...
}
A common use of the private key is for SSL client authentication. This can be implemented by using an HttpsURLConnection with a custom X509KeyManager that returns the PrivateKey retrieved from the KeyChain API. The open source Email application for ICS uses KeyChain with an X509ExtendedKeyManager. To learn more, have a look at the source code (in SSLUtils.java).
This API provides a unified way to access the system key store credentials. If your application uses client certificates (take note: enterprise email client or web browser developers) you should definitely look into the KeyChain API for your next update!