Obrazy systemu operacyjnego Android korzystają z podpisów kryptograficznych w dwóch miejscach:
- Każdy plik
.apk
znajdujący się w obrazie musi być podpisany. Menedżer pakietów Androida używa podpisu.apk
na dwa sposoby:- W przypadku wymiany aplikacji, aby uzyskać dostęp do danych starej aplikacji, należy ją podpisać tym samym kluczem, co stara aplikacja. Dotyczy to zarówno aktualizacji aplikacji użytkownika poprzez zastąpienie
.apk
, jak i zastąpienia aplikacji systemowej nowszą wersją zainstalowaną w/data
. - Jeśli dwie lub więcej aplikacji chce współdzielić identyfikator użytkownika (aby mogły udostępniać dane itp.), muszą być podpisane tym samym kluczem.
- W przypadku wymiany aplikacji, aby uzyskać dostęp do danych starej aplikacji, należy ją podpisać tym samym kluczem, co stara aplikacja. Dotyczy to zarówno aktualizacji aplikacji użytkownika poprzez zastąpienie
- Pakiety aktualizacji OTA muszą być podpisane jednym z kluczy oczekiwanych przez system, w przeciwnym razie proces instalacji je odrzuci.
Zwolnij klawisze
Drzewo Androida zawiera klucze testowe w build/target/product/security
. Zbudowanie obrazu systemu operacyjnego Android za pomocą make
spowoduje podpisanie wszystkich plików .apk
przy użyciu kluczy testowych. Ponieważ klucze testowe są publicznie znane, każdy może podpisywać własne pliki .apk tymi samymi kluczami, co może pozwolić im na zastępowanie lub przejmowanie aplikacji systemowych wbudowanych w obraz systemu operacyjnego. Z tego powodu niezwykle ważne jest podpisanie każdego publicznie udostępnionego lub wdrożonego obrazu systemu operacyjnego Android specjalnym zestawem kluczy wersji , do których tylko Ty masz dostęp.
Aby wygenerować własny, unikalny zestaw kluczy wydania, uruchom następujące polecenia z katalogu głównego drzewa Androida:
subject='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
mkdir ~/.android-certs
for x in releasekey platform shared media networkstack; do \ ./development/tools/make_key ~/.android-certs/$x "$subject"; \ done
$subject
należy zmienić, aby odzwierciedlał informacje o Twojej organizacji. Możesz użyć dowolnego katalogu, ale pamiętaj, aby wybrać lokalizację, która ma kopię zapasową i jest bezpieczna. Niektórzy dostawcy decydują się na szyfrowanie swojego klucza prywatnego silnym hasłem i przechowywanie zaszyfrowanego klucza w kontroli źródła; inni przechowują klucze zwalniające w zupełnie innym miejscu, na przykład na komputerze z otwartą przestrzenią powietrzną.
Aby wygenerować obraz wydania, użyj:
make dist
sign_target_files_apks \ -o \ # explained in the next section --default_key_mappings ~/.android-certs out/dist/*-target_files-*.zip \ signed-target_files.zip
sign_target_files_apks
pobiera plik .zip
plików docelowych jako dane wejściowe i tworzy nowy plik .zip
plików docelowych, w którym wszystkie pliki .apk
zostały podpisane nowymi kluczami. Nowo podpisane obrazy można znaleźć w zakładce IMAGES/
w signed-target_files.zip
.
Podpisz pakiety OTA
Podpisany plik zip plików docelowych można przekonwertować na podpisany plik zip aktualizacji OTA, korzystając z następującej procedury:
ota_from_target_files \
-k (--package_key)
signed-target_files.zip \
signed-ota_update.zip
Podpisy i ładowanie boczne
Ładowanie boczne nie omija normalnego mechanizmu weryfikacji podpisu pakietu podczas odzyskiwania — przed zainstalowaniem pakietu odzyskiwanie sprawdza, czy jest on podpisany jednym z kluczy prywatnych pasujących do kluczy publicznych przechowywanych na partycji odzyskiwania, tak samo jak w przypadku pakietu dostarczonego przez -powietrze.
Pakiety aktualizacji otrzymane z systemu głównego są zazwyczaj weryfikowane dwukrotnie: raz przez system główny przy użyciu metody RecoverySystem.verifyPackage()
w interfejsie API systemu Android, a następnie ponownie poprzez odzyskiwanie. API RecoverySystem sprawdza podpis względem kluczy publicznych przechowywanych w systemie głównym, w pliku /system/etc/security/otacerts.zip
(domyślnie). Odzyskiwanie sprawdza podpis względem kluczy publicznych przechowywanych na dysku RAM partycji odzyskiwania, w pliku /res/keys
.
Domyślnie plik .zip
plików docelowych utworzony przez kompilację ustawia certyfikat OTA tak, aby pasował do klucza testowego. Na udostępnionym obrazie należy użyć innego certyfikatu, aby urządzenia mogły zweryfikować autentyczność pakietu aktualizacji. Przekazanie flagi -o
do sign_target_files_apks
, jak pokazano w poprzedniej sekcji, zastępuje certyfikat klucza testowego certyfikatem klucza wydania z katalogu certyfikatów.
Zwykle obraz systemu i obraz odzyskiwania przechowują ten sam zestaw kluczy publicznych OTA. Dodając klucz tylko do zestawu kluczy odzyskiwania, możliwe jest podpisywanie pakietów, które można zainstalować tylko poprzez ładowanie boczne (zakładając, że mechanizm pobierania aktualizacji głównego systemu poprawnie przeprowadza weryfikację względem pliku otacerts.zip). Możesz określić dodatkowe klucze, które mają być uwzględniane tylko podczas odzyskiwania, ustawiając zmienną PRODUCT_EXTRA_RECOVERY_KEYS w definicji produktu:
vendor/yoyodyne/tardis/products/tardis.mk
[...] PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
Obejmuje to vendor/yoyodyne/security/tardis/sideload.x509.pem
w pliku kluczy odzyskiwania, aby mógł zainstalować podpisane nim pakiety. Dodatkowy klucz nie jest jednak zawarty w otacerts.zip, dlatego systemy poprawnie weryfikujące pobrane pakiety nie wywołują odzyskiwania pakietów podpisanych tym kluczem.
Certyfikaty i klucze prywatne
Każdy klucz występuje w dwóch plikach: certyfikat z rozszerzeniem .x509.pem i klucz prywatny z rozszerzeniem .pk8. Klucz prywatny należy zachować w tajemnicy i jest on niezbędny do podpisania przesyłki. Sam klucz może być chroniony hasłem. Certyfikat natomiast zawiera tylko publiczną połowę klucza, dzięki czemu może być szeroko rozpowszechniany. Służy do sprawdzenia, czy paczka została podpisana odpowiednim kluczem prywatnym.
Standardowa kompilacja Androida wykorzystuje pięć kluczy, z których wszystkie znajdują się w build/target/product/security
:
- klucz testowy
- Ogólny klucz domyślny dla pakietów, które w inny sposób nie określają klucza.
- platforma
- Klucz testowy dla pakietów będących częścią platformy podstawowej.
- wspólny
- Klucz testowy dla rzeczy udostępnianych w procesie domu/kontaktów.
- głoska bezdźwięczna
- Klucz testowy dla pakietów będących częścią systemu multimediów/pobierania.
Poszczególne pakiety określają jeden z tych kluczy, ustawiając LOCAL_CERTIFICATE w swoim pliku Android.mk. (testkey jest używany, jeśli ta zmienna nie jest ustawiona.) Możesz także określić zupełnie inny klucz poprzez nazwę ścieżki, np.:
device/yoyodyne/apps/SpecialApp/Android.mk
[...] LOCAL_CERTIFICATE := device/yoyodyne/security/special
Teraz kompilacja używa klucza device/yoyodyne/security/special.{x509.pem,pk8}
do podpisywania pliku SpecialApp.apk. W kompilacji można używać wyłącznie kluczy prywatnych, które nie są chronione hasłem.
Zaawansowane opcje podpisywania
Wymiana klucza podpisującego APK
Skrypt sign_target_files_apks
działa na plikach docelowych wygenerowanych dla kompilacji. Wszystkie informacje o certyfikatach i kluczach prywatnych używanych w czasie kompilacji są zawarte w plikach docelowych. Podczas uruchamiania skryptu podpisywania w celu podpisania wydania klucze podpisu można zastąpić na podstawie nazwy klucza lub nazwy pliku APK.
Użyj flag --key_mapping
i --default_key_mappings
, aby określić zamianę klucza na podstawie nazw kluczy:
- Flaga
--key_mapping src_key = dest_key
określa zamianę jednego klucza na raz. - Flaga
--default_key_mappings dir
określa katalog z pięcioma kluczami, które mają zastąpić wszystkie klucze wbuild/target/product/security
; jest to równoznaczne z pięciokrotnym użyciem--key_mapping
w celu określenia mapowań.
build/target/product/security/testkey = dir/releasekey build/target/product/security/platform = dir/platform build/target/product/security/shared = dir/shared build/target/product/security/media = dir/media build/target/product/security/networkstack = dir/networkstack
Użyj --extra_apks apk_name1,apk_name2,... = key
aby określić zamienniki kluczy podpisujących na podstawie nazw plików APK. Jeśli key
pozostanie pusty, skrypt traktuje określone pliki APK jako wstępnie podpisane.
W przypadku hipotetycznego produktu tardis potrzebujesz sześciu kluczy chronionych hasłem: pięć do zastąpienia pięciu kluczy w build/target/product/security
i jeden do zastąpienia dodatkowego klucza device/yoyodyne/security/special
wymaganego przez SpecialApp w powyższym przykładzie. Jeżeli klucze znajdowały się w następujących plikach:
vendor/yoyodyne/security/tardis/releasekey.x509.pem vendor/yoyodyne/security/tardis/releasekey.pk8 vendor/yoyodyne/security/tardis/platform.x509.pem vendor/yoyodyne/security/tardis/platform.pk8 vendor/yoyodyne/security/tardis/shared.x509.pem vendor/yoyodyne/security/tardis/shared.pk8 vendor/yoyodyne/security/tardis/media.x509.pem vendor/yoyodyne/security/tardis/media.pk8 vendor/yoyodyne/security/tardis/networkstack.x509.pem vendor/yoyodyne/security/tardis/networkstack.pk8 vendor/yoyodyne/security/special.x509.pem vendor/yoyodyne/security/special.pk8 # NOT password protected vendor/yoyodyne/security/special-release.x509.pem vendor/yoyodyne/security/special-release.pk8 # password protected
Następnie podpisałbyś wszystkie aplikacje w ten sposób:
./build/make/tools/releasetools/sign_target_files_apks \
--default_key_mappings vendor/yoyodyne/security/tardis \
--key_mapping vendor/yoyodyne/security/special=vendor/yoyodyne/security/special-release \
--extra_apks PresignedApp= \
-o tardis-target_files.zip \
signed-tardis-target_files.zip
Wyświetla się następujące informacje:
Enter password for vendor/yoyodyne/security/special-release key> Enter password for vendor/yoyodyne/security/tardis/networkstack key> Enter password for vendor/yoyodyne/security/tardis/media key> Enter password for vendor/yoyodyne/security/tardis/platform key> Enter password for vendor/yoyodyne/security/tardis/releasekey key> Enter password for vendor/yoyodyne/security/tardis/shared key> signing: Phone.apk (vendor/yoyodyne/security/tardis/platform) signing: Camera.apk (vendor/yoyodyne/security/tardis/media) signing: NetworkStack.apk (vendor/yoyodyne/security/tardis/networkstack) signing: Special.apk (vendor/yoyodyne/security/special-release) signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey) [...] signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared) signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared) NOT signing: PresignedApp.apk (skipped due to special cert string) rewriting SYSTEM/build.prop: replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform) rewriting RECOVERY/RAMDISK/default.prop: replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys using: vendor/yoyodyne/security/tardis/releasekey.x509.pem for OTA package verification done.
Po poproszeniu użytkownika o podanie haseł do wszystkich kluczy chronionych hasłem skrypt ponownie podpisuje wszystkie pliki APK w docelowym wejściowym pliku .zip
za pomocą kluczy zwalniających. Przed uruchomieniem polecenia możesz także ustawić zmienną środowiskową ANDROID_PW_FILE
na tymczasową nazwę pliku; następnie skrypt wywołuje edytor, aby umożliwić wprowadzenie haseł dla wszystkich kluczy (może to być wygodniejszy sposób wprowadzania haseł).
Wymiana klucza podpisującego APEX
W Androidzie 10 wprowadzono format pliku APEX umożliwiający instalację modułów systemowych niższego poziomu. Jak wyjaśniono w podpisywania APEX , każdy plik APEX jest podpisany dwoma kluczami: jeden dla obrazu mini systemu plików w APEX, a drugi dla całego APEX.
Podczas podpisywania w celu wydania dwa klucze podpisujące plik APEX są zastępowane kluczami zwalniającymi. Klucz ładunku systemu plików jest określony za pomocą flagi --extra_apex_payload
, a cały klucz podpisywania pliku APEX jest określony za pomocą flagi --extra_apks
.
W przypadku produktu tardis załóżmy, że masz następującą konfigurację kluczy dla plików com.android.conscrypt.apex
, com.android.media.apex
i com.android.runtime.release.apex
APEX.
name="com.android.conscrypt.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" name="com.android.media.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" name="com.android.runtime.release.apex" public_key="vendor/yoyodyne/security/testkeys/com.android.runtime.avbpubkey" private_key="vendor/yoyodyne/security/testkeys/com.android.runtime.pem" container_certificate="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.x509.pem" container_private_key="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.pk8"
Masz następujące pliki zawierające klucze zwalniające:
vendor/yoyodyne/security/runtime_apex_container.x509.pem vendor/yoyodyne/security/runtime_apex_container.pk8 vendor/yoyodyne/security/runtime_apex_payload.pem
Poniższe polecenie zastępuje klucze podpisywania dla com.android.runtime.release.apex
i com.android.tzdata.apex
podczas podpisywania wersji. W szczególności com.android.runtime.release.apex
jest podpisany określonymi kluczami wydania ( runtime_apex_container
dla pliku APEX i runtime_apex_payload
dla ładunku obrazu pliku). com.android.tzdata.apex
jest traktowany jako wstępnie podpisany. Wszystkie pozostałe pliki APEX są obsługiwane przez domyślną konfigurację wymienioną w plikach docelowych.
./build/make/tools/releasetools/sign_target_files_apks \
--default_key_mappings vendor/yoyodyne/security/tardis \
--extra_apks com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_container \
--extra_apex_payload_key com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_payload.pem \
--extra_apks com.android.media.apex= \
--extra_apex_payload_key com.android.media.apex= \
-o tardis-target_files.zip \
signed-tardis-target_files.zip
Uruchomienie powyższego polecenia daje następujące logi:
[...] signing: com.android.runtime.release.apex container (vendor/yoyodyne/security/runtime_apex_container) : com.android.runtime.release.apex payload (vendor/yoyodyne/security/runtime_apex_payload.pem) NOT signing: com.android.conscrypt.apex (skipped due to special cert string) NOT signing: com.android.media.apex (skipped due to special cert string) [...]
Inne opcje
Skrypt sign_target_files_apks
zapisuje opis kompilacji i odcisk palca w plikach właściwości kompilacji, aby odzwierciedlić, że kompilacja jest kompilacją podpisaną. Flaga --tag_changes
kontroluje, jakie zmiany zostaną wprowadzone w odcisku palca. Uruchom skrypt z opcją -h
, aby wyświetlić dokumentację dotyczącą wszystkich flag.
Ręcznie wygeneruj klucze
Android używa 2048-bitowych kluczy RSA z wykładnikiem publicznym 3. Możesz wygenerować pary certyfikatów/kluczy prywatnych za pomocą narzędzia openssl z openssl.org :
# generate RSA keyopenssl genrsa -3 -out temp.pem 2048
Generating RSA private key, 2048 bit long modulus ....+++ .....................+++ e is 3 (0x3) # create a certificate with the public part of the keyopenssl req -new -x509 -key temp.pem -out releasekey.x509.pem -days 10000 -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'
# create a PKCS#8-formatted version of the private keyopenssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt
# securely delete the temp.pem fileshred --remove temp.pem
Podane powyżej polecenie openssl pkcs8 tworzy plik .pk8 bez hasła, odpowiedni do użycia w systemie kompilacji. Aby utworzyć plik .pk8 zabezpieczony hasłem (co powinieneś zrobić dla wszystkich aktualnych kluczy wydania), zamień argument -nocrypt
na -passout stdin
; następnie openssl zaszyfruje klucz prywatny hasłem odczytanym ze standardowego wejścia. Nie jest drukowany żaden monit, więc jeśli stdin jest terminalem, program będzie wyglądał na zawieszony, gdy w rzeczywistości będzie tylko czekał na wprowadzenie hasła. Można użyć innych wartości argumentu-passout, aby odczytać hasło z innych lokalizacji; szczegółowe informacje można znaleźć w dokumentacji openssl .
Plik pośredni temp.pem zawiera klucz prywatny bez żadnego zabezpieczenia hasłem, dlatego podczas generowania kluczy wydania należy go ostrożnie pozbyć się. W szczególności narzędzie GNUshred może nie działać w sieciowych lub kronikowanych systemach plików. Możesz użyć katalogu roboczego znajdującego się na dysku RAM (takim jak partycja tmpfs) podczas generowania kluczy, aby mieć pewność, że produkty pośrednie nie zostaną przypadkowo ujawnione.
Twórz pliki obrazów
Kiedy już masz signed-target_files.zip
, musisz utworzyć obraz, aby móc umieścić go na urządzeniu. Aby utworzyć podpisany obraz z plików docelowych, uruchom następujące polecenie w katalogu głównym drzewa Androida:
img_from_target_files signed-target_files.zip signed-img.zipWynikowy plik,
signed-img.zip
, zawiera wszystkie pliki .img
. Aby załadować obraz na urządzenie, użyj funkcji fastboot w następujący sposób:fastboot update signed-img.zip