In Keymaster 1 waren alle Keymaster-Schlüssel kryptografisch an den Root of Trust des Geräts oder den verifizierten Startschlüssel gebunden. In Keymaster 2 und 3 sind alle Schlüssel auch an das Betriebssystem und den Patchlevel des Systemabbilds gebunden. Dadurch wird sichergestellt, dass ein Angreifer, der eine Schwachstelle in einer alten Version des Systems oder der TEE-Software entdeckt, ein Gerät nicht auf die anfällige Version zurücksetzen und Schlüssel verwenden kann, die mit der neueren Version erstellt wurden. Wenn ein Schlüssel mit einer bestimmten Version und Patchebene auf einem Gerät verwendet wird, das auf eine neuere Version oder Patchebene aktualisiert wurde, wird der Schlüssel außerdem aktualisiert, bevor er verwendet werden kann, und die vorherige Version des Schlüssels wird ungültig. Wenn das Gerät aktualisiert wird, werden die Schlüssel auf diese Weise zusammen mit dem Gerät "ratschen", aber jede Zurücksetzung des Geräts auf eine frühere Version führt dazu, dass die Schlüssel unbrauchbar werden.
Um die modulare Struktur von Treble zu unterstützen und die Bindung von system.img an boot.img zu unterbrechen, hat Keymaster 4 das Schlüsselversions-Bindungsmodell geändert, um separate Patch-Level für jede Partition zu haben. Dadurch kann jede Partition unabhängig aktualisiert werden, während gleichzeitig ein Rollback-Schutz bereitgestellt wird.
In Android 9 haben die boot
, system
und vendor
-Partitionen jeweils einen eigenen Patch-Level.
- Geräte mit Android Verified Boot (AVB) können alle Patch-Level und die Systemversion in vbmeta ablegen, sodass der Bootloader sie Keymaster zur Verfügung stellen kann. Bei verketteten Partitionen befinden sich die Versionsinformationen für die Partition in der verketteten vbmeta. Im Allgemeinen sollten sich Versionsinformationen in der
vbmeta struct
befinden, die die Überprüfungsdaten (Hash oder Hashtree) für eine bestimmte Partition enthält. - Auf Geräten ohne AVB:
- Verifizierte Boot-Implementierungen müssen dem Bootloader einen Hash der Versionsmetadaten bereitstellen, damit der Bootloader Keymaster den Hash bereitstellen kann.
-
boot.img
kann weiterhin Patchlevel im Header speichern -
system.img
kann Patch-Level und OS-Version weiterhin in schreibgeschützten Eigenschaften speichern -
vendor.img
speichert den Patch-Level in der schreibgeschützten Eigenschaftro.vendor.build.version.security_patch
. - Der Bootloader kann Keymaster einen Hash aller Daten bereitstellen, die durch verifiziertes Booten validiert wurden.
- Verwenden Sie in Android 9 die folgenden Tags, um Versionsinformationen für die folgenden Partitionen bereitzustellen:
-
VENDOR_PATCH_LEVEL
:vendor
-
BOOT_PATCH_LEVEL
:boot
Partition -
OS_PATCH_LEVEL
undOS_VERSION
:system
. (OS_VERSION
wird aus demboot.img
Header entfernt.
-
- Keymaster-Implementierungen sollten alle Patch-Level unabhängig voneinander behandeln. Schlüssel können verwendet werden, wenn alle Versionsinformationen mit den Werten übereinstimmen, die einem Schlüssel zugeordnet sind, und
IKeymaster::upgradeDevice()
bei Bedarf auf eine höhere Patchebene rollt.
HAL-Änderungen
Um die Versionsbindung und den Versionsnachweis zu unterstützen, wurden in Android 7.1 die Tags Tag::OS_VERSION
und Tag::OS_PATCHLEVEL
sowie die Methoden configure
und upgradeKey
. Die Versions-Tags werden von Keymaster 2+-Implementierungen automatisch zu allen neu generierten (oder aktualisierten) Schlüsseln hinzugefügt. Darüber hinaus wird jeder Versuch, einen Schlüssel zu verwenden, dessen Betriebssystemversion oder Patchlevel nicht mit der aktuellen Betriebssystemversion bzw. Patchlevel übereinstimmt, mit ErrorCode::KEY_REQUIRES_UPGRADE
.
Tag::OS_VERSION
ist ein UINT
Wert, der die Major-, Minor- und Sub-Minor-Teile einer Android-Systemversion als MMmmss darstellt, wobei MM die Major-Version, mm die Minor-Version und ss die Sub-Minor-Version ist. Beispielsweise würde 6.1.2 als 060102 dargestellt.
Tag::OS_PATCHLEVEL
ist ein UINT
Wert, der das Jahr und den Monat der letzten Aktualisierung des Systems als JJJJMM darstellt, wobei JJJJ das vierstellige Jahr und MM der zweistellige Monat ist. Beispielsweise würde März 2016 als 201603 dargestellt.
UpgradeKey
Damit Schlüssel auf die neue Betriebssystemversion und Patchebene des Systemabbilds aktualisiert werden können, hat Android 7.1 die upgradeKey
Methode zur HAL hinzugefügt:
Schlüsselmeister 3
upgradeKey(vec keyBlobToUpgrade, vec upgradeParams) generates(ErrorCode error, vec upgradedKeyBlob);
Schlüsselmeister 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
ist die Gerätestruktur -
keyBlobToUpgrade
ist der Schlüssel, der aktualisiert werden muss -
upgradeParams
sind Parameter, die zum Upgrade des Schlüssels benötigt werden. Dazu gehörenTag::APPLICATION_ID
undTag::APPLICATION_DATA
, die zum Entschlüsseln des Schlüsselblobs erforderlich sind, wenn sie während der Generierung bereitgestellt wurden. -
upgradedKeyBlob
ist der Ausgabeparameter, der verwendet wird, um das neue Schlüssel-Blob zurückzugeben.
Wenn upgradeKey
mit einem Schlüsselblob aufgerufen wird, das nicht analysiert werden kann oder anderweitig ungültig ist, wird ErrorCode::INVALID_KEY_BLOB
. Wenn es mit einem Schlüssel aufgerufen wird, dessen Patchlevel größer ist als der aktuelle Systemwert, gibt es ErrorCode::INVALID_ARGUMENT
zurück. Wenn es mit einem Schlüssel aufgerufen wird, dessen Betriebssystemversion größer als der aktuelle Systemwert ist, und der Systemwert ungleich Null ist, gibt es ErrorCode::INVALID_ARGUMENT
zurück. Upgrades der Betriebssystemversion von Nicht-Null auf Null sind zulässig. Bei Fehlern bei der Kommunikation mit der sicheren Welt gibt es einen entsprechenden Fehlerwert zurück (z. B. ErrorCode::SECURE_HW_ACCESS_DENIED
, ErrorCode::SECURE_HW_BUSY
). Andernfalls wird ErrorCode::OK
und ein neues Schlüssel-Blob in upgradedKeyBlob
zurückgegeben.
keyBlobToUpgrade
bleibt nach dem upgradeKey
-Aufruf gültig und könnte theoretisch wieder verwendet werden, wenn das Gerät heruntergestuft würde. In der Praxis ruft deleteKey
im Allgemeinen deleteKey für das Blob keyBlobToUpgrade
kurz nach dem Aufruf von upgradeKey
auf. Wenn keyBlobToUpgrade
das Tag Tag::ROLLBACK_RESISTANT
ROLLBACK_RESISTANT hatte, sollte upgradedKeyBlob
es auch haben (und Rollback-resistent sein).
Sichere Konfiguration
Um die Versionsbindung zu implementieren, benötigt der Keymaster TA eine Möglichkeit, die aktuelle OS-Version und den Patch-Level (Versionsinformationen) sicher zu empfangen und sicherzustellen, dass die Informationen, die er erhält, stark mit den Informationen über das laufende System übereinstimmen.
Um die sichere Übermittlung von Versionsinformationen an den TA zu unterstützen, wurde dem Boot-Image-Header ein OS_VERSION
-Feld hinzugefügt. Das Boot-Image-Erstellungsskript füllt dieses Feld automatisch aus. OEMs und Keymaster-TA-Implementierer müssen zusammenarbeiten, um Geräte-Bootloader zu modifizieren, um die Versionsinformationen aus dem Boot-Image zu extrahieren und sie an den TA zu übergeben, bevor das nicht sichere System gebootet wird. Dadurch wird sichergestellt, dass Angreifer die Bereitstellung von Versionsinformationen an den TA nicht stören können.
Außerdem muss sichergestellt werden, dass das Systemabbild die gleichen Versionsinformationen wie das Boot-Abbild hat. Zu diesem Zweck wurde der Keymaster-HAL die Methode configure hinzugefügt:
keymaster_error_t (*configure)(const struct keymaster2_device* dev, const keymaster_key_param_set_t* params);
Das Argument params
enthält Tag::OS_VERSION
und Tag::OS_PATCHLEVEL
. Diese Methode wird von keymaster2-Clients aufgerufen, nachdem die HAL geöffnet wurde, aber bevor andere Methoden aufgerufen werden. Wenn vor configure eine andere Methode aufgerufen wird, gibt der TA ErrorCode::KEYMASTER_NOT_CONFIGURED
zurück.
Beim ersten Aufruf von configure
nach dem Booten des Geräts sollte überprüft werden, ob die bereitgestellten Versionsinformationen mit denen übereinstimmen, die vom Bootloader bereitgestellt wurden. Wenn die Versionsinformationen nicht übereinstimmen, gibt configure
ErrorCode::INVALID_ARGUMENT
zurück, und alle anderen Keymaster-Methoden geben weiterhin ErrorCode::KEYMASTER_NOT_CONFIGURED
. Wenn die Informationen übereinstimmen, gibt configure
ErrorCode::OK
zurück und andere Keymaster-Methoden beginnen normal zu funktionieren.
Nachfolgende Aufrufe zum configure
geben denselben Wert zurück, der vom ersten Aufruf zurückgegeben wurde, und ändern den Zustand von keymaster nicht. Beachten Sie, dass dieser Prozess ERFORDERLICH ist, dass alle OTAs sowohl System- als auch Boot-Images aktualisieren; Sie können nicht separat aktualisiert werden, um die Versionsinformationen synchron zu halten.
Da configure
von dem System aufgerufen wird, dessen Inhalt validiert werden soll, gibt es für einen Angreifer ein enges Zeitfenster, um das System-Image zu kompromittieren und es zu zwingen, Versionsinformationen bereitzustellen, die mit dem Boot-Image übereinstimmen, aber nicht das tatsächliche sind Version des Systems. Die Kombination aus Boot-Image-Überprüfung, dm-verity-Validierung des System-Image-Inhalts und der Tatsache, dass configure
sehr früh beim Systemstart aufgerufen wird, sollte es schwierig machen, dieses Zeitfenster auszunutzen.