Esquema de firma de APK v4

Android 11 admite un esquema de firma compatible con la transmisión con APK Signature Scheme v4. La firma v4 se basa en el árbol hash de Merkle calculado sobre todos los bytes del APK. Sigue exactamente la estructura del árbol hash fs-verity (por ejemplo, rellenando con ceros la sal y rellenando con ceros el último bloque). Android 11 almacena la firma en un archivo separado, <apk name>.apk.idsig Una firma v4 requiere una firma v2 o v3 complementaria.

Formato de archivo

Todos los campos numéricos están en little endian. Todos los campos ocupan exactamente el número de bytes que su sizeof() , sin relleno implícito ni alineación añadida.

A continuación se muestra una estructura auxiliar para simplificar 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 son los parámetros utilizados para la generación del árbol hash + 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 o, si no está presente, del bloque v2 (ver apk_digest )

Para crear y verificar un código de signature , debe serializar los siguientes datos en un blob binario y pasarlo al algoritmo de firma/verificación como 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;
};
  1. merkle_tree es todo el árbol de Merkle del APK, calculado como se describe en la documentación de fs-verity .

Productores y consumidores

La herramienta SDK de Android apksigner ahora genera el archivo de firma v4 si lo ejecuta con los parámetros predeterminados. La firma v4 se puede deshabilitar de la misma manera que los otros esquemas de firma. También puede verificar si la firma v4 es válida.

adb espera que el archivo .apk.idsig esté presente junto al .apk cuando se ejecuta el comando adb install --incremental
También utilizará el archivo .idsig para probar la instalación incremental de forma predeterminada y volverá a una instalación normal si falta o no es válida.

Cuando se crea una sesión de instalación, la nueva API de instalación de transmisión en PackageInstaller acepta la firma v4 eliminada como argumento independiente al agregar 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 un ioctl para recuperar el blobsigning_info de incfs, lo analiza y verifica la firma.

Se espera que el componente Incremental Data Loader transmita 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 de package install-incremental acepta el archivo de firma v4 eliminado codificado como base64 como un parámetro para cada archivo agregado. El árbol de Merkle correspondiente debe enviarse a la stdin del comando.

apk_digest

apk_digest es el primer resumen de contenido disponible en orden:

  1. V3, bloque de 1 MB, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
  2. V3, bloque de 4 KB, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
  3. V3, bloque de 1 MB, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
  4. V2, SHA2-512,
  5. V2, SHA2-256.

Vea la secuencia con prefijo de longitud de firmas con prefijo de longitud en APK Signature Scheme v3.

proceso de validación de apk v4
Figura 1 : Proceso de validación de APK v4

Validación y prueba

Valide la implementación usando Feature Unit Tests y CTS.

  • CtsIncrementalInstallHostTestCases
    • /android/cts/hostsidetests/instalación incremental

Probando el formato de la firma

Para probar el formato de la firma, configure un entorno de desarrollo y ejecute las siguientes pruebas manuales:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

Prueba de formato de firma con Android SDK (ADB y apksigner)

Para probar el formato de firma con Android SDK, configure un entorno de desarrollo y asegúrese de haber completado la implementación de IncFS . Luego, actualice la compilación en un dispositivo físico o emulador de destino. Debe generar u obtener un APK existente y luego crear una clave de firma de depuración . Finalmente, firme e instale el apk con formato de firma v4 desde la carpeta de herramientas de compilación.

Señal

$ ./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