Verificação completa de transparência do APK dos serviços do sistema do Google

Esta página descreve vários métodos para garantir que o APK instalado no seu dispositivo Android corresponda à declaração feita no modelo do requerente. Isso envolve extrair o APK em questão do dispositivo, verificar a integridade do código e realizar uma prova de inclusão de registro no artefato extraído.

Processo de verificação

Um registro de transparência é implementado com uma árvore Merkle que consiste em hashes. Um nó folha contém dados, e um nó pai contém o hash dos filhos.

Basicamente, duas computações são realizadas na árvore Merkle para verificar a propriedade de evidência de violação dos registros de transparência: a prova de inclusão e a prova de consistência. A primeira prova que o registro inclui uma entrada correspondente a uma versão específica do APK. A entrada de registro inclui um hash, que é o resumo SHA256 do token de assinatura de código na forma de um JSON Web Token (JWT), que pode ser extraído dos APKs correspondentes. A segunda prova que, quando novas entradas são adicionadas à árvore, o novo checkpoint é (criptograficamente) consistente com a versão anterior da árvore.

Para verificar um APK coberto, realize um teste de prova de inclusão com base em um checkpoint testemunhado. Estamos planejando integrar esse registro a uma rede de testemunhas pública usando um protocolo de testemunhas padronizado. Isso vai fornecer um checkpoint testemunhado, que garante a consistência do registro.

Se você quiser se convencer de que o APK no seu dispositivo está de acordo com a declaração feita no modelo do requerente, consulte o texto abaixo.

Prova de inclusão

Um usuário do Android pode verificar se um APK coberto no dispositivo está no registro. Para isso, primeiro extraia o APK e os metadados relevantes e compare o hash raiz recalculado com o hash raiz contido no checkpoint publicado. Se eles corresponderem, o usuário do Android poderá ter certeza de algumas proteções descritas no modelo de ameaça.

Como verificar a inclusão de um APK no registro

Conforme descrito anteriormente, a lista de APKs cobertos no momento pode ser encontrada listada na página de visão geral.

Pré-requisitos de verificação

Antes de prosseguir para verificar se o artefato (firmware ou APK) está de acordo com a declaração, confira se as ferramentas a seguir estão disponíveis em um computador conectado à rede. Dependendo do destino da verificação, talvez você não precise de todas elas.

Golang

A ferramenta de verificação é escrita em Go. Para criá-la, instale o Go 1.24 ou mais recente no site do Go.

Android Debug Bridge

ADB é uma ferramenta que se comunica com um dispositivo Android para inspecionar a imagem ou extrair APKs, disponível no site do SDK Platform Tools do Android .

Verificador de prova de inclusão

O verificador de prova de inclusão é um módulo Go que consulta o registro de transparência e informa se um artefato está incluído no registro. Ele é publicado no repositório android-binary-transparency do GitHub em https://github.com/android/android-binary-transparency/tree/main.

Para clonar o repositório avb do AOSP:

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

Para clonar o repositório android-binary-transparency do GitHub:

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

AAPT2

O AAPT2 (Android Asset Packaging Tool) é uma ferramenta de build usada para compilar e empacotar recursos de um app Android. Ele pode ser encontrado como uma ferramenta independente no Android SDK Build Tools versão 26.0.2 e mais recentes.

bundletool

O bundletool é uma ferramenta usada para criar um Android App Bundle (AAB). Ele também pode ser usado para verificar assinaturas de código APK. Ele pode ser baixado do GitHub.

wget ou curl

wget e curl são ferramentas que podem ser usadas para recuperar ou baixar arquivos da Internet. Confira se uma dessas ferramentas está instalada, porque os scripts de verificação podem depender delas.

Avbtool

avbtool é usado para calcular o resumo do VBMeta das imagens de fábrica e a verificação de binários. Depois de clonar o repositório avb (conforme mostrado na seção Verificador de prova de inclusão ), avbtool.py pode ser encontrado no diretório avb clonado. Adicione esse diretório à variável de ambiente $PATH.

computer:~$ PATH=$PATH:DIRECTORY_CONTAINING_AVBTOOL

Fbpacktool

fbpacktool é um script Python usado para descompactar componentes individuais no bootloader.img. Você não precisa dele se estiver verificando APKs. Essa ferramenta é importante porque permite que avbtool.py descubra as imagens necessárias para a verificação.

Para usar essa ferramenta, baixe os três scripts Python a seguir para o diretório em que avbtool.py está, torne fbpacktool.py executável, e crie um link simbólico chamado fbpacktool para fbpacktool.py para facilitar.

Se você tiver wget:

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

Se você tiver curl:

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 ajuda a realizar várias operações criptográficas usando o terminal no fluxo de trabalho de verificação. Confira se ele está instalado no seu sistema. Você pode verificar no terminal executando o comando a seguir e conferindo se o resultado retornado não está vazio:

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

Criar um payload para verificação

Para verificar se o APK extraído do seu dispositivo está de acordo com nossas declarações, crie um payload de registro com informações derivadas do APK.

Antes de começar, confira se o adb pode ser usado no seu dispositivo ativando a depuração adb no seu dispositivo.

Em seguida, localize onde o APK está instalado no dispositivo. Para fins deste guia, vamos usar o Verificador de Chaves do Sistema Android APK (com.google.android.contactkeys) como nosso exemplo de trabalho.

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

Se o APK do Verificador de Chaves do Sistema Android estiver instalado no seu dispositivo, o comando acima vai retornar um caminho indicando onde ele está instalado. Caso contrário, não haverá saída.

Em seguida, baixe o APK do seu dispositivo Android para o computador em que você está trabalhando usando este comando (o local real e o nome do arquivo APK no seu dispositivo podem 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 extrair e, assim, verificar o nome do pacote do APK que você acabou de baixar, primeiro descompacte o APK, já que ele é um tipo especial de arquivo ZIP.

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

Essa etapa descompacta todos os arquivos que compõem o APK. O nome e a versão do pacote podem ser encontrados no manifesto do APK, que geralmente está em um arquivo chamado AndroidManifest.xml.

No entanto, o arquivo de manifesto extraído está em formato binário, que não é legível para humanos. Para converter o XML binário em um formato legível para humanos, fazemos uso da ferramenta aapt2 instalada anteriormente (conforme necessário para instalação na seção de pré-requisitos).

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'

Na saída acima, podemos ter certeza de que o nome do pacote desse APK é com.google.android.contactkeys e o número da versão (versionCode) é 1413.

Agora, vamos procurar a assinatura de transparência do código no APK. Ele deve ser um arquivo chamado code_transparency_signed.jwt contido na pasta META-INF entre os outros arquivos extraídos do APK.

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

Com essa string de hash, agora temos todas as informações necessárias para montar um payload de registro de acordo com o formato descrito na seção Conteúdo do registro. Neste exemplo, um payload de registro correspondente deve ter esta aparência:

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

Observe também o caractere de nova linha após a versão do pacote.

Você pode salvar o conteúdo em um arquivo, como payload.txt. Isso será útil ao fazer o teste de prova de inclusão mais tarde.

Verificar a autenticidade da assinatura de código do APK

Agora, vamos verificar a autenticidade do token de assinatura de código incorporado no APK. Para isso, usamos o bundletool e a chave pública do par de chaves que foi usado para assiná-lo. Eles são publicados em cada seção dos respectivos APKs. Supondo que você tenha salvo o certificado de chave pública (por exemplo, para o Verificador de Chaves do Sistema Android) em um arquivo chamado signing_cert_pubkey.pem, siga o guia abaixo para realizar a verificação da assinatura de código.

Primeiro, crie um arquivo ZIP e adicione o APK candidato a ele.

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

Agora estamos prontos para usar o comando check-transparency do bundletool para verificar se a assinatura de código incorporada no APK candidato corresponde à publicada.

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.

Confira se a saída do comando acima afirma que a assinatura de transparência do código e a transparência do código foram verificadas. Se não forem, por exemplo, se você receber uma saída como Code transparency verification failed because the provided public key certificate does not match the transparency file, isso significa que a integridade do código do APK em questão pode estar comprometida e você não deve confiar no APK. Verifique se você está verificando com o certificado de chave pública correto. Caso contrário, se tudo estiver correto, isso significa que a autenticidade da assinatura de código foi verificada para o APK que você está validando.

Verificar a inclusão do pacote (prova de inclusão)

Usando o payload que você criou anteriormente, agora você está pronto para testar se o pacote em questão foi incluído no registro de transparência.

Uma ferramenta de prova de inclusão foi publicada no avb repositório dentro do Android Open Source Project. Para executá-la:

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

O verificador usa o checkpoint correspondente e o conteúdo do registro (encontrado no diretório de blocos) para verificar se o payload do APK está no registro de transparência, verificando se ele foi publicado pelo Google.

A saída do comando é gravada em stdout:

  • OK. inclusion check success! se o código do pacote estiver incluído no registro,
  • FAILURE caso contrário.