Keystore supportato da hardware

La disponibilità di un ambiente di esecuzione affidabile in un sistema su un chip (SoC) offre ai dispositivi Android l'opportunità di fornire servizi di sicurezza robusti e supportati da hardware al sistema operativo Android, ai servizi della piattaforma e persino alle app di terze parti. Gli sviluppatori che cercano le estensioni Android-specifici dovrebbero andare a android.security.keystore .

Prima di Android 6.0, Android disponeva già di una semplice API per servizi di crittografia basata su hardware, fornita dalle versioni 0.2 e 0.3 di Keymaster Hardware Abstraction Layer (HAL). Keystore ha fornito operazioni di firma e verifica digitali, oltre alla generazione e importazione di coppie di chiavi di firma asimmetrica. Questo è già implementato su molti dispositivi, ma ci sono molti obiettivi di sicurezza che non possono essere facilmente raggiunti solo con un'API di firma. Keystore in Android 6.0 estende l'API Keystore per fornire una gamma più ampia di funzionalità.

In Android 6.0, Keystore aggiunto primitive crittografiche simmetriche , AES e HMAC, e un sistema di controllo di accesso per le chiavi hardware-backed. I controlli di accesso vengono specificati durante la generazione della chiave e applicati per tutta la durata della chiave. È possibile limitare l'utilizzo delle chiavi solo dopo che l'utente si è autenticato e solo per scopi specificati o con parametri crittografici specificati. Per ulteriori informazioni, vedere le autorizzazioni Tag e Funzioni pagine.

Oltre ad espandere la gamma di primitive crittografiche, Keystore in Android 6.0 aggiunge quanto segue:

  • Uno schema di controllo dell'utilizzo per limitare l'utilizzo delle chiavi, per mitigare il rischio di compromissione della sicurezza a causa di un uso improprio delle chiavi of
  • Uno schema di controllo degli accessi per consentire la restrizione delle chiavi a utenti, client e un intervallo di tempo definito

In Android 7.0, Keymaster 2 ha aggiunto il supporto per l'attestazione della chiave e l'associazione della versione. Attestazione chiave fornisce certificati a chiave pubblica che contengono una descrizione dettagliata della chiave e dei suoi controlli di accesso, per rendere l'esistenza della chiave hardware sicuro e la sua configurazione in remoto verificabile.

Versione vincolante chiavi si lega al sistema operativo e la versione del livello di patch. Ciò garantisce che un utente malintenzionato che scopre un punto debole in una vecchia versione del sistema o del software TEE non possa riportare un dispositivo alla versione vulnerabile e utilizzare le chiavi create con la versione più recente. Inoltre, quando una chiave con una data versione e livello di patch viene utilizzata su un dispositivo che è stato aggiornato a una versione oa un livello di patch più recenti, la chiave viene aggiornata prima di poter essere utilizzata e la versione precedente della chiave viene invalidata. Quando il dispositivo viene aggiornato, i tasti si spostano in avanti insieme al dispositivo, ma qualsiasi ripristino del dispositivo a una versione precedente rende i tasti inutilizzabili.

In Android 8.0, Keymaster 3 è passato dalla vecchia struttura C-Hardware Abstraction Layer (HAL) all'interfaccia C++ HAL generata da una definizione nel nuovo Hardware Interface Definition Language (HIDL). Come parte del cambiamento, molti dei tipi di argomento sono cambiati, sebbene i tipi e i metodi abbiano una corrispondenza uno a uno con i vecchi tipi e i metodi HAL struct. Vedere la Funzioni pagina per maggiori dettagli.

Oltre a questa revisione dell'interfaccia, Android 8.0 estende funzione di attestazione di Keymaster 2 al supporto ID attestazione . L'attestazione dell'ID fornisce un meccanismo limitato e facoltativo per l'attestazione degli identificatori hardware, come il numero di serie del dispositivo, il nome del prodotto e l'ID del telefono (IMEI/MEID). Per implementare questa aggiunta, modificare 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 rilevanti, nonché definire un meccanismo per disabilitare in modo sicuro e permanente la funzione.

In Android 9, gli aggiornamenti includono:

  • Update per Keymaster 4
  • Supporto per Secure Element incorporati
  • Supporto per l'importazione di chiavi sicure
  • Supporto per la crittografia 3DES
  • Modifiche al binding della versione in modo che boot.img e system.img abbiano versioni impostate separatamente per consentire aggiornamenti indipendenti

Glossario

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

AndroidKeystore è l'API quadro Android e componente utilizzata dalle applicazioni per accedere alle funzionalità Keystore. È implementato come un'estensione delle API standard dell'architettura di crittografia Java e consiste in codice Java che viene eseguito nello spazio di processo dell'app. AndroidKeystore soddisfa le richieste di app per il comportamento Keystore inoltrandole al demone chiavi.

Il demone di chiavi è un demone di sistema Android che fornisce l'accesso a tutte le funzionalità Keystore tramite un'API Raccoglitore . È responsabile della memorizzazione dei "blob di chiavi", che contengono l'effettivo materiale della chiave segreta, crittografato in modo che Keystore possa archiviarlo ma non utilizzarlo o rivelarlo.

keymasterd è un server HIDL che fornisce l'accesso alla Keymaster TA. (Questo nome non è standardizzato ed è per scopi concettuali.)

Keymaster TA (applicazione attendibile) è il software in esecuzione in un contesto sicuro, più spesso in TrustZone su un SoC ARM, che fornisce tutte le operazioni sicure Keystore, ha accesso al materiale della chiave grezza, convalida tutte le condizioni di controllo di accesso sui tasti , eccetera.

LockSettingsService è il componente di sistema Android responsabile per l'autenticazione degli utenti, sia la password e impronta digitale. Non fa parte di Keystore, ma è rilevante perché molte operazioni con le chiavi di Keystore richiedono l'autenticazione dell'utente. LockSettingsService interagisce con il gatekeeper TA e Fingerprint TA per ottenere i token di autenticazione che essa fornisce al daemon chiavi, e che sono in definitiva consumata dall'applicazione Keymaster TA.

Gatekeeper TA (applicazione attendibile) è un altro componente in esecuzione nel contesto sicuro, che è responsabile per l'autenticazione delle password utente e la generazione di autenticazione token utilizzati per dimostrare al Keymaster TA che l'autenticazione è stato fatto per un particolare utente in un determinato punto nel tempo.

Fingerprint TA (applicazione attendibile) è un altro componente in esecuzione nel contesto sicuro che è responsabile per l'autenticazione delle impronte digitali degli utenti e la generazione di autenticazione token utilizzati per dimostrare al Keymaster TA che l'autenticazione è stato fatto per un particolare utente in un determinato punto nel tempo.

Architettura

L'API Android Keystore e l'HAL Keymaster sottostante forniscono un set base ma adeguato di primitive crittografiche per consentire l'implementazione di protocolli utilizzando chiavi supportate dall'hardware con controllo dell'accesso.

Keymaster HAL è una libreria caricabile dinamicamente fornita dall'OEM utilizzata dal servizio Keystore per fornire servizi crittografici supportati da hardware. Per mantenere le cose al sicuro, le implementazioni HAL non eseguono alcuna operazione sensibile nello spazio utente e nemmeno nello spazio kernel. Le operazioni sensibili sono delegate a un processore sicuro raggiungibile tramite qualche interfaccia del kernel. L'architettura risultante è simile a questa:

Accesso a Keymaster

Figura 1. L'accesso al Keymaster

All'interno di un dispositivo Android, il "client" di Keymaster HAL è costituito da più livelli (es. app, framework, demone Keystore), ma che possono essere ignorati ai fini di questo documento. Ciò significa che l'API HAL di Keymaster descritta è di basso livello, utilizzata dai componenti interni della piattaforma e non esposta agli sviluppatori di app. L'API di livello superiore è descritto sul sito per sviluppatori Android .

Lo scopo del Keymaster HAL non è implementare gli algoritmi sensibili alla sicurezza, ma solo eseguire il marshalling e l'unmarshal delle richieste al mondo protetto. Il formato del filo è definito dall'implementazione.

Compatibilità con le versioni precedenti

Il Keymaster 1 HAL è completamente incompatibile con gli HAL rilasciati in precedenza, ad esempio Keymaster 0.2 e 0.3. Per facilitare l'interoperabilità sui dispositivi che eseguono Android 5.0 e versioni precedenti avviate con i vecchi Keymaster HAL, Keystore fornisce un adattatore che implementa l'HAL Keymaster 1 con chiamate alla libreria hardware esistente. Il risultato non può fornire l'intera gamma di funzionalità nel Keymaster 1 HAL. In particolare, supporta solo gli algoritmi RSA ed ECDSA e tutta l'imposizione dell'autorizzazione chiave viene eseguita dall'adattatore, nel mondo non sicuro.

Keymaster 2 ulteriormente semplificata l'interfaccia HAL rimuovendo le get_supported_* metodi e permettendo la finish() metodo per accettare input. Ciò riduce il numero di round trip al TEE nei casi in cui l'input è disponibile tutto in una volta e semplifica l'implementazione della decrittazione AEAD.

In Android 8.0, Keymaster 3 è passato dalla vecchia struttura C-HAL all'interfaccia C++ HAL generata da una definizione nel nuovo Hardware Interface Definition Language (HIDL). Un'implementazione HAL nuovo stile viene creato sottoclasse generato IKeymasterDevice classe ed attuazione dei metodi virtuali puri. Come parte del cambiamento, molti dei tipi di argomento sono cambiati, sebbene tipi e metodi abbiano una corrispondenza uno a uno con i vecchi tipi e i metodi HAL struct.

Panoramica HIDL

L'Hardware Interface Definition Language (HIDL) fornisce un meccanismo di implementazione indipendente dal linguaggio per specificare le interfacce hardware. Gli strumenti HIDL attualmente supportano la generazione di interfacce C++ e Java. Ci si aspetta che la maggior parte degli implementatori di Trusted Execution Environment (TEE) trovino gli strumenti C++ più convenienti, quindi questo documento discute solo la rappresentazione C++.

Le interfacce HIDL sono costituite da un insieme di metodi, espressi come:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Esistono vari tipi predefiniti e gli HAL possono definire nuovi tipi enumerati e di struttura. Per maggiori dettagli su HIDL, vedere la sezione di riferimento .

Un metodo esempio dal Keymaster 3 IKeymasterDevice.hal è:

generateKey(vec<KeyParameter> keyParams)
        generates(ErrorCode error, vec<uint8_t> keyBlob,
                  KeyCharacteristics keyCharacteristics);

Questo è l'equivalente di quanto segue dal keymaster2 HAL:

keymaster_error_t (*generate_key)(
        const struct keymaster2_device* dev,
        const keymaster_key_param_set_t* params,
        keymaster_key_blob_t* key_blob,
        keymaster_key_characteristics_t* characteristics);

Nella versione HIDL, il dev argomento è stato rimosso, perché è implicito. Il params argomentazione non è più una struttura che contiene un puntatore riferimento a un array di key_parameter_t oggetti, ma un vec (vettore) contenente KeyParameter oggetti. I valori di ritorno sono elencati nella " generates " clausola, compreso un vettore di uint8_t valori per il blob chiave.

Il metodo virtuale C++ generato dal compilatore HIDL è:

Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                         generateKey_cb _hidl_cb) override;

Dove generate_cb è un puntatore alla funzione definita come:

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                   const KeyCharacteristics& keyCharacteristics)>

Cioè, generate_cb è una funzione che assume i valori restituiti elencati nella clausola generare. La classe di implementazione HAL priorità su questa generateKey metodo e chiama la generate_cb puntatore a funzione per restituire il risultato dell'operazione al chiamante. Nota la chiamata puntatore a funzione è sincrona. Il chiamante chiama generateKey e generateKey chiama il puntatore a funzione in dotazione, che esegue a compimento, restituire il controllo al generateKey attuazione, che quindi torna al chiamante.

Per un esempio dettagliato, consultare l'implementazione di default in hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp . L'implementazione predefinita fornisce la compatibilità con le versioni precedenti per i dispositivi con HALS keymaster0, keymaster1 o keymaster2 vecchio stile.

Controllo di accesso

La regola di base del controllo dell'accesso all'archivio chiavi è che ogni app ha il proprio spazio dei nomi. Ma per ogni regola c'è un'eccezione. Keystore dispone di alcune mappe codificate che consentono a determinati componenti del sistema di accedere a determinati altri spazi dei nomi. Questo è uno strumento molto schietto in quanto dà a un componente il pieno controllo su un altro spazio dei nomi. E poi c'è la questione dei componenti del fornitore come clienti di Keystore. Al momento non abbiamo modo di stabilire uno spazio dei nomi per i componenti di un fornitore, ad esempio, supplicant WPA.

Al fine di accogliere i componenti del fornitore e generalizzare il controllo degli accessi senza eccezioni codificate, Keystore 2.0 introduce domini e spazi dei nomi selinux.

Domini archivio chiavi

Con i domini Keystore, possiamo separare gli spazi dei nomi dagli uid. I client che accedono a una chiave nel keystore devono specificare il dominio, lo spazio dei nomi e l'alias a cui desiderano accedere. Sulla base di questa tupla e dell'identità del chiamante, possiamo determinare a quale chiave il chiamante vuole accedere e se dispone delle autorizzazioni appropriate.

Introduciamo cinque parametri di dominio che regolano il modo in cui è possibile accedere alle chiavi. Controllano la semantica del parametro dello spazio dei nomi del descrittore di chiave e come viene eseguito il controllo di accesso.

  • DOMAIN_APP : Il dominio applicazione copre il comportamento legacy. Java Keystore SPI utilizza questo dominio per impostazione predefinita. Quando viene utilizzato questo dominio, l'argomento dello spazio dei nomi viene ignorato e viene invece utilizzato l'uid del chiamante. L'accesso a questo dominio è controllato dal marchio chiavi alla classe keystore_key nella policy di SELinux.
  • DOMAIN_SELINUX : Questo dominio indica che lo spazio dei nomi ha un'etichetta nella policy di SELinux. Il parametro namespace è apprezzato e tradotto in un contesto di destinazione, e un assegno il permesso viene eseguita per il contesto di SELinux chiedendo la keystore_key di classe. Quando l'autorizzazione è stata stabilita per l'operazione data, la tupla completa viene utilizzata per la ricerca della chiave.
  • DOMAIN_GRANT : Il dominio concessione indica che il parametro namespace è un identificatore di sovvenzione. Il parametro alias viene ignorato. I controlli di Selinux vengono eseguiti quando viene creata la concessione. Un ulteriore controllo degli accessi verifica solo se l'uid del chiamante corrisponde all'uid dei beneficiari della concessione richiesta.
  • DOMAIN_KEY_ID : Questo dominio indica che il parametro namespace è una chiave id unico. La chiave stessa potrebbe essere stato creato con DOMAIN_APP o DOMAIN_SELINUX . La verifica di permesso viene eseguita dopo il domain e namespace sono stati caricati dal database chiave nello stesso modo come se il blob è stato caricato dal dominio, spazio dei nomi e alias tuple. La logica per il dominio ID chiave è la continuità. Quando si accede a una chiave tramite alias, le chiamate successive possono operare su chiavi diverse, poiché una nuova chiave potrebbe essere stata generata o importata e associata a questo alias. L'ID chiave, tuttavia, non cambia mai. Quindi, quando si utilizza una chiave per ID chiave dopo che è stata caricata dal database del keystore utilizzando l'alias una volta, si può essere certi che si tratti della stessa chiave finché l'ID chiave esiste ancora. Questa funzionalità non è esposta agli sviluppatori di app, ma viene utilizzata all'interno di Android Keystore SPI per fornire un'esperienza più coerente anche se utilizzata contemporaneamente in modo non sicuro.
  • DOMAIN_BLOB : Il dominio blob indica che il chiamante gestisce la blob di per sé. Viene utilizzato per i client che devono accedere al Keystore prima che la partizione dati venga montata. Il blob chiave è inclusa nel blob campo del descrittore chiave.

Usando il dominio SELinux, possiamo fornire ai componenti del fornitore l'accesso a spazi dei nomi di keystore molto specifici che possono essere condivisi dai componenti di sistema come la finestra di dialogo delle impostazioni.

Politica SELinux per keystore_key

Etichette Spazio dei nomi sono configurati usando il keystore2_key_context file.
Ogni riga in questi file mappa un ID di spazio dei nomi numerico su un'etichetta SELinux. Per 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

Dopo aver impostato in questo modo un nuovo spazio dei nomi della chiave, possiamo dare accesso ad esso aggiungendo una policy appropriata. Ad esempio, per consentire wpa_supplicant per ottenere e utilizzare i tasti nel nuovo spazio dei nomi vorremmo aggiungere la seguente riga alla hal_wifi_supplicant.te :

allow hal_wifi_supplicant wifi_keys:keystore2_key { get, use };

Dopo aver impostato il nuovo spazio dei nomi AndroidKeyStore può essere utilizzato quasi come al solito. L'unica differenza è che l'ID dello spazio dei nomi deve essere specificato. Per il caricamento e importazione chiavi da e verso Keystore, l'id namespace viene specificato utilizzando AndroidKeyStoreLoadStoreParameter . Per esempio,

import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import java.security.KeyStore;

KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
keystore.load(new AndroidKeyStoreLoadStoreParameter(102));

Per generare una chiave in un determinato spazio dei nomi, l'ID spazio dei nomi deve essere data utilizzando KeyGenParameterSpec.Builder#setNamespace():

import android.security.keystore.KeyGenParameterSpec;
KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder();
specBuilder.setNamespace(102);

I seguenti file di contesto possono essere utilizzati per configurare gli spazi dei nomi SELinux di Keystore 2.0. Ogni partizione ha un diverso intervallo riservato di 10.000 ID spazio dei nomi per evitare collisioni.

Partizione Gamma File di configurazione
Sistema 0 ... 9.999
/system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
Sistema esteso 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
Venditore 30.000 ... 39.999
/vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

Il client richiede la chiave richiedendo il dominio SELinux e lo spazio dei nomi virtuali desiderata, qui "wifi_keys" , con il suo ID numerico.

Oltre a ciò sono stati definiti i seguenti namespace. Quando sostituiscono regole speciali, la tabella seguente indica l'UID a cui corrispondevano.

ID spazio dei nomi Etichetta SEPolicy UID Descrizione
0 su_key N / A Chiave utente eccellente. Utilizzato solo per i test su userdebug e build eng. Non rilevante per le build dell'utente.
1 shell_key N / A Spazio dei nomi disponibile per la shell. Utilizzato principalmente per i test, ma può essere utilizzato anche su build utente dalla riga di comando.
100 vold_key N / A Destinato all'uso da parte di vold.
101 odsing_key N / A Utilizzato dal demone di firma sul dispositivo.
102 wfi_key AID_WIFI(1010) Utilizzato dal sybsystem Wifi di Android incluso wpa_supplicant.
120 resume_on_reboot_key AID_SYSTEM(1000) Utilizzato dal server di sistema di Android per supportare la ripresa al riavvio.

Accedi ai vettori

La classe SELinux keystore_key è invecchiato un po 'e alcune delle autorizzazioni, come ad esempio verify o sign hanno perso il loro significato. Ecco la nuova serie di permessi, keystore2_key , che Keystore 2.0 sarà far rispettare.

Autorizzazione Senso
delete Selezionato durante la rimozione delle chiavi da Keystore.
get_info Selezionato quando vengono richiesti i metadati di una chiave.
grant Il chiamante ha bisogno di questa autorizzazione per creare una concessione alla chiave nel contesto di destinazione.
manage_blob Il chiamante può utilizzare DOMAIN_BLOB sul dato spazio dei nomi di SELinux, riuscendo così blob di per sé. Questo è particolarmente utile per vold.
rebind Questa autorizzazione controlla se un alias può essere ricollegato a una nuova chiave. Ciò è necessario per l'inserimento e implica che la chiave associata in precedenza verrà eliminata. È fondamentalmente un permesso di inserimento, ma cattura meglio la semantica del keystore.
req_forced_op I client con questa autorizzazione possono creare operazioni non eliminabili e la creazione di operazioni non fallisce mai a meno che tutti gli slot delle operazioni non vengano occupati da operazioni non eliminabili.
update Necessario per aggiornare il sottocomponente di una chiave.
use Selezionato durante la creazione di un'operazione Keymint che utilizza il materiale della chiave, ad es. per la firma, la codifica/decrittografia.
use_dev_id Necessario quando si generano informazioni di identificazione del dispositivo, come l'attestazione dell'ID del dispositivo.

Inoltre, abbiamo diviso un insieme di specifiche autorizzazioni keystore non chiave nella classe di sicurezza SELinux keystore2 :

Autorizzazione Senso
add_auth Richiesto dal provider di autenticazione come Gatekeeper o BiometricsManager per l'aggiunta di token di autenticazione.
clear_ns Precedentemente clear_uid, questa autorizzazione consente a un non proprietario di uno spazio dei nomi di eliminare tutte le chiavi in ​​quello spazio dei nomi.
list Richiesto dal sistema per enumerare le chiavi in ​​base a varie proprietà, come la proprietà o il limite di autenticazione. Questa autorizzazione non è richiesta dai chiamanti che enumerano i propri spazi dei nomi. Questo è coperto dalla get_info permesso.
lock Questa autorizzazione consente di bloccare Keystore, ovvero eliminare la chiave principale, in modo che le chiavi associate all'autenticazione diventino inutilizzabili e non creabili.
reset Questa autorizzazione consente di ripristinare Keystore alle impostazioni di fabbrica, eliminando tutte le chiavi che non sono vitali per il funzionamento del sistema operativo Android
unlock Questa autorizzazione è necessaria per tentare di sbloccare la chiave principale per le chiavi associate all'autenticazione.