Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Almacén de claves respaldado por hardware

La disponibilidad de un entorno de ejecución confiable en un sistema en un chip (SoC) ofrece una oportunidad para que los dispositivos Android brinden servicios de seguridad sólidos y respaldados por hardware al sistema operativo Android, a los servicios de la plataforma e incluso a las aplicaciones de terceros. Los desarrolladores que buscan las extensiones Android específicos deben ir a android.security.keystore .

Antes de Android 6.0, Android ya tenía una API de servicios criptográficos simple, respaldada por hardware, proporcionada por las versiones 0.2 y 0.3 de Keymaster Hardware Abstraction Layer (HAL). Keystore proporcionó operaciones de verificación y firma digital, además de la generación e importación de pares de claves de firma asimétrica. Esto ya está implementado en muchos dispositivos, pero hay muchos objetivos de seguridad que no se pueden lograr fácilmente con solo una API de firma. Keystore en Android 6.0 amplió la API de Keystore para proporcionar una gama más amplia de capacidades.

En Android 6.0, Keystore añadió primitivas criptográficas simétricas , AES y HMAC, y un sistema de control de acceso con la codificación de hardware respaldados. Los controles de acceso se especifican durante la generación de la clave y se aplican durante la vida útil de la clave. Las claves se pueden restringir para que se puedan usar solo después de que el usuario haya sido autenticado y solo para fines específicos o con parámetros criptográficos específicos. Para obtener más información, consulte la autorización Etiquetas y Funciones páginas.

Además de ampliar la gama de primitivas criptográficas, Keystore en Android 6.0 agregó lo siguiente:

  • Un esquema de control de uso para permitir que el uso de claves sea limitado, para mitigar el riesgo de compromiso de seguridad debido al uso indebido de claves.
  • Un esquema de control de acceso para permitir la restricción de claves a usuarios específicos, clientes y un rango de tiempo definido.

En Android 7.0, Keymaster 2 agregó soporte para la certificación de claves y el enlace de versiones. Certificación clave proporciona certificados de clave pública que contienen una descripción detallada de la llave y sus controles de acceso, para que la existencia de la llave en hardware seguro y su configuración de forma remota verificable.

Versión vinculante teclas se une al sistema operativo y la versión de nivel de parche. Esto asegura que un atacante que descubre una debilidad en una versión anterior del sistema o el software TEE no puede revertir un dispositivo a la versión vulnerable y usar claves creadas con la versión más reciente. Además, cuando se usa una clave con una versión y un nivel de parche determinados en un dispositivo que se ha actualizado a una versión o nivel de parche más reciente, la clave se actualiza antes de que pueda usarse y la versión anterior de la clave se invalida. A medida que se actualiza el dispositivo, las teclas se mueven hacia adelante junto con el dispositivo, pero cualquier reversión del dispositivo a una versión anterior hace que las teclas no se puedan utilizar.

En Android 8.0, Keymaster 3 pasó de la capa de abstracción de hardware (HAL) de estructura C de estilo antiguo a la interfaz C ++ HAL generada a partir de una definición en el nuevo lenguaje de definición de interfaz de hardware (HIDL). Como parte del cambio, muchos de los tipos de argumentos cambiaron, aunque los tipos y métodos tienen una correspondencia uno a uno con los tipos antiguos y los métodos de estructura HAL. Ver la Funciones de la página para más detalles.

Además de esta revisión de la interfaz, Android 8.0 extendió función de certificación de Keymaster 2 de soporte certificado de identificación . La atestación de identificación proporciona un mecanismo limitado y opcional para dar fe de los identificadores de hardware, como el número de serie del dispositivo, el nombre del producto y la identificación del teléfono (IMEI / MEID). Para implementar esta adición, Android 8.0 cambió el esquema de atestación ASN.1 para agregar la atestación de ID. Las implementaciones de Keymaster deben encontrar alguna forma segura de recuperar los elementos de datos relevantes, así como definir un mecanismo para deshabilitar la función de forma segura y permanente.

