El kernel de GKI incluye un módulo del kernel de Linux llamado fips140.ko
que cumple con los requisitos de FIPS 140-3 para los módulos de software criptográficos. Este módulo se puede enviar para la certificación FIPS si el producto que ejecuta el kernel de GKI lo requiere.
En particular, se deben cumplir los siguientes requisitos de FIPS 140-3 antes de que se puedan usar las rutinas criptográficas:
- El módulo debe verificar su propia integridad antes de poner a disposición los algoritmos criptográficos.
- El módulo debe ejercitar y verificar sus algoritmos criptográficos aprobados con autoevaluaciones de respuestas conocidas antes de ponerlos a disposición.
Por qué un módulo del kernel independiente
La validación de FIPS 140-3 se basa en la idea de que, una vez que se certifica un módulo basado en software o hardware, nunca se cambia. Si se cambia, se debe volver a certificar. Esto no coincide fácilmente con los procesos de desarrollo de software que se usan actualmente y, como resultado de este requisito, los módulos de software que cumplen con FIPS generalmente se diseñan para enfocarse lo más posible en los componentes criptográficos, de modo que los cambios que no estén relacionados con la criptografía no requieran una reevaluación de la criptografía.
El kernel de GKI está diseñado para actualizarse con regularidad durante toda su vida útil admitida. Esto hace que sea inviable que todo el kernel esté dentro del límite del módulo FIPS, ya que dicho módulo debería volver a certificarse con cada actualización del kernel. Definir el "módulo FIPS" como un subconjunto de la imagen del kernel mitigaría este problema, pero no lo resolvería, ya que el contenido binario del "módulo FIPS" seguiría cambiando con mucha más frecuencia de la necesaria.
Antes de la versión 6.1 del kernel, otra consideración era que el GKI se compilaba con la LTO (optimización en tiempo de vinculación) habilitada, ya que la LTO era un requisito previo para la Integridad del flujo de control, que es una función de seguridad importante.
Por lo tanto, todo el código que está cubierto por los requisitos de FIPS 140-3 se empaqueta en un módulo del kernel independiente fips140.ko
que solo depende de las interfaces estables expuestas por el código fuente del kernel de GKI desde el que se compiló. Esto significa que el módulo se puede usar con diferentes versiones de GKI de la misma generación y que solo se debe actualizar y volver a enviar para la certificación si se corrigieron problemas en el código que contiene el módulo.
Cuándo usar el módulo
El kernel de GKI en sí incluye código que depende de las rutinas criptográficas que también se empaquetan en el módulo del kernel de FIPS 140-3. Por lo tanto, las rutinas criptográficas integradas no se quitan del kernel del GKI, sino que se copian en el módulo. Cuando se carga el módulo, las rutinas criptográficas integradas se anulan del CryptoAPI de Linux y se reemplazan por las que contiene el módulo.
Esto significa que el módulo fips140.ko
es completamente opcional y solo tiene sentido implementarlo si la certificación FIPS 140-3 es un requisito. Además de eso, el módulo no proporciona capacidades adicionales, y cargarlo innecesariamente solo afectará el tiempo de arranque, sin proporcionar ningún beneficio.
Cómo implementar el módulo
El módulo se puede incorporar a la compilación de Android con los siguientes pasos:
- Agrega el nombre del módulo a
BOARD_VENDOR_RAMDISK_KERNEL_MODULES
. Esto hace que el módulo se copie en el ramdisk del proveedor. - Agrega el nombre del módulo a
BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD
. Esto hace que el nombre del módulo se agregue amodules.load
en el destino.modules.load
contiene la lista de módulos que cargainit
cuando se inicia el dispositivo.
La autoverificación de integridad
El módulo de kernel de FIPS 140-3 toma el resumen de HMAC-SHA256 de sus propias secciones .code
y .rodata
en el momento de la carga del módulo y lo compara con el resumen registrado en el módulo. Esto ocurre después de que el cargador de módulos de Linux ya realizó las modificaciones habituales, como el procesamiento de la reubicación de ELF y la aplicación de parches de alternativas para las erratas de la CPU en esas secciones. Se toman los siguientes pasos adicionales para garantizar que el resumen se pueda reproducir correctamente:
- Las reubicaciones de ELF se conservan dentro del módulo para que se puedan aplicar de forma inversa a la entrada del HMAC.
- El módulo revierte los parches de código que realizó el kernel para la pila de llamadas de sombra dinámica. Específicamente, el módulo reemplaza cualquier instrucción que inserte o quite elementos de la pila de llamadas sombra con las instrucciones del código de autenticación de puntero (PAC) que estaban presentes originalmente.
- Todas las demás correcciones de código están inhabilitadas para el módulo, incluidas las claves estáticas y, por lo tanto, los puntos de seguimiento y los hooks del proveedor.
Las autopruebas de respuesta conocida
Todos los algoritmos implementados que estén cubiertos por los requisitos de la FIPS 140-3 deben realizar una autoevaluación de respuesta conocida antes de usarse. Según la Guía de implementación de FIPS 140-3, sección 10.3.A, un solo vector de prueba por algoritmo que use cualquiera de las longitudes de clave admitidas es suficiente para los cifrados, siempre y cuando se prueben tanto la encriptación como la desencriptación.
La CryptoAPI de Linux tiene una noción de prioridades de algoritmos, en la que pueden coexistir varias implementaciones (como una que usa instrucciones criptográficas especiales y una alternativa para las CPU que no implementan esas instrucciones) del mismo algoritmo. Por lo tanto, es necesario probar todas las implementaciones del mismo algoritmo. Esto es necesario porque la CryptoAPI de Linux permite evitar la selección basada en la prioridad y, en su lugar, seleccionar un algoritmo de menor prioridad.
Algoritmos incluidos en el módulo
A continuación, se indican todos los algoritmos incluidos en el módulo de la FIPS 140-3.
Esto se aplica a las ramas del kernel android12-5.10
, android13-5.10
, android13-5.15
, android14-5.15
, android14-6.1
y android15-6.6
, aunque se indican las diferencias entre las versiones del kernel cuando corresponde.
Algoritmo | Implementaciones | Aprobable | Definición |
---|---|---|---|
aes |
aes-generic , aes-arm64 , aes-ce , biblioteca de AES |
Sí | Cifrado en bloque AES simple, sin modo de operación: Se admiten todos los tamaños de clave (128, 192 y 256 bits). Todas las implementaciones, excepto la de la biblioteca, se pueden componer con un modo de operación a través de una plantilla. |
cmac(aes) |
cmac (plantilla), cmac-aes-neon , cmac-aes-ce |
Sí | AES-CMAC: Se admiten todos los tamaños de clave AES. La plantilla cmac se puede componer con cualquier implementación de aes usando cmac(<aes-impl>) . Las otras implementaciones son independientes. |
ecb(aes) |
ecb (plantilla), ecb-aes-neon , ecb-aes-neonbs , ecb-aes-ce |
Sí | AES-ECB: Se admiten todos los tamaños de clave AES. La plantilla ecb se puede componer con cualquier implementación de aes usando ecb(<aes-impl>) . Las otras implementaciones son independientes. |
cbc(aes) |
cbc (plantilla), cbc-aes-neon , cbc-aes-neonbs , cbc-aes-ce |
Sí | AES-CBC: Se admiten todos los tamaños de clave AES. La plantilla cbc se puede componer con cualquier implementación de aes usando ctr(<aes-impl>) . Las otras implementaciones son independientes. |
cts(cbc(aes)) |
cts (plantilla), cts-cbc-aes-neon , cts-cbc-aes-ce |
Sí | AES-CBC-CTS o AES-CBC con robo de texto cifrado: La convención que se usa es CS3 ; los dos últimos bloques de texto cifrado se intercambian de forma incondicional. Se admiten todos los tamaños de clave AES. La plantilla cts se puede componer con cualquier implementación de cbc usando cts(<cbc(aes)-impl>) . Las otras implementaciones son independientes. |
ctr(aes) |
ctr (plantilla), ctr-aes-neon , ctr-aes-neonbs , ctr-aes-ce |
Sí | AES-CTR: Se admiten todos los tamaños de clave AES. La plantilla ctr se puede componer con cualquier implementación de aes usando ctr(<aes-impl>) . Las otras implementaciones son independientes. |
xts(aes) |
xts (plantilla), xts-aes-neon , xts-aes-neonbs , xts-aes-ce |
Sí | AES-XTS: En la versión 6.1 y versiones anteriores del kernel, se admiten todos los tamaños de clave AES. En la versión 6.6 y versiones posteriores del kernel, solo se admiten AES-128 y AES-256. La plantilla xts se puede componer con cualquier implementación de ecb(aes) usando xts(<ecb(aes)-impl>) . Las otras implementaciones son independientes. Todas las implementaciones realizan la verificación de claves débiles que exige el FIPS, es decir, se rechazan las claves XTS cuyas primera y segunda mitad son iguales. |
gcm(aes) |
gcm (plantilla), gcm-aes-ce |
No1 | AES-GCM: Se admiten todos los tamaños de clave AES. Solo se admiten IV de 96 bits. Al igual que con todos los demás modos de AES en este módulo, el llamador es responsable de proporcionar los IV. La plantilla gcm se puede componer con cualquier implementación de ctr(aes) y ghash usando gcm_base(<ctr(aes)-impl>,<ghash-impl>) . Las otras implementaciones son independientes. |
sha1 |
sha1-generic , sha1-ce |
Sí | Función hash criptográfica SHA-1 |
sha224 |
sha224-generic , sha224-arm64 , sha224-ce |
Sí | Función hash criptográfica SHA-224: El código se comparte con SHA-256. |
sha256 |
sha256-generic , sha256-arm64 , sha256-ce , biblioteca SHA-256 |
Sí | Función hash criptográfica SHA-256: Se proporciona una interfaz de biblioteca para SHA-256 además de la interfaz estándar de CryptoAPI. Esta interfaz de biblioteca usa una implementación diferente. |
sha384 |
sha384-generic , sha384-arm64 , sha384-ce |
Sí | Función hash criptográfica SHA-384: El código se comparte con SHA-512. |
sha512 |
sha512-generic , sha512-arm64 , sha512-ce |
Sí | Función hash criptográfica SHA-512 |
sha3-224 |
sha3-224-generic |
Sí | Función hash criptográfica SHA3-224. Solo está presente en la versión 6.6 y posteriores del kernel. |
sha3-256 |
sha3-256-generic |
Sí | Igual que el anterior, pero con una longitud de resumen de 256 bits (SHA3-256). Todas las longitudes de resúmenes usan la misma implementación de Keccak. |
sha3-384 |
sha3-384-generic |
Sí | Igual que el anterior, pero con una longitud de resumen de 384 bits (SHA3-384). Todas las longitudes de resúmenes usan la misma implementación de Keccak. |
sha3-512 |
sha3-512-generic |
Sí | Igual que el anterior, pero con una longitud de resumen de 512 bits (SHA3-512). Todas las longitudes de resúmenes usan la misma implementación de Keccak. |
hmac |
hmac (plantilla) |
Sí | HMAC (código de autenticación de mensajes basado en hash con clave): La plantilla hmac se puede componer con cualquier algoritmo o implementación de SHA usando hmac(<sha-alg>) o hmac(<sha-impl>) . |
stdrng |
drbg_pr_hmac_sha1 , drbg_pr_hmac_sha256 , drbg_pr_hmac_sha384 , drbg_pr_hmac_sha512 |
Sí | HMAC_DRBG se instancia con la función hash con nombre y con la resistencia a la predicción habilitada: Se incluyen las verificaciones de estado. Los usuarios de esta interfaz obtienen sus propias instancias de DRBG. |
stdrng |
drbg_nopr_hmac_sha1 , drbg_nopr_hmac_sha256 , drbg_nopr_hmac_sha384 , drbg_nopr_hmac_sha512 |
Sí | Son los mismos que los algoritmos de drbg_pr_* , pero con la resistencia a la predicción inhabilitada. El código se comparte con la variante resistente a la predicción. En la versión 5.10 del kernel, el DRBG de mayor prioridad es drbg_nopr_hmac_sha256 . En la versión 5.15 del kernel y versiones posteriores, es drbg_pr_hmac_sha512 . |
jitterentropy_rng |
jitterentropy_rng |
No | El Jitter RNG, ya sea la versión 2.2.0 (kernel 6.1 y versiones anteriores) o la versión 3.4.0 (kernel 6.6 y versiones posteriores) Los usuarios de esta interfaz obtienen sus propias instancias de RNG de Jitter. No reutilizan las instancias que usan los DRBG. |
xcbc(aes) |
xcbc-aes-neon , xcbc-aes-ce |
No | |
xctr(aes) |
xctr-aes-neon , xctr-aes-ce |
No | Solo está presente en la versión 5.15 y versiones posteriores del kernel. |
cbcmac(aes) |
cbcmac-aes-neon , cbcmac-aes-ce |
No | |
essiv(cbc(aes),sha256) |
essiv-cbc-aes-sha256-neon , essiv-cbc-aes-sha256-ce |
No |
Compila el módulo desde el código fuente
En el caso de Android 14 y versiones posteriores (incluido android-mainline
), compila el módulo fips140.ko
desde la fuente con los siguientes comandos.
Compila con Bazel:
tools/bazel run //common:fips140_dist
Compila con
build.sh
(heredado):BUILD_CONFIG=common/build.config.gki.aarch64.fips140 build/build.sh
Estos comandos realizan una compilación completa, incluido el kernel y el módulo fips140.ko
con el contenido del resumen HMAC-SHA256 incorporado.
Orientación para usuarios finales
Orientación del oficial criptográfico
Para operar el módulo del kernel, el sistema operativo debe restringirse a un solo modo de operación. Android lo controla automáticamente con el hardware de administración de memoria del procesador.
El módulo del kernel no se puede instalar por separado; se incluye como parte del firmware del dispositivo y se carga automáticamente durante el inicio. Solo funciona en un modo de operación aprobado.
El oficial de criptografía puede hacer que se ejecuten las autocomprobaciones en cualquier momento reiniciando el dispositivo.
Orientación para el usuario
Los usuarios del módulo del kernel son otros componentes del kernel que necesitan usar algoritmos criptográficos. El módulo del kernel no proporciona lógica adicional en el uso de los algoritmos ni almacena ningún parámetro más allá del tiempo necesario para realizar una operación criptográfica.
El uso de los algoritmos para fines de cumplimiento de FIPS se limita a los algoritmos aprobados. Para satisfacer el requisito de "indicador de servicio" de la FIPS 140-3, el módulo proporciona una función fips140_is_approved_service
que indica si un algoritmo está aprobado.
Errores de la autoprueba
En caso de que falle la autocomprobación, el módulo del kernel hace que este entre en pánico y el dispositivo no continúa con el arranque. Si el reinicio del dispositivo no resuelve el problema, el dispositivo debe iniciarse en modo de recuperación para corregir el problema volviendo a escribir la memoria flash del dispositivo.
-
Se espera que las implementaciones de AES-GCM del módulo puedan estar "aprobadas por el algoritmo", pero no "aprobadas por el módulo". Se pueden validar, pero AES-GCM no se puede considerar un algoritmo aprobado desde el punto de vista de un módulo FIPS. Esto se debe a que los requisitos del módulo FIPS para GCM son incompatibles con las implementaciones de GCM que no generan sus propios IV. ↩