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:
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 allakeystore_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 classekeystore_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 conDOMAIN_APP
oDOMAIN_SELINUX
. L'autorizzazione il controllo viene eseguito dopodomain
enamespace
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 campoblob
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. |