Versionsbindung

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 Eigenschaft ro.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 und OS_VERSION : system . ( OS_VERSION wird aus dem boot.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ören Tag::APPLICATION_ID und Tag::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.