En Android 9, las actualizaciones incluyeron:

  • Actualizar para Keymaster 4
  • Soporte para elementos seguros integrados
  • Soporte para importación segura de claves
  • Soporte para cifrado 3DES
  • Cambios en el enlace de versiones para que boot.img y system.img tengan versiones configuradas por separado para permitir actualizaciones independientes

Glosario

A continuación, se ofrece una descripción general rápida de los componentes del almacén de claves y sus relaciones.

AndroidKeystore es la API del marco de Android y el componente utilizado por aplicaciones para acceder a la funcionalidad del almacén de claves. Se implementa como una extensión de las API estándar de Java Cryptography Architecture y consta de código Java que se ejecuta en el propio espacio de proceso de la aplicación. AndroidKeystore cumple las peticiones de aplicaciones para el comportamiento del almacén de claves mediante el envío de ellos al demonio almacén de claves.

El demonio de almacén de claves es un demonio del sistema Android que proporciona acceso a todas las funciones del almacén de claves a través de una API Carpeta . Es responsable de almacenar "blobs de claves", que contienen el material de la clave secreta real, cifrado para que Keystore pueda almacenarlos pero no usarlos ni revelarlos.

keymasterd es un servidor HIDL que proporciona acceso a la 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 mayor frecuencia en TrustZone en un ARM SoC, que proporciona todas las operaciones de almacén de claves seguras, tiene acceso al material prima clave, valida todas las condiciones de control de acceso en las teclas etc.

LockSettingsService es el componente del sistema Android responsable de la autenticación de usuario, contraseña y tanto la huella digital. No es parte del almacén de claves, pero es relevante porque muchas operaciones de claves del almacén de claves requieren autenticación de usuario. LockSettingsService interactúa con el Gatekeeper TA y la huella digital TA para obtener tokens de autenticación, que proporciona a la daemon almacén de claves, y que son en última instancia consumida por la aplicación Keymaster TA.

Gatekeeper TA (aplicación de confianza) es otro componente que se ejecuta en el contexto seguro, que es responsable de autenticar las contraseñas de usuario y la generación de tokens de autenticación utiliza para demostrar al Keymaster TA que una autenticación se realizó para un usuario particular en un punto particular en el tiempo.

Huella digital TA (aplicación de confianza) es otro componente que se ejecuta en el contexto seguro que es responsable de la autenticación de huellas dactilares del usuario y la generación de tokens de autenticación utiliza para demostrar al Keymaster TA que una autenticación se realizó para un usuario particular en un punto particular en el tiempo.

Arquitectura

La API de Android Keystore y el Keymaster HAL subyacente proporcionan un conjunto básico pero adecuado de primitivas criptográficas para permitir la implementación de protocolos utilizando claves de acceso controlado y respaldadas por hardware.

Keymaster HAL es una biblioteca de carga dinámica proporcionada por el OEM que utiliza el servicio de almacén de claves para proporcionar servicios criptográficos respaldados por hardware. Para mantener las cosas seguras, las implementaciones de HAL no realizan operaciones sensibles en el espacio del usuario, ni siquiera en el espacio del kernel. Las operaciones confidenciales se delegan a un procesador seguro al que se accede a través de alguna interfaz del kernel. La arquitectura resultante se ve así:

Acceso a Keymaster

Figura 1. El acceso a Keymaster

Dentro de un dispositivo Android, el "cliente" de Keymaster HAL consta de varias capas (por ejemplo, aplicación, marco, demonio de almacén de claves), pero que pueden ignorarse a los efectos de este documento. Esto significa que la API de Keymaster HAL descrita es de bajo nivel, utilizada por componentes internos de la plataforma y no está expuesta a los desarrolladores de aplicaciones. La API de alto nivel se describe en el sitio para desarrolladores de Android .

El propósito de Keymaster HAL no es implementar los algoritmos sensibles a la seguridad, sino solo ordenar y deshacer solicitudes al mundo seguro. El formato de cable está definido por la implementación.

Compatibilidad con versiones anteriores

