Verifica completa della trasparenza degli APK dei servizi di sistema di Google

Questa pagina descrive vari metodi per assicurarsi che l'APK installato sul tuo dispositivo Android corrisponda all'affermazione fatta nel modello del richiedente. Ciò comporta l'estrazione dell'APK in questione dal dispositivo, il controllo dell'integrità del codice e l'esecuzione di una prova di inclusione del log sull'artefatto estratto.

Procedura di verifica

Un log di trasparenza viene implementato con una struttura ad albero Merkle costituita da hash. Un nodo foglia contiene dati, mentre un nodo padre contiene l'hash dei relativi nodi secondari.

Fondamentalmente, vengono eseguiti due calcoli sull'albero Merkle per verificare la proprietà antimanomissione dei log di trasparenza: la prova di inclusione e la prova di coerenza. Il primo dimostra che il log include una voce corrispondente a una particolare versione dell'APK. La voce di log include un hash, ovvero il digest SHA256 del token di firma del codice sotto forma di token web JSON (JWT), che può essere ottenuto dagli APK corrispondenti. Quest'ultimo dimostra che quando vengono aggiunte nuove voci all'albero, il nuovo checkpoint è (crittograficamente) coerente con la versione precedente dell'albero.

Per verificare un APK coperto, esegui un test di prova di inclusione basato su un checkpoint testimoniato. Tieni presente che prevediamo di integrare questo log con una rete di testimoni pubblica utilizzando un protocollo di testimonianza standardizzato. In questo modo, viene fornito un punto di controllo verificato, che garantisce la coerenza del log.

Se vuoi verificare che l'APK presente sul tuo dispositivo sia conforme all'affermazione contenuta nel modello del richiedente, consulta la descrizione riportata di seguito.

Prova di inclusione

Un utente Android può verificare che un APK coperto sul proprio dispositivo sia nel log estratto prima l'APK e i relativi metadati, quindi confrontando l'hash radice ricalcolato con l'hash radice contenuto nel checkpoint pubblicato. Se corrispondono, l'utente Android può essere certo di alcune protezioni descritte nel modello di minaccia.

Come verificare l'inclusione di un APK nel log

Come descritto in precedenza, l'elenco degli APK attualmente coperti è disponibile nella pagina Panoramica.

Prerequisiti per la verifica

Prima di procedere con la verifica che l'APK appena estratto dal tuo dispositivo sia conforme alla nostra rivendicazione, dovrai installare i seguenti strumenti da un computer connesso a una rete.

Android Debug Bridge (ADB)

ADB è uno strumento che comunica con un dispositivo Android, disponibile sul sito web degli strumenti della piattaforma SDK Android .

AAPT2

AAPT2 (Android Asset Packaging Tool) è uno strumento di compilazione utilizzato per la compilazione e il packaging delle risorse di un'app per Android. È disponibile come strumento autonomo in Android SDK Build Tools 26.0.2 e versioni successive.

bundletool

bundletool è uno strumento utilizzato per creare un Android App Bundle (AAB). Può essere utilizzato anche per convertire un AAB in APK che possono essere installati sui dispositivi. Può essere scaricato da GitHub.

Inclusion Proof verifier

Si tratta di un modulo Go che abbiamo pubblicato in un repository Git all'interno di Android Open Source Project (AOSP) denominato avb. È in grado di eseguire query sul log di trasparenza degli APK dei servizi di sistema di Google e indica se un pacchetto è incluso nel log. Un esempio di come viene utilizzato è riportato in una sezione successiva.

Per scaricare questo strumento, devi prima clonare il repository avb.

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

Il codice sorgente del verificatore è disponibile in tools/transparency/verify all'interno del repository avb.

Creare un payload per la verifica

Per verificare che l'APK estratto dal dispositivo corrisponda alle nostre rivendicazioni, devi creare un payload di log a partire dalle informazioni derivate dall'APK.

Prima di iniziare, assicurati che adb possa essere utilizzato sul tuo dispositivo attivando il debug adb sul tuo dispositivo.

