In Keymaster 1 waren alle Keymaster-Schlüssel kryptografisch an den Root of Trust des Geräts oder den Schlüssel für den verifizierten Bootmodus gebunden. In Keymaster 2 und 3 sind alle Schlüssel auch an das Betriebssystem und den Patch-Level des System-Images gebunden. So wird verhindert, dass ein Angreifer, der eine Schwachstelle in einer alten Version der System- oder TEE-Software entdeckt, ein Gerät auf die anfällige Version zurücksetzen und mit den mit der neueren Version erstellten Schlüsseln verwenden kann. Wenn ein Schlüssel mit einer bestimmten Version und einem bestimmten Patch-Level auf einem Gerät verwendet wird, das auf eine neuere Version oder ein neueres Patch-Level aktualisiert wurde, wird der Schlüssel aktualisiert, bevor er verwendet werden kann. Die vorherige Version des Schlüssels wird ungültig. Wenn das Gerät aktualisiert wird, werden die Schlüssel entsprechend angepasst. Wenn das Gerät jedoch auf eine frühere Version zurückgesetzt wird, sind die Schlüssel nicht mehr verwendbar.
Um die modulare Struktur von Treble zu unterstützen und die Bindung von system.img an boot.img aufzuheben, wurde in Keymaster 4 das Modell für die Schlüsselversionsbindung so geändert, dass für jede Partition separate Patch-Ebenen vorhanden sind. So kann jede Partition unabhängig aktualisiert werden und es gibt trotzdem einen Rollback-Schutz.
Für die Implementierung dieser Versionsbindung benötigt die KeyMint-Trusted App (TA) eine Möglichkeit, die aktuelle Betriebssystemversion und die Patch-Ebenen sicher zu empfangen und dafür zu sorgen, dass die empfangenen Informationen mit allen Informationen über das ausgeführte System übereinstimmen.
- Bei Geräten mit Android Verified Boot (AVB) können alle Patch-Ebenen und die Systemversion in vbmeta gespeichert werden, sodass der Bootloader sie an Keymaster übergeben kann. Bei verketteten Partitionen befinden sich die Versionsinformationen für die Partition in der verketteten vbmeta. Im Allgemeinen sollten Versionsinformationen im
vbmeta struct
enthalten sein, das die Prüfdaten (Hash oder Hashbaum) für eine bestimmte Partition enthält. - Auf Geräten ohne AVB:
- Implementierungen des Bootmodus mit Verifikation müssen einen Hash der Versionsmetadaten für den Bootloader bereitstellen, damit der Bootloader den Hash an Keymaster weitergeben kann.
boot.img
kann den Patch-Level weiterhin im Header speichern.system.img
kann weiterhin Patch-Level und Betriebssystemversion in schreibgeschützten Properties speichern.vendor.img
speichert die Patch-Ebene in der schreibgeschützten Eigenschaftro.vendor.build.version.security_patch
.- Der Bootloader kann einen Hash aller Daten, die von Verified Boot validiert wurden, an Keymaster senden.
- In Android 9 verwenden Sie die folgenden Tags, um Versionsinformationen für die folgenden Partitionen anzugeben:
VENDOR_PATCH_LEVEL
:vendor
-PartitionBOOT_PATCH_LEVEL
:boot
-PartitionOS_PATCH_LEVEL
undOS_VERSION
:system
-Partition.OS_VERSION
wird aus dem Headerboot.img
entfernt.
-
Keymaster-Implementierungen sollten alle Patch-Ebenen unabhängig voneinander behandeln. Schlüssel sind verwendbar, wenn alle Versionsinformationen mit den Werten übereinstimmen, die einem Schlüssel zugeordnet sind, und
IKeymaster::upgradeDevice()
bei Bedarf auf ein höheres Patch-Level aktualisiert wird.
HAL-Änderungen
Zur Unterstützung von Versionsbindung und Versionsbestätigung 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. Außerdem wird jeder Versuch, einen Schlüssel zu verwenden, der keine Betriebssystemversion oder kein Patch-Level hat, die bzw. das mit der aktuellen Betriebssystemversion oder dem aktuellen Patch-Level des Systems übereinstimmt, mit ErrorCode::KEY_REQUIRES_UPGRADE
abgelehnt.
Tag::OS_VERSION
ist ein UINT
-Wert, der die Haupt-, Neben- und Sub-Minor-Anteile einer Android-Systemversion als MMmmss darstellt, wobei MM die Hauptversion, mm die Nebenversion und ss die Sub-Minor-Version ist. 6.1.2 würde beispielsweise als 060102 dargestellt.
Tag::OS_PATCHLEVEL
ist ein UINT
-Wert, der das Jahr und den Monat des letzten Updates des Systems als YYYYMM darstellt. YYYY ist das vierstellige Jahr und MM der zweistellige Monat. Beispiel: März 2016 wird als 201603 dargestellt.
UpgradeKey
Damit Schlüssel auf die neue Betriebssystemversion und das neue Patch-Level des System-Images aktualisiert werden können, wurde in Android 7.1 die Methode upgradeKey
in den HAL eingeführt:
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
ist die Gerätestruktur.keyBlobToUpgrade
ist der Schlüssel, der aktualisiert werden muss.upgradeParams
sind Parameter, die für das Upgrade des Schlüssels erforderlich sind. Dazu gehörenTag::APPLICATION_ID
undTag::APPLICATION_DATA
, die zum Entschlüsseln des Schlüssel-Blobs erforderlich sind, sofern sie bei der Generierung angegeben wurden.upgradedKeyBlob
ist der Ausgabeparameter, der zum Zurückgeben des neuen Schlüssel-Blobs verwendet wird.
Wenn upgradeKey
mit einem Schlüssel-Blob aufgerufen wird, der nicht geparst werden kann oder anderweitig ungültig ist, wird ErrorCode::INVALID_KEY_BLOB
zurückgegeben. Wenn die Funktion mit einem Schlüssel aufgerufen wird, dessen Patch-Level höher als der aktuelle Systemwert ist, wird ErrorCode::INVALID_ARGUMENT
zurückgegeben. Wenn die Funktion 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. Betriebssystemversions-Upgrades von einer Version ungleich null auf Version 0 sind zulässig. Bei Fehlern bei der Kommunikation mit der sicheren Welt wird ein entsprechender Fehlerwert zurückgegeben (z. B. ErrorCode::SECURE_HW_ACCESS_DENIED
, ErrorCode::SECURE_HW_BUSY
). Andernfalls wird ErrorCode::OK
zurückgegeben und ein neuer Schlüssel-Blob in upgradedKeyBlob
.
keyBlobToUpgrade
bleibt nach dem upgradeKey
-Aufruf gültig und könnte theoretisch wieder verwendet werden, wenn das Gerät auf eine frühere Version zurückgestuft würde. In der Praxis ruft Keystore deleteKey
für den keyBlobToUpgrade
-Blob kurz nach dem Aufruf von upgradeKey
auf. Wenn keyBlobToUpgrade
das Tag Tag::ROLLBACK_RESISTANT
hatte, sollte upgradedKeyBlob
es auch haben (und rollback-resistent sein).
Sichere Konfiguration
Für die Implementierung der Versionsbindung benötigt die Keymaster-TA eine Möglichkeit, die aktuelle Betriebssystemversion und den aktuellen Patch-Level (Versionsinformationen) sicher zu empfangen und dafür zu sorgen, dass die empfangenen Informationen mit den Informationen zum ausgeführten System übereinstimmen.
Zur Unterstützung der sicheren Übermittlung von Versionsinformationen an das TA wurde dem Boot-Image-Header das OS_VERSION
-Feld hinzugefügt. Dieses Feld wird automatisch vom Boot-Image-Build-Skript ausgefüllt. OEMs und Keymaster TA-Implementierer müssen zusammenarbeiten, um Geräte-Bootloader so zu ändern, dass die Versionsinformationen aus dem Boot-Image extrahiert und an die TA übergeben werden, bevor das nicht sichere System gestartet wird. So wird verhindert, dass Angreifer die Bereitstellung von Versionsinformationen für die TA manipulieren können.
Außerdem muss das System-Image dieselben Versionsinformationen wie das Boot-Image haben. Dazu wurde die Methode „configure“ dem 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 aufgerufen, nachdem das HAL geöffnet wurde, aber bevor andere Methoden aufgerufen werden. Wenn vor „configure“ eine andere Methode aufgerufen wird, gibt die TA ErrorCode::KEYMASTER_NOT_CONFIGURED
zurück.
Wenn configure
zum ersten Mal nach dem Starten des Geräts aufgerufen wird, sollte geprüft werden, ob die angegebenen Versionsinformationen mit den vom Bootloader bereitgestellten Informationen übereinstimmen. Wenn die Versionsinformationen nicht übereinstimmen, gibt configure
den Wert 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 funktionieren wieder normal.
Bei nachfolgenden Aufrufen von configure
wird derselbe Wert zurückgegeben wie beim ersten Aufruf. Der Status von Keymaster wird nicht geändert.
Da configure
vom System aufgerufen wird, dessen Inhalt es validieren soll, hat ein Angreifer nur ein kleines Zeitfenster, um das System-Image zu manipulieren und es zu zwingen, Versionsinformationen bereitzustellen, die mit dem Boot-Image übereinstimmen, aber nicht die tatsächliche Version des Systems sind. Die Kombination aus der Überprüfung des Boot-Images, der dm-verity-Validierung des Inhalts des System-Images und der Tatsache, dass configure
sehr früh im Systemstart aufgerufen wird, sollte es schwierig machen, diese Sicherheitslücke auszunutzen.