En esta página, se proporcionan detalles y lineamientos adicionales para ayudar a los implementadores de la capa de abstracción de hardware (HAL) de KeyMint. La documentación principal de la HAL es la especificación de la interfaz AIDL.
Uso inadecuado de la API
Los llamadores pueden crear claves de KeyMint con autorizaciones que son válidas como parámetros de la API, pero que hacen que las claves resultantes sean inseguras o inutilizables. No es necesario que las implementaciones de KeyMint fallen en esos casos ni que emitan un diagnóstico. Las implementaciones no deben diagnosticar el uso de claves demasiado pequeñas, la especificación de parámetros de entrada irrelevantes, la reutilización de IVs o nonces, la generación de claves sin propósitos (por lo tanto, inútiles) y similares.
Es responsabilidad de las apps, el framework y el almacén de claves de Android garantizar que las llamadas a los módulos de KeyMint sean razonables y útiles.
Punto de entrada addRngEntropy
El punto de entrada addRngEntropy agrega entropía proporcionada por el llamador al grupo que usa la implementación de KeyMint para generar números aleatorios, para claves y IVs.
Las implementaciones de KeyMint deben mezclar de forma segura la entropía proporcionada en su grupo, que también debe contener entropía generada internamente a partir de un generador de números aleatorios de hardware. La mezcla debe controlarse de modo que un atacante que tenga control total de los bits proporcionados por addRngEntropy o de los bits generados por hardware (pero no ambos) no tenga una ventaja significativa para predecir los bits generados a partir del grupo de entropía.
Características principales
Cada uno de los mecanismos (generateKey, importKey y importWrappedKey) que crean claves de KeyMint muestra las características de la clave recién creada, divididas de forma adecuada en los niveles de seguridad que aplican cada característica. Las características que se muestran incluyen todos los parámetros especificados para la creación de claves, excepto Tag::APPLICATION_ID y Tag::APPLICATION_DATA.
Si estas etiquetas se incluyen en los parámetros de clave, se quitan de las características que se muestran para que no sea posible encontrar sus valores examinando el keyblob que se muestra. Sin embargo, están vinculadas de forma criptográfica al keyblob, de modo que, si no se proporcionan los valores correctos cuando se usa la clave, el uso falla. Del mismo modo, Tag::ROOT_OF_TRUST está vinculada de forma criptográfica a la clave, pero no se puede especificar durante la creación o importación de claves, y nunca se muestra.
Además de las etiquetas proporcionadas, la implementación de KeyMint también agrega Tag::ORIGIN, que indica la forma en que se creó la clave (KeyOrigin::GENERATED, KeyOrigin::IMPORTED o KeyOrigin::SECURELY_IMPORTED).
Resistencia a la reversión
La resistencia a la reversión se indica con Tag::ROLLBACK_RESISTANCE y significa que, una vez que se borra una clave con deleteKey o deleteAllKeys, el hardware seguro garantiza que nunca más se pueda usar.
Las implementaciones de KeyMint muestran el material de clave generado o importado al llamador como un keyblob, un formulario encriptado y autenticado. Cuando el almacén de claves borra el keyblob, la clave desaparece, pero un atacante que haya logrado recuperar el material de clave podría restablecerlo en el dispositivo.
Una clave es resistente a la reversión si el hardware seguro garantiza que las claves borradas no se puedan restablecer más adelante. Por lo general, esto se hace almacenando metadatos de clave adicionales en una ubicación de confianza que un atacante no puede manipular. En los dispositivos móviles, el mecanismo que se usa para esto suele ser bloques de memoria protegidos contra repetición (RPMB). Debido a que la cantidad de claves que se pueden crear no tiene límites y el almacenamiento de confianza que se usa para la resistencia a la reversión puede tener un tamaño limitado, la implementación puede fallar en las solicitudes para crear claves resistentes a la reversión cuando el almacenamiento está lleno.
begin
El punto de entrada begin() inicia una operación criptográfica con la clave especificada, para el propósito especificado, con los parámetros especificados (según corresponda). Muestra un nuevo objeto Binder IKeyMintOperation que se usa para completar la operación. Además, se muestra un valor de desafío que se usa como parte del token de autenticación en operaciones autenticadas.
Una implementación de KeyMint admite al menos 16 operaciones simultáneas. El almacén de claves usa hasta 15, y deja una para que vold la use para la encriptación de contraseñas. Cuando el almacén de claves tiene 15 operaciones en curso (begin() se
llamó, pero no se llamó a finish ni a abort) y recibe una solicitud para iniciar una 16ª, llama a
abort() en la operación usada más recientemente para reducir la cantidad de
operaciones activas a 14 antes de llamar a begin() para iniciar la
operación recién solicitada.
Si se especificaron Tag::APPLICATION_ID o Tag::APPLICATION_DATA durante la generación o importación de claves, las llamadas a begin() deben incluir esas etiquetas con los valores especificados originalmente en el argumento params de este método.
Manejo de errores
Si un método en un IKeyMintOperation muestra un código de error que no sea ErrorCode::OK, se anula la operación y se invalida el objeto Binder de la operación. Cualquier uso futuro del objeto muestra ErrorCode::INVALID_OPERATION_HANDLE.
Aplicación de la autorización
La aplicación de la autorización de claves se realiza principalmente en begin(). La única excepción es el caso en el que la clave tiene uno o más valores Tag::USER_SECURE_ID y no tiene un valor Tag::AUTH_TIMEOUT.
En este caso, la clave requiere una autorización por operación, y los métodos update() o finish() reciben un token de autenticación en el argumento authToken. Para garantizar que el token sea válido, la implementación de KeyMint hace lo siguiente:
- Verifica la firma HMAC en el token de autenticación.
- Verifica que el token contenga un ID de usuario seguro que coincida con uno asociado a la clave.
- Verifica que el tipo de autenticación del token coincida con el
Tag::USER_AUTH_TYPEde la clave. - Verifica que el token contenga el valor de desafío para la operación actual en el campo de desafío.
Si no se cumplen estas condiciones, KeyMint muestra ErrorCode::KEY_USER_NOT_AUTHENTICATED.
El llamador proporciona el token de autenticación a cada llamada a update() y finish(). La implementación puede validar el token solo una vez.