Podpisz kompilacje do opublikowania

Obrazy systemu operacyjnego Android używają podpisów kryptograficznych w 2 miejscach:

  1. Każdy plik .apk w obrazie musi być podpisany. Android Menedżer pakietów używa podpisu .apk na 2 sposoby:
    • Zastąpiona aplikacja musi być podpisana tym samym kluczem co starej aplikacji w celu uzyskania dostępu do jej danych. Zawiera true (prawda) zarówno w przypadku aktualizowania aplikacji użytkownika przez zastąpienie instrukcji .apk, jak i dla zastępując aplikację systemową nowszą wersją zainstalowaną pod /data
    • Jeśli co najmniej 2 aplikacje chcą udostępniać identyfikator użytkownika (aby mogły udostępniać dane itp.), muszą być podpisane tym samym kluczem.
  2. Pakiety aktualizacji OTA muszą być podpisane jednym z kluczy oczekiwanych przez system, w przeciwnym razie proces instalacji je odrzuci.

Klawisze zwalniania

Drzewo Androida zawiera klucze testowe w sekcji build/target/product/security. Kompilacja obrazu systemu operacyjnego Android za pomocą make spowoduje podpisanie wszystkich plików .apk za pomocą kluczy testowych. Klucze testowe są publicznie znane, więc każdy może podpisać własne pliki .apk z tymi samymi kluczami, co może umożliwić ich zastąpienie lub przejęcie systemu; z aplikacjami wbudowanymi w obraz systemu operacyjnego. Dlatego ważne jest, aby podpisać każdy opublikowany publicznie lub wdrożony obraz systemu operacyjnego Android za pomocą specjalnego zestawu kluczy wersji, do których dostęp ma tylko Ty.

Aby wygenerować własny, unikalny zestaw kluczy wersji, uruchom te polecenia w korzenia 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ć, tak aby odzwierciedlały ustawienia i informacjami o nich. Możesz użyć dowolnego katalogu, ale pamiętaj, by wybrać lokalizacji, której kopia zapasowa jest bezpieczna. Niektórzy dostawcy decydują się na zaszyfrowanie klucza prywatnego za pomocą silnego hasła i przechowywanie zaszyfrowanego klucza w systemie kontroli wersji. Inni przechowują klucze wersji gdzie indziej, na przykład na komputerze z funkcją air-gap.

Aby wygenerować obraz wersji, 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

Skrypt sign_target_files_apks pobiera pliki docelowe .zip jako dane wejściowe i tworzy nowe pliki docelowe .zip w , w którym wszystkie pliki .apk zostały podpisane nowymi kluczami. Nowy podpisane obrazy można znaleźć w domenie IMAGES/ w signed-target_files.zip

Podpisywanie pakietów OTA

Za pomocą tej procedury możesz przekonwertować podpisany plik ZIP z plikami docelowymi na podpisany plik ZIP z aktualizacją OTA:
ota_from_target_files \
-k  (--package_key) 
signed-target_files.zip \
signed-ota_update.zip

Podpisy i przenoszenie na urządzenie

Ładowanie z zewnętrznego źródła nie omija normalnego mechanizmu weryfikacji podpisu pakietu w przywróceniu. Przed zainstalowaniem pakietu funkcja przywracania zweryfikuje, czy jest on podpisany jednym z kluczy prywatnych pasujących do kluczy publicznych zapisanych na partycji odzyskiwania, tak jak w przypadku pakietu dostarczanego przez sieć.

Pakiety aktualizacji otrzymane z głównego systemu są zwykle weryfikowane dwukrotnie: raz przez system główny za pomocą metody RecoverySystem.verifyPackage() w interfejsie API Androida, a potem ponownie przez funkcję odzyskiwania. Interfejs RecoverySystem API sprawdza podpis pod kątem kluczy publicznych przechowywane w głównym systemie, w pliku /system/etc/security/otacerts.zip (domyślnie). Odzyskiwanie sprawdza podpis pod kątem kluczy publicznych przechowywanych na dysku RAM partycji odzyskiwania w pliku /res/keys.

Domyślnie pliki docelowe .zip tworzone przez kompilację ustawiają certyfikat OTA zgodny z kluczem testowym. W przypadku opublikowanego obrazu należy użyć innego certyfikatu, aby urządzenia mogły zweryfikować autentyczność pakietu aktualizacji. Podanie parametru -o parametrowi sign_target_files_apks, jak pokazano w poprzedniej sekcji, powoduje zastąpienie certyfikatu klucza testowego certyfikatem klucza wersji z katalogu certyfikatów.

