Android 11 obsługuje schemat podpisywania zgodny ze strumieniowaniem w ramach schematu podpisu plików APK w wersji 4. Podpis w wersji 4 jest oparty na drzewie haszowania Merkle obliczanym na podstawie wszystkich bajtów pliku APK. Jest ona zgodna ze strukturą drzewa skrótów fs-verity (np. wypełnianie zerami zerowymi soli i ostatniego bloku). Android 11 przechowuje podpis w oddzielnym pliku.<apk name>.apk.idsigPodpis w wersji 4 wymaga uzupełniającego podpisu w wersji 2 lub wersji 3.
Format pliku
Wszystkie pola liczbowe są w postaci little-endian. Wszystkie pola zajmują dokładnie tyle bajtów, ile zajmują ich sizeof(), bez dodawania domyślnego wypełnienia ani wyrównania.
Poniżej znajduje się pomocnicza struktura, która upraszcza definicje.
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
Treść głównego 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 haszy + hasz 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 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_digestjest pobierany z bloku podpisywania w wersji 3 pliku APK lub, jeśli go nie ma, z bloku w wersji 2 (patrz apk_digest).
Aby utworzyć i zweryfikować kod signature, musisz zakodować te dane w postaci binarnego bloba i przekazać je algorytmowi 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;
};merkle_treeto cała krotka Merkla pliku APK, obliczona zgodnie z opisem w dokumentacji fs-verity.
Producenci i konsumenci
apksigner Narzędzie Android SDK generuje teraz plik podpisu w wersji 4, jeśli uruchomisz je z parametrami domyślnymi. Podpisywanie w wersji 4 można wyłączyć w taki sam sposób jak inne schematy podpisywania. Może też zweryfikować, czy podpis v4 jest prawidłowy.
adb oczekuje, że plik .apk.idsig będzie obecny obok pliku .apk podczas wykonywania polecenia adb install --incremental
. Domyślnie użyje też pliku .idsig, aby spróbować zainstalować pakiet stopniowo, a jeśli go nie ma lub jest nieprawidłowy, użyje zwykłej instalacji.
Gdy tworzona jest sesja instalacji, nowe API instalacji strumieniowej w PackageInstaller akceptuje odcięty podpis v4 jako oddzielny argument podczas dodawania pliku do sesji.
W tym momencie signing_info jest przekazywany do incfs jako całość. Incfs wyodrębnia z bloba hasz główny.
Gdy sesja instalacji jest zatwierdzana, usługa PackageManagerService wykonuje ioctl, aby pobrać blob signing_info z incfs, przeanalizować go i zweryfikować podpis.
Komponent cząstkowego ładowania danych powinien przesyłać część podpisu w formie drzewa Merkle za pomocą natywnego interfejsu API ładowania danych.
package polecenie service shell install-incremental
akceptuje odchudzony plik podpisu v4 zakodowany w formacie base64 jako parametr każdego dodanego pliku. Odpowiednie drzewo Merkle musi zostać wysłane w ramach polecenia stdin.
apk_digest
apk_digest to pierwszy dostępny zbiór treści w kolejności:
- V3, blok 1 MB, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
- V3, blok 4 KB, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
- V3, blok 1 MB, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
- V2, SHA2-512,
- V2, SHA2-256.
Zobacz sekwencję podpisów z długością w prefiksie w schemacie podpisu pliku APK w wersji 3.
Weryfikacja i testowanie
Sprawdź implementację za pomocą testów jednostek funkcji i CTS.
CtsIncrementalInstallHostTestCases- /android/cts/hostsidetests/incrementalinstall
Testowanie formatu podpisu
Aby przetestować format podpisu, skonfiguruj środowisko programistyczne i uruchom te testy ręczne:
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
Testowanie formatu podpisu za pomocą pakietu Android SDK (ADB i apksigner)
Aby przetestować format podpisu za pomocą pakietu Android SDK, skonfiguruj środowisko programistyczne i upewnij się, że została zakończona implementacja IncFS. Następnie przeprowadź flashowanie kompilacji na docelowym urządzeniu fizycznym lub w emulatorze. Musisz wygenerować lub pobrać istniejący plik APK, a potem utworzyć klucz debugowania. Na koniec podpisz i zainstaluj plik APK za pomocą formatu podpisu w wersji 4 z folderu build-tools.
Podpis
$ ./apksigner sign --ks debug.keystore game.apk
Zainstaluj
$ ./adb install game.apk
Gdzie można znaleźć te testy?
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java