Verificación completa de transparencia del APK de los servicios del sistema de Google

En esta página, se describen varios métodos para garantizar que el APK instalado en tu dispositivo Android corresponda al reclamo que se realizó en el modelo de solicitante. Esto implica extraer el APK en cuestión de tu dispositivo, verificar la integridad de su código y realizar una prueba de inclusión de registros en el artefacto extraído.

Proceso de verificación

Se implementa un registro de transparencia con un árbol Merkle que consta de hashes. Un nodo hoja contiene datos, y un nodo principal contiene el hash de sus nodos secundarios.

Básicamente, se realizan dos cálculos en el árbol de Merkle para verificar la propiedad de evidencia de manipulación de los registros de transparencia: la prueba de inclusión y la prueba de coherencia. El primero demuestra que el registro incluye una entrada correspondiente a una versión de APK en particular. La entrada de registro incluye un hash, que es el resumen SHA256 del token de firma de código en forma de un token web JSON (JWT), que se puede obtener de los APKs correspondientes. Este último demuestra que, cuando se agregan entradas nuevas al árbol, el nuevo punto de control es (criptográficamente) coherente con la versión anterior del árbol.

Para verificar un APK cubierto, realiza una prueba de prueba de inclusión basada en un punto de control presenciado. Ten en cuenta que planeamos integrar este registro con una red de testigos pública a través de un protocolo de testigos estandarizado. Esto proporcionará un punto de control certificado, lo que garantiza la coherencia del registro.

Si quieres convencerte de que el APK que tienes en tu dispositivo cumple con la afirmación que se hace en el modelo del reclamante, consulta el siguiente texto.

Prueba de inclusión

Un usuario de Android puede verificar que un APK cubierto en su dispositivo esté en el registro. Para ello, primero debe extraer el APK y sus metadatos pertinentes, y, luego, comparar el hash raíz recalculado con el hash raíz que se incluye en el punto de control publicado. Si coinciden, el usuario de Android puede tener la certeza de que cuenta con algunas de las protecciones que se describen en el Modelo de amenazas.

Cómo verificar la inclusión de un APK en el registro

Como se describió anteriormente, la lista de APKs que se incluyen actualmente se encuentra en la página de descripción general.

Requisitos previos a la verificación

Antes de verificar que el artefacto (firmware o APK) cumpla con la declaración, asegúrate de que las siguientes herramientas estén disponibles en una computadora conectada a la red. Según el objetivo de la verificación, es posible que no necesites todos los documentos.

Golang

La herramienta de verificación está escrita en Go. Para compilarla, instala Go 1.24 o una versión posterior desde el sitio de Go.

Android Debug Bridge (ADB)

ADB es una herramienta que se comunica con un dispositivo Android para inspeccionar la imagen o extraer APKs, disponible en el sitio web de las Herramientas de la plataforma del SDK de Android.

Verificador de prueba de inclusión

El verificador de prueba de inclusión es un módulo de Go que consulta el registro de transparencia y muestra si un artefacto se incluye en el registro. Se publica en el repositorio de GitHub de android-binary-transparency en https://github.com/android/android-binary-transparency/tree/main.

Para clonar el repositorio avb del AOSP, haz lo siguiente:

computer:~$ git clone https://android.googlesource.com/platform/external/avb

Para clonar el repositorio de GitHub android-binary-transparency, haz lo siguiente:

computer:~$ git clone https://github.com/android/android-binary-transparency

AAPT2

AAPT2 (Android Asset Packaging Tool) es una herramienta de compilación que se usa para compilar y empaquetar los recursos de una app para Android. Se puede encontrar como una herramienta independiente en la versión 26.0.2 y posteriores de Android SDK Build Tools.

bundletool

bundletool es una herramienta que se usa para compilar un Android App Bundle (AAB). También se puede usar para verificar las firmas de código de APK. Se puede descargar desde GitHub.

wget o curl

wget y curl son herramientas que se pueden usar para recuperar o descargar archivos de Internet. Asegúrate de tener instalada alguna de estas herramientas, ya que los scripts de verificación pueden depender de ellas.

Avbtool

avbtool se usa para calcular el resumen de VBMeta de las imágenes de fábrica y la verificación de los archivos binarios. Después de clonar el repositorio avb (como se muestra en la sección del verificador de prueba de inclusión), se puede encontrar avbtool.py dentro del directorio avb clonado. Debes agregar este directorio a tu variable de entorno $PATH.

computer:~$ PATH=$PATH:DIRECTORY_CONTAINING_AVBTOOL

Fbpacktool

