Vincolo della versione

In Keymaster 1, tutte le chiavi Keymaster erano associate crittograficamente alla Root of Trust del dispositivo o alla chiave di Avvio verificato. In Keymaster 2 e 3, tutte le chiavi sono associate anche al sistema operativo e al livello patch dell'immagine di sistema. In questo modo, un aggressore che scopre una vulnerabilità in una vecchia versione del software di sistema o TEE non può eseguire il rollback di un dispositivo alla versione vulnerabile e utilizzare le chiavi create con la versione più recente. Inoltre, quando una chiave con una determinata versione e un determinato livello patch viene utilizzata su un dispositivo di cui è stato eseguito l'upgrade a una versione o a un livello patch più recente, la chiave viene sottoposta all'upgrade prima di poter essere utilizzata e la versione precedente della chiave viene invalidata. In questo modo, man mano che viene eseguito l'upgrade del dispositivo, le chiavi vengono *incrementate* insieme al dispositivo, ma qualsiasi ripristino del dispositivo a una release precedente rende inutilizzabili le chiavi.

Per supportare la struttura modulare di Treble e interrompere l'associazione di system.img a boot.img, Keymaster 4 ha modificato il modello di associazione della versione della chiave in modo da avere livelli patch separati per ogni partizione. In questo modo, ogni partizione può essere aggiornata in modo indipendente, pur continuando a fornire la protezione del rollback.