El Keymaster 1 HAL es completamente incompatible con los HAL lanzados anteriormente, por ejemplo, Keymaster 0.2 y 0.3. Para facilitar la interoperabilidad en dispositivos que ejecutan Android 5.0 y versiones anteriores que se lanzaron con los HAL de Keymaster anteriores, Keystore proporciona un adaptador que implementa el HAL de Keymaster 1 con llamadas a la biblioteca de hardware existente. El resultado no puede proporcionar la gama completa de funciones en Keymaster 1 HAL. En particular, solo admite algoritmos RSA y ECDSA, y el adaptador realiza toda la aplicación de la autorización de claves en el mundo no seguro.

Keymaster 2 simplifica aún más la interfaz HAL mediante la eliminación de los get_supported_* métodos y permitiendo que el finish() método para aceptar la entrada. Esto reduce el número de viajes de ida y vuelta al TEE en los casos en que la entrada está disponible de una vez y simplifica la implementación del descifrado AEAD.

En Android 8.0, Keymaster 3 pasó de la estructura C de estilo antiguo HAL a la interfaz C ++ HAL generada a partir de una definición en el nuevo lenguaje de definición de interfaz de hardware (HIDL). Una aplicación HAL de nuevo estilo es creado por la subclasificación del generada IKeymasterDevice clase y la aplicación de los métodos virtuales puros. Como parte del cambio, muchos de los tipos de argumentos han cambiado, aunque los tipos y métodos tienen una correspondencia uno a uno con los tipos antiguos y los métodos de estructura HAL.

Descripción general de HIDL

El lenguaje de definición de interfaz de hardware (HIDL) proporciona un mecanismo de implementación independiente del lenguaje para especificar interfaces de hardware. Las herramientas HIDL actualmente admiten la generación de interfaces C ++ y Java. Se espera que la mayoría de los implementadores de Trusted Execution Environment (TEE) encuentren las herramientas de C ++ más convenientes, por lo que este documento solo analiza la representación de C ++.

Las interfaces HIDL constan de un conjunto de métodos, expresados ​​como:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Hay varios tipos predefinidos y los HAL pueden definir nuevos tipos enumerados y de estructura. Para más detalles sobre HIDL, consulte la sección de referencia .

Un procedimiento de ejemplo de la Keymaster 3 IKeymasterDevice.hal es:

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

Este es el equivalente de lo siguiente del 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);

En la versión HIDL, el dev se retira argumento, porque es implícito. El params argumento ya no es una estructura que contiene un puntero de referencia a una serie de key_parameter_t objetos, pero un vec (vector) que contiene KeyParameter objetos. Los valores de retorno se enumeran en la " generates cláusula", incluyendo un vector de uint8_t valores para el blob clave.

El método virtual de C ++ generado por el compilador HIDL es:

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

Donde generate_cb es un puntero de función define como:

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

Es decir, generate_cb es una función que toma los valores de retorno que figuran en la cláusula generar. La clase de implementación HAL anula esta generateKey método y llama a la generate_cb puntero de función para devolver el resultado de la operación a la persona que llama. Tenga en cuenta la llamada puntero de función es sincrónico. La persona llama generateKey y generateKey llama a la función de puntero suministrado, que ejecuta hasta su finalización, devolver el control al generateKey aplicación, que luego vuelve a la persona que llama.

Para un ejemplo detallado, ver la implementación por defecto en hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp . La implementación predeterminada proporciona compatibilidad con versiones anteriores para dispositivos con keymaster0, keymaster1 o keymaster2 HALS de estilo antiguo.

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 propio espacio de nombres. Pero para cada regla hay una excepción. Keystore tiene algunos mapas codificados que permiten que ciertos componentes del sistema accedan a otros espacios de nombres. Este es un instrumento muy directo en el sentido de que le da a un componente control total sobre otro espacio de nombres. Y luego está la cuestión de los componentes del proveedor como clientes de Keystore. Actualmente no tenemos forma de establecer un espacio de nombres para los componentes del proveedor, por ejemplo, el suplicante de WPA.

Para adaptarse a los componentes de los proveedores y generalizar el control de acceso sin excepciones codificadas de forma rígida, Keystore 2.0 introduce dominios y espacios de nombres SELinux.