fbpacktool es una secuencia de comandos de Python que se usa para desempaquetar componentes individuales en bootloader.img de Pixel. No necesitas esto si verificas APKs. Esta herramienta es importante porque permite que avbtool.py descubra las imágenes necesarias para la verificación.

Para usar esta herramienta, debes descargar las siguientes tres secuencias de comandos de Python en el directorio en el que se encuentra tu avbtool.py, hacer que fbpacktool.py sea ejecutable y crear un vínculo simbólico llamado fbpacktool a fbpacktool.py para mayor comodidad.

Si tienes wget, haz lo siguiente:

computer:dir_to_avbtool$ wget https://source.android.com/devices/bootloader/tools/pixel/fw_unpack/fbpacktool.py \
https://source.android.com/devices/bootloader/tools/pixel/fw_unpack/fbpack.py \
https://source.android.com/devices/bootloader/tools/pixel/fw_unpack/packedstruct.py
computer:dir_to_avbtool$ chmod +x fbpacktool.py
computer:dir_to_avbtool$ ln -s fbpacktool.py fbpacktool

Si tienes curl, haz lo siguiente:

computer:dir_to_avbtool$ curl -O https://source.android.com/devices/bootloader/tools/pixel/fw_unpack/fbpacktool.py
computer:dir_to_avbtool$ curl -O https://source.android.com/devices/bootloader/tools/pixel/fw_unpack/fbpack.py
computer:dir_to_avbtool$ curl -O https://source.android.com/devices/bootloader/tools/pixel/fw_unpack/packedstruct.py
computer:dir_to_avbtool$ chmod +x fbpacktool.py
computer:dir_to_avbtool$ ln -s fbpacktool.py fbpacktool

OpenSSL

openssl ayuda a realizar varias operaciones criptográficas con la terminal en el flujo de trabajo de verificación. Asegúrate de que esté instalado en tu sistema. Para verificarlo en la terminal, ejecuta el siguiente comando y asegúrate de que el resultado que se muestra no esté vacío:

computer:~$ which openssl
/usr/bin/openssl

Cómo construir una carga útil para la verificación

Para verificar que el APK que extrajiste de tu dispositivo según nuestras afirmaciones, debes crear una carga útil de registro a partir de la información derivada del APK.

Antes de comenzar, asegúrate de que se pueda usar adb en tu dispositivo habilitando la depuración de adb en él.

Luego, busca dónde se instaló el APK en tu dispositivo. Para los fines de esta guía, usaremos el APK de Android System Key Verifier (com.google.android.contactkeys) como nuestro ejemplo de trabajo.

computer:~$ adb shell pm list packages -f | grep contactkeys
package:/data/app/~~i5WYSO4PuAAv798-eHdM7A==/com.google.android.contactkeys-PQCKjnn7xDqjeVhcUDibBA==/base.apk=com.google.android.contactkeys

Si el APK de Android System Key Verifier está instalado en tu dispositivo, el comando anterior devolverá una ruta de acceso que indica dónde está instalado en tu dispositivo. De lo contrario, no verás ningún resultado.

Luego, descarga el APK de tu dispositivo Android en la computadora en la que estás trabajando con este comando (ten en cuenta que la ubicación real y el nombre de archivo del APK en tu dispositivo pueden variar):

computer:~$ mkdir -p /tmp/testdir && cd /tmp/testdir
computer:/tmp/testdir$ adb pull /data/app/~~i5WYSO4PuAAv798-eHdM7A==/com.google.android.contactkeys-PQCKjnn7xDqjeVhcUDibBA==/base.apk ./contactkeys_candidate.apk

Para obtener y, de este modo, verificar el nombre del paquete del APK que acabas de descargar, primero deberás descomprimirlo, ya que, en última instancia, un APK es un tipo especial de archivo ZIP.

computer:/tmp/testdir$ mkdir extracted && unzip contactkeys_candidate.apk -d extracted/

En este paso, se descomprimen todos los archivos que componen el APK. El nombre y la versión del paquete se pueden encontrar en el manifiesto del APK, que suele estar en un archivo llamado AndroidManifest.xml.

Sin embargo, el archivo de manifiesto obtenido está en formato binario, que no es legible para los humanos. Para convertir el XML binario en un formato legible, usamos la herramienta aapt2 que instalamos antes (como se requiere en la sección de requisitos previos).

computer:/tmp/testdir$ aapt2 dump badging ./contactkeys_candidate.apk
package: name='com.google.android.contactkeys' versionCode='7805' versionName='1.219.791156583' platformBuildVersionName='Baklava' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='Baklava'

