Schemat podpisu APK v4

Android 11 obsługuje schemat podpisywania zgodny z transmisją strumieniową za pomocą schematu podpisu APK w wersji 4. Podpis v4 jest oparty na drzewie skrótów Merkle obliczonym na wszystkich bajtach pliku APK. Dokładnie podąża za strukturą drzewa mieszającego fs-verity (na przykład dopełnianie zerami soli i dopełnianie zerami ostatniego bloku). Android 11 przechowuje podpis w osobnym pliku <apk name>.apk.idsig Podpis w wersji 4 wymaga uzupełniającego podpisu w wersji 2 lub 3 .

Format pliku

Wszystkie pola numeryczne są zapisane w Little Endian. Wszystkie pola zajmują dokładnie tyle bajtów, ile wynosi ich sizeof() , nie dodano żadnego ukrytego dopełnienia ani wyrównania.

Poniżej znajduje się struktura pomocnicza upraszczająca definicje.

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

Główna zawartość pliku:

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 to parametry używane do generowania drzewa skrótów + skrót główny:

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 to następująca struktura:

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 jest pobierany z bloku podpisywania pliku APK v3 lub, jeśli nie istnieje, z bloku v2 (patrz apk_digest )

Aby utworzyć i zweryfikować kod signature , należy serializować następujące dane do binarnego obiektu blob i przekazywać je do algorytmu podpisywania/weryfikacji jako podpisane dane :

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 to całe drzewo Merkle pakietu APK, obliczone zgodnie z opisem w dokumentacji fs-verity .

Producenci i konsumenci

Narzędzie apksigner Android SDK generuje teraz plik podpisu w wersji 4, jeśli uruchomisz go z domyślnymi parametrami. Podpisywanie v4 można wyłączyć w taki sam sposób, jak inne schematy podpisywania. Może także sprawdzić, czy podpis v4 jest ważny.

adb oczekuje, że plik .apk.idsig będzie obecny obok pliku .apk podczas uruchamiania polecenia adb install --incremental
Użyje także pliku .idsig, aby domyślnie spróbować instalacji przyrostowej i powróci do zwykłej instalacji, jeśli jej brakuje lub jest ona nieprawidłowa.

Po utworzeniu sesji instalacyjnej nowy interfejs API instalacji przesyłania strumieniowego w PackageInstaller akceptuje pozbawiony podpisu v4 jako osobny argument podczas dodawania pliku do sesji. W tym momencie signing_info jest przekazywane do incfs jako cały obiekt blob. Incfs wyodrębnia skrót główny z obiektu blob.

Kiedy sesja instalacyjna jest zatwierdzana, PackageManagerService wykonuje ioctl, aby pobrać obiekt BLOB podpisania_info z incfs, analizuje go i weryfikuje podpis.

Oczekuje się, że komponent przyrostowego modułu ładującego dane będzie przesyłać strumieniowo część podpisu drzewa Merkle za pośrednictwem natywnego interfejsu API modułu ładowania danych.
Komenda powłoki usługi package install-incremental akceptuje pozbawiony pliku podpisu v4 zakodowany jako base64 jako parametr dla każdego dodanego pliku. Odpowiednie drzewo Merkle należy wysłać do stdin polecenia.

apk_digest

apk_digest to pierwszy dostępny skrót treści w kolejności:

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

Zobacz sekwencję podpisów z przedrostkiem długości w schemacie podpisów APK v3.

proces sprawdzania poprawności apk v4
Rysunek 1 : Proces sprawdzania poprawności pliku APK v4

Walidacja i testowanie

Zweryfikuj implementację za pomocą testów jednostkowych funkcji i CTS.

  • CtsIncrementalInstallHostTestCases
    • /Android/cts/hostsidetests/inkrementalna instalacja

Testowanie formatu podpisu

Aby przetestować format podpisu, skonfiguruj środowisko programistyczne i uruchom następujące testy ręczne:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

Testowanie formatu podpisu za pomocą zestawu SDK systemu Android (ADB i apksigner)

Aby przetestować format podpisu za pomocą zestawu SDK systemu Android, skonfiguruj środowisko programistyczne i upewnij się, że implementacja IncFS została ukończona. Następnie flashuj kompilację na docelowym urządzeniu fizycznym lub emulatorze. Musisz wygenerować lub uzyskać istniejący plik APK, a następnie utworzyć klucz podpisywania debugowania . Na koniec podpisz i zainstaluj apk w formacie podpisu v4 z folderu build-tools.

Podpisać

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

zainstalować

$ ./adb install game.apk

Gdzie można znaleźć te testy?

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