Archivio chiavi supportato da hardware

La disponibilità di un Trusted Execution Environment (TEE) in un system on a chip (SoC) offre ai dispositivi Android l'opportunità di fornire servizi di sicurezza avanzati supportati dall'hardware al sistema operativo Android, ai servizi della piattaforma e persino ad app di terze parti (sotto forma di estensioni specifiche di Android dell'architettura Java Cryptography, vedi KeyGenParameterSpec).

Glossario

Ecco una rapida panoramica dei componenti di Keystore e delle loro relazioni.

AndroidKeyStore
L'API e il componente Android Framework utilizzati dalle app per accedere alla funzionalità Keystore. È un'implementazione delle API Java Cryptography Architecture standard, ma aggiunge anche estensioni specifiche per Android ed è costituito da codice Java che viene eseguito nello spazio dei processi dell'app. AndroidKeyStore soddisfa le richieste di app per il comportamento dell'archivio chiavi inoltrandole al daemon dell'archivio chiavi.
keystore daemon
Un daemon di sistema Android che fornisce l'accesso a tutte le funzionalità di Keystore tramite un'API Binder. Questo daemon è responsabile dell'archiviazione dei keyblob creati dall'implementazione KeyMint (o Keymaster) sottostante, che contengono il materiale della chiave segreta, criptato in modo che Keystore possa archiviarli, ma non utilizzarli o rivelarli.
Servizio KeyMint HAL
Un server AIDL che implementa l'HAL IKeyMintDevice, che fornisce l'accesso alla TA KeyMint sottostante.
App attendibile KeyMint (TA)
Software in esecuzione in un contesto sicuro, in genere in TrustZone su un SoC ARM, che fornisce tutte le operazioni di crittografia sicure. Questa app ha accesso al materiale della chiave non elaborato e convalida tutte le condizioni di controllo dell'accesso alle chiavi prima di consentirne l'utilizzo.
LockSettingsService
Il componente di sistema Android responsabile dell'autenticazione dell'utente, sia con password che con impronta. Non fa parte di Keystore, ma è pertinente perché Keystore supporta il concetto di chiavi associate all'autenticazione: chiavi che possono essere utilizzate solo se l'utente ha eseguito l'autenticazione. LockSettingsService interagisce con Gatekeeper TA e Fingerprint TA per ottenere token di autenticazione, che fornisce al daemon del keystore e che vengono utilizzati da KeyMint TA.
Gatekeeper TA
Il componente in esecuzione nell'ambiente sicuro responsabile dell'autenticazione delle password utente e della generazione dei token di autenticazione utilizzati per dimostrare alla TA KeyMint che è stata eseguita un'autenticazione per un determinato utente in un determinato momento.
TA impronta
Il componente in esecuzione nell'ambiente sicuro responsabile dell'autenticazione delle impronte dell'utente e della generazione di token di autenticazione utilizzati per dimostrare alla TA KeyMint che è stata eseguita un'autenticazione per un determinato utente in un determinato momento.

Architettura

L'API Android Keystore e l'HAL KeyMint sottostante forniscono un insieme di primitive crittografiche di base ma adeguate per consentire l'implementazione di protocolli che utilizzano chiavi con controllo dell'accesso e supportate dall'hardware.

L'HAL KeyMint è un servizio fornito dall'OEM utilizzato dal servizio Keystore per fornire servizi di crittografia supportati dall'hardware. Per mantenere sicuro il materiale della chiave privata, le implementazioni HAL non eseguono operazioni sensibili nello spazio utente e nemmeno nello spazio kernel. Il servizio KeyMint HAL in esecuzione in Android delega le operazioni sensibili a un TA in esecuzione in un tipo di ambiente sicuro, in genere eseguendo il marshalling e l'unmarshalling delle richieste in un formato di trasferimento definito dall'implementazione.

L'architettura risultante ha il seguente aspetto:

Accesso a KeyMint

Figura 1. Accesso a KeyMint.

L'API KeyMint HAL è di basso livello, utilizzata dai componenti interni della piattaforma e non esposta agli sviluppatori di app. L'API Java di livello superiore disponibile per le app è descritta sul sito Android Developers.

Controllo dell'accesso

Android Keystore fornisce un componente centrale per l'archiviazione e l'utilizzo di chiavi crittografiche supportate dall'hardware, sia per le app che per altri componenti di sistema. Pertanto, l'accesso a qualsiasi singola chiave è normalmente limitato all'app o al componente di sistema che l'ha creata.

Domini dell'archivio chiavi

Per supportare questo controllo dell'accesso, le chiavi vengono identificate in Keystore con un descrittore di chiave. Questo descrittore di chiave indica un dominio a cui appartiene il descrittore, insieme a un'identità all'interno di quel dominio.

Le app per Android accedono all'archivio chiavi utilizzando l'architettura Java Cryptography standard, che identifica le chiavi con un alias stringa. Questo metodo di identificazione viene mappato internamente al dominio APP di Keystore; viene incluso anche l'UID del chiamante per distinguere le chiavi di app diverse, impedendo a un'app di accedere alle chiavi di un'altra.

A livello interno, il codice dei framework riceve anche un ID chiave numerico univoco dopo il caricamento di una chiave. Questo ID numerico viene utilizzato come identificatore per i descrittori delle chiavi all'interno del dominio KEY_ID. Tuttavia, il controllo dell'accesso viene comunque eseguito: anche se un'app rileva un ID chiave per la chiave di un'altra app, non può utilizzarlo in circostanze normali.

Tuttavia, è possibile che un'app conceda l'utilizzo di una chiave a un'altra app (identificata dall'UID). Questa operazione di concessione restituisce un identificatore di concessione univoco, che viene utilizzato come identificatore per i descrittori di chiavi all'interno del dominio GRANT. Anche in questo caso, il controllo dell'accesso viene comunque eseguito: anche se un'app di terze parti scopre l'ID concessione per la chiave di un beneficiario, non può utilizzarlo.

Keystore supporta anche altri due domini per i descrittori delle chiavi, che vengono utilizzati per altri componenti di sistema e non sono disponibili per le chiavi create dalle app:

  • Il dominio BLOB indica che non esiste un identificatore per la chiave nel descrittore della chiave; al contrario, il descrittore della chiave contiene il keyblob stesso e il client gestisce l'archiviazione del keyblob. Viene utilizzato dai client (ad esempio vold) che devono accedere a Keystore prima che venga montata la partizione dei dati.
  • Il dominio SELINUX consente ai componenti di sistema di condividere le chiavi, con accesso regolato da un identificatore numerico che corrisponde a un'etichetta SELinux (vedi Norme SELinux per keystore_key).

Norme SELinux per keystore_key

I valori degli identificatori utilizzati per i descrittori delle chiavi Domain::SELINUX sono configurati nel file dei criteri SELinux keystore2_key_context. Ogni riga di questi file mappa un valore numerico a un'etichetta SELinux, ad esempio:

# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and
# Settings to share Keystore keys.
102            u:object_r:wifi_key:s0

Un componente che deve accedere alla chiave con ID 102 nel dominio SELINUX deve avere il criterio SELinux corrispondente. Ad esempio, per consentire a wpa_supplicant di ottenere e utilizzare queste chiavi, aggiungi la seguente riga a hal_wifi_supplicant.te:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Gli identificatori numerici per le chiavi Domain::SELINUX sono suddivisi in intervalli per supportare partizioni diverse senza collisioni:

Partizione Intervallo File di configurazione
Sistema 0 ... 9999 /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
Extended System 10.000… 19.999 /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
Prodotto 20.000 - 29.999 /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
Fornitore 30.000… 39.999 /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

Per la partizione di sistema sono stati definiti i seguenti valori specifici:

ID spazio dei nomi Etichetta SEPolicy UID Descrizione
0 su_key N/D Chiave superutente. Utilizzato solo per i test sulle build userdebug e eng. Non pertinente per le build utente.
1 shell_key N/D Spazio dei nomi disponibile per la shell. Utilizzato principalmente per i test, ma può essere utilizzato anche nelle build utente dalla riga di comando.
100 vold_key N/D Destinato all'uso da parte di vold.
101 odsign_key N/D Utilizzato dal daemon di firma on-device.
102 wifi_key AID_WIFI(1010) Utilizzato dal sottosistema Wi-Fi di Android, incluso wpa_supplicant.
103 locksettings_key N/D Utilizzato da LockSettingsService
120 resume_on_reboot_key AID_SYSTEM(1000) Utilizzato dal server di sistema di Android per supportare la ripresa al riavvio.

Vettori di accesso

Keystore consente di controllare quali operazioni possono essere eseguite su una chiave, oltre a controllare l'accesso generale a una chiave. Le autorizzazioni keystore2_key sono descritte nel file KeyPermission.aidl.

Autorizzazioni di sistema

Oltre ai controlli di accesso per chiave descritti in Norme SELinux per keystore_key, la seguente tabella descrive altre autorizzazioni SELinux necessarie per eseguire varie operazioni di sistema e di manutenzione:

Autorizzazione Significato
add_auth Obbligatorio per aggiungere token di autenticazione al keystore; utilizzato da provider di autenticazione come Gatekeeper o BiometricManager.
clear_ns Obbligatorio per eliminare tutte le chiavi in uno spazio dei nomi specifico; utilizzato come operazione di manutenzione quando le app vengono disinstallate.
list Richiesto dal sistema per enumerare le chiavi in base a varie proprietà, ad esempio la proprietà o se sono associate all'autenticazione. Questa autorizzazione non è richiesta ai chiamanti che enumerano i propri spazi dei nomi (coperti dall'autorizzazione get_info).
lock Obbligatorio per comunicare al keystore che il dispositivo è stato bloccato, il che a sua volta espelle le super-chiavi per garantire che le chiavi associate all'autenticazione non siano disponibili.
unlock Necessario per comunicare al keystore che il dispositivo è stato sbloccato, ripristinando l'accesso alle super-chiavi che proteggono le chiavi associate all'autenticazione.
reset Obbligatorio per il ripristino delle impostazioni di fabbrica di Keystore, l'eliminazione di tutte le chiavi che non sono essenziali per il funzionamento del sistema operativo Android.

Cronologia

In Android 5 e versioni precedenti, Android aveva un'API di servizi di crittografia semplice e supportata dall'hardware, fornita dalle versioni 0.2 e 0.3 dell'hardware abstraction layer (HAL) Keymaster. Il keystore ha fornito operazioni di firma e verifica digitali, oltre alla generazione e all'importazione di coppie di chiavi di firma asimmetriche. Questa funzionalità è già implementata su molti dispositivi, ma ci sono molti obiettivi di sicurezza che non possono essere raggiunti facilmente solo con un'API di firma. Android 6.0 ha esteso l'API Keystore per fornire una gamma più ampia di funzionalità.

Android 6.0

In Android 6.0, Keymaster 1.0 ha aggiunto primitive crittografiche simmetriche, AES e HMAC, e un sistema di controllo dell'accesso per le chiavi supportate dall'hardware. I controlli di accesso vengono specificati durante la generazione della chiave e applicati per tutta la durata della chiave. Le chiavi possono essere limitate in modo da essere utilizzabili solo dopo l'autenticazione dell'utente e solo per scopi specifici o con parametri crittografici specifici.

Oltre a espandere la gamma di primitive crittografiche, Keystore in Android 6.0 ha aggiunto quanto segue:

  • Uno schema di controllo dell'utilizzo per consentire di limitare l'utilizzo delle chiavi, per ridurre il rischio di compromissione della sicurezza dovuto all'uso improprio delle chiavi
  • Un sistema di controllo dell'accesso per consentire la limitazione delle chiavi a utenti, client e un intervallo di tempo definiti

Android 7.0

In Android 7.0, Keymaster 2 ha aggiunto il supporto per l'attestazione delle chiavi e l'associazione delle versioni.

L'attestazione della chiave fornisce certificati di chiave pubblica che contengono una descrizione dettagliata della chiave e dei relativi controlli dell'accesso, per rendere verificabile da remoto l'esistenza della chiave in un hardware sicuro e la sua configurazione.

Version Binding associa le chiavi alla versione del sistema operativo e al livello di patch. In questo modo, un malintenzionato che scopre una debolezza in una vecchia versione del sistema o del software 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 di patch viene utilizzata su un dispositivo di cui è stato eseguito l'upgrade 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. Man mano che il dispositivo viene aggiornato, le chiavi vengono avanzate insieme al dispositivo, ma qualsiasi ripristino di una versione precedente del dispositivo rende le chiavi inutilizzabili.

Android 8.0

In Android 8.0, Keymaster 3 è passato dal vecchio HAL con struttura C all'interfaccia HAL C++ generata da una definizione nel nuovo linguaggio di definizione dell'interfaccia hardware (HIDL). Nell'ambito della modifica, molti tipi di argomenti sono cambiati, anche se i tipi e i metodi hanno una corrispondenza uno a uno con i tipi precedenti e i metodi della struttura HAL.

Oltre a questa revisione dell'interfaccia, Android 8.0 ha esteso la funzionalità di attestazione di Keymaster 2 per supportare l'attestazione dell'ID. L'attestazione dell'ID fornisce un meccanismo limitato e facoltativo per attestare con certezza gli identificatori hardware, come il numero di serie del dispositivo, il nome del prodotto e l'ID del telefono (IMEI o MEID). Per implementare questa aggiunta, Android 8.0 ha modificato lo schema di attestazione ASN.1 per aggiungere l'attestazione ID. Le implementazioni di Keymaster devono trovare un modo sicuro per recuperare gli elementi di dati pertinenti, nonché definire un meccanismo per disattivare la funzionalità in modo sicuro e permanente.

Android 9

In Android 9, gli aggiornamenti includevano:

  • Aggiornamento a Keymaster 4
  • Supporto per gli elementi sicuri incorporati
  • Supporto per l'importazione sicura delle chiavi
  • Supporto della crittografia 3DES
  • Modifiche al binding delle versioni in modo che boot.img e system.img abbiano versioni impostate separatamente per consentire aggiornamenti indipendenti

Android 10

Android 10 ha introdotto la versione 4.1 dell'HAL Keymaster, che ha aggiunto:

  • Supporto delle chiavi utilizzabili solo quando il dispositivo è sbloccato
  • Supporto per le chiavi che possono essere utilizzate solo nelle prime fasi di avvio
  • Supporto facoltativo per le chiavi di archiviazione protette dall'hardware
  • Supporto facoltativo per l'attestazione univoca del dispositivo in StrongBox

Android 12

Android 12 ha introdotto il nuovo KeyMint HAL, che sostituisce Keymaster HAL ma fornisce funzionalità simili. Oltre a tutte le funzionalità sopra descritte, l'HAL KeyMint include anche:

  • Supporto per l'accordo chiave ECDH
  • Supporto per le chiavi di attestazione specificate dall'utente
  • Supporto per chiavi con un numero limitato di utilizzi

Android 12 include anche una nuova versione del daemon di sistema keystore, riscritta in Rust e nota come keystore2

Android 13

Android 13 ha aggiunto la versione 2 dell'HAL KeyMint, che aggiunge il supporto di Curve25519 sia per la firma che per l'accordo sulle chiavi.