Dominios del almacén de claves

Con los dominios de almacén de claves, podemos desacoplar los espacios de nombres de los UID. Los clientes que acceden a una clave en Keystore deben especificar el dominio, el espacio de nombres y el alias al que desean acceder. Basándonos en esta tupla y la identidad de la persona que llama, podemos determinar a qué clave quiere acceder la persona que llama y si tiene los permisos adecuados.

Introducimos cinco parámetros de dominio que gobiernan 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 aplicación cubre el comportamiento heredado. El SPI del almacén de claves de Java utiliza este dominio de forma predeterminada. Cuando se usa este dominio, se ignora el argumento del espacio de nombres y en su lugar se usa el UID de la persona que llama. El acceso a este dominio está controlado por la etiqueta del almacén de claves a la clase keystore_key en la política de SELinux.
  • DOMAIN_SELINUX : Este dominio indica que el espacio de nombres tiene una etiqueta en la política de SELinux. El parámetro de espacio de nombres se levantó y se traduce en un contexto de destino, y una comprobación de permisos se realiza para el contexto SELinux pidiendo la keystore_key clase. Cuando se ha establecido el permiso para la operación dada, se usa la tupla completa para la búsqueda de claves.
  • DOMAIN_GRANT : El dominio concesión indica que el parámetro de espacio de nombres es un identificador de subvención. El parámetro de alias se ignora. Las comprobaciones de SELinux se realizan cuando se crea la concesión. El control de acceso adicional solo verifica si el UID de la persona que llama coincide con el UID de los beneficiarios de la subvención solicitada.
  • DOMAIN_KEY_ID : Este dominio indica que el parámetro de espacio de nombres es un identificador de clave única. La clave puede haber sido creada con DOMAIN_APP o DOMAIN_SELINUX . La comprobación de permisos se lleva a cabo después de que el domain y el namespace se han cargado desde la base de datos clave de la misma manera como si la mancha ha sido cargado por el dominio, espacio de nombres y alias de tupla. El fundamento del dominio de identificación clave es la continuidad. Al acceder a una clave por alias, las llamadas posteriores pueden operar en diferentes claves, porque una nueva clave puede haber sido generada o importada y vinculada a este alias. Sin embargo, la identificación de la clave nunca cambia. Por lo tanto, cuando se usa una clave por identificación de clave después de que se haya cargado desde la base de datos del almacén de claves usando el alias una vez, uno puede estar seguro de que es la misma clave siempre que la identificación de clave todavía exista. Esta funcionalidad no está expuesta a los desarrolladores de aplicaciones. En su lugar, se utiliza dentro de Android Keystore SPI para proporcionar una experiencia más coherente incluso cuando se utiliza al mismo tiempo de forma insegura.
  • DOMAIN_BLOB : El dominio burbuja indica que la persona que llama gestiona la burbuja por sí mismo. Se utiliza para los clientes que necesitan acceder al almacén de claves antes de que se monte la partición de datos. La burbuja clave está incluido en el blob campo del descriptor clave.

Al utilizar el dominio SELinux, podemos dar acceso a los componentes del proveedor a espacios de nombres de almacén de claves muy específicos que pueden ser compartidos por componentes del sistema, como el cuadro de diálogo de configuración.

Política de SELinux para keystore_key

Etiquetas de espacio de nombres se configuran utilizando el keystore2_key_context archivo.
Cada línea de estos archivos asigna un identificador de espacio de nombres numérico a una etiqueta 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 haber configurado un nuevo espacio de nombres clave de esta manera, podemos darle acceso agregando una política apropiada. Por ejemplo, para permitir wpa_supplicant para obtener y utilizar las teclas en el nuevo espacio de nombres que habría que añadir la siguiente línea al 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 de costumbre. La única diferencia es que se debe especificar el ID del espacio de nombres. Para cargar e importar claves del y al almacén de claves, el identificador de espacio de nombres se especifica mediante el 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 dado, el identificador de espacio de nombres se deben especificar con KeyGenParameterSpec.Builder#setNamespace():

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

