Rilegatura della versione

In Keymaster 1, tutte le chiavi keymaster erano legate crittograficamente alla Root of Trust del dispositivo o alla chiave di avvio verificata. In Keymaster 2 e 3, tutte le chiavi sono anche legate al sistema operativo e al livello di patch dell'immagine di sistema. Ciò garantisce che un utente malintenzionato che scopre un punto debole in una vecchia versione del sistema o del software TEE non possa ripristinare un dispositivo alla versione vulnerabile e utilizzare le chiavi create con la versione più recente. Inoltre, quando una chiave con una determinata versione e livello di patch viene utilizzata su un dispositivo che è stato aggiornato a una versione o a un livello di patch più recente, la chiave viene aggiornata prima di poter essere utilizzata e la versione precedente della chiave viene invalidata. In questo modo, man mano che il dispositivo viene aggiornato, i tasti "si muoveranno" in avanti insieme al dispositivo, ma qualsiasi ripristino del dispositivo a una versione precedente renderà i tasti inutilizzabili.

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 per avere livelli di patch separati per ciascuna partizione. Ciò consente a ciascuna partizione di essere aggiornata in modo indipendente, garantendo comunque la protezione dal rollback.

In Android 9 le partizioni boot , system e vendor hanno ciascuna il proprio livello di patch.

  • I dispositivi con Android Verified Boot (AVB) possono inserire tutti i livelli di 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 saranno nel file vbmeta concatenato. In generale, le informazioni sulla versione dovrebbero trovarsi nella vbmeta struct che contiene i dati di verifica (hash o hashtree) per una determinata partizione.
  • Sui dispositivi senza AVB:
    • Le implementazioni di avvio verificate 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 di patch nell'intestazione
    • system.img può continuare a memorizzare il livello di patch e la versione del sistema operativo nelle proprietà di sola lettura
    • vendor.img memorizza il livello di patch nella proprietà di sola lettura ro.vendor.build.version.security_patch .
    • Il bootloader può fornire al keymaster un hash di tutti i dati convalidati dall'avvio verificato.
  • 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 : partizione system . ( OS_VERSION viene rimosso dall'intestazione boot.img .
  • Le implementazioni di Keymaster dovrebbero trattare tutti i livelli di 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 di patch superiore, se necessario.

Modifiche all'HAL

Per supportare l'associazione 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 di versione vengono aggiunti automaticamente dalle implementazioni Keymaster 2+ 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 di patch corrispondente rispettivamente alla versione del sistema operativo corrente o al livello di patch del sistema, viene rifiutato con ErrorCode::KEY_REQUIRES_UPGRADE .

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

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

Chiave di aggiornamento

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

Maestro delle chiavi 3

    upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
        generates(ErrorCode error, vec upgradedKeyBlob);

Maestro delle chiavi 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 che deve essere aggiornata
  • upgradeParams sono parametri necessari per aggiornare la chiave. Questi includeranno Tag::APPLICATION_ID e Tag::APPLICATION_DATA , necessari per decrittografare il key blob, se sono stati forniti durante la generazione.
  • upgradedKeyBlob è il parametro di output, utilizzato per restituire il nuovo BLOB di chiave.

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

keyBlobToUpgrade rimane valido dopo la chiamata upgradeKey e teoricamente potrebbe essere utilizzato nuovamente se il dispositivo venisse declassato. In pratica, il keystore in genere chiama deleteKey sul BLOB keyBlobToUpgrade subito dopo la chiamata a upgradeKey . Se keyBlobToUpgrade avesse il tag Tag::ROLLBACK_RESISTANT , anche upgradedKeyBlob dovrebbe averlo (e dovrebbe essere resistente al rollback).

Configurazione sicura

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

Per supportare la consegna sicura delle informazioni sulla versione al TA, è stato aggiunto un campo OS_VERSION all'intestazione dell'immagine di avvio. Lo script di creazione dell'immagine di avvio popola automaticamente questo campo. Gli OEM e gli implementatori TA keymaster devono collaborare per modificare i bootloader del dispositivo per estrarre le informazioni sulla versione dall'immagine di avvio e trasmetterle al TA prima dell'avvio del sistema non sicuro. Ciò garantisce che gli aggressori non possano interferire con la fornitura delle informazioni sulla versione al TA.

È inoltre necessario garantire che l'immagine di sistema contenga le stesse informazioni sulla versione dell'immagine di avvio. A tal fine, il metodo configure è stato aggiunto 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 qualsiasi altro metodo. Se viene chiamato qualsiasi altro metodo prima della configurazione, TA restituisce ErrorCode::KEYMASTER_NOT_CONFIGURED .

La prima volta che viene richiamata configure dopo l'avvio del dispositivo, dovrebbe 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. Tieni presente che questo processo richiede che tutti gli OTA aggiornino sia le immagini di sistema che quelle di avvio; non possono essere aggiornati separatamente per mantenere sincronizzate le informazioni sulla versione.

Poiché configure verrà chiamato dal sistema di cui si intende convalidare il contenuto, esiste una ristretta finestra di opportunità affinché un utente malintenzionato possa compromettere l'immagine del sistema e costringerlo a fornire informazioni sulla versione che corrisponde all'immagine di avvio, ma che non è quella effettiva. versione del sistema. La combinazione di verifica dell'immagine di avvio, convalida dm-verity del contenuto dell'immagine di sistema e il fatto che configure viene chiamato molto presto nell'avvio del sistema dovrebbe rendere difficile sfruttare questa finestra di opportunità.