The availability of a trusted execution environment in a system on a chip (SoC) offers an opportunity for Android devices to provide hardware-backed, strong security services to the Android OS, to platform services, and even to third-party apps. Developers seeking the Android-specific extensions should go to android.security.keystore.
Before Android 6.0, Android already had a simple, hardware-backed crypto services API, provided by versions 0.2 and 0.3 of the Keymaster Hardware Abstraction Layer (HAL). Keystore provided digital signing and verification operations, plus generation and import of asymmetric signing key pairs. This is already implemented on many devices, but there are many security goals that cannot easily be achieved with only a signature API. Keystore in Android 6.0 extended the Keystore API to provide a broader range of capabilities.
In Android 6.0, Keystore added symmetric cryptographic primitives, AES and HMAC, and an access control system for hardware-backed keys. Access controls are specified during key generation and enforced for the lifetime of the key. Keys can be restricted to be usable only after the user has been authenticated, and only for specified purposes or with specified cryptographic parameters. For more information, see the Authorization Tags and Functions pages.
In addition to expanding the range of cryptographic primitives, Keystore in Android 6.0 added the following:
- A usage control scheme to allow key usage to be limited, to mitigate the risk of security compromise due to misuse of keys
- An access control scheme to enable restriction of keys to specified users, clients, and a defined time range
In Android 7.0, Keymaster 2 added support for key attestation and version binding. Key attestation provides public key certificates that contain a detailed description of the key and its access controls, to make the key's existence in secure hardware and its configuration remotely verifiable.
Version binding binds keys to the operating system and patch level version. This ensures that an attacker who discovers a weakness in an old version of the system or the TEE software cannot roll a device back to the vulnerable version and use keys created with the newer version. In addition, when a key with a given version and patch level is used on a device that has been upgraded to a newer version or patch level, the key is upgraded before it can be used, and the previous version of the key invalidated. As the device is upgraded, the keys "ratchet" forward along with the device, but any reversion of the device to a previous release causes the keys to be unusable.
In Android 8.0, Keymaster 3 transitioned from the old-style C-structure Hardware Abstraction Layer (HAL) to the C++ HAL interface generated from a definition in the new Hardware Interface Definition Language (HIDL). As part of the change, many of the argument types changed, though types and methods have a one-to-one correspondence with the old types and the HAL struct methods. See the Functions page for more details.
In addition to this interface revision, Android 8.0 extended Keymaster 2's attestation feature to support ID attestation. ID attestation provides a limited and optional mechanism for strongly attesting to hardware identifiers, such as device serial number, product name, and phone ID (IMEI / MEID). To implement this addition, Android 8.0 changed the ASN.1 attestation schema to add ID attestation. Keymaster implementations need to find some secure way to retrieve the relevant data items, as well as to define a mechanism for securely and permanently disabling the feature.
In Android 9, updates included:
- Update to Keymaster 4
- Support for embedded Secure Elements
- Support for secure key import
- Support for 3DES encryption
- Changes to version binding so that boot.img and system.img have separately set versions to allow for independent updates
Glossary
Here is a quick overview of Keystore components and their relationships.
AndroidKeystore is the Android Framework API and component used
by apps to access Keystore functionality. It is implemented as an extension to
the standard Java Cryptography Architecture APIs, and consists of Java code that
runs in the app's own process space. AndroidKeystore
fulfills app
requests for Keystore behavior by forwarding them to the keystore daemon.
The keystore daemon is an Android system daemon that provides access to all Keystore functionality with a Binder API. It's responsible for storing "key blobs", which contain the actual secret key material, encrypted so Keystore can store them but not use or reveal them.
keymasterd is a HIDL server that provides access to the Keymaster TA. (This name isn't standardized and is for conceptual purposes.)
Keymaster TA (trusted app) is the software running in a secure context, most often in TrustZone on an ARM SoC, that provides all of the secure Keystore operations, has access to the raw key material, validates all of the access control conditions on keys, etc.
LockSettingsService is the Android system component responsible
for user authentication, both password and fingerprint. It's not part of
Keystore, but relevant because many Keystore key operations require user
authentication. LockSettingsService
interacts with the Gatekeeper
TA and Fingerprint TA to obtain authentication tokens, which it provides to the
keystore daemon, and which are ultimately consumed by the Keymaster TA
app.
Gatekeeper TA (trusted app) is another component running in the secure context, which is responsible for authenticating user passwords and generating authentication tokens used to prove to the Keymaster TA that an authentication was done for a particular user at a particular point in time.
Fingerprint TA (trusted app) is another component running in the secure context which is responsible for authenticating user fingerprints and generating authentication tokens used to prove to the Keymaster TA that an authentication was done for a particular user at a particular point in time.
Architecture
The Android Keystore API and the underlying Keymaster HAL provide a basic but adequate set of cryptographic primitives to allow the implementation of protocols using access-controlled, hardware-backed keys.
The Keymaster HAL is an OEM-provided, dynamically loadable library used by the Keystore service to provide hardware-backed cryptographic services. To keep things secure, HAL implementations don't perform any sensitive operations in user space, or even in kernel space. Sensitive operations are delegated to a secure processor reached through some kernel interface. The resulting architecture looks like this:
Within an Android device, the "client" of the Keymaster HAL consists of multiple layers (for example, app, framework, Keystore daemon), but that can be ignored for the purposes of this document. This means that the described Keymaster HAL API is low-level, used by platform-internal components, and not exposed to app developers. The higher-level API is described on the Android Developer site.
The purpose of the Keymaster HAL isn't to implement the security-sensitive algorithms but only to marshal and unmarshal requests to the secure world. The wire format is implementation-defined.
Compatibility with previous versions
The Keymaster 1 HAL is completely incompatible with the previously released HALs, for example, Keymaster 0.2 and 0.3. To facilitate interoperability on devices running Android 5.0 and earlier that launched with the older Keymaster HALs, Keystore provides an adapter that implements the Keymaster 1 HAL with calls to the existing hardware library. The result cannot provide the full range of functionality in the Keymaster 1 HAL. In particular, it only supports RSA and ECDSA algorithms, and all of the key authorization enforcement is performed by the adapter, in the non-secure world.
Keymaster 2 further simplified the HAL interface by removing the
get_supported_*
methods and allowing the finish()
method to accept input. This reduces the number of round trips to the TEE in
cases where the input is available all at once, and simplifies implementation of
AEAD decryption.
In Android 8.0, Keymaster 3 transitioned from the old-style C-structure
HAL to the C++ HAL interface generated from a definition in the new
Hardware Interface Definition Language (HIDL). A new-style HAL
implementation is created by subclassing the generated
IKeymasterDevice
class and implementing the pure virtual
methods. As part of the change, many of the argument types have changed,
though types and methods have a one-to-one correspondence with the old
types and the HAL struct methods.
HIDL overview
The Hardware Interface Definition Language (HIDL) provides an implementation language-independent mechanism for specifying hardware interfaces. The HIDL tooling currently supports generation of C++ and Java interfaces. We expect that most Trusted Execution Environment (TEE) implementers will find the C++ tooling more convenient, so this page discusses only the C++ representation.
HIDL interfaces consist of a set of methods, expressed as:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
There are various pre-defined types, and HALs can define new enumerated and structure types. For more details on HIDL, see the Reference section.
An example method from the Keymaster 3 IKeymasterDevice.hal
is:
generateKey(vec<KeyParameter> keyParams) generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
This is the equivalent of the following from the keymaster2 HAL:
keymaster_error_t (*generate_key)( const struct keymaster2_device* dev, const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics);
In the HIDL version, the dev
argument is removed, because it's
implicit. The params
argument is no longer a struct containing a
pointer referencing an array of key_parameter_t
objects, but a
vec
(vector) containing KeyParameter
objects. The
return values are listed in the "generates
" clause, including a
vector of uint8_t
values for the key blob.
The C++ virtual method generated by the HIDL compiler is:
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, generateKey_cb _hidl_cb) override;
Where generateKey_cb
is a function pointer defined as:
std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics)>
That is, generateKey_cb
is a function that takes the return values
listed in the generate clause. The HAL implementation class overrides this
generateKey
method and calls the generateKey_cb
function
pointer to return the result of the operation to the caller. Note the function
pointer call is synchronous. The caller calls
generateKey
and generateKey
calls the supplied
function pointer, which executes to completion, returning control to the
generateKey
implementation, which then returns to the caller.
For a detailed example, see the default implementation in
hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
.
The default implementation provides backward compatibility for devices with
old-style keymaster0, keymaster1, or keymaster2 HALS.
Access control
The most basic rule of Keystore access control is that each app has its own namespace. But for every rule there is an exception. Keystore has some hard-coded maps that allow certain system components to access certain other namespaces. This is a very blunt instrument in that it gives one component full control over another namespace. And then there is the matter of vendor components as clients to Keystore. We currently have no way of establishing a namespace for vendor components, for example, WPA supplicant.
In order to accommodate vendor components and generalize access control without hard-coded exceptions, Keystore 2.0 introduces domains and SELinux namespaces.
Keystore domains
With Keystore domains, we can decouple namespaces from UIDs. Clients accessing a key in Keystore have to specify the domain, namespace, and alias that they want to access. Based on this tuple and the identity of the caller we can determine which key the caller wants to access and if it has appropriate permissions.
We introduce five domain parameters which govern how keys can be accessed. They control the semantics of the namespace parameter of the key descriptor and how access control is performed.
DOMAIN_APP
: The app domain covers the legacy behavior. The Java Keystore SPI uses this domain by default. When this domain is used, the namespace argument is ignored and the UID of the caller is used instead. Access to this domain is controlled by the Keystore label to the classkeystore_key
in the SELinux policy.DOMAIN_SELINUX
: This domain indicates that the namespace has a label in the SELinux policy. The namespace parameter is looked up and translated into a target context, and a permission check is performed for the calling SELinux context for thekeystore_key
class. When the permission has been established for the given operation, the full tuple is used for the key lookup.DOMAIN_GRANT
: The grant domain indicates that the namespace parameter is a grant identifier. The alias parameter is ignored. SELinux checks are performed when the grant is created. Further access control only checks if the caller UID matches the grantees UID of the requested grant.DOMAIN_KEY_ID
: This domain indicates that the namespace parameter is a unique key id. The key itself might have been created withDOMAIN_APP
orDOMAIN_SELINUX
. The permission check is performed after thedomain
and thenamespace
have been loaded from the key database in the same way as if the blob was loaded by the domain, namespace, and alias tuple. The rationale for the key id domain is continuity. When accessing a key by alias, subsequent calls can operate on different keys, because a new key might have been generated or imported and bound to this alias. The key id, however, never changes. So when using a key by key id after it has been loaded from the Keystore database using the alias once, one can be certain that it is the same key as long as the key id still exists. This functionality isn't exposed to app developers. Instead, it is used within the Android Keystore SPI to provide a more consistent experience even when used concurrently in an unsafe way.DOMAIN_BLOB
: The blob domain indicates that the caller manages the blob by itself. This is used for clients that need to access the Keystore before the data partition is mounted. The key blob is included in theblob
field of the key descriptor.
Using the SELinux domain, we can give vendor components access to very specific Keystore namespaces which can be shared by system components such as the settings dialog.
SELinux policy for keystore_key
Namespace labels are configured using the keystore2_key_context
file.
Each line in these files maps a numeric namespace id to an SELinux label.
For example,
# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and # Settings to share keystore keys. 102 u:object_r:wifi_key:s0
After having set up a new key namespace in this way, we can give access to it
by adding an appropriate policy. For example, to allow
wpa_supplicant
to get and use keys in the new namespace we would
add the following line to hal_wifi_supplicant.te
:
allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };
After setting up the new namespace, AndroidKeyStore can be used almost as
usual. The only difference is that the namespace ID must be specified. For
loading and importing keys from and into Keystore, the namespace id is specified
using the AndroidKeyStoreLoadStoreParameter
. For example,
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import java.security.KeyStore; KeyStore keystore = KeyStore.getInstance("AndroidKeyStore"); keystore.load(new AndroidKeyStoreLoadStoreParameter(102));
To generate a key in a given namespace, the namespace id must be given
using KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
The following context files can be used to configure Keystore 2.0 SELinux namespaces. Each partition has a different reserved range of 10,000 namespace ids to avoid collisions.
Partition | Range | Config files |
---|---|---|
System | 0 ... 9,999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
Extended System | 10,000 ... 19,999 | /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts |
Product | 20,000 ... 29,999 | /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts |
Vendor | 30,000 ... 39,999 | /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts |
The client requests the key by requesting the SELinux domain and the desired
virtual namespace, in this case "wifi_key"
, by its numeric id.
Above that, the following namespaces have been defined. If they replace special rules, the following table indicates the UID they used to correspond to.
Namespace ID | SEPolicy Label | UID | Description |
---|---|---|---|
0 | su_key | N/A | Super user key. Only used for testing on userdebug and eng builds. Not relevant on user builds. |
1 | shell_key | N/A | Namespace available to shell. Mostly used for testing, but can be used on user builds as well from the command line. |
100 | vold_key | N/A | Intended for use by vold. |
101 | odsing_key | N/A | Used by the on-device signing daemon. |
102 | wifi_key | AID_WIFI(1010) | Used by Android's Wifi sybsystem including wpa_supplicant. |
120 | resume_on_reboot_key | AID_SYSTEM(1000) | Used by Android's system server to support resume on reboot. |
Access vectors
The SELinux class keystore_key
has aged quite a bit and some of
the permissions, such as verify
or sign
have lost
their meaning. Here is the new set of permissions, keystore2_key
,
that Keystore 2.0 enforces.
Permission | Meaning |
---|---|
delete
|
Checked when removing keys from Keystore. |
get_info
|
Checked when a key's metadata is requested. |
grant
|
The caller needs this permission to create a grant to the key in the target context. |
manage_blob
|
The caller can use DOMAIN_BLOB on the given SELinux namespace,
thereby managing blobs by itself. This is specifically useful for
vold. |
rebind
|
This permission controls if an alias can be rebound to a new key. This is required for insertion and implies that the previously bound key is deleted. It's an insert permission, but it captures the semantic of keystore better. |
req_forced_op
|
Clients with this permission can create unpruneable operations, and operation creation never fails unless all operation slots are taken by unpruneable operations. |
update
|
Required to update the subcomponent of a key. |
use
|
Checked when creating a Keymint operation that uses the key material, for example, for signing, encyption, decryption. |
use_dev_id
|
Required when generating device identifying information, such as device id attestation. |
Additionally, we split out a set of non key specific keystore permissions in
the SELinux security class keystore2
:
Permission | Meaning |
---|---|
add_auth
|
Required by authentication provider such as Gatekeeper or BiometricsManager for adding auth tokens. |
clear_ns
|
Formerly clear_uid, this permission allows a non owner of a namespace to delete all keys in that namespace. |
list
|
Required by the system for enumerating keys by various properties, such as
ownership or auth boundedness. This permission isn't required by callers
enumerating their own namespaces. This is covered by the
get_info permission. |
lock
|
This permission allows to lock Keystore, that is, evict the master key, such that auth bound keys become unusable and uncreatable. |
reset
|
This permission allows to reset Keystore to factory default, deleting all keys that aren't vital to the functioning of the Android OS. |
unlock
|
This permission is required to attempt to unlock the master key for auth bound keys. |