Los siguientes archivos de contexto se pueden utilizar para configurar los espacios de nombres SELinux de Keystore 2.0. Cada partición tiene un rango reservado diferente de 10,000 identificadores de espacio de nombres para evitar colisiones.

Dividir Distancia Archivos de configuración
Sistema 0 ... 9999
/system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
Sistema extendido 10,000 ... 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
Vendedor 30.000 ... 39.999
/vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

El cliente solicita la clave al solicitar el dominio SELinux y el espacio de nombres virtual deseada, en este caso "wifi_key" , por su id numérico.

Por encima de eso, se han definido los siguientes espacios de nombres. Si reemplazan reglas especiales, la siguiente tabla indica el UID al que solían corresponder.

ID de espacio de nombres SEPolicy Label UID Descripción
0 su_key N / A Super clave de usuario. Solo se usa para probar en compilaciones userdebug y eng. No es relevante para las compilaciones de los usuarios.
1 shell_key N / A Espacio de nombres disponible para shell. Se usa principalmente para pruebas, pero también se puede usar en compilaciones de usuarios desde la línea de comandos.
100 vold_key N / A Destinado a ser utilizado por vold.
101 odsing_key N / A Utilizado por el demonio de firma en el dispositivo.
102 wifi_key AID_WIFI (1010) Utilizado por el sybsystem Wifi de Android, incluido wpa_supplicant.
120 resume_on_reboot_key AID_SYSTEM (1000) Utilizado por el servidor del sistema de Android para admitir la reanudación al reiniciar.

Vectores de acceso

La clase de SELinux keystore_key ha envejecido un poco y algunos de los permisos, tales como verify o sign han perdido su significado. Aquí es el nuevo conjunto de permisos, keystore2_key , que Keystore 2,0 hará cumplir.

Permiso Sentido
delete Comprobado al eliminar claves del almacén de claves.
get_info Se comprueba cuando se solicitan los metadatos de una clave.
grant La persona que llama necesita este permiso para crear una concesión a la clave en el contexto de destino.
manage_blob La persona que llama puede utilizar DOMAIN_BLOB en el espacio de nombres de SELinux dado, logrando así manchas por sí mismo. Esto es especialmente útil para vold.
rebind Este permiso controla si un alias puede volver a vincularse a una nueva clave. Esto es necesario para la inserción e implica que se eliminará la clave enlazada anteriormente. Es básicamente un permiso de inserción, pero captura mejor la semántica del almacén de claves.
req_forced_op Los clientes con este permiso pueden crear operaciones no podables, y la creación de operaciones nunca falla a menos que todas las ranuras de operación sean ocupadas por operaciones no podables.
update Requerido para actualizar el subcomponente de una clave.
use Se marca al crear una operación Keymint que utiliza el material de la clave, por ejemplo, para firmar, encriptar / descifrar.
use_dev_id Obligatorio al generar información de identificación del dispositivo, como la certificación de identificación del dispositivo.

Además, dividimos a cabo un conjunto de claves permisos no específica del almacén de claves en la clase de seguridad de SELinux keystore2 :

Permiso Sentido
add_auth Requerido por un proveedor de autenticación como Gatekeeper o BiometricsManager para agregar tokens de autenticación.
clear_ns Anteriormente, clear_uid, este permiso permite que un no propietario de un espacio de nombres elimine todas las claves en ese espacio de nombres.
list Requerido por el sistema para enumerar claves por varias propiedades, como propiedad o límite de autorización. Las personas que llaman no requieren este permiso para enumerar sus propios espacios de nombres. Esto se explica por el get_info permiso.
lock Este permiso permite bloquear el almacén de claves, es decir, desalojar la clave maestra, de modo que las claves vinculadas a la autenticación se vuelvan inutilizables e imposibles de crear.
reset Este permiso permite restablecer Keystore a los valores predeterminados de fábrica, eliminando todas las claves que no son vitales para el funcionamiento del sistema operativo Android.
unlock Este permiso es necesario para intentar desbloquear la clave maestra para las claves vinculadas a la autenticación.