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 API, pero que hacen que las claves resultantes sean inseguras o inutilizables. No es necesario que las implementaciones de KeyMint fallen en estos 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 IV o nonces, la generación de claves sin fines (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 sensatas y útiles.
Punto de entrada addRngEntropy
El punto de entrada addRngEntropy
agrega entropía proporcionada por la entidad llamadora al grupo que usa la implementación de KeyMint para generar números aleatorios, para claves y IV.
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 combinación debe controlarse de manera que un atacante que tenga control completo de los bits proporcionados por addRngEntropy
o de los bits generados por hardware (pero no de ambos) no tenga una ventaja significativa para predecir los bits generados a partir del grupo de entropía.
Características clave
Cada uno de los mecanismos (generateKey
, importKey
y importWrappedKey
) que crean claves de KeyMint devuelve 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 devueltas 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 clave, se quitan de las características devueltas para que no sea posible encontrar sus valores examinando el keyblob devuelto. Sin embargo, están vinculados criptográficamente al objeto 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á vinculado criptográficamente a la clave, pero no se puede especificar durante la creación o importación de la clave y nunca se devuelve.
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 devuelven el material de clave generado o importado al llamador como un keyblob, una forma encriptada y autenticada. Cuando Keystore borra el objeto keyblob, la clave desaparece, pero un atacante que haya logrado recuperar el material de la clave podría restablecerla 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 claves 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 el de bloques de memoria protegidos contra repetición (RPMB). Dado que la cantidad de claves que se pueden crear es prácticamente ilimitada 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 rechazar 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 y con los parámetros especificados (según corresponda). Devuelve un nuevo objeto Binder IKeyMintOperation
que se usa para completar la operación. Además, se devuelve un valor de desafío que se usa como parte del token de autenticación en las operaciones autenticadas.
Una implementación de KeyMint admite al menos 16 operaciones simultáneas. El almacén de claves usa hasta 15, lo que deja uno para que vold
lo use para la encriptación de contraseñas. Cuando el almacén de claves tiene 15 operaciones en curso (se llamó a begin()
, pero no a finish
ni a abort
) y recibe una solicitud para comenzar una operación número 16, llama a abort()
en la operación usada menos recientemente para reducir la cantidad de operaciones activas a 14 antes de llamar a begin()
para comenzar la operación solicitada recientemente.
Si se especificaron Tag::APPLICATION_ID
o Tag::APPLICATION_DATA
durante la generación o importación de la clave, 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
devuelve un código de error distinto de ErrorCode::OK
, se anula la operación y se invalida el objeto Binder de la operación. Cualquier uso futuro del objeto devolverá 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 de Tag::USER_SECURE_ID
y no tiene un valor de 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 autorización en el argumento authToken
. Para garantizar que el token sea válido, la implementación de KeyMint debe hacer lo siguiente:
- Verifica la firma HMAC en el token de autorizació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_TYPE
de la clave. - Verifica que el token contenga el valor del desafío para la operación actual en el campo de desafío.
Si no se cumplen estas condiciones, KeyMint devuelve ErrorCode::KEY_USER_NOT_AUTHENTICATED
.
El llamador proporciona el token de autenticación en cada llamada a update()
y finish()
. La implementación solo puede validar el token una vez.