Android OS-Images verwenden kryptografische Signaturen an zwei Stellen:
- Jede
.apk
-Datei innerhalb des Bildes muss signiert sein. Der Paket-Manager von Android verwendet eine.apk
-Signatur auf zwei Arten:- Wenn eine Anwendung ersetzt wird, muss sie mit demselben Schlüssel wie die alte Anwendung signiert werden, um Zugriff auf die Daten der alten Anwendung zu erhalten. Dies gilt sowohl für das Aktualisieren von Benutzer-Apps durch Überschreiben der
.apk
als auch für das Überschreiben einer System-App mit einer neueren Version, die unter/data
installiert ist. - Wenn zwei oder mehr Anwendungen eine Benutzer-ID teilen möchten (um Daten auszutauschen usw.), müssen sie mit demselben Schlüssel signiert werden.
- Wenn eine Anwendung ersetzt wird, muss sie mit demselben Schlüssel wie die alte Anwendung signiert werden, um Zugriff auf die Daten der alten Anwendung zu erhalten. Dies gilt sowohl für das Aktualisieren von Benutzer-Apps durch Überschreiben der
- OTA-Aktualisierungspakete müssen mit einem der vom System erwarteten Schlüssel signiert werden, sonst werden sie vom Installationsprozess abgelehnt.
Tasten loslassen
Der Android -Baum enthält Testschlüssel unter build/target/product/security
. Beim Erstellen eines Android-Betriebssystemabbilds mit make
werden alle .apk
-Dateien mit den Testschlüsseln signiert. Da die Testschlüssel öffentlich bekannt sind, kann jeder seine eigenen .apk-Dateien mit denselben Schlüsseln signieren, was es ihm ermöglichen kann, in Ihr Betriebssystem-Image integrierte System-Apps zu ersetzen oder zu entführen. Aus diesem Grund ist es wichtig, jedes öffentlich freigegebene oder bereitgestellte Android-Betriebssystem-Image mit einem speziellen Satz von Freigabeschlüsseln zu signieren, auf die nur Sie Zugriff haben.
Um Ihren eigenen eindeutigen Satz von Freigabeschlüsseln zu generieren, führen Sie diese Befehle im Stammverzeichnis Ihres Android-Baums aus:
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
sollte geändert werden, um die Informationen Ihrer Organisation widerzuspiegeln. Sie können ein beliebiges Verzeichnis verwenden, aber achten Sie darauf, einen gesicherten und sicheren Speicherort auszuwählen. Einige Anbieter verschlüsseln ihren privaten Schlüssel mit einer starken Passphrase und speichern den verschlüsselten Schlüssel in der Quellcodeverwaltung. andere speichern ihre Freigabeschlüssel ganz woanders, beispielsweise auf einem Air-Gap-Computer.
Um ein Release-Image zu generieren, verwenden Sie:
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
Das Skript sign_target_files_apks
nimmt eine .zip
-Datei mit Zieldateien als Eingabe und erzeugt eine neue .zip
-Datei mit Zieldateien, in der alle .apk
-Dateien mit neuen Schlüsseln signiert wurden. Die neu signierten Bilder finden Sie unter IMAGES/
in signed-target_files.zip
.
Signieren von OTA-Paketen
Eine signierte ZIP-Datei mit Zieldateien kann mithilfe des folgenden Verfahrens in eine signierte OTA-Update-ZIP-Datei konvertiert werden:
ota_from_target_files \
-k (--package_key)
signed-target_files.zip \
signed-ota_update.zip
Signaturen und Sideloading
Sideloading umgeht nicht den normalen Verifizierungsmechanismus der Paketsignatur von Recovery – vor der Installation eines Pakets überprüft Recovery, ob es mit einem der privaten Schlüssel signiert ist, der mit den öffentlichen Schlüsseln übereinstimmt, die in der Wiederherstellungspartition gespeichert sind, genau wie bei einem Paket, das über das Internet bereitgestellt wird -Luft.
Update-Pakete, die vom Hauptsystem empfangen werden, werden normalerweise zweimal verifiziert: einmal durch das Hauptsystem mithilfe der RecoverySystem.verifyPackage()
Methode in der Android-API und dann noch einmal durch die Wiederherstellung. Die RecoverySystem-API prüft die Signatur anhand öffentlicher Schlüssel, die im Hauptsystem in der Datei /system/etc/security/otacerts.zip
(standardmäßig) gespeichert sind. Die Wiederherstellung prüft die Signatur anhand öffentlicher Schlüssel, die auf der RAM-Disk der Wiederherstellungspartition in der Datei /res/keys
gespeichert sind.
Standardmäßig legt die vom Build erstellte .zip
-Zieldatei das OTA-Zertifikat so fest, dass es mit dem Testschlüssel übereinstimmt. Auf einem freigegebenen Image muss ein anderes Zertifikat verwendet werden, damit Geräte die Authentizität des Updatepakets überprüfen können. Das Übergeben des Flags -o
an sign_target_files_apks
, wie im vorherigen Abschnitt gezeigt, ersetzt das Testschlüsselzertifikat durch das Freigabeschlüsselzertifikat aus Ihrem Verzeichnis certs .
Normalerweise speichern das System-Image und das Wiederherstellungs-Image denselben Satz öffentlicher OTA-Schlüssel. Durch das Hinzufügen eines Schlüssels nur zum Wiederherstellungsschlüsselsatz ist es möglich, Pakete zu signieren, die nur per Querladen installiert werden können (vorausgesetzt, der Update-Download-Mechanismus des Hauptsystems führt die Überprüfung anhand von otacerts.zip korrekt durch). Sie können zusätzliche Schlüssel angeben, die nur in die Wiederherstellung eingeschlossen werden sollen, indem Sie die Variable PRODUCT_EXTRA_RECOVERY_KEYS in Ihrer Produktdefinition festlegen:
vendor/yoyodyne/tardis/products/tardis.mk
[...] PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
Dazu gehört der öffentliche Schlüssel vendor/yoyodyne/security/tardis/sideload.x509.pem
in der Wiederherstellungsschlüsseldatei, damit damit signierte Pakete installiert werden können. Der zusätzliche Schlüssel ist jedoch nicht in otacerts.zip enthalten, sodass Systeme, die heruntergeladene Pakete korrekt überprüfen, keine Wiederherstellung für mit diesem Schlüssel signierte Pakete aufrufen.
Zertifikate und private Schlüssel
Jeder Schlüssel besteht aus zwei Dateien: dem Zertifikat mit der Erweiterung .x509.pem und dem privaten Schlüssel mit der Erweiterung .pk8. Der private Schlüssel sollte geheim gehalten werden und wird benötigt, um ein Paket zu signieren. Der Schlüssel selbst kann durch ein Passwort geschützt sein. Das Zertifikat hingegen enthält nur die öffentliche Hälfte des Schlüssels, sodass es weit verbreitet werden kann. Es wird verwendet, um zu überprüfen, ob ein Paket mit dem entsprechenden privaten Schlüssel signiert wurde.
Der Standard-Android-Build verwendet fünf Schlüssel, die sich alle in build/target/product/security
befinden:
- Testschlüssel
- Allgemeiner Standardschlüssel für Pakete, die ansonsten keinen Schlüssel angeben.
- Plattform
- Testschlüssel für Pakete, die Teil der Kernplattform sind.
- geteilt
- Testschlüssel für Dinge, die im Home/Contacts-Prozess geteilt werden.
- Medien
- Testschlüssel für Pakete, die Teil des Medien-/Downloadsystems sind.
Einzelne Pakete geben einen dieser Schlüssel an, indem sie LOCAL_CERTIFICATE in ihrer Android.mk-Datei festlegen. (testkey wird verwendet, wenn diese Variable nicht gesetzt ist.) Sie können auch einen ganz anderen Schlüssel per Pfadnamen angeben, z. B.:
device/yoyodyne/apps/SpecialApp/Android.mk
[...] LOCAL_CERTIFICATE := device/yoyodyne/security/special
Jetzt verwendet der Build den Schlüssel device/yoyodyne/security/special.{x509.pem,pk8}
, um SpecialApp.apk zu signieren. Der Build kann nur private Schlüssel verwenden, die nicht passwortgeschützt sind.
Erweiterte Signieroptionen
Ersetzen des APK-Signaturschlüssels
Das Signaturskript sign_target_files_apks
arbeitet mit den für einen Build generierten Zieldateien. Alle Informationen zu Zertifikaten und privaten Schlüsseln, die zur Erstellungszeit verwendet werden, sind in den Zieldateien enthalten. Beim Ausführen des Signaturskripts zum Signieren für die Veröffentlichung können Signaturschlüssel basierend auf dem Schlüsselnamen oder dem APK-Namen ersetzt werden.
Verwenden Sie die --key_mapping
und --default_key_mappings
, um die Schlüsselersetzung basierend auf Schlüsselnamen anzugeben:
- Das
--key_mapping src_key = dest_key
gibt die Ersetzung für jeweils einen Schlüssel an. - Das
--default_key_mappings dir
gibt ein Verzeichnis mit fünf Schlüsseln an, um alle Schlüssel inbuild/target/product/security
zu ersetzen; Dies entspricht der fünfmaligen Verwendung von--key_mapping
zur Angabe der Zuordnungen.
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
Verwenden Sie das --extra_apks apk_name1,apk_name2,... = key
, um die Signaturschlüsselersetzungen basierend auf APK-Namen anzugeben. Wenn der key
leer gelassen wird, behandelt das Skript die angegebenen APKs als vorsigniert.
Für das hypothetische tardis-Produkt benötigen Sie sechs passwortgeschützte Schlüssel: fünf zum Ersetzen der fünf in build/target/product/security
und einen zum Ersetzen des zusätzlichen Schlüssels device/yoyodyne/security/special
, der von SpecialApp im obigen Beispiel benötigt wird. Wenn sich die Schlüssel in den folgenden Dateien befanden:
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
Dann würden Sie alle Apps wie folgt signieren:
./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
Dies bringt Folgendes hervor:
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.
Nachdem der Benutzer zur Eingabe von Passwörtern für alle passwortgeschützten Schlüssel aufgefordert wurde, signiert das Skript alle APK-Dateien in der .zip
-Datei des Eingabeziels erneut mit den Freigabeschlüsseln. Bevor Sie den Befehl ausführen, können Sie auch die Umgebungsvariable ANDROID_PW_FILE
auf einen temporären Dateinamen setzen; Das Skript ruft dann Ihren Editor auf, damit Sie Passwörter für alle Schlüssel eingeben können (dies ist möglicherweise eine bequemere Art, Passwörter einzugeben).
Ersetzen des APEX-Signaturschlüssels
Android 10 führt das APEX-Dateiformat für die Installation von untergeordneten Systemmodulen ein. Wie in APEX-Signierung erläutert, wird jede APEX-Datei mit zwei Schlüsseln signiert: einer für das Mini-Dateisystem-Image innerhalb eines APEX und der andere für das gesamte APEX.
Beim Signieren für die Freigabe werden die beiden Signierschlüssel für eine APEX-Datei durch Freigabeschlüssel ersetzt. Der Payload-Schlüssel des Dateisystems wird mit dem Flag --extra_apex_payload
und der gesamte Signaturschlüssel der APEX-Datei mit dem Flag --extra_apks
angegeben.
Gehen Sie für das Produkt tardis davon aus, dass Sie die folgende Schlüsselkonfiguration für die APEX-Dateien com.android.conscrypt.apex
, com.android.media.apex
und 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"
Und Sie haben die folgenden Dateien, die die Freigabeschlüssel enthalten:
vendor/yoyodyne/security/runtime_apex_container.x509.pem vendor/yoyodyne/security/runtime_apex_container.pk8 vendor/yoyodyne/security/runtime_apex_payload.pem
Der folgende Befehl überschreibt die Signaturschlüssel für com.android.runtime.release.apex
und com.android.tzdata.apex
während der Release-Signierung. Insbesondere wird com.android.runtime.release.apex
mit den angegebenen Freigabeschlüsseln signiert ( runtime_apex_container
für die APEX-Datei und runtime_apex_payload
für die Datei-Image-Payload). com.android.tzdata.apex
wird als vorsigniert behandelt. Alle anderen APEX-Dateien werden von der Standardkonfiguration behandelt, die in den Zieldateien aufgeführt ist.
./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
Wenn Sie den obigen Befehl ausführen, erhalten Sie die folgenden Protokolle:
[...] 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) [...]
Andere Optionen
Das sign_target_files_apks
schreibt die Build-Beschreibung und den Fingerabdruck in den Build-Eigenschaftendateien neu, um anzuzeigen, dass es sich bei dem Build um einen signierten Build handelt. Das Flag --tag_changes
steuert, welche Änderungen am Fingerabdruck vorgenommen werden. Führen Sie das Skript mit -h
aus, um die Dokumentation zu allen Flags anzuzeigen.
Manuelle Generierung von Schlüsseln
Android verwendet 2048-Bit-RSA-Schlüssel mit dem öffentlichen Exponenten 3. Sie können Paare aus Zertifikat und privatem Schlüssel mit dem Werkzeug openssl von openssl.org generieren :
# 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
Der oben angegebene Befehl openssl pkcs8 erstellt eine .pk8-Datei ohne Passwort, die für die Verwendung mit dem Build-System geeignet ist. Um eine .pk8-Datei zu erstellen, die mit einem Passwort gesichert ist (was Sie für alle tatsächlichen Freigabeschlüssel tun sollten), ersetzen Sie das Argument -nocrypt
durch -passout stdin
; dann verschlüsselt openssl den privaten Schlüssel mit einem Passwort, das aus der Standardeingabe gelesen wird. Es wird keine Eingabeaufforderung ausgegeben. Wenn also stdin das Terminal ist, scheint das Programm zu hängen, wenn es wirklich nur darauf wartet, dass Sie ein Passwort eingeben. Andere Werte können für das Argument-passout verwendet werden, um das Passwort von anderen Orten zu lesen; Details finden Sie in der openssl-Dokumentation .
Die Zwischendatei temp.pem enthält den privaten Schlüssel ohne jeglichen Passwortschutz, entsorgen Sie ihn also sorgfältig, wenn Sie Freigabeschlüssel generieren. Insbesondere das Dienstprogramm GNUshred ist auf Netzwerk- oder Journaldateisystemen möglicherweise nicht effektiv. Sie können beim Generieren von Schlüsseln ein Arbeitsverzeichnis auf einer RAM-Disk (z. B. einer tmpfs-Partition) verwenden, um sicherzustellen, dass die Zwischendateien nicht versehentlich offengelegt werden.
Bilddateien erstellen
Nachdem Sie die Datei „signed-target-files.zip“ erstellt haben, müssen Sie das Image erstellen, damit Sie es auf ein Gerät übertragen können. Um das signierte Image aus den Zieldateien zu erstellen, führen Sie den folgenden Befehl im Stammverzeichnis der Android-Struktur aus:
img_from_target_files signed-target-files.zip signed-img.zipDie resultierende Datei
signed-img.zip
enthält alle .img-Dateien. Um ein Image auf ein Gerät zu laden, verwenden Sie fastboot wie folgt:fastboot update signed-img.zip