Archivio chiavi supportato da hardware

La disponibilità di un ambiente di esecuzione affidabile in un system on a chip (SoC) offre ai dispositivi Android l'opportunità di fornire funzionalità basate su hardware, potenti servizi di sicurezza al sistema operativo Android, ai servizi di piattaforma e persino app di terze parti. Gli sviluppatori alla ricerca di estensioni specifiche per Android dovrebbero all'indirizzo android.security.keystore.

Prima di Android 6.0, Android possedeva già una semplice crittografia basata sull'hardware fornita dalle versioni 0.2 e 0.3 di Keymaster Hardware Abstraction Layer (HAL). Firma digitale e verifica fornite dall'archivio chiavi operazioni, oltre alla generazione e all'importazione di coppie di chiavi di firma asimmetriche. Questo è sono già implementate su molti dispositivi, ma ci sono molti obiettivi di sicurezza che non possono essere facilmente ottenibili con un'API di firma. Archivio chiavi in Android 6.0 ha esteso l'API Keystore per fornire una gamma più ampia di funzionalità.

In Android 6.0, l'archivio chiavi ha aggiunto primitive crittografiche simmetriche, AES e HMAC e un sistema di controllo dell'accesso per chiavi basate su hardware. Accesso vengono specificati durante la generazione della chiave e applicati per tutta la durata del la chiave. È possibile limitare le chiavi in modo che siano utilizzabili solo dopo che l'utente è stato autenticati e solo per scopi specifici o con crittografia specificata parametri. Per ulteriori informazioni, consulta Tag di autorizzazione e Pagine Funzioni.

Oltre ad ampliare la gamma di primitive crittografiche, l'archivio chiavi Android 6.0 ha aggiunto quanto segue:

  • Uno schema di controllo dell’utilizzo per consentire la limitazione dell’uso della chiave, per mitigare rischio di compromissione della sicurezza a causa di un uso improprio delle chiavi
  • Uno schema di controllo dell'accesso per consentire la limitazione delle chiavi a utenti specifici, clienti e un intervallo di tempo definito

In Android 7.0, Keymaster 2 ha aggiunto il supporto per l'attestazione e la versione della chiave associazione. Attestazione chiave fornisce certificati di chiave pubblica che contengono una descrizione dettagliata della chiave e i relativi controlli di accesso, per garantire l'esistenza della chiave in hardware sicuro verificabile da remoto.

Associazione delle versioni associa le chiavi al sistema operativo e alla versione a livello di patch. Ciò garantisce che un aggressore che scopre una debolezza in una vecchia versione del sistema o Il software TEE non può eseguire il rollback di un dispositivo alla versione vulnerabile e utilizzare chiavi creato con la versione più recente. Inoltre, quando una chiave con una determinata versione e a livello di patch viene utilizzato su un dispositivo di cui è stato eseguito l'upgrade a una versione più recente a livello di patch o di aggiornamento, la chiave viene aggiornata prima di poter essere utilizzata e la versione versione della chiave invalidata. Quando il dispositivo viene aggiornato, i tasti "a cricchetto" avanti insieme al dispositivo, ma qualsiasi ripristino del dispositivo a una versione rende i tasti inutilizzabili.

In Android 8.0, Keymaster 3 è passato dall'hardware C-structure vecchio stile l'HAL (Abstraction Layer) all'interfaccia C++ HAL generata da una definizione nel nuovo Hardware Interface Definition Language (HIDL). Nell'ambito di questa modifica, molti dei tipi di argomento sono cambiati, sebbene tipi e metodi abbiano un corrispondenza con i vecchi tipi e con i metodi struct HAL. Consulta le Pagina Funzioni per scoprire di più i dettagli.

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

In Android 9, gli aggiornamenti includevano:

  • Aggiorna a Keymaster 4
  • Supporto per Secure Element incorporati
  • Supporto per l'importazione di chiavi sicure
  • Supporto della crittografia 3DES
  • Modifiche all'associazione di versione in modo che boot.img e system.img abbiano Impostare le versioni separatamente per consentire aggiornamenti indipendenti

Glossario

Di seguito è riportata una rapida panoramica dei componenti dell'archivio chiavi e delle loro relazioni.

