Jelly Bean hardware-backed credential storage

Along with all the user facing new features everyone is talking about, the latest Android release has quite a bit of security improvements under the hood. Of those only app encryption has been properly announced, while the rest remain mostly covered up by upper level APIs. This, of course, is not fair, so let's call them up (the list is probably not exhaustive):
  • RSA and DSA key generation and signatures are now implemented in native code for better performance
  • TLS v1.2 support
  • improved system key store
  • new OpenSSL interface (engine) to the system key store
  • new key management HAL component -- keymaster
  • hardware-backed keymaster implementation on Galaxy Nexus and Nexus 7
The first two features are mostly self-explanatory, but the rest merit some exploration. Let's look into each one in turn.

System key store improvements

As we have already discussed, the system key store in Android is provided by a native daemon that encrypts secrets using a key derived from the device unlock password, stores them on disk and regulates key access based on UID. In ICS and previous versions, the keystore daemon simply stores opaque encrypted blobs and the only meatdata available (UID of owner and key name) was encoded in the file name under which blobs are stored. In Jelly Bean (JB), blobs also have a version field and a type field. The following key types are newly defined:
  • TYPE_GENERIC
  • TYPE_MASTER_KEY
  • TYPE_KEY_PAIR
TYPE_GENERIC is used for key blobs saved using the previous get/put interface, and TYPE_MASTER_KEY is, of course, only used for the key store master key. The newly added TYPE_KEY_PAIR is used for key blobs created using the new GENERATE and IMPORT commands. Before we go into more details, here are the keystore commands added in Jelly Bean:
  • GENERATE
  • IMPORT
  • SIGN
  • VERIFY
  • GET_PUBKEY
  • DEL_KEY
  • GRANT
  • UNGRANT
In order to use a key stored using the pre-JB implementation, we needed to first export the raw key bytes, and then use them to initialize an actual key object. Thus even though the key blob is encrypted on disk, the plain text key eventually needed to be exposed (in memory). The new commands let us generate an RSA key pair and sign or verify data without the key ever leaving the key store. There is however no way to specify key size for generated keys, it is fixed at 2048 bits. There is no restriction for importing keys though, so shorter (or longer keys) can be used as well (confirmed for 512-4096 bit keys). Importing requires that keys are encoded using the PKCS#8 format. The sign operation doesn't do any automatic padding and therefore requires input data to be equal to the RSA key size (it's essentially performs raw RSA encryption using the private key). VERIFY takes the key name, signed data and signature value as input, and outputs the verification result. GET_PUBKEY works as expected -- it returns the public key in X.509 format. As mentioned above, the keystore daemon does access control based on UID, and pre-JB a process could use only a key it had created itself. The new GRANT / UNGRANT commands allow the OS to temporarily allow access to system keys to other processes. The grants are not persisted, so they are lost on restart.

Key store OpenSSL engine

The next addition to Android's security system is the keystore-backed OpenSSL engine (pluggable cryptographic module). It only supports loading of and signing with RSA private keys, but that is usually enough to implement key-based authentication (such as SSL client authentication). This small engine makes it possible for native code that uses OpenSSL APIs to use private keys saved in the system key store without any code modifications. It also has a Java wrapper (OpenSSLEngine), which is used to implement the KeyChain.getPrivateKey() API. Thus all apps that acquire a private key reference via the KeyChain API get the benefit of using the new native implementation.

keymaster module overview

And finally, time for our feature presentation -- the keymaster module and its hardware-based implementation on Galaxy Nexus (and Nexus 7, but that currently has no relevant source code in AOSP, so we will focus on the GN). Jelly Bean introduces a new libhardware (aka HAL) module, called keymaster. It defines structures and methods for generating keys and signing/verifying data. The keymaster module is meant to decouple Android from the actual device security hardware, and a typical implementation would use a vendor-provided library to communicate with the crypto-enabled hardware. Jelly Bean comes with a default softkeymaster module that does all key operations in software only (using the ubiquitous OpenSSL). It is used on the emulator and probably will be included in devices that lack dedicated cryptographic hardware. The currently defined operations are listed below. Only RSA is supported at present.
  • generate_keypair
  • import_keypair
  • sign_data
  • verify_data
  • get_keypair_public
  • delete_keypair
  • delete_all