Normalnie obraz systemu i obraz przywracania zawierają ten sam zestaw OTA. kluczy publicznych. Dodanie klucza tylko do zestawu kluczy do odzyskiwania można podpisywać pakiety, które można instalować tylko przez instalowanie z innego urządzenia (przy założeniu, że mechanizm pobierania aktualizacji głównego systemu działa prawidłowo weryfikacji za pomocą pliku otacerts.zip). Możesz określić dodatkowe klucze, uwzględnione tylko w odzyskiwaniu przez ustawienie PRODUCT_EXTRA_RECOVERY_KEYS w definicji produktu:

vendor/yoyodyne/tardis/products/tardis.mk
 [...]

PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload

Obejmuje to klucz publiczny vendor/yoyodyne/security/tardis/sideload.x509.pem w pliku z kluczami odzyskiwania, aby można było instalować pakiety podpisane za jego pomocą. Plik otacerts.zip nie zawiera jednak dodatkowego klucza, systemy, które prawidłowo weryfikują pobrane pakiety, nie wywołują opcji przywracania pakietów podpisanych tym kluczem.

Certyfikaty i klucze prywatne

Każdy klucz jest dostarczany w 2 plikach: certyfikat o rozszerzeniu .x509.pem oraz klucz prywatny o rozszerzeniu .pk8. Klucz prywatny należy przechowywać w tajemnicy. Jest on potrzebny do podpisania pakietu. Klucz może być chroniona hasłem. Certyfikat zawiera natomiast tylko publiczną część klucza, więc można go rozpowszechniać. Służy do sprawdzania, czy pakiet został podpisany odpowiednim kluczem prywatnym.

Standardowa wersja Androida używa 5 kluczy, które znajdują się w folderze build/target/product/security:

testkey
Ogólny klucz domyślny dla pakietów, które nie określają innego klucza.
platform
Klucz testowy do pakietów, które są częścią platformy podstawowej.
udostępniony
Klucz do testowania elementów udostępnianych w domu i kontaktach.
multimedia
Klucz testowy dla pakietów, które są częścią systemu multimediów/pobierania.
atak sieci
Klucz testowy dla pakietów, które są częścią systemu sieciowego. Klucz networkstack służy do podpisywania binarek zaprojektowanych jako elementy składowe systemu modularnego. Jeśli aktualizacje modułów są kompilowane osobno i integrowane jako wstępnie utworzone w obrazie urządzenia, nie musisz generować klucza networkstack w drzewie źródłowym Androida.

Poszczególne pakiety określają jeden z tych kluczy, ustawiając parametr LOCAL_CERTIFICATE w pliku Android.mk. (Jeśli ta zmienna nie jest ustawiona, używany jest klucz testowy). Ty Możesz też podać zupełnie inny klucz za pomocą nazwy ścieżki, na przykład:

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 podpisania pliku SpecialApp.apk. Kompilacja może używać tylko kluczy prywatnych, które: nie są chronione hasłem.

Zaawansowane opcje podpisywania

Wymiana klucza podpisywania pliku APK

Skrypt podpisywania sign_target_files_apks działa na plikach docelowych wygenerowanych dla kompilacji. Wszystkie informacje o certyfikatach i prywatnych klucze używane podczas kompilacji są uwzględniane w plikach docelowych. Podczas uruchamiania skryptu podpisywania w celu podpisania wersji można zastąpić klucze podpisywania na podstawie nazwy klucza lub nazwy pliku APK.

Użyj flag --key_mapping i --default_key_mappings, aby określić zastąpienie klucza na podstawie nazwy klucza:

  • Flaga --key_mapping src_key=dest_key określa zastąpienie jednego klucza naraz.
  • Flaga --default_key_mappings dir określa katalog z 5 kluczami, które zastępują wszystkie klucze w pliku build/target/product/security. Jest to równoznaczne z 5-krotnym użyciem pliku --key_mapping do 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 parametru --extra_apks apk_name1,apk_name2,...=key, aby określić zastąpienia klucza podpisywania na podstawie nazw plików APK. Jeśli Pole key jest puste, skrypt traktuje określone pliki APK na wstępnie podpisanej.

W przypadku hipotetycznej usługi tardis potrzebujesz 6 kluczy chronionych hasłem: pięć, aby zastąpić pięć w grupie build/target/product/security i jeden aby zastąpić dodatkowy klucz device/yoyodyne/security/special wymagane przez SpecialApp w powyższym przykładzie. Jeśli klucze były w tych miejscach pliki:

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 podpisz 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