En el resultado anterior, ahora podemos confirmar que el nombre del paquete de este APK es com.google.android.contactkeys y el número de versión (versionCode) es 1413.

Ahora, buscaremos la firma de transparencia de código dentro del APK. Debe ser un archivo llamado code_transparency_signed.jwt que se encuentre dentro de la carpeta META-INF entre los demás archivos extraídos del APK.

computer:/tmp/testdir$ sha256sum extracted/META-INF/code_transparency_signed.jwt
1779a2aee029112c2c9bfc9390b9678f3e5f4595b39705e8528dd522e8042f11  code_transparency_signed.jwt

Con esta cadena hash, ahora tenemos toda la información necesaria para armar una carga útil de registro según el formato que se describe en la sección Contenido del registro. En este ejemplo, una carga útil de registro correspondiente debería verse de la siguiente manera:

1779a2aee029112c2c9bfc9390b9678f3e5f4595b39705e8528dd522e8042f11
SHA256(Signed Code Transparency JWT)
com.google.android.contactkeys
1143

También observa el carácter de nueva línea después de la versión del paquete.

Puedes guardar el contenido en un archivo, como payload.txt. Esto será útil cuando realices la prueba de inclusión más adelante.

Cómo verificar la autenticidad de la firma de código del APK

Ahora, debemos verificar la autenticidad del token de firma de código incorporado en el APK. Para ello, usamos bundletool y la clave pública del par de claves que se usó para firmarlo en primer lugar. Se publican en cada sección de los APKs respectivos. Suponiendo que guardaste el certificado de clave pública (p.ej., para Android System Key Verifier) en un archivo llamado signing_cert_pubkey.pem, sigue la siguiente guía para realizar la verificación de la firma de código.

Primero, debes crear un archivo ZIP y agregar el APK candidato a él.

computer:/tmp/testdir$ zip -u test.zip contactkeys_candidate.apk
        zip warning: test.zip not found or empty
  adding: contactkeys_candidate.apk (deflated 58%)

computer:/tmp/testdir$ file test.zip
test.zip: Zip archive data, at least v2.0 to extract, compression method=deflate

Ahora podemos usar el comando check-transparency de bundletool para verificar si la firma de código integrada en el APK candidato coincide con la que se publicó.

computer:/tmp/testdir$ java -jar BUNDLETOOL_INSTALL_PATH/bundletool-all-version.jar check-transparency \
  --mode=apk \
  --apk-zip=test.zip \
  --transparency-key-certificate=signing_cert_pubkey.pem

APK signature is valid. SHA-256 fingerprint of the apk signing key certificate (must be compared with the developer's public key manually): D9 E1 73 5B 2A 39 51 27 3A 87 35 B7 66 9E F1 9E F5 3A F1 C1 27 5C BA 31 39 3C 18 40 8B 03 79 D0
Code transparency signature verified for the provided code transparency key certificate.
Code transparency verified: code related file contents match the code transparency file.

Debes asegurarte de que el resultado del comando anterior indique que se verificaron tanto la firma de transparencia del código como la transparencia del código. Si no es así, por ejemplo, si ves un resultado como Code transparency verification failed because the provided public key certificate does not match the transparency file, significa que la integridad del código del APK en cuestión podría estar comprometida y no debes confiar en él. Recuerda verificar que los estés comparando con el certificado de clave pública correcto. De lo contrario, si todo lo demás está bien, esto significa que se verificó la autenticidad de la firma del código para el APK que estás validando.

Verificación de la inclusión del paquete (prueba de inclusión)

Con la carga útil que creaste anteriormente, ya puedes probar si el paquete en cuestión se incluyó en el registro de transparencia.

Se publicó una herramienta de prueba de inclusión en el repositorio de avb dentro del Proyecto de código abierto de Android. Para ejecutarlo, haz lo siguiente:

computer:external/avb/tools/transparency/verify$ PAYLOAD_PATH=PATH_TO_PAYLOAD_DIR/payload.txt
computer:external/avb/tools/transparency/verify$ go build cmd/verifier/verifier.go
computer:external/avb/tools/transparency/verify$ ./verifier --payload_path=${PAYLOAD_PATH} --log_type=google_1p_code

El verificador usa el punto de control correspondiente y el contenido del registro (que se encuentra en el directorio de segmentos) para verificar que la carga útil del APK esté en el registro de transparencia y, así, confirmar que Google lo publicó.

El resultado del comando se escribe en stdout:

  • OK. inclusion check success! si el código del paquete se incluye en el registro
  • FAILURE si no lo es.