If those look familiar, this is because they are pretty much the same as the newly added keystore commands listed in the previous section. All of the asymmetric key operations exposed by the keystore daemon are implemented by calling the system keymaster module. Thus if the keymaster HAL module is backed by a hardware cryptographic device, all upper level commands and APIs that use the keystore daemon interface automatically get to use hardware crypto.

Galaxy Nexus keymaster implementation

Let's look at how this is implemented on Galaxy Nexus, starting from the lowest level, the actual hardware. Galaxy Nexus is built using the Texas Instruments OMAP4460 SoC, which integrates TI's M-Shield (not to be confused with nShield) mobile security technology. Among other things, M-Shield provides cryptographic acceleration, a secure random number generator and secure on-chip key storage. On top of that sits TI's Security Middleware Component (SMC), which is essentially a Trusted Execution Environment (TEE, Global Platform specs and white paper) implementation. The actual software is by Trusted Logic Mobility, marketed under the name Trusted Foundations. Looking at this TI white paper, it looks like secure key storage was planned for ICS (Android 4.0), but apparently, it got pushed to back to Jelly Bean (4.1). Cf. this statement from the white paper: 'Android 4.0 also introduces a new keychain API and underlying encrypted storage that are protected by M-Shield hardware security on the OMAP 4 platform.'.  

With all the buzzwords and abbreviations out of the way, let's say a few words about TEE. As the name implies, TEE is defined as a logical execution environment, separate from the device's main OS, referred to as the REE (Rich Execution Environment). Its purpose is both to protect assets and execute trusted code. It is also required to be protected against certain physical attacks, although the level of protection is typically lower that that of a tamper-resistant module such as a Secure Element (SE). The TEE can host trusted applications (TAs) which utilize the TEE's services via the standardized internal APIs. Those fall under 4 categories:
  • trusted storage
  • cryptographic operations
  • time-related
  • arithmetical (for dealing with big numbers)
Applications running in the REE (the Android OS and apps) can only communicate with TAs via a low level Client API (essentially sending commands and receiving responses synchronously, where the protocol is defined by each TA). The Client API also lets the REE and TA applications share memory in a controlled manner for efficient data transfer.

Finally, let's see how all this is tied together in the GN build of Jelly Bean. A generic PKCS#11 module (libtf_crypto_sst.so) uses the TEE Client API to communicate with a TA that implements hashing, key generation, encryption/decryption, signing/verification and random number generation. Since there doesn't seem to a 'official' name for the TA on the Galaxy Nexus, and its commands map pretty much one-to-one to PKCS#11 interfaces, we will be calling it the 'token TA' from now on. The GN keymaster HAL module calls the PKCS#11 module to implement RSA key pair generation and import, as well as signing and verification. This in turn is used by the keystore daemon to implement the corresponding commands.

However, it turns out that the hardware-backed keymaster module is not in the latest GN build (JRO03C at the time of this writing. Update: according to this commit message, the reason for its being removed is that it has a power usage bug). Fortunately it is quite easy to build it and install it on the device (notice that the keymaster module, for whatever reason, is actually called keystore.so):

$ make -j8 keystore.tuna
$ adb push out/product/maguro/system/lib/hw/keystore.tuna.so /mnt/sdcard
$ adb shell
$ su
# mount -o remount,rw /system
# cp /mnt/sdcard/keystore.tuna.so /system/lib/hw

Then all we need to do is reboot the device to have it load the new module (otherwise it will continue to use the software-only keystore.default.so). If we send a few keystore commands, we see the following output (maybe a bit too verbose for a production device), confirming that cryptographic operations are actually executed by the TEE:

V/TEEKeyMaster(  299): Opening subsession 0x414f2a88
V/TEEKeyMaster(  299): public handle = 0x60011, private handle = 0x60021
V/TEEKeyMaster(  299): Closing object handle 0x60021
V/TEEKeyMaster(  299): Closing object handle 0x60011
V/TEEKeyMaster(  299): Closing subsession 0x414f2a88: 0x0
I/keystore(  299): uid: 10164 action: a -> 1 state: 1 -> 1 retry: 4
V/TEEKeyMaster(  299): tee_sign_data(0x414ea008, 0xbea018fc, 36, 0xbea1195c, 256, 0xbea018c4, 0xbea018c8)
V/TEEKeyMaster(  299): Opening subsession 0x414f2ab8
V/TEEKeyMaster(  299): Found 1 object 0x60011 : class 0x2
V/TEEKeyMaster(  299): Found 1 object 0x60021 : class 0x3
V/TEEKeyMaster(  299): public handle = 0x60011, private handle = 0x60021
V/TEEKeyMaster(  299): tee_sign_data(0x414ea008, 0xbea018fc, 36, 0xbea1195c, 256, 0xbea018c4, 0xbea018c8) 
=> 0x414f2838 size 256
V/TEEKeyMaster(  299): Closing object handle 0x60021
V/TEEKeyMaster(  299): Closing object handle 0x60011
V/TEEKeyMaster(  299): Closing subsession 0x414f2ab8: 0x0
I/keystore(  299): uid: 10164 action: n -> 1 state: 1 -> 1 retry: 4

This produces key files in the keystore daemon data directory, bus as you can see in the listing below, they are not large enough to store 2048 bit RSA keys. They only store a key identifier, as returned by the underlying PKCS#11 module. Keys are loaded based on this ID, and signing are verification are preformed within the token TA, without the keys being exported to the REE.

# ls -l /data/misc/keystore/10164*
-rw------- keystore keystore       84 2012-07-12 14:15 10164_foobar
-rw------- keystore keystore       84 2012-07-12 14:15 10164_imported

So where are the actual keys? It turns out they are in the /data/smc/user.bin file. The format is, of course, proprietary, but it would be a safe bet that it is encrypted with a key stored on the SoC (or at least somehow protected by a hardware key). This allows to have practically an unlimited number of keys inside the TEE, without being bounded by the limited storage space on the physical chip.

keymaster usage and performance

Currently installing a PKCS#12 packaged key and certificate via the public KeyChain API (or importing via Settings->Security->Insall from storage) will import the private key into the token TA and getting a private key object using KeyChain.getPrivateKey() will return a reference to the stored key. Subsequent signature operations using this key object will be performed by the token TA and take advantage of the OMAP4 chip's cryptographic hardware. There are currently no public APIs or stock applications that use the generate key functionality, but if you want to generate a key protected by the token TA, you can call android.security.KeyStore.generate() directly (via reflection or by duplicating the class in your project). This API can potentially be used for things like generating a CSR request from a browser and other types of PKI enrollment.

The OMAP4 chip is advertised as having hardware accelerated cryptographic operations, so let's see how RSA key generation, signing and verification measure up against the default Android software implementations:

Average 2048-bit RSA operation speed on Galaxy Nexus
Crypto Provider/OperationKey generation Signing Verification
Bouncy Castle2176.20 [ms] 34.60 [ms]1.90 [ms]
OpenSSL2467.40 [ms] 29.80 [ms] 1.00 [ms]
TEE3487.00 [ms] 10.90 [ms] 10.60 [ms]

As you can see from the table above, Bouncy Castle and OpensSSL perform about the same, while the TEE takes more time to generate keys (most probably because it's using a hardware RNG, not a PRNG), but signing is about 3 times faster compared to the software implementations. Verification takes about the same time as signing, and is slower than software. It should be noted that this test is not exactly precise: calling the token TA via the keystore daemon causes a lot of TEE client API sessions to be open and closed which has its overhead. Getting more accurate times will require benchmarking using the Client API directly, but the order of the results should be the same.

Summary

To sum things up: Jelly Bean finally has a standard hardware key storage and cryptographic operations API in the keymater HAL module definition. The implementation for each device is hardware-dependent, and the currently available implementations use the TEE Client API on the Galaxy Nexus and Nexus 7 to take advantage of the TEE capabilities of the respective SoC (OMAP4 and Tegra 3). The current interface and implementation only support generating/importing of RSA keys and signing/verification, but will probably be extended in the future with more key types and operations. It is integrated with the system credential storage (managed by the keystore daemon) and allows us to generate, import and use RSA keys protected by the devices's TEE from Android applications.

Comments

caprifinity said…
Perhaps because of these backend changes to the Android 4.1 Keychain that your article explores, I'm noticing a lot of breakage in apps that previously worked fine on 4.0. See:

http://code.google.com/p/android/issues/detail?id=36545

and

http://stackoverflow.com/questions/11261774/using-android-4-1-keychain

For example, you say that the KeyChain.getPrivateKey() API method should automatically use the hardware-based keystores, but I'm finding (as one of the above links reports) that even calling KeyChain.getPrivateKey by itself will cause a segfault as soon as the VM garbage collects the returned key.

What is the canonical way to compute an RSA signature on 4.1 in the same way that this code used to work (but now segfaults) on 4.0:

privateKey = KeyChain.getPrivateKey(context,mAlias);
byte[] data;
Cipher rsasinger = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1PADDING");
rsasinger.init(Cipher.ENCRYPT_MODE, privkey);
byte[] signed_bytes = rsasinger.doFinal(data);
Unknown said…
This comment has been removed by the author.
Unknown said…
It is probably related. The key chain now returns opaque keys which have a reference to either an OpenSSL native key (with the default keymaster module) or an reference/ID to a key stored in the hardware keystore. You can only use those keys via the associated libraries and not directly.

While I agree that there have been some bugs (key names with dashes not working, etc.), "RSA/ECB/PKCS1PADDING" is definitely not the 'canonical' way to compute an RSA signature. Use the Signature class, it should link to the proper lower implementation (OpenSSL or hardware keystore) correctly.

Haven't seen a segfault with stock JB, are you using some custom ROM?
Unknown said…
And yes, what you have is an 'evil' hack, it will probably break on anything that has the hardware-backed keystore enabled, such as the Nexus 7.
Unknown said…
Looking at this again, it does actually go through the keystore OpenSSL engine, so it should work with hardware-based keystores too. Cool project BTW.
Anonymous said…
Please tell me how to install SD card certificate file on my tablet?
Nelson Silva said…
I´m devoloped an android application to sign documents with some certificate. My code works good on android version 4.0. However when I updated to android 4.1 my code don´t work anymore.

The problem seems be here: KeyChain.getPrivateKey(). When I getEncoded method gives me a null value.

There is some other way to get Private Key from certificate p12?

Thanks in advance
Lukas said…
Do you know if it's possible to encrypt using an RSA key stored that way, or can it only be used for signing/verification?
Unknown said…
The usual restrictions apply, but should be possible. Not really useful unless it's part of a higher level protocol (TLS) though.
Lukas said…
How would that be implemented, since only the SIGN and VERIFY commands are available? Is the RSA implementation low-level enough that they can be used "in reverse" to allow encryption and decryption?
Unknown said…
At the lowest level SIGN is actually implemented as encryption with the private key. The software implementation uses RSA_private_encrypt(..., RSA_NO_PADDING). Hardware-backed ones should be compatible.
Lukas said…
Ah, that explains it. Thank you very much for your replies and your blog posts, especially those on Android security.
AR said…
Thanks for the post, is there a way to detect/query whether hardware or software backed storage is used, i.e. if the keymaster HAL module is backed by a hardware cryptographic device, in order to know for example whether the private key returned through KeyChain.getPrivateKey() API is protected by hardware cryptographic device?
Lukas said…
Starting with Android 4.3, KeyChain has a method isBoundKeyAlgorithm that seems to do what you want:

http://developer.android.com/reference/android/security/KeyChain.html#isBoundKeyAlgorithm(java.lang.String)
AR said…
Thanks, it seems like the method isBoundKeyAlgorithm("RSA") should return false if not backed by hardware crypto.

Popular posts from this blog

Decrypting Android M adopted storage

Unpacking Android backups

Using app encryption in Jelly Bean