Android 11 admite un esquema de firma compatible con la transmisión con el esquema de firma de APK v4. La firma v4 se basa en el árbol hash de Merkle calculado sobre todos los bytes del APK. El esquema sigue exactamente la estructura del árbol hash de fs-verity (por ejemplo, se agregan ceros al final del salt y del último bloque). Android 11 almacena la firma en un archivo independiente, <apk name>.apk.idsig. Una firma v4 requiere una firma complementaria v2 o v3.
Formato de archivo
Todos los campos numéricos están en formato little endian. Todos los campos ocupan exactamente la cantidad de bytes que indica su sizeof(), sin relleno ni alineación implícitos.
La siguiente struct auxiliar simplifica las definiciones:
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
Contenido del archivo principal:
struct V4Signature {
int32 version; // only version 2 is supported as of now
sized_bytes<int32> hashing_info;
sized_bytes<int32> signing_info;
sized_bytes<int32> merkle_tree; // optional
};hashing_info es el parámetro que se usa para la generación del árbol hash, más el hash raíz:
struct hashing_info.bytes {
int32 hash_algorithm; // only 1 == SHA256 supported
int8 log2_blocksize; // only 12 (block size 4096) supported now
sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max
sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page
};signing_info es la siguiente estructura:
struct signing_info.bytes {
sized_bytes<int32> apk_digest; // used to match with the corresponding APK
sized_bytes<int32> x509_certificate; // ASN.1 DER form
sized_bytes<int32> additional_data; // a free-form binary data blob
sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate
int32 signature_algorithm_id; // see the APK v2 doc for the list
sized_bytes<int32> signature;
};apk_digest se toma del bloque de firma v3 del APK. Si ese bloque no está presente, se toma del bloque v2 (consulta apk_digest).
Para crear y verificar, un código signature debe serializar los siguientes datos en un BLOB binario y pasarlos al algoritmo de firma y verificación como los datos firmados:
struct V4DataForSigning {
int32 size;
int64 file_size; // the size of the file that's been hashed.
hashing_info.hash_algorithm;
hashing_info.log2_blocksize;
hashing_info.salt;
hashing_info.raw_root_hash;
signing_info.apk_digest;
signing_info.x509_certificate;
signing_info.additional_data;
};merkle_tree es el árbol de Merkle completo del APK, calculado como se describe en la documentación de fs-verity.
Productores y consumidores
La herramienta apksigner del SDK de Android genera el archivo de firma v4 si la ejecutas con parámetros predeterminados. Puedes inhabilitar la firma v4 de la misma manera que los otros esquemas de firma. La herramienta también puede verificar si la firma de la versión 4 es válida.
adb espera que el archivo .apk.idsig esté presente junto al APK cuando se ejecute el comando adb install --incremental. adb también usa el archivo IDSIG para intentar una instalación incremental de forma predeterminada y recurre a una instalación normal si falta o no es válido.
Cuando se crea una sesión de instalación, la nueva API de instalación de transmisión en PackageInstaller acepta la firma de v4 despojada como un argumento independiente cuando se agrega un archivo a la sesión.
En este punto, signing_info se pasa a IncFS como un BLOB completo. IncFS extrae el hash raíz del BLOB.
Cuando se confirma la sesión de instalación, PackageManagerService realiza una llamada a ioctl para recuperar el blob signing_info de IncFS, lo analiza y verifica la firma.
El componente Incremental Data Loader transmite la parte del árbol de Merkle de la firma a través de la API nativa del cargador de datos. El comando de shell del servicio package install-incremental acepta el archivo de firma v4 despojado codificado como Base64 como parámetro para cada archivo agregado. El árbol de Merkle correspondiente se debe enviar al stdin del comando.
apk_digest
apk_digest es el primer resumen de contenido disponible en orden:
- V3, bloque de 1 MB, SHA2-512 (
CONTENT_DIGEST_CHUNKED_SHA512) - V3, bloque de 4 KB, SHA2-256 (
CONTENT_DIGEST_VERITY_CHUNKED_SHA256) - V3, bloque de 1 MB, SHA2-256 (
CONTENT_DIGEST_CHUNKED_SHA256) - V2, SHA2-512
- V2, SHA2-256
Consulta secuencia con prefijo de longitud del firmante con prefijo de longitud en el esquema de firma de APK v3.
Validación y pruebas
En la siguiente figura, se ilustra el proceso de validación de APK v4:

Figura 1: Proceso de validación de APK v4.
Valida la implementación con pruebas de unidades de funciones y CTS:
CtsIncrementalInstallHostTestCases/android/cts/hostsidetests/incrementalinstall
Prueba el formato de la firma
Para probar el formato de firma, configura un entorno de compilación y ejecuta las siguientes pruebas manuales:
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
Prueba el formato de firma con el SDK de Android (adb y apksigner)
Sigue este proceso para probar el formato de firma con el SDK de Android:
- Configura un entorno de compilación y asegúrate de haber completado la implementación de IncFS.
- Instala la compilación en un dispositivo físico o emulador de destino.
- Genera u obtén un APK existente y, luego, crea una clave de firma de depuración.
- Firma e instala el APK con el formato de firma v4 desde la carpeta build-tools.
Sign
$ ./apksigner sign --ks debug.keystore game.apk
Instalar
$ ./adb install game.apk
Dónde se pueden encontrar estas pruebas
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java