Versionsbindung

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 die Patch-Ebene des System-Image 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 Schlüssel verwenden kann, die mit der neueren Version erstellt wurden. 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 werden die Schlüssel mit dem Upgrade des Geräts *hochgestuft*. 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, wurde in Keymaster 4 das Modell für die Bindung der Schlüsselversion geändert, sodass für jede Partition separate Patch-Ebenen vorhanden sind. So kann jede Partition unabhängig aktualisiert werden, während gleichzeitig ein Rollback-Schutz besteht.

Um diese Versionsbindung zu implementieren, benötigt die vertrauenswürdige KeyMint-App (Trusted App, TA) eine Möglichkeit, die aktuelle Betriebssystemversion und die Patch-Ebenen sicher zu empfangen und sicherzustellen, dass die empfangenen Informationen mit allen Informationen zum ausgeführten System übereinstimmen.

  • Auf Geräten mit Android Bootmodus mit Verifikation (AVB) können alle Patch-Ebenen und die Systemversion in „vbmeta“ gespeichert werden, 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 die Versionsinformationen in der vbmeta struct befinden, die die Daten zur Identitätsbestätigung (Hash oder hashtree) für eine bestimmte Partition enthält.
  • Auf Geräten ohne AVB:
    • Implementierungen des Bootmodus mit Verifikation müssen einen Hash der Versionsmetadaten an den Bootloader senden, damit dieser den Hash an Keymaster weitergeben kann.
    • In boot.img kann die Patch-Ebene weiterhin im Header gespeichert werden.
    • system.img können Patch-Ebene und Betriebssystemversion weiterhin in schreibgeschützten Eigenschaften gespeichert werden.
    • vendor.img speichert die Patch-Ebene in der schreibgeschützten Eigenschaft ro.vendor.build.version.security_patch.
    • Der Bootloader kann Keymaster einen Hash aller Daten zur Verfügung stellen, die durch den Bootmodus mit Verifikation bestätigt wurden.
  • Verwenden Sie in Android 9 die folgenden Tags, um Versionsinformationen für die folgenden Partitionen anzugeben:
    • VENDOR_PATCH_LEVEL: vendor-Partition
    • BOOT_PATCH_LEVEL: boot-Partition
    • OS_PATCH_LEVEL und OS_VERSION: system Partition. OS_VERSION wird aus dem Header entfernt.boot.img
  • Keymaster-Implementierungen sollten alle Patch-Ebenen unabhängig voneinander behandeln. Schlüssel können verwendet werden, wenn alle Versionsinformationen mit den Werten übereinstimmen, die mit einem Schlüssel verknüpft sind. IKeymaster::upgradeDevice() wird bei Bedarf auf eine höhere Patch-Ebene hochgestuft.

HAL-Änderungen

Zur Unterstützung der Versionsbindung und -bestätigung wurden in Android 7.1 die Tags Tag::OS_VERSION und Tag::OS_PATCHLEVEL sowie die Methoden configure und upgradeKey hinzugefügt. Die Versionstags werden von Keymaster 2+-Implementierungen automatisch zu allen neu generierten (oder aktualisierten) Schlüsseln hinzugefügt. Außerdem wird jeder Versuch, einen Schlüssel zu verwenden, dessen Betriebssystemversion oder Patch-Ebene nicht mit der aktuellen Betriebssystemversion oder Patch-Ebene des Systems übereinstimmt, mit ErrorCode::KEY_REQUIRES_UPGRADE abgelehnt.

Tag::OS_VERSION ist ein UINT-Wert, der die Haupt-, Neben- und Unterversionen einer Android-Systemversion als MMmmss darstellt, wobei MM die Hauptversion, mm die Nebenversion und ss die Unterversion ist. Beispiel: 6.1.2 wird als 060102 dargestellt.

Tag::OS_PATCHLEVEL ist ein UINT-Wert, der das Jahr und den Monat des letzten Updates des Systems als YYYYMM darstellt, wobei YYYY das vierstellige Jahr und MM der zweistellige Monat ist. Beispiel: März 2016 wird als 201603 dargestellt.

UpgradeKey

Damit Schlüssel auf die neue Betriebssystemversion und Patch-Ebene des System-Image 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ätestruktur.
  • keyBlobToUpgrade ist der Schlüssel, der aktualisiert werden muss.
  • upgradeParams sind Parameter, die zum Aktualisieren des Schlüssels erforderlich sind. Dazu gehören Tag::APPLICATION_ID und Tag::APPLICATION_DATA, die zum Entschlüsseln des Schlüssel Blobs erforderlich sind, wenn 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 Methode mit einem Schlüssel aufgerufen wird, dessen Patch-Ebene höher als der aktuelle Systemwert ist, wird ErrorCode::INVALID_ARGUMENT zurückgegeben. Wenn die Methode 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. Betriebssystemversionsupgrades 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, ErrorCode::SECURE_HW_BUSY). Andernfalls wird ErrorCode::OK zurückgegeben und ein neuer Schlüssel-Blob in upgradedKeyBlob zurückgegeben.

keyBlobToUpgrade bleibt nach dem Aufruf von upgradeKey gültig und könnte theoretisch wieder verwendet werden, wenn das Gerät auf eine frühere Version zurückgesetzt wird. In der Praxis ruft Keystore in der Regel kurz nach dem Aufruf von upgradeKey die Methode deleteKey für den Blob keyBlobToUpgrade auf. Wenn keyBlobToUpgrade das Tag Tag::ROLLBACK_RESISTANT hatte, sollte upgradedKeyBlob es ebenfalls haben (und rollbacksicher sein).

Sichere Konfiguration

Um die Versionsbindung zu implementieren, benötigt die Keymaster-TA eine Möglichkeit, die aktuelle Betriebssystemversion und Patch-Ebene (Versionsinformationen) sicher zu empfangen und sicherzustellen, dass die empfangenen Informationen genau mit den Informationen zum ausgeführten System übereinstimmen.

Zur Unterstützung der sicheren Übermittlung von Versionsinformationen an die TA wurde dem Header des Boot-Image das OS_VERSION Feld hinzugefügt. Das Boot-Image-Build-Skript füllt dieses Feld automatisch aus. OEMs und Keymaster-TA-Implementierer müssen zusammenarbeiten, um die Bootloader der Geräte 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 stören.

Außerdem muss sichergestellt werden, dass das System-Image dieselben Versionsinformationen wie das Boot-Image 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 Keymaster 2-Clients aufgerufen, nachdem die HAL geöffnet wurde, aber bevor andere Methoden aufgerufen werden. Wenn eine andere Methode vor „configure“ aufgerufen wird, gibt die TA ErrorCode::KEYMASTER_NOT_CONFIGURED zurück.

Wenn configure nach dem Start des Geräts zum ersten Mal aufgerufen wird, sollte überprüft werden, ob die angegebenen Versionsinformationen mit den vom Bootloader bereitgestellten Informationen ü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 normal.

Nachfolgende Aufrufe von configure geben denselben Wert zurück wie der erste Aufruf und ändern den Status von Keymaster nicht.

Da configure vom System aufgerufen wird, dessen Inhalt validiert werden soll, haben Angreifer nur ein kleines Zeitfenster, um das System-Image zu kompromittieren 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 Bestätigung des Boot-Image, der dm-verity-Bestätigung des Inhalts des System-Image und der Tatsache, dass configure sehr früh im Systemstart aufgerufen wird, sollte es schwierig machen, dieses Zeitfenster auszunutzen.