In Keymaster 1 waren alle Keymaster-Schlüssel kryptografisch an den Root of Trust des Geräts oder den Verified Boot-Schlüssel gebunden. Auch bei Keymaster 2 und 3 sind alle Schlüssel an das Betriebssystem und den Patch-Level des System-Images 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 mit der neueren Version erstellte Schlüssel verwenden kann. Wenn außerdem ein Schlüssel mit einer bestimmten Version und Patch-Ebene auf einem Gerät verwendet wird, das auf eine neuere Version oder Patch-Ebene aktualisiert wurde, wird der Schlüssel aktualisiert, bevor er verwendet werden kann, und die vorherige Version des Schlüssels wird ungültig. Auf diese Weise „rasten“ die Tasten bei der Aktualisierung des Geräts zusammen mit dem Gerät nach vorne, aber jede Rückstellung des Geräts auf eine frühere Version führt dazu, dass die Tasten unbrauchbar werden.
Um die modulare Struktur von Treble zu unterstützen und die Bindung von system.img an boot.img aufzuheben, hat Keymaster 4 das Bindungsmodell der Schlüsselversion geändert, um für jede Partition separate Patch-Level zu haben. Dadurch kann jede Partition unabhängig aktualisiert werden, während gleichzeitig ein Rollback-Schutz gewährleistet ist.
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 bereitstellen kann. Bei verketteten Partitionen befinden sich die Versionsinformationen für die Partition in der verketteten VBMETA. Im Allgemeinen sollten Versionsinformationen in der
vbmeta struct
enthalten sein, die die Verifizierungsdaten (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 den Hash an Keymaster bereitstellen kann.
-
boot.img
kann weiterhin den Patch-Level im Header speichern -
system.img
kann weiterhin Patch-Level und Betriebssystemversion in schreibgeschützten Eigenschaften speichern -
vendor.img
speichert den Patch-Level in der schreibgeschützten Eigenschaftro.vendor.build.version.security_patch
. - Der Bootloader kann einen Hash aller Daten bereitstellen, die durch den verifizierten Start an Keymaster 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
-
OS_PATCH_LEVEL
undOS_VERSION
:system
. (OS_VERSION
wird aus demboot.img
Header entfernt.
-
- Keymaster-Implementierungen sollten alle Patch-Level unabhängig behandeln. Schlüssel sind verwendbar, wenn alle Versionsinformationen mit den mit einem Schlüssel verknüpften Werten übereinstimmen und
IKeymaster::upgradeDevice()
bei Bedarf auf eine höhere Patch-Ebene umschaltet.
HAL-Änderungen
Um Versionsbindung und Versionsnachweis zu unterstützen, wurden in Android 7.1 die Tags Tag::OS_VERSION
und Tag::OS_PATCHLEVEL
sowie die Methoden configure
und upgradeKey
hinzugefügt. Die Versions-Tags werden von Keymaster 2+-Implementierungen automatisch allen neu generierten (oder aktualisierten) Schlüsseln hinzugefügt. Darüber hinaus wird jeder Versuch, einen Schlüssel zu verwenden, dessen Betriebssystemversion oder Patch-Level nicht mit der Betriebssystemversion bzw. dem Patch-Level des aktuellen Systems übereinstimmt, mit ErrorCode::KEY_REQUIRES_UPGRADE
abgelehnt.
Tag::OS_VERSION
ist ein UINT
Wert, der die Haupt-, Neben- und Nebenteile einer Android-Systemversion als MMmmss darstellt, wobei MM die Hauptversion, mm die Nebenversion und ss die Nebenversion 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 Patch-Ebene des Systemabbilds aktualisiert werden können, hat Android 7.1 die upgradeKey
Methode zum 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 Aktualisieren des Schlüssels erforderlich sind. Dazu gehörenTag::APPLICATION_ID
undTag::APPLICATION_DATA
, die zum Entschlüsseln des Schlüsselblobs erforderlich sind, sofern sie während der Generierung bereitgestellt wurden. -
upgradedKeyBlob
ist der Ausgabeparameter, der zum Zurückgeben des neuen Schlüssel-Blobs verwendet wird.
Wenn upgradeKey
mit einem Schlüsselblob aufgerufen wird, das nicht analysiert werden kann oder anderweitig ungültig ist, wird ErrorCode::INVALID_KEY_BLOB
zurückgegeben. Wenn es mit einem Schlüssel aufgerufen wird, dessen Patch-Level größer als der aktuelle Systemwert ist, wird ErrorCode::INVALID_ARGUMENT
zurückgegeben. Wenn es mit einem Schlüssel aufgerufen wird, dessen Betriebssystemversion größer als der aktuelle Systemwert ist und der Systemwert ungleich Null ist, wird ErrorCode::INVALID_ARGUMENT
zurückgegeben. Upgrades der Betriebssystemversion von ungleich 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
zurückgegeben und ein neuer Schlüsselblob in upgradedKeyBlob
zurückgegeben.
keyBlobToUpgrade
bleibt nach dem upgradeKey
Aufruf gültig und könnte theoretisch bei einem Downgrade des Geräts wieder verwendet werden. In der Praxis ruft Keystore im Allgemeinen kurz nach dem Aufruf von upgradeKey
deleteKey
für das Blob keyBlobToUpgrade
auf. Wenn keyBlobToUpgrade
das Tag Tag::ROLLBACK_RESISTANT
hatte, sollte upgradedKeyBlob
es ebenfalls haben (und Rollback-resistent sein).
Sichere Konfiguration
Um die Versionsbindung zu implementieren, benötigt der Keymaster-TA eine Möglichkeit, die aktuelle Betriebssystemversion und den Patch-Level (Versionsinformationen) sicher zu empfangen und sicherzustellen, dass die empfangenen Informationen genau 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 so zu modifizieren, dass sie die Versionsinformationen aus dem Boot-Image extrahieren und an den TA übergeben, bevor das nicht sichere System gebootet wird. Dadurch wird sichergestellt, dass Angreifer die Bereitstellung von Versionsinformationen an den TA nicht beeinträchtigen können.
Außerdem muss sichergestellt werden, dass das System-Image dieselben Versionsinformationen wie das Boot-Image aufweist. Zu diesem Zweck wurde die Methode configure zur Keymaster-HAL 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 nach dem Öffnen der HAL, aber vor dem Aufruf anderer Methoden aufgerufen. Wenn vor der Konfiguration eine andere Methode aufgerufen wird, gibt der TA ErrorCode::KEYMASTER_NOT_CONFIGURED
zurück.
Beim ersten Aufruf von configure
nach dem Gerätestart sollte überprüft werden, ob die bereitgestellten Versionsinformationen mit denen des Bootloaders übereinstimmen. Wenn die Versionsinformationen nicht übereinstimmen, configure
ErrorCode::INVALID_ARGUMENT
zurück und alle anderen Keymaster-Methoden geben weiterhin ErrorCode::KEYMASTER_NOT_CONFIGURED
zurück. Wenn die Informationen übereinstimmen, gibt configure
ErrorCode::OK
zurück und andere Keymaster-Methoden beginnen normal zu funktionieren.
Nachfolgende Aufrufe von configure
geben denselben Wert zurück, der vom ersten Aufruf zurückgegeben wurde, und ändern den Status von keymaster nicht. Beachten Sie, dass dieser Prozess erfordert, 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 Inhalte validiert werden sollen, besteht für einen Angreifer nur ein begrenztes Zeitfenster, um das Systemabbild zu kompromittieren und es zur Bereitstellung von Versionsinformationen zu zwingen, die mit dem Startabbild übereinstimmen, aber nicht der tatsächlichen Version entsprechen 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.