W efekcie:

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 wyświetleniu użytkownikowi haseł do wszystkich kluczy chronionych hasłem skrypt ponownie podpisuje wszystkie pliki APK w docelniku wejściowym .zip za pomocą kluczy wersji. Przed uruchomieniem polecenia możesz też ustawić zmienną środowiskową ANDROID_PW_FILE jako nazwę pliku tymczasowego. Skrypt wywoła wtedy edytor, aby umożliwić Ci wprowadzenie haseł do wszystkich kluczy (może to być wygodniejszy sposób wprowadzania haseł).

Wymiana klucza podpisywania APEX

Android 10 wprowadza Format pliku APEX do instalacji. z modułów systemowych niższego poziomu. Jak wyjaśniono w artykule Podpisywanie pakietu APEX, każdy plik APEX jest podpisywany 2 kluczami: jednym dla obrazu mini systemu plików w pakiecie APEX i drugim dla całego pakietu APEX.

Podczas podpisywania wersji publikowanej 2 klucze podpisywania pliku APEX są zastępowane kluczami wersji publikowanej. Klucz ładunku systemu plików jest określony za pomocą funkcji --extra_apex_payload, a cały klucz podpisywania pliku APEX to z flagą --extra_apks.

W przypadku usługi tardis załóżmy, że masz następującą konfigurację klucza dla com.android.conscrypt.apex, com.android.media.apex i Pliki APEX: com.android.runtime.release.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 też te pliki zawierające klucze wersji:

vendor/yoyodyne/security/runtime_apex_container.x509.pem
vendor/yoyodyne/security/runtime_apex_container.pk8
vendor/yoyodyne/security/runtime_apex_payload.pem

Podane niżej polecenie zastępuje klucze podpisywania com.android.runtime.release.apexcom.android.tzdata.apex podczas podpisywania wersji. W szczególności com.android.runtime.release.apex jest podpisany(a) przy użyciu: kluczy zwalniających (runtime_apex_container dla pliku APEX oraz runtime_apex_payload dla ładunku obrazu pliku). Element 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 polecenia powyżej spowoduje wyświetlenie tych dzienników:

        [...]
    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 podpisywania sign_target_files_apks przepisuje kompilację opis i odcisk cyfrowy w plikach właściwości kompilacji, aby pokazać, że to podpisana kompilacja. Flaga --tag_changes określa, jakie zmiany są wprowadzane w odciskach palców. Uruchom skrypt z parametrem -h, aby zobaczyć dokumentacji dotyczącej wszystkich flag.

Ręczne generowanie kluczy

Android używa 2048-bitowych kluczy RSA z wykładnikiem publicznym 3. Pary kluczy certyfikatu i klucza prywatnego możesz generować za pomocą narzędzia openssl z openssl.org:

# generate RSA key
openssl 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 key
openssl 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 key
openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt

# securely delete the temp.pem file
shred --remove temp.pem

Podane powyżej polecenie opensl pkcs8 powoduje utworzenie pliku .pk8 z wartością no. Hasło odpowiednie do użytku z systemem kompilacji. Aby utworzyć zabezpieczony plik .pk8, i podaj hasło (które należy zrobić w przypadku wszystkich kluczy zwalniających), zastąp -nocrypt argument z -passout stdin; a następnie Opensl zaszyfruje klucz prywatny za pomocą hasła odczytanego ze standardowych danych wejściowych. Nie ten komunikat jest drukowany, więc jeśli terminalem jest stdin, program będzie się zawieszać. kiedy tak naprawdę czeka na Twoje wpisanie hasła. Inne wartości używany jako argument -passout do odczytu hasła z innych lokalizacji; w przypadku , zapoznaj się z Opensl.

Plik tymczasowy temp.pem zawiera klucz prywatny bez żadnej ochrony hasłem, dlatego należy go ostrożnie usunąć po wygenerowaniu kluczy wersji. W szczególności narzędzie GNUshred może nie być skuteczne w przypadku systemów plików sieciowych lub dziennika. Możesz użyć katalogu roboczego znajdującego się na dysku RAM (np. partycję tmpfs) podczas generowania kluczy, aby zapewnić, że ścieżki pośrednie nie zostały przypadkowo ujawnione.

Tworzenie plików z obrazami

Gdy masz signed-target_files.zip, musisz: utworzyć obraz, aby móc go umieścić na urządzeniu. Aby utworzyć podpisany obraz z plików docelowych, uruchom polecenie to polecenie w katalogu głównym Androida drzewo:

img_from_target_files signed-target_files.zip signed-img.zip
Powstały plik signed-img.zip zawiera wszystkie .img pliki. Aby wczytać obraz na urządzenie, użyj fastboot jako następujące:
fastboot update signed-img.zip