In Keymaster 1 waren alle Keymaster-Schlüssel kryptografisch an den Root of Trust oder den Schlüssel für den verifizierten Bootmodus gebunden. In Keymaster 2 und 3 sind alle Schlüssel auch an das Betriebssystem und die Patchebene 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 der neueren Version erstellte Schlüssel verwenden kann. Wenn ein Schlüssel mit einer bestimmten Version und Patchebene auf einem Gerät verwendet wird, das auf eine neuere Version oder Patchebene umgestellt wurde, wird der Schlüssel vor der Verwendung aktualisiert und die vorherige Version des Schlüssels ungültig. So werden die Schlüssel beim Upgrade des Geräts zusammen mit dem Gerät weitergeführt. Wenn das Gerät jedoch auf eine frühere Version zurückgesetzt wird, können die Schlüssel nicht mehr verwendet 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 für die Schlüsselversion geändert, sodass für jede Partition separate Patchebenen vorhanden sind. So kann jede Partition unabhängig aktualisiert werden und es bleibt ein Rollback-Schutz erhalten.
In Android 9 haben die Partitionen boot
, system
und vendor
jeweils eine eigene Patchebene.
- Geräte mit Android Verified Boot (AVB) können alle Patchebenen und die Systemversion in vbmeta ablegen, damit der Bootloader sie an Keymaster weitergeben 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 Bestätigungsdaten (Hash oder Hash-Baum) für eine bestimmte Partition enthält. - Auf Geräten ohne AVB:
- Bei der Implementierung von Verified Boot muss dem Bootloader ein Hash der Versionsmetadaten bereitgestellt werden, damit der Bootloader den Hash an Keymaster weitergeben kann.
boot.img
kann die Patchebene weiterhin im Header speichernsystem.img
kann Patchebene und Betriebssystemversion weiterhin in schreibgeschützten Properties speichernvendor.img
speichert die Patchebene in der nur lesbaren Eigenschaftro.vendor.build.version.security_patch
.- Der Bootloader kann dem Keymaster einen Hash aller Daten zur Verfügung stellen, die durch den verifizierten Start validiert wurden.
- Verwenden Sie unter Android 9 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 demboot.img
-Header entfernt.
-
Keymaster-Implementierungen sollten alle Patchebenen unabhängig voneinander behandeln. Schlüssel können verwendet werden, wenn alle Versionsinformationen mit den mit einem Schlüssel verknüpften Werten übereinstimmen. Bei Bedarf wird
IKeymaster::upgradeDevice()
auf eine höhere Patchebene umgestellt.
HAL-Änderungen
Zur Unterstützung der Versionsbindung und der Versionsattestierung 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 und höher automatisch allen neu generierten (oder aktualisierten) Schlüsseln hinzugefügt. Außerdem wird jeder Versuch, einen Schlüssel zu verwenden, dessen Betriebssystemversion oder Patchebene nicht mit der aktuellen Betriebssystemversion oder Patchebene des Systems übereinstimmt, mit ErrorCode::KEY_REQUIRES_UPGRADE
abgelehnt.
Tag::OS_VERSION
ist ein UINT
-Wert, der die Haupt-, Neben- und Sub-Minor-Versionen einer Android-Systemversion in Form von MMmmss darstellt. Dabei steht MM für die Hauptversion, mm für die Nebenversion und ss für die Sub-Minor-Version. Beispiel: 6.1.2 wird als 060102 dargestellt.
Tag::OS_PATCHLEVEL
ist ein UINT
-Wert, der das Jahr und den Monat der letzten Systemaktualisierung im Format JJJJMM angibt. JJJJ ist die vierstellige Jahreszahl und MM der zweistellige Monat. März 2016 würde beispielsweise als 201603 dargestellt.
UpgradeKey
Damit Schlüssel auf die neue Betriebssystemversion und Patchebene des System-Images aktualisiert werden können, wurde in Android 7.1 die Methode upgradeKey
zur HAL hinzugefügt:
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ätestrukturkeyBlobToUpgrade
ist der Schlüssel, der aktualisiert werden muss.upgradeParams
sind Parameter, die zum Upgrade des Schlüssels erforderlich sind. Dazu gehörenTag::APPLICATION_ID
undTag::APPLICATION_DATA
, die zur Entschlüsselung des Schlüssel-Blobs erforderlich sind, sofern sie bei der Generierung angegeben wurden.upgradedKeyBlob
ist der Ausgabeparameter, mit dem der neue Schlüssel-Blob zurückgegeben 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 er mit einem Schlüssel aufgerufen wird, dessen Patch-Ebene über dem aktuellen Systemwert liegt, wird ErrorCode::INVALID_ARGUMENT
zurückgegeben. Wenn die Funktion mit einem Schlüssel aufgerufen wird, dessen Betriebssystemversion höher als der aktuelle Systemwert ist und der Systemwert nicht null ist, wird ErrorCode::INVALID_ARGUMENT
zurückgegeben. Upgrades der Betriebssystemversion von einem Wert ungleich null auf null 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
oder 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 kann theoretisch wieder verwendet werden, wenn das Gerät auf eine niedrigere Version herabgestuft wird. In der Praxis ruft der Keystore in der Regel kurz nach dem Aufruf von upgradeKey
deleteKey
auf den keyBlobToUpgrade
-Blob auf. Wenn keyBlobToUpgrade
das Tag Tag::ROLLBACK_RESISTANT
hatte, sollte upgradedKeyBlob
es auch haben (und Rollback-resistent sein).
Sichere Konfiguration
Zur Implementierung der Versionsbindung benötigt die Keymaster-TA eine Möglichkeit, die aktuelle Betriebssystemversion und Patchebene (Versionsinformationen) sicher zu empfangen und dafür zu sorgen, dass die empfangenen Informationen genau mit den Informationen zum laufenden System übereinstimmen.
Zur sicheren Übermittlung von Versionsinformationen an das TA wurde dem Boot-Image-Header ein OS_VERSION
-Feld hinzugefügt. Dieses Feld wird automatisch vom Build-Script für das Boot-Image ausgefüllt. OEMs und Keymaster-TA-Implementierer müssen zusammenarbeiten, um die Geräte-Bootloader so zu ändern, dass die Versionsinformationen aus dem Boot-Image extrahiert und an die TA übergeben werden, bevor das unsichere System gestartet wird. So wird verhindert, dass Angreifer die Bereitstellung von Versionsinformationen an die TA stören können.
Außerdem muss das System-Image dieselben Versionsinformationen wie das Boot-Image enthalten. Dazu 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 nach dem Öffnen der HAL, aber vor dem Aufrufen anderer Methoden aufgerufen. Wenn vor „configure“ eine andere Methode aufgerufen wird, gibt der TA ErrorCode::KEYMASTER_NOT_CONFIGURED
zurück.
Wenn configure
nach dem Starten des Geräts zum ersten Mal aufgerufen wird, sollte geprüft werden, ob die angegebenen Versionsinformationen mit den vom Bootloader angegebenen übereinstimmen. Wenn die Versionsinformationen nicht übereinstimmen, gibt 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 funktionieren wieder normal.
Nachfolgende Aufrufe von configure
geben denselben Wert zurück, der beim ersten Aufruf zurückgegeben wurde, und ändern den Status von Keymaster nicht.
Da configure
vom System aufgerufen wird, dessen Inhalt überprüft werden soll, hat ein Angreifer nur wenig Zeit, das System-Image zu manipulieren und es dazu zu zwingen, Versionsinformationen anzugeben, die mit dem Boot-Image übereinstimmen, aber nicht der tatsächlichen Version des Systems entsprechen. Die Kombination aus der Überprüfung des Boot-Images, der dm-verity-Validierung des System-Image-Inhalts und der Tatsache, dass configure
sehr früh beim Systemstart aufgerufen wird, sollte es schwierig machen, diese Gelegenheit zu nutzen.