Quindi, individua la posizione in cui è installato l'APK sul tuo dispositivo. Ai fini di questa guida, utilizzeremo l'APK Android System Key Verifier (com.google.android.contactkeys) come esempio pratico.

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 l'APK di Android System Key Verifier è installato sul tuo dispositivo, il comando precedente restituirà un percorso che indica dove è installato sul dispositivo. Altrimenti, non vedrai alcun output.

Quindi, scarica l'APK dal tuo dispositivo Android sul computer su cui stai lavorando utilizzando questo comando (tieni presente che la posizione effettiva e il nome file dell'APK sul tuo dispositivo potrebbero variare):

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

Per ottenere e quindi verificare il nome del pacchetto dell'APK che hai appena scaricato, devi prima decomprimere l'APK, in quanto un APK è in definitiva un tipo speciale di file ZIP.

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

Questo passaggio decomprime tutti i file che componevano l'APK. Il nome del pacchetto e la versione sono disponibili nel manifest dell'APK, che di solito si trova in un file denominato AndroidManifest.xml.

Tuttavia, il file manifest ottenuto è in formato binario, che non è leggibile. Per convertire l'XML binario in un formato leggibile, utilizziamo lo strumento aapt2 installato in precedenza (come richiesto nella sezione prerequisiti).

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'

Dall'output precedente, ora possiamo essere certi che il nome del pacchetto di questo APK sia com.google.android.contactkeys e che il numero di versione (versionCode) sia 1413.

Ora cercheremo la firma di trasparenza del codice all'interno dell'APK. Deve essere un file denominato code_transparency_signed.jwt contenuto nella cartella META-INF tra gli altri file estratti dall'APK.

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

Con questa stringa hash, ora abbiamo tutte le informazioni necessarie per ricostruire un payload di log in base al formato descritto nella sezione Contenuto del log. In questo esempio, un payload di log corrispondente dovrebbe avere il seguente aspetto:

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

Tieni presente anche il carattere di nuova riga dopo la versione del pacchetto.

Puoi salvare i contenuti in un file, ad esempio payload.txt. Ti sarà utile quando eseguirai il test di inclusione della prova in un secondo momento.

Verificare l'autenticità della firma del codice APK

Ora dobbiamo verificare l'autenticità del token di firma del codice incorporato nell'APK. A questo scopo, utilizziamo bundletool e la chiave pubblica della coppia di chiavi che è stata utilizzata per firmarlo in primo luogo. Vengono pubblicate all'interno di ogni sezione dei rispettivi APK. Supponendo di aver salvato il certificato di chiave pubblica (ad es. per Android System Key Verifier) in un file denominato signing_cert_pubkey.pem, segui la guida riportata di seguito per eseguire la verifica della firma del codice.

Innanzitutto, devi creare un archivio zip e aggiungervi l'APK candidato.

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

Ora siamo pronti a utilizzare il comando check-transparency di bundletool per verificare se la firma del codice incorporata nell'APK candidato corrisponde a quella pubblicata.

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.

Devi assicurarti che l'output del comando precedente indichi che sia la firma di trasparenza del codice sia la trasparenza del codice siano verificate. In caso contrario, ad esempio se visualizzi un output come Code transparency verification failed because the provided public key certificate does not match the transparency file, significa che l'integrità del codice dell'APK in questione potrebbe essere compromessa e non devi considerare attendibile l'APK. Ricorda di verificare che siano confrontati con il certificato della chiave pubblica corretto. In caso contrario, se tutto il resto è verificato, significa che l'autenticità della firma del codice è verificata per l'APK che stai convalidando.

Verifica dell'inclusione del pacchetto (prova di inclusione)

Utilizzando il payload che hai creato in precedenza, ora puoi verificare se il pacchetto in questione è stato incluso nel log di trasparenza.

È stato pubblicato uno strumento di verifica dell'inclusione nel avb repository all'interno dell'Android Open Source Project. Per eseguirlo:

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_system_apk

Il verificatore utilizza il checkpoint corrispondente e i contenuti del log (disponibili nella directory dei riquadri) per verificare che il payload dell'APK si trovi nel log di trasparenza, verificando che sia effettivamente pubblicato da Google.

L'output del comando viene scritto in stdout:

  • OK. inclusion check success! se il codice del pacchetto è incluso nel log,
  • FAILURE se non lo è.