La disponibilidad de un entorno de ejecución confiable en un sistema en chip (SoC) ofrece a los dispositivos Android la oportunidad de ofrecer copias de seguridad servicios de seguridad sólidos para el SO Android, los servicios de plataforma e incluso para aplicaciones de terceros. Los desarrolladores que busquen extensiones específicas para Android deben visitar en android.security.keystore.
Antes de la versión 6.0 de Android, Android ya tenía un método criptográfico simple respaldado por hardware. de Google Services, proporcionada por las versiones 0.2 y 0.3 del hardware de Keymaster Capa de abstracción (HAL). Firma digital y verificación que proporcionó el almacén de claves además de la importación y generación de pares de claves de firma asimétricas. Este es que ya se implementaron en muchos dispositivos, pero hay muchos objetivos de seguridad no se puede lograr fácilmente con una API de firma. Almacén de claves en Android 6.0 extendió la API de Keystore para proporcionar una gama más amplia de capacidades.
En Android 6.0, Keystore agregó primitivas criptográficas simétricas, AES y HMAC, además de un sistema de control de acceso para claves guardadas en hardware. Acceso los controles se especifican durante la generación de la clave y se aplican durante el ciclo de vida de la clave. Se pueden restringir las claves para que solo se puedan usar después de que el usuario haya ingresado a él. autenticados, y solo para fines específicos o con claves criptográficas parámetros. Para obtener más información, consulta la las etiquetas de autorización Funciones.
Además de expandir el rango de primitivas criptográficas, Keystore En Android 6.0, se agregó lo siguiente:
- Un esquema de control de uso que permita limitar el uso de la clave y mitigará la riesgo de compromiso de seguridad debido al uso inadecuado de claves
- Un esquema de control de acceso para habilitar la restricción de claves a usuarios específicos. clientes y un intervalo de tiempo definido
En Android 7.0, Keymaster 2 agregó compatibilidad con la certificación de claves y la versión. la vinculación. Certificación de claves proporciona certificados de clave pública que contienen una descripción detallada de la clave y sus controles de acceso, para que la clave exista en el hardware seguro configuración remota y verificable de forma remota.
Vinculación de versión vincula las claves al sistema operativo y a la versión de nivel de parche. Esto garantiza que un atacante que descubre una debilidad en una versión anterior del sistema o El software de TEE no puede revertir un dispositivo a la versión vulnerable ni usar claves creado con la versión más reciente. Además, cuando una clave con una versión determinada y el nivel de parche se usa en un dispositivo que se actualizó a una versión más reciente o parche, esta se actualiza antes de que se pueda usar, y la versión versión de la clave invalidada. A medida que se actualiza el dispositivo, las claves fallan reenviar junto con el dispositivo, pero cualquier reversión versión hace que las claves queden inutilizables.
En Android 8.0, Keymaster 3 hizo la transición del hardware de estructura C de estilo antiguo. Capa de abstracción (HAL) para la interfaz de la HAL de C++ generada a partir de una definición en el nuevo Lenguaje de definición de la interfaz de hardware (HIDL). Como parte del cambio, muchos de los tipos de argumentos cambiaron, aunque los tipos y los métodos tienen una relación con los tipos antiguos y los métodos de struct de la HAL. Consulta la Functions para obtener más información más detalles.
Además de esta revisión de la interfaz, Android 8.0 extendió de certificación para admitir Certificación de ID. La certificación de ID brinda un mecanismo limitado y opcional para realizar una certificación sólida. los identificadores de hardware, como el número de serie del dispositivo, el nombre del producto y el número de o un ID (IMEI / MEID). Para implementar esta adición, Android 8.0 cambió el ASN.1 de certificación para agregar una certificación de ID. Las implementaciones de Keymaster deben busca una manera segura de recuperar los elementos de datos relevantes y definir un mecanismo para inhabilitar la función de forma segura y permanente.
En Android 9, se incluyeron las siguientes actualizaciones:
- Actualizar a Keymaster 4
- Compatibilidad con Elementos seguros incorporados
- Compatibilidad con la importación segura de claves
- Compatibilidad con la encriptación 3DES
- Se realizaron cambios en la vinculación de versión para que boot.img y system.img tengan versiones por separado para permitir actualizaciones independientes
Glosario
Esta es una descripción general de los componentes de Keystore y sus relaciones.
AndroidKeystore es la API del framework de Android y el componente que se usa.
las apps para acceder a la funcionalidad del almacén de claves. Se implementa como una extensión del
las APIs estándar de arquitectura de criptografía de Java y consta de código Java
se ejecuta en el propio espacio de procesos de la app. AndroidKeystore
entrega la app
para el comportamiento del almacén de claves mediante su reenvío al daemon del almacén de claves.
El daemon de almacén de claves es un daemon del sistema Android que proporciona Acceso a todas las funciones del almacén de claves a través de una API de Binder. Se encarga de almacenar los “BLOB de claves”, contienen el material real de la clave secreta, encriptado para que el almacén de claves pueda almacenarlo, pero no usarlos ni revelarlos.
keymasterd es un servidor HIDL que proporciona acceso al Keymaster TA. (Este nombre no está estandarizado y tiene fines conceptuales).
Keymaster TA (aplicación de confianza) es el software que se ejecuta en un contexto seguro, con frecuencia en TrustZone en un SoC ARM, que proporciona toda la las operaciones seguras de Keystore, tiene acceso al material sin procesar de claves, las condiciones de control de acceso de las claves, etcétera.
LockSettingsService es el componente del sistema Android responsable
para la autenticación de usuarios, con contraseña y huella dactilar. No forma parte de
Almacén de claves, pero es relevante porque muchas operaciones de claves del almacén de claves requieren
autenticación. LockSettingsService
interactúa con el recepcionista
TA y TA de huella digital para obtener tokens de autenticación, que se proporcionan al
un daemon de almacén de claves y que, en última instancia, son consumidos por el TA de Keymaster
y mantener la integridad de su aplicación.
Gatekeeper TA (aplicación de confianza) es otro componente que se ejecuta en un contexto seguro, que es responsable de autenticar contraseñas y generar tokens de autenticación utilizados para dar pruebas al TA de Keymaster que se realizó una autenticación para un usuario concreto en un punto determinado tiempo.
La TA de huella digital (aplicación de confianza) es otro componente que se ejecuta en un contexto seguro y que es responsable de autenticar huellas digitales y la generación de tokens de autenticación para demostrarle al Keymaster TA que indica que se realizó una autenticación para un usuario concreto en un punto determinado a tiempo.
Arquitectura
La API de Android Keystore y la HAL subyacente de Keymaster un conjunto básico, pero adecuado, de primitivas criptográficas implementación de protocolos mediante claves con acceso controlado y guardadas en hardware.
La HAL de Keymaster es una biblioteca de carga dinámica que brinda el OEM y que usa para proporcionar servicios criptográficos respaldados en hardware. Para conservar las implementaciones de HAL no realizan operaciones sensibles espacio del usuario o de kernel. Las operaciones sensibles se delegan a un un procesador seguro al que se accede mediante alguna interfaz de kernel. La arquitectura resultante se ve así:
![Acceso a Keymaster](https://source.android.com/static/docs/security/images/access-to-keymaster.png?authuser=1&hl=es-419)
Figura 1: Acceso a Keymaster
En un dispositivo Android, el "cliente" de la HAL de Keymaster consta de varias capas (p.ej., aplicación, framework, daemon de almacén de claves), pero se pueden ignorar para los fines de este documento. Esto significa que la HAL de Keymaster descrita La API es de bajo nivel; la usan los componentes internos de la plataforma; no está expuesta a la app desarrolladores. La API de nivel superior se describe en el sitio para desarrolladores de Android.
El propósito de la HAL de Keymaster no es implementar la interfaz sensible sino solo para reunir y deserializar solicitudes en el mundo seguro. El el formato de conexión está definido por la implementación.
Compatibilidad con la anterior versiones
La HAL de Keymaster 1 es completamente incompatible con el HAL lanzadas anteriormente, p.ej., Keymaster 0.2 y 0.3. Para facilitar interoperabilidad en dispositivos con Android 5.0 y versiones anteriores que se lanzaron con las HALs de Keymaster antiguas, Keystore proporciona un adaptador que implementa HAL de Keymaster 1 con llamadas a la biblioteca de hardware existente. El resultado no se puede proporcionan el rango completo de funcionalidades en la HAL de Keymaster 1. En particular, solo es compatible con los algoritmos RSA y ECDSA, y todas las claves de autorización el adaptador realiza la aplicación forzosa en el mundo no seguro.
Keymaster 2 simplificó aún más la interfaz de la HAL, ya que quitó las
get_supported_*
y permitir el uso de finish()
para aceptar la entrada. Esto reduce el número de recorridos de ida y vuelta al TEE en
en los que la entrada está disponible de una sola vez y simplifica la implementación de
Desencriptación de AEAD.
En Android 8.0, Keymaster 3 pasó de la estructura C de estilo anterior.
HAL a la interfaz de la HAL de C++ generada a partir de una definición en el nuevo
Lenguaje de definición de la interfaz de hardware (HIDL). Un HAL de estilo nuevo
del proyecto se crea mediante la subclasificación del
IKeymasterDevice
e implementar la interfaz de usuario
. Como parte del cambio, muchos de los tipos de argumentos cambiaron,
aunque los tipos y los métodos tienen
una correspondencia uno a uno con la
de la HAL y los métodos de struct de la HAL.
Descripción general de HIDL
El lenguaje de definición de la interfaz de hardware (HIDL) proporciona mecanismo independiente del lenguaje para especificar interfaces de hardware. El HIDL Las herramientas actualmente admiten la generación de interfaces C++ y Java. Está previsto que la mayoría de los implementadores del entorno de ejecución confiable (TEE) encontrarán el código C++ por lo que en este documento solo se analiza la representación de C++.
Las interfaces HIDL constan de un conjunto de métodos, que se expresan de la siguiente manera:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
Existen varios tipos predefinidos, y las HAL pueden definir nuevos tipos tipos de estructura. Para obtener más detalles sobre HIDL, consulta la sección de referencia.
Un método de ejemplo de IKeymasterDevice.hal
de Keymaster 3 es el siguiente:
generateKey(vec<KeyParameter> keyParams) generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
Esto equivale a lo siguiente de la HAL de 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);
En la versión HIDL, el argumento dev
se quita, ya que es
implícita. El argumento params
ya no es un struct que contenga un
que hace referencia a un array de objetos key_parameter_t
, pero un
vec
(vector) que contiene objetos KeyParameter
. El
los valores que se devuelven se enumeran en la tabla “generates
” incluida una
Vector de valores uint8_t
para el BLOB de clave.
El método virtual de C++ que genera el compilador HIDL es el siguiente:
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, generateKey_cb _hidl_cb) override;
Donde generateKey_cb
es un puntero de función definido de la siguiente manera:
std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics)>
Es decir, generateKey_cb
es una función que toma los valores que se muestran
que figuran en la cláusula generate. La clase de implementación de HAL anula esto.
generateKey
y llama a la función generateKey_cb
.
para mostrar el resultado de la operación al llamador. Observa la función
llamada de puntero es síncrona. El emisor llama
generateKey
y generateKey
llaman a la API de
puntero de función, que se ejecuta hasta la finalización y devuelve el control al
generateKey
, que luego regresa al llamador.
Para obtener un ejemplo detallado, consulta la implementación predeterminada en
hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
La implementación predeterminada proporciona retrocompatibilidad para dispositivos con
las HALS antiguas keymaster0, keymaster1 o keymaster2.
Control de acceso
La regla más básica del control de acceso al almacén de claves es que cada aplicación tiene su espacio de nombres propio. Pero para cada regla hay una excepción. El almacén de claves tiene algunas mapas codificados que permiten que ciertos componentes del sistema accedan a otros los espacios de nombres. Este instrumento es muy brusco, ya que proporciona un componente control total sobre otro espacio de nombres. Y luego está la cuestión del proveedor como clientes al almacén de claves. Actualmente no tenemos forma de establecer un para los componentes del proveedor, como solicitante WPA.
Con el fin de adaptarse a los componentes del proveedor y generalizar el control de acceso sin excepciones codificadas, Keystore 2.0 introduce dominios y SELinux los espacios de nombres.
Dominios de almacén de claves
Con los dominios del almacén de claves, podemos separar los espacios de nombres de los UIDs. Clientes cuando acceden a una clave en el almacén de claves deben especificar el dominio, el espacio de nombres y el alias a las que quieren acceder. Según esta tupla y la identidad del emisor, puede determinar a qué tecla quiere acceder el emisor y si tiene acceso permisos.
Presentamos cinco parámetros de dominio que rigen cómo se puede acceder a las claves. Controlan la semántica del parámetro de espacio de nombres del descriptor de clave y cómo se realiza el control de acceso.
DOMAIN_APP
: El dominio de la app cubre la el comportamiento heredado. La SPI de Java Keystore utiliza este dominio de forma predeterminada. Cuando esta dominio, se ignora el argumento del espacio de nombres y el UID del emisor en su lugar. El acceso a este dominio está controlado por la etiqueta del almacén de claves al la clasekeystore_key
en la política de SELinux.DOMAIN_SELINUX
: Este dominio indica que el tienen una etiqueta en la política de SELinux. El parámetro de espacio de nombres se ve y traducirse a un contexto objetivo, y se realiza una verificación de permisos para el contexto de SELinux de llamada para la clasekeystore_key
. Cuando permiso establecido para la operación, se usa la tupla completa para la búsqueda de claves.DOMAIN_GRANT
: El dominio de concesión indica que el parámetro de espacio de nombres es un identificador de concesión. Se ignora el parámetro de alias. Las verificaciones de SELinux se realizan cuando se crea la concesión. Control de acceso adicional solo verifica si el UID del emisor coincide con el UID de los beneficiarios de la concesión solicitada.DOMAIN_KEY_ID
: Este dominio indica que el espacio de nombres es un ID de clave único. Es posible que la clave se haya creado. conDOMAIN_APP
oDOMAIN_SELINUX
. El permiso la verificación se realiza después dedomain
ynamespace
se cargaron desde la base de datos de claves de la misma manera que si se cargara el BLOB dominio, espacio de nombres y tupla de alias. La lógica para el dominio del ID de clave es la continuidad. Cuando se accede a una clave por alias, las llamadas posteriores pueden operar en claves diferentes, ya que es posible que una clave nueva se haya generado, importado y vinculado a este alias. Sin embargo, el ID de la clave nunca cambia. Cuando se usa una clave por ID de clave, después de que se cargó desde la base de datos del almacén de claves usando el alias. Una vez, puedes estar seguro de que es la misma clave, siempre que el ID de clave siga existiendo. Esta no se expone a los desarrolladores de apps. En cambio, se usa dentro del SPI de Android Keystore para proporcionar una experiencia más coherente, incluso cuando se usa. al mismo tiempo de forma insegura.DOMAIN_BLOB
: El dominio de BLOB indica lo siguiente: el llamador administra el BLOB por sí mismo. Esto se usa para clientes que necesitan acceder al almacén de claves antes de activar la partición de datos. El BLOB de clave es incluido en el campoblob
del descriptor de clave.
Con el dominio SELinux, podemos permitir que los componentes del proveedor accedan a espacios de nombres específicos del almacén de claves que pueden compartir los componentes del sistema, como en el cuadro de diálogo de configuración.
Política de SELinux para keystore_key
Las etiquetas de espacio de nombres se configuran con keystore2_key_context
.
Cada línea de estos archivos asigna un ID de espacio de nombres numérico a una etiqueta de SELinux.
Por ejemplo:
# 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
Después de configurar un nuevo espacio de nombres de claves de esta manera, podemos otorgar acceso a él.
agregando una política adecuada. Por ejemplo, para permitir
wpa_supplicant
para obtener y usar claves en el espacio de nombres nuevo que utilizaríamos
Agrega la siguiente línea a hal_wifi_supplicant.te
:
allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };
Después de configurar el nuevo espacio de nombres, AndroidKeyStore se puede usar casi como
normalmente. La única diferencia es que se debe especificar el ID del espacio de nombres. Para
importando y cargando claves desde y hacia el almacén de claves, se especifica el ID del espacio de nombres.
con AndroidKeyStoreLoadStoreParameter
. Por ejemplo:
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import java.security.KeyStore; KeyStore keystore = KeyStore.getInstance("AndroidKeyStore"); keystore.load(new AndroidKeyStoreLoadStoreParameter(102));
Para generar una clave en un espacio de nombres determinado, se debe proporcionar el ID del espacio de nombres.
usando KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
Los siguientes archivos de contexto se pueden usar para configurar Keystore 2.0 SELinux los espacios de nombres. Cada partición tiene un rango reservado diferente de 10,000 espacios de nombres IDs para evitar colisiones.
Partición | Rango | Archivos de configuración |
---|---|---|
Sistema | 0 ... 9,999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
Sistema ampliado | De 10,000 a 19,999 | /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts |
Producto | 20,000 ... 29,999 | /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts |
Proveedor | 30,000 ... 39,999 | /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts |
El cliente solicita la clave solicitando el dominio SELinux y los permisos
espacio de nombres virtual, en este caso "wifi_key"
, por su ID numérico.
Arriba de eso, se definieron los siguientes espacios de nombres. Si reemplazan reglas especiales, la siguiente tabla indica el UID que usaron para corresponder a los que tiene acceso una cuenta.
ID del espacio de nombres | Etiqueta de SEPolicy | UID | Descripción |
---|---|---|---|
0 | su_clave | N/A | Tecla de superusuario. Solo se usa para realizar pruebas en compilaciones userdebug y eng. No relevante para las compilaciones de los usuarios. |
1 | clave_shell | N/A | Espacio de nombres disponible para shell. Se usa principalmente para pruebas, pero puede usarse en usuario también desde la línea de comandos. |
100 | clave_vold | N/A | Diseñado para que lo use vold. |
101 | clave_odsing | N/A | Lo usa el daemon de firma integrado en el dispositivo. |
102 | clave_wifi | AID_WIFI(1010) | Lo usa el sistema de Wi-Fi de Android, incluido wpa_supplicant. |
120 | reanudar_con_clave_de_reinicio | AID_SYSTEM(1,000) | El servidor del sistema de Android lo usa para admitir la reanudación durante el reinicio. |
Vectores de acceso
La clase keystore_key
de SELinux ha envejecido bastante y algunas de
se perdieron los permisos, como verify
o sign
su significado. Este es el nuevo conjunto de permisos, keystore2_key
,
que se aplicará a Keystore 2.0.
Permiso | Significado |
---|---|
delete
|
Se marca cuando se quitan las claves del almacén de claves. |
get_info
|
Se verifica cuando se solicitan los metadatos de una clave. |
grant
|
El llamador necesita este permiso para otorgar un permiso a la clave en el destino adicional. |
manage_blob
|
El llamador puede usar DOMAIN_BLOB en el espacio de nombres de SELinux determinado.
y, por lo tanto, administrar los BLOB por sí solos. Esto es especialmente útil para
vold. |
rebind
|
Este permiso controla si un alias se puede volver a vincular a una clave nueva. Este es obligatoria para la inserción y también implica que la clave previamente vinculada se borrar. En esencia, es un permiso de inserción, pero captura la semántica del almacén de claves. |
req_forced_op
|
Los clientes con este permiso pueden crear operaciones que no se pueden reducir. la creación de operaciones nunca falla, a menos que todas las ranuras de operación las ocupen operaciones imposibles de reducir. |
update
|
Es obligatorio para actualizar el subcomponente de una clave. |
use
|
Se marca cuando se crea una operación Keymint que usa el material de la clave (p.ej., para firmar y desencriptar/desencriptar. |
use_dev_id
|
Obligatorio cuando se genera información de identificación del dispositivo, como el ID certificación. |
Además, dividimos un conjunto de permisos de claves de claves no específicos de claves en
la clase de seguridad de SELinux keystore2
:
Permiso | Significado |
---|---|
add_auth
|
Solicitado por un proveedor de autenticación, como Gatekeeper o BiometricsManager para agregar tokens de autenticación. |
clear_ns
|
Este permiso (anteriormente clear_uid) permite que los usuarios que no son propietarios de un espacio de nombres o borrar todas las claves de ese espacio de nombres. |
list
|
Obligatorio por el sistema para enumerar claves según diversas propiedades, como
la propiedad o los límites de autenticación. Los emisores no requieren este permiso
y enumerar sus propios espacios de nombres. Esto se aborda en el
get_info . |
lock
|
Este permiso permite bloquear el almacén de claves, es decir, expulsar la clave maestra, como que las claves vinculadas a la autenticación se vuelven inutilizables y no se pueden crear. |
reset
|
Este permiso permite restablecer el almacén de claves a la configuración predeterminada de fábrica y borrar todo que no son esenciales para el funcionamiento del SO Android. |
unlock
|
Se requiere este permiso para intentar desbloquear la clave maestra para la autenticación claves vinculadas. |