Per implementare questa associazione di versione, l'app attendibile KeyMint (TA) ha bisogno di un modo per ricevere in modo sicuro la versione e i livelli patch del sistema operativo corrente e per assicurarsi che le informazioni ricevute corrispondano a tutte le informazioni sul sistema in esecuzione.

  • I dispositivi con Avvio verificato Android (AVB) possono inserire tutti i livelli patch e la versione del sistema in vbmeta, in modo che il bootloader possa fornirli a Keymaster. Per le partizioni concatenate, le informazioni sulla versione della partizione si trovano in vbmeta concatenato. In generale, le informazioni sulla versione devono essere nella vbmeta struct che contiene i dati di verifica (hash o hashtree) per una determinata partizione.
  • Sui dispositivi senza AVB:
    • Le implementazioni di Avvio verificato devono fornire un hash dei metadati della versione al bootloader, in modo che il bootloader possa fornire l'hash a Keymaster.
    • boot.img può continuare a memorizzare il livello patch nell'intestazione
    • system.img può continuare a memorizzare il livello patch e la versione del sistema operativo nelle proprietà di sola lettura
    • vendor.img memorizza il livello patch nella proprietà di sola lettura ro.vendor.build.version.security_patch.
    • Il bootloader può fornire un hash di tutti i dati convalidati da Avvio verificato a Keymaster.
  • In Android 9, utilizza i seguenti tag per fornire informazioni sulla versione per le seguenti partizioni:
    • VENDOR_PATCH_LEVEL: partizione vendor
    • BOOT_PATCH_LEVEL: partizione boot
    • OS_PATCH_LEVEL e OS_VERSION: system partizione. (OS_VERSION viene rimosso dall' intestazione boot.img.
  • Le implementazioni di Keymaster devono trattare tutti i livelli patch in modo indipendente. Le chiavi sono utilizzabili se tutte le informazioni sulla versione corrispondono ai valori associati a una chiave e IKeymaster::upgradeDevice() passa a un livello patch superiore, se necessario.

Modifiche HAL

Per supportare l'associazione di versione e l'attestazione della versione, Android 7.1 ha aggiunto i tag Tag::OS_VERSION e Tag::OS_PATCHLEVEL e i metodi configure e upgradeKey. I tag della versione vengono aggiunti automaticamente dalle implementazioni di Keymaster 2 e versioni successive a tutte le chiavi appena generate (o aggiornate). Inoltre, qualsiasi tentativo di utilizzare una chiave che non ha una versione del sistema operativo o un livello patch corrispondente alla versione del sistema operativo o al livello patch corrente del sistema, rispettivamente, viene rifiutato con ErrorCode::KEY_REQUIRES_UPGRADE.

Tag::OS_VERSION è un valore UINT che rappresenta le parti principale, secondaria e secondaria secondaria di una versione del sistema Android come MMmmss, dove MM è la versione principale, mm è la versione secondaria e ss è la versione secondaria secondaria. Ad esempio, 6.1.2 sarebbe rappresentato come 060102.

Tag::OS_PATCHLEVEL è un valore UINT che rappresenta l'anno e il mese dell'ultimo aggiornamento del sistema come YYYYMM, dove YYYY è l'anno di quattro cifre e MM è il mese di due cifre. Ad esempio, marzo 2016 sarebbe rappresentato come 201603.

UpgradeKey

Per consentire l'upgrade delle chiavi alla nuova versione del sistema operativo e al nuovo livello patch dell'immagine di sistema, Android 7.1 ha aggiunto il metodo upgradeKey all'HAL:

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 è la struttura del dispositivo
  • keyBlobToUpgrade è la chiave di cui è necessario eseguire l'upgrade
  • upgradeParams sono i parametri necessari per eseguire l'upgrade della chiave. Questi includono Tag::APPLICATION_ID e Tag::APPLICATION_DATA, necessari per decriptare il blob della chiave, se sono stati forniti durante la generazione.
  • upgradedKeyBlob è il parametro di output, utilizzato per restituire il nuovo blob della chiave.

Se upgradeKey viene chiamato con un blob della chiave che non può essere analizzato o non è valido, restituisce ErrorCode::INVALID_KEY_BLOB. Se viene chiamato con una chiave il cui livello patch è superiore al valore corrente del sistema, restituisce ErrorCode::INVALID_ARGUMENT. Se viene chiamato con una chiave la cui versione del sistema operativo è superiore al valore corrente del sistema e il valore del sistema è diverso da zero, restituisce ErrorCode::INVALID_ARGUMENT. Sono consentiti gli upgrade della versione del sistema operativo da un valore diverso da zero a zero. In caso di errori di comunicazione con il mondo sicuro, restituisce un valore di errore appropriato (ad esempio, ErrorCode::SECURE_HW_ACCESS_DENIED, ErrorCode::SECURE_HW_BUSY). In caso contrario, restituisce ErrorCode::OK e un nuovo blob della chiave in upgradedKeyBlob.

keyBlobToUpgrade rimane valido dopo la chiamata upgradeKey e, in teoria, potrebbe essere riutilizzato se venisse eseguito il downgrade del dispositivo. In pratica, keystore in genere chiama deleteKey sul blob keyBlobToUpgrade poco dopo la chiamata a upgradeKey. Se keyBlobToUpgrade aveva il tag Tag::ROLLBACK_RESISTANT, anche upgradedKeyBlob dovrebbe averlo (e dovrebbe essere resistente al rollback).

Configurazione sicura

Per implementare l'associazione di versione, il TA Keymaster ha bisogno di un modo per ricevere in modo sicuro la versione e il livello patch del sistema operativo corrente (informazioni sulla versione) e per assicurarsi che le informazioni ricevute corrispondano alle informazioni sul sistema in esecuzione.

Per supportare la distribuzione sicura delle informazioni sulla versione al TA, è stato aggiunto un OS_VERSION campo all'intestazione dell'immagine di avvio. Lo script di build dell'immagine di avvio compila automaticamente questo campo. I produttori di apparecchiature originali e gli implementatori di TA Keymaster devono collaborare per modificare i bootloader dei dispositivi in modo da estrarre le informazioni sulla versione dall'immagine di avvio e passarle al TA prima dell'avvio del sistema non sicuro. In questo modo, gli aggressori non possono interferire con il provisioning delle informazioni sulla versione al TA.

È inoltre necessario assicurarsi che l'immagine di sistema abbia le stesse informazioni sulla versione dell'immagine di avvio. A questo scopo, è stato aggiunto il metodo configure all'HAL Keymaster:

keymaster_error_t (*configure)(const struct keymaster2_device* dev,
  const keymaster_key_param_set_t* params);

L'argomento params contiene Tag::OS_VERSION e Tag::OS_PATCHLEVEL. Questo metodo viene chiamato dai client keymaster2 dopo l'apertura dell'HAL, ma prima di chiamare altri metodi. Se viene chiamato un altro metodo prima di configure, il TA restituisce ErrorCode::KEYMASTER_NOT_CONFIGURED.

La prima volta che viene chiamato configure dopo l'avvio del dispositivo, deve verificare che le informazioni sulla versione fornite corrispondano a quelle fornite dal bootloader. Se le informazioni sulla versione non corrispondono, configure restituisce ErrorCode::INVALID_ARGUMENT e tutti gli altri metodi Keymaster continuano a restituire ErrorCode::KEYMASTER_NOT_CONFIGURED. Se le informazioni corrispondono, configure restituisce ErrorCode::OK e gli altri metodi Keymaster iniziano a funzionare normalmente.

Le chiamate successive a configure restituiscono lo stesso valore restituito dalla prima chiamata e non modificano lo stato di Keymaster.

Poiché configure viene chiamato dal sistema di cui deve convalidare i contenuti, un aggressore ha una finestra di opportunità limitata per compromettere l'immagine di sistema e forzarla a fornire informazioni sulla versione che corrispondono all'immagine di avvio, ma che non sono la versione effettiva del sistema. La combinazione di verifica dell'immagine di avvio, convalida dm-verity dei contenuti dell'immagine di sistema e il fatto che configure venga chiamato molto presto durante l'avvio del sistema dovrebbe rendere difficile lo sfruttamento di questa finestra di opportunità.