Schema di firma dell'APK v4

Android 11 supporta uno schema di firma compatibile con lo streaming con lo schema di firma dell'APK v4. La firma v4 si basa sull'albero hash di Merkle calcolato su tutti i byte dell'APK. Segue esattamente la struttura dell'albero hash fs-verity (ad esempio, il padding con zeri del sale e dell'ultimo blocco). Android 11 memorizza la firma in un file separato. <apk name>.apk.idsigUna firma v4 richiede una firma v2 o v3 complementare.

Formato file

Tutti i campi numerici sono in little endian. Tutti i campi occupano esattamente il numero di byte corrispondente al loro sizeof(), senza spaziatura aggiuntiva o allineamento implicito.

Di seguito è riportata una struct di supporto per semplificare le definizioni.

template <class SizeT>
struct sized_bytes {
        SizeT size;
        byte bytes[size];
};

Contenuti del file principale:

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 sono i parametri utilizzati per la generazione dell'albero di hash + l'hash principale:

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 è la seguente struct:

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 viene preso dal blocco di firma v3 dell'APK o, se non è presente, dal blocco v2 (vedi apk_digest)

Per creare e verificare un codice signature, devi serializzare i seguenti dati in un blob binario e passarli all'algoritmo di firma / verifica come dati firmati:

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 è l'intero albero Merkle dell'APK, calcolato come descritto nella documentazione di fs-verity.

Produttori e consumatori

apksigner Lo strumento SDK Android ora genera il file della firma v4 se lo esegui con i parametri predefiniti. La firma v4 può essere disattivata nello stesso modo degli altri schemi di firma. Può anche verificare se la firma V4 è valida.

adb si aspetta che il file .apk.idsig sia presente accanto al file .apk quando viene eseguito il comando adb install --incremental
. Inoltre, utilizzerà il file .idsig per provare l'installazione incrementale per impostazione predefinita e tornerà a un'installazione normale se il file non è presente o non è valido.

Quando viene creata una sessione di installazione, la nuova API di installazione in streaming in PackageInstaller accetta la firma v4 asportata come argomento separato quando viene aggiunto un file alla sessione. A questo punto, signing_info viene passato a incfs come intero blob. Incfs estrae l'hash principale dal blob.

Quando la sessione di installazione viene eseguita, PackageManagerService esegue un ioctl per recuperare il blob signing_info da incfs, lo analizza e ne verifica la firma.

Il componente Incremental Data Loader dovrebbe trasmettere in streaming la parte della firma dell'albero Merkle tramite l'API nativa del caricatore di dati.Il comando
package service shell install-incremental accetta il file della firma v4 senza dati sensibili codificato in base64 come parametro per ogni file aggiunto. L'albero Merkle corrispondente deve essere inviato in stdin del comando.

apk_digest

apk_digest è il primo digest dei contenuti disponibile in ordine:

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

Consulta la sequenza con prefisso di lunghezza di firme con prefisso di lunghezza nello schema di firma dell'APK v3.

procedura di convalida dell&#39;apk v4
Figura 1: procedura di convalida dell'APK v4

Convalida e test

Convalida l'implementazione utilizzando i test delle unità di funzionalità e CTS.

  • CtsIncrementalInstallHostTestCases
    • /android/cts/hostsidetests/incrementalinstall

Testare il formato della firma

Per testare il formato della firma, configura un ambiente di sviluppo ed esegui i seguenti test manuali:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

Testare il formato della firma con l'SDK Android (ADB e apksigner)

Per testare il formato della firma con l'SDK Android, configura un ambiente di sviluppo e assicurati di aver completato l'implementazione di IncFS. Dopodiché esegui il flashing della build su un dispositivo fisico o un emulatore di destinazione. Devi generare o ottenere un APK esistente e poi creare una chiave di firma di debug. Infine, firma e installa l'APK con il formato di firma v4 dalla cartella build-tools.

Firma

$ ./apksigner sign --ks debug.keystore game.apk

Installa

$ ./adb install game.apk

Dove posso trovare questi test?

/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java