AndroidKeystore è l'API e il componente Android Framework utilizzato dalle app per accedere alla funzionalità dell'archivio chiavi. Viene implementata come estensione le API Java Cryptography Architecture standard ed è costituito da codice Java che nello spazio di processo dell'app. AndroidKeystore evade l'app per il comportamento degli archivi chiavi inoltrandole al daemon dell'archivio chiavi.

Il daemon keystore è un daemon di sistema Android che fornisce accesso a tutte le funzionalità dell'archivio chiavi tramite un'API Binder. È responsabile dell'archiviazione dei "blob chiave", che contengono il materiale effettivo della chiave segreta, criptato in modo che l'archivio chiavi possa archiviarli, non usarli o rivelarli.

keymasterd è un server HIDL che consente di accedere Keymaster TA. Questo nome non è standardizzato e serve a fini concettuali.

Keymaster TA (applicazione attendibile) è il software eseguito in un contesto sicuro, molto spesso in TrustZone su un SoC ARM, che fornisce tutte le operazioni sicure dell'archivio chiavi, ha accesso al materiale delle chiavi non elaborate, convalida le condizioni di controllo dell'accesso sulle chiavi, ecc.

LockSettingsService è il componente di sistema Android responsabile per l'autenticazione degli utenti, sia con password che con impronta. Non fa parte di Archivio chiavi, ma pertinente perché molte operazioni con le chiavi dell'archivio chiavi richiedono autenticazione. LockSettingsService interagisce con il Gatekeeper TA e TA per ottenere i token di autenticazione, che fornisce agli daemon dell'archivio chiavi e che vengono utilizzati dall'assistente un'applicazione.

Gatekeeper TA (applicazione attendibile) è un altro componente in esecuzione nel contesto sicuro, responsabile dell'autenticazione dell'utente password e la generazione di token di autenticazione utilizzati per dimostrare all'agente di supporto Keymaster indica che è stata eseguita un'autenticazione per un determinato utente in un determinato momento nel tempo.

Fingerprint TA (applicazione attendibile) è un altro componente in esecuzione nel contesto sicuro responsabile dell'autenticazione dell'utente le impronte digitali e la generazione di token di autenticazione utilizzati per dimostrare a Keymaster TA indica che è stata eseguita un'autenticazione per un determinato utente in un determinato momento nel tempo.

Architettura

L'API Android Keystore e il Keymaster HAL sottostante un insieme di primitive crittografiche di base, ma adeguato, per consentire implementazione di protocolli mediante chiavi hardware-supportate e controllate dall'accesso.

Keymaster HAL è una libreria fornita dall'OEM e caricabile dinamicamente, utilizzata da il servizio di archiviazione chiavi per fornire servizi crittografici basati su hardware. Per mantenere la sicurezza, le implementazioni HAL non eseguono operazioni sensibili dello spazio utente o perfino nello spazio del kernel. Le operazioni sensibili sono delegate a un tramite un'interfaccia del kernel. L'architettura risultante è simile alla seguente:

Accesso a Keymaster

Figura 1. Accesso a Keymaster

In un dispositivo Android, il "client" del Keymaster HAL è costituito più livelli (ad es. app, framework, daemon Keystore), ma questo può essere ignorato ai fini del presente documento. Ciò significa che il Keymaster HAL descritto L'API è di basso livello, è utilizzata dai componenti interni della piattaforma e non è esposta all'app sviluppatori. L'API di livello superiore è descritta sul sito Android for Developers.

Lo scopo di Keymaster HAL non è quello di implementare ma solo per eseguire il marshal e le richieste inviate al mondo sicuro. La è definito dall'implementazione.

Compatibilità con i precedenti versioni

Keymaster 1 HAL è del tutto incompatibile con HAL rilasciati in precedenza, ad esempio Keymaster 0.2 e 0.3. Per facilitare sui dispositivi con Android 5.0 e versioni precedenti lanciati con gli HAL Keymaster meno recenti, Keystore fornisce un adattatore che implementa Keymaster 1 HAL con chiamate alla libreria hardware esistente. Il risultato non può offrono l'intera gamma di funzionalità del Keymaster 1 HAL. In particolare, supporta solo gli algoritmi RSA ed ECDSA e tutte le chiavi di autorizzazione viene eseguita dall'adattatore in un ambiente non sicuro.

Keymaster 2 ha semplificato ulteriormente l'interfaccia dell'HAL rimuovendo il componente metodi get_supported_* e autorizzare finish() per accettare l'input. Questo riduce il numero di viaggi di andata e ritorno per il TEE in nei casi in cui l'input è disponibile contemporaneamente e semplifica l'implementazione Decrittografia AEAD.

In Android 8.0, Keymaster 3 è passato dalla struttura C tradizionale l'HAL all'interfaccia C++ HAL generata da una definizione nel nuovo HIDL (Hardware Interface Definition Language, linguaggio di definizione dell'interfaccia hardware). Un HAL nuovo stile viene creata creando sottoclassi del modello IKeymasterDevice corso e implementa la modalità virtuale pura di machine learning. Nell'ambito di questa modifica, sono cambiati molti tipi di argomenti. sebbene tipi e metodi abbiano una corrispondenza 1:1 con il e i metodi struct HAL.

Panoramica HIDL

L'Hardware Interface Definition Language (HIDL) fornisce un'implementazione meccanismo indipendente dal linguaggio per la specifica delle interfacce hardware. HIDL supporta attualmente la generazione di interfacce C++ e Java. È previsto che la maggior parte degli implementer dell'ambiente di esecuzione affidabile (TEE, Trusted Execution Environment, TEE) troveranno il file C++ strumenti più pratici, per cui in questo documento parleremo solo della rappresentazione C++.

Le interfacce HIDL consistono di un insieme di metodi, espressi come:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Esistono vari tipi predefiniti e gli HAL possono definire nuovi tipi di struttura. Per ulteriori dettagli sull'HIDL, consulta la sezione Riferimenti.

Un metodo di esempio da Keymaster 3 IKeymasterDevice.hal è:

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

Equivale a quanto segue dell'HAL keymaster2:

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, l'argomento dev viene rimosso perché è in modo implicito. L'argomento params non è più uno struct contenente un un puntatore che fa riferimento a un array di oggetti key_parameter_t, ma vec (vettore) contenente KeyParameter oggetti. La i valori restituiti sono elencati in "generates" , che include una vettore di valori uint8_t per il blob della chiave.

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

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

Dove generateKey_cb è un puntatore di funzione definito come:

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

Vale a dire, generateKey_cb è una funzione che prende i valori restituiti elencato nella clausola generate. La classe di implementazione HAL sostituisce questo generateKey e chiama la funzione generateKey_cb per restituire il risultato dell'operazione al chiamante. Osserva la funzione la chiamata del puntatore è sincrona. Il chiamante chiama generateKey e generateKey chiamano il token di funzione, che viene eseguita fino al completamento, restituendo il controllo generateKey, che a sua volta ritorna al chiamante.

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

Controllo dell'accesso

La regola più basilare per il controllo dell'accesso all'archivio chiavi è che ogni app ha il suo del tuo spazio dei nomi. Ma c'è un'eccezione per ogni regola. L'archivio chiavi ha alcune mappe hardcoded che consentono ad alcuni componenti del sistema di accedere a spazi dei nomi. Si tratta di uno strumento molto smussato in quanto fornisce un componente il controllo completo su un altro spazio dei nomi. E poi c'è la questione del fornitore come client all'archivio chiavi. Al momento non abbiamo modo di stabilire una per i componenti del fornitore, ad esempio il supplicante WPA.

al fine di ospitare i componenti del fornitore e generalizzare il controllo dell'accesso. senza eccezioni hardcoded, Keystore 2.0 introduce domini e SELinux spazi dei nomi.

Domini archivio chiavi

Con i domini dell'archivio chiavi, possiamo disaccoppiare gli spazi dei nomi dagli UID. Clienti quando si accede a una chiave nell'archivio chiavi devono specificare il dominio, lo spazio dei nomi e l'alias a cui vuole accedere. In base a questa tupla e all'identità del chiamante, può stabilire a quale chiave desidera accedere e se ha autorizzazioni aggiuntive.

Introduciamo cinque parametri di dominio che regolano l'accesso alle chiavi. Controllano la semantica del parametro dello spazio dei nomi del descrittore della chiave e come viene eseguito il controllo dell'accesso.

  • DOMAIN_APP: il dominio dell'app copre la un comportamento precedente. L'SPI dell'archivio chiavi Java utilizza questo dominio per impostazione predefinita. Quando questo dominio, l'argomento dello spazio dei nomi viene ignorato e l'UID del chiamante al suo posto. L'accesso a questo dominio è controllato dall'etichetta dell'archivio chiavi alla keystore_key nel criterio SELinux.
  • DOMAIN_SELINUX: questo dominio indica che ha un'etichetta nel criterio SELinux. Il parametro dello spazio dei nomi viene controllato viene tradotto in un contesto di destinazione e viene eseguito un controllo delle autorizzazioni il contesto SELinux di chiamata per la classe keystore_key. Quando per l'operazione specificata, viene utilizzata la tupla completa per la ricerca della chiave.
  • DOMAIN_GRANT: il dominio della concessione indica che il parametro spazio dei nomi è un identificatore di concessione. Il parametro alias viene ignorato. I controlli di SELinux vengono eseguiti al momento della creazione della concessione. Ulteriore controllo dell'accesso verifica solo se l'UID del chiamante corrisponde all'UID del beneficiario della concessione richiesta.
  • DOMAIN_KEY_ID: questo dominio indica che è un ID chiave univoco. La chiave stessa potrebbe essere stata creata con DOMAIN_APP o DOMAIN_SELINUX. L'autorizzazione il controllo viene eseguito dopo domain e namespace siano stati caricati dal database delle chiavi come se il BLOB fosse caricato dal dominio, dallo spazio dei nomi e dalla tupla alias. La logica del dominio dell'ID chiave è la continuità. Quando si accede a una chiave tramite alias, le chiamate successive potrebbero funzionare diverse chiavi, perché è possibile che una nuova chiave sia stata generata o importata e vincolata a questo alias. Tuttavia, l'ID chiave non cambia mai. Quindi, quando utilizzi una chiave per ID chiave dopo essere stato caricato dal database dell'archivio chiavi utilizzando l'alias una volta, uno puoi essere certo che si tratta della stessa chiave finché l'ID della chiave esiste ancora. Questo non vengono esposte agli sviluppatori di app. Viene utilizzato all'interno SPI dell'archivio chiavi Android per offrire un'esperienza più coerente anche quando viene utilizzato contemporaneamente in modo non sicuro.
  • DOMAIN_BLOB: il dominio del blob indica che il chiamante gestisce il blob da solo. Viene utilizzato per i client che devono per accedere all'archivio chiavi prima di montare la partizione dati. Il blob chiave è incluso nel campo blob del descrittore della chiave.

Utilizzando il dominio SELinux, possiamo concedere ai componenti del fornitore l'accesso a spazi dei nomi specifici dell'archivio chiavi che possono essere condivisi dai componenti di sistema come la finestra di dialogo delle impostazioni.

Criterio SELinux per keystore_key

Le etichette dello spazio dei nomi vengono configurate utilizzando l'keystore2_key_context .
Ogni riga in questi file mappa un ID spazio dei nomi 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

Dopo aver impostato un nuovo spazio dei nomi della chiave in questo modo, possiamo concedergli l'accesso aggiungendo un criterio appropriato. Ad esempio, per consentire wpa_supplicant per ottenere e utilizzare le chiavi nel nuovo spazio dei nomi che dovremmo aggiungi la seguente riga a hal_wifi_supplicant.te:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Dopo aver configurato il nuovo spazio dei nomi, AndroidKeyStore può essere utilizzato quasi al solito. L'unica differenza è che è necessario specificare l'ID dello spazio dei nomi. Per caricamento e importazione delle chiavi da e nell'archivio chiavi, viene specificato l'ID spazio dei nomi utilizzando l'AndroidKeyStoreLoadStoreParameter. Ad 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, è necessario fornire l'ID spazio dei nomi utilizzo di KeyGenParameterSpec.Builder#setNamespace():

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

Per configurare l'archivio chiavi 2.0 SELinux possono essere utilizzati i seguenti file di contesto spazi dei nomi. Ogni partizione ha un intervallo riservato diverso di 10.000 spazi dei nomi per evitare collisioni.

Partizione Intervallo File di configurazione
Sistema 0 ... 9999
/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
Fornitore 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 il spazio dei nomi virtuale, in questo caso "wifi_key", per l'ID numerico.

Al di sopra sono stati definiti i seguenti spazi dei nomi. Se sostituiscono regole speciali, la tabella seguente indica l'UID utilizzato a.

ID spazio dei nomi Etichetta SEPolicy UID Descrizione
0 Su_key N/D Chiave super utente. Utilizzato solo per i test su build di userdebug ed eng. No pertinenti sulle build degli utenti.
1 chiave_shell N/D Spazio dei nomi disponibile per la shell. Utilizzato principalmente per i test, ma può essere utilizzato su dall'utente dalla riga di comando.
100 chiave_vold N/D Destinato all'uso da parte di vold.
101 tasto_odsing N/D Utilizzato dal daemon di firma sul dispositivo.
102 chiave_wifi AID_WI-FI(1010) Utilizzato dal sistema Wi-Fi di Android, incluso wpa_supplicant.
120 riprendi_alla_chiave_riavvio AID_SYSTEM(1000) Utilizzato dal server di sistema Android per supportare la ripresa al riavvio.

Vettori di accesso

La classe SELinux keystore_key è in età discreta e alcuni le autorizzazioni, ad esempio verify o sign, hanno perso il loro significato. Ecco il nuovo insieme di autorizzazioni, keystore2_key, verrà applicato l'archivio chiavi 2.0.

Autorizzazione Significato
delete Opzione selezionata durante la rimozione delle chiavi dall'archivio chiavi.
get_info Selezionata quando vengono richiesti i metadati di una chiave.
grant Il chiamante ha bisogno di questa autorizzazione per creare una concessione alla chiave nella destinazione contesto.
manage_blob Il chiamante può usare DOMAIN_BLOB nello spazio dei nomi SELinux specificato, gestendo così i blob da soli. Questa funzionalità è particolarmente utile per vold.
rebind Questa autorizzazione consente di stabilire se un alias può essere reindirizzato a una nuova chiave. Questo è richiesta per l'inserimento, il che implica che la chiave associata in precedenza eliminati. Si tratta essenzialmente di un'autorizzazione di inserimento, ma acquisisce la semantica dell'archivio chiavi.
req_forced_op I client con questa autorizzazione potrebbero creare operazioni non eliminabili e la creazione delle operazioni non riesce mai a meno che tutti gli slot delle operazioni non vengano di operazioni non potabili.
update Necessario per aggiornare il sottocomponente di una chiave.
use Selezionata durante la creazione di un'operazione Keymint che utilizza il materiale della chiave, ad esempio per la firma e la crittografia.
use_dev_id Obbligatorio quando vengono generate informazioni che consentono l'identificazione del dispositivo, ad esempio l'ID dispositivo l'attestazione.

Inoltre, abbiamo suddiviso un insieme di autorizzazioni dell'archivio chiavi non specifiche per le chiavi in della classe di sicurezza SELinux keystore2:

Autorizzazione Significato
add_auth Richiesto da un provider di autenticazione come Gatekeeper o BiometricsManager per l'aggiunta di token di autenticazione.
clear_ns Precedentemente clear_uid, questa autorizzazione consente a chi non è proprietario di uno spazio dei nomi di eliminare tutte le chiavi nello spazio dei nomi.
list Richiesto dal sistema per enumerare le chiavi in base a varie proprietà, come limiti della proprietà o dell'autorizzazione. Questa autorizzazione non è richiesta dai chiamanti enumerando i propri spazi dei nomi. Questo aspetto è coperto dalle Autorizzazione get_info.
lock Questa autorizzazione consente di bloccare l'archivio chiavi, ovvero rimuovere la chiave master, le chiavi associate all'autenticazione diventano inutilizzabili e non creabili.
reset Questa autorizzazione consente di ripristinare i dati di fabbrica dell'archivio chiavi, eliminando tutti chiave non essenziali per il funzionamento del sistema operativo Android.
unlock Questa autorizzazione è richiesta per tentare di sbloccare la chiave master per l'autenticazione associate.