In Keymaster 1, all keymaster keys were cryptographically bound to the device Root of Trust, or the Verified Boot key. In Keymaster 2 and 3, all keys are also bound to the operating system and patch level of the system image. This ensures that an attacker who discovers a weakness in an old version of system or 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. In this way, 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.
To support Treble's modular structure and break the binding of system.img to boot.img, Keymaster 4 changed the key version binding model to have separate patch levels for each partition. This allows each partition to be updated independently, while still providing rollback protection.
In Android 9 the boot
, system
, and vendor
partitions each have their own patch level.
- Devices with Android Verified Boot (AVB) can put all of the patch levels
and the system version in vbmeta, so the bootloader can provide them to
Keymaster. For chained partitions, the version info for the partition is
in the chained vbmeta. In general, version information should be in the
vbmeta struct
that contains the verification data (hash or hashtree) for a given partition. - On devices without AVB:
- Verified Boot implementations need to provide a hash of the version metadata to bootloader, so that bootloader can provide the hash to Keymaster.
boot.img
can continue storing patch level in the headersystem.img
can continue storing patch level and OS version in read-only propertiesvendor.img
stores the patch level in the read-only propertyro.vendor.build.version.security_patch
.- The bootloader can provide a hash of all data validated by verified boot to keymaster.
- In Android 9, use the following tags to supply version information for
the following partitions:
VENDOR_PATCH_LEVEL
:vendor
partitionBOOT_PATCH_LEVEL
:boot
partitionOS_PATCH_LEVEL
andOS_VERSION
:system
partition. (OS_VERSION
is removed from theboot.img
header.
-
Keymaster implementations should treat all patch levels independently. Keys are
usable if all version info matches the values associated with a key, and
IKeymaster::upgradeDevice()
rolls to a higher patch level if needed.
HAL changes
To support version binding and version attestation, Android 7.1 added the
tags Tag::OS_VERSION
and Tag::OS_PATCHLEVEL
and the
methods configure
and upgradeKey
. The version tags
are automatically added by Keymaster 2+ implementations to all newly generated
(or updated) keys. Further, any attempt to use a key that doesn't have an OS
version or patch level matching the current system OS version or patch level,
respectively, is rejected with ErrorCode::KEY_REQUIRES_UPGRADE
.
Tag::OS_VERSION
is a UINT
value that represents the
major, minor, and sub-minor portions of an Android system version as MMmmss,
where MM is the major version, mm is the minor version and ss is the sub-minor
version. For example 6.1.2 would be represented as 060102.
Tag::OS_PATCHLEVEL
is a UINT
value that represents the
year and month of the last update to the system as YYYYMM, where YYYY is the
four-digit year and MM is the two-digit month. For example, March 2016 would be
represented as 201603.
UpgradeKey
To allow keys to be upgraded to the new OS version and patch level of the system
image, Android 7.1 added the upgradeKey
method to the HAL:
Keymaster 3
upgradeKey(vec keyBlobToUpgrade, vec upgradeParams) generates(ErrorCode error, vec upgradedKeyBlob);
Keymaster 2
keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev, const keymaster_key_blob_t* key_to_upgrade, const keymaster_key_param_set_t* upgrade_params, keymaster_key_blob_t* upgraded_key);
dev
is the device structurekeyBlobToUpgrade
is the key which needs to be upgradedupgradeParams
are parameters needed to upgrade the key. These includeTag::APPLICATION_ID
andTag::APPLICATION_DATA
, which are necessary to decrypt the key blob, if they were provided during generation.upgradedKeyBlob
is the output parameter, used to return the new key blob.
If upgradeKey
is called with a key blob that cannot be parsed or
is otherwise invalid, it returns ErrorCode::INVALID_KEY_BLOB
. If it
is called with a key whose patch level is greater than the current system value,
it returns ErrorCode::INVALID_ARGUMENT
. If it is called with a key
whose OS version is greater than the current system value, and the system value
is non-zero, it returns ErrorCode::INVALID_ARGUMENT
. OS version
upgrades from non-zero to zero are allowed. In the event of errors
communicating with the secure world, it returns an appropriate error value (for example,
ErrorCode::SECURE_HW_ACCESS_DENIED
,
ErrorCode::SECURE_HW_BUSY
). Otherwise, it returns
ErrorCode::OK
and returns a new key blob in
upgradedKeyBlob
.
keyBlobToUpgrade
remains valid after the upgradeKey
call, and could theoretically be used again if the device were downgraded. In
practice, keystore generally calls deleteKey
on the
keyBlobToUpgrade
blob shortly after the call to
upgradeKey
. If keyBlobToUpgrade
had tag
Tag::ROLLBACK_RESISTANT
, then upgradedKeyBlob
should
have it as well (and should be rollback resistant).
Secure configuration
To implement version binding, the keymaster TA needs a way to securely receive the current OS version and patch level (version information), and to ensure that the information it receives strongly matches the information about the running system.
To support secure delivery of version information to the TA, an OS_VERSION
field has been added to the boot image header. The boot image build
script automatically populates this field. OEMs and keymaster TA implementers
need to work together to modify device bootloaders to extract the version
information from the boot image and pass it to the TA before the non-secure
system is booted. This ensures that attackers cannot interfere with provisioning
of version information to the TA.
It is also necessary to ensure that the system image has the same version information as the boot image. To that end, the configure method has been added to the keymaster HAL:
keymaster_error_t (*configure)(const struct keymaster2_device* dev, const keymaster_key_param_set_t* params);
The params
argument contains Tag::OS_VERSION
and
Tag::OS_PATCHLEVEL
. This method is called by keymaster2 clients
after opening the HAL, but before calling any other methods. If any other method
is called before configure, the TA returns
ErrorCode::KEYMASTER_NOT_CONFIGURED
.
The first time configure
is called after the device boots, it
should verify that the version information provided matches what was provided by
the bootloader. If the version information doesn't match,
configure
returns ErrorCode::INVALID_ARGUMENT
, and all
other keymaster methods continue returning
ErrorCode::KEYMASTER_NOT_CONFIGURED
. If the information matches,
configure
returns ErrorCode::OK
, and other keymaster
methods begin functioning normally.
Subsequent calls to configure
return the same value returned by the
first call, and don't change the state of keymaster.
Because configure
is called by the system whose contents it is
intended to validate, there is a narrow window of opportunity for an attacker to
compromise the system image and force it to provide version information that
matches the boot image, but which isn't the actual version of the system. The
combination of boot image verification, dm-verity validation of the system image
contents, and the fact that configure
is called very early in the
system boot should make this window of opportunity difficult to exploit.