In Android OS-Images werden kryptografische Signaturen an zwei Stellen verwendet:
- Jede
.apk
-Datei im Image muss signiert sein. Der Paketmanager 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 Nutzeranwendungen durch Überschreiben von
.apk
als auch für das Überschreiben einer Systemanwendung mit einer neueren Version, die unter/data
installiert ist. - Wenn zwei oder mehr Anwendungen eine Nutzer-ID gemeinsam nutzen möchten (damit sie z. B. Daten teilen können), müssen sie mit demselben Schlüssel signiert sein.
- 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 Nutzeranwendungen durch Überschreiben von
- OTA-Update-Pakete müssen mit einem der vom System erwarteten Schlüssel signiert sein, da sie andernfalls vom Installationsprozess abgelehnt werden.
Release-Schlüssel
Der Android-Baum enthält unter build/target/product/security
Testschlüssel. Wenn Sie ein Android-Betriebssystem-Image mit make
erstellen, 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. Dadurch können System-Apps, die in Ihr Betriebssystem-Image integriert sind, möglicherweise ersetzt oder missbraucht werden. Aus diesem Grund ist es wichtig, jedes öffentlich veröffentlichte oder bereitgestellte Android-Betriebssystem-Image mit einer speziellen Reihe von Release-Schlüsseln zu signieren, auf die nur Sie Zugriff haben.
Wenn Sie Ihre eigenen Release-Schlüssel generieren möchten, führen Sie die folgenden Befehle aus dem 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 entsprechend den Informationen Ihrer Organisation geändert werden. Sie können jedes Verzeichnis verwenden, achten Sie aber darauf, einen gesicherten Speicherort auszuwählen. Einige Anbieter verschlüsseln ihren privaten Schlüssel mit einer starken Passphrase und speichern den verschlüsselten Schlüssel in der Versionskontrolle. Andere speichern ihre Release-Schlüssel an einem ganz anderen Ort, z. B. auf einem Air-Gapped-Computer.
So generierst du ein Release-Image:
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 sign_target_files_apks
-Script nimmt eine Zieldatei.zip
als Eingabe und erstellt eine neue Zieldatei.zip
, in der alle .apk
-Dateien mit neuen Schlüsseln signiert wurden. Die neu signierten Bilder finden Sie unter IMAGES/
in signed-target_files.zip
.
OTA-Pakete signieren
Eine signierte ZIP-Datei mit Zieldateien kann mithilfe des folgenden Verfahrens in eine signierte ZIP-Datei mit OTA-Update konvertiert werden:
ota_from_target_files \
-k (--package_key)
signed-target_files.zip \
signed-ota_update.zip
Signaturen und Sideloading
Beim Sideloading wird der normale Mechanismus zur Überprüfung der Paketsignatur der Wiederherstellung nicht umgangen. Vor der Installation eines Pakets wird geprüft, ob es mit einem der privaten Schlüssel signiert ist, die mit den in der Wiederherstellungspartition gespeicherten öffentlichen Schlüsseln übereinstimmen, genau wie bei einem per WLAN übertragenen Paket.
Update-Pakete, die vom Hauptsystem empfangen werden, werden in der Regel zweimal überprüft: einmal vom Hauptsystem mithilfe der RecoverySystem.verifyPackage()
-Methode in der Android API und dann noch einmal vom Wiederherstellungssystem. Die RecoverySystem API prüft die Signatur anhand der öffentlichen Schlüssel, die im Hauptsystem in der Datei /system/etc/security/otacerts.zip
(standardmäßig) gespeichert sind. Bei der Wiederherstellung wird die Signatur mit öffentlichen Schlüsseln verglichen, die in der Datei /res/keys
auf der RAM-Disk der Wiederherstellungspartition gespeichert sind.
Standardmäßig legen die vom Build erstellten Zieldateien .zip
das OTA-Zertifikat so fest, dass es mit dem Testschlüssel übereinstimmt. Bei einem veröffentlichten Image muss ein anderes Zertifikat verwendet werden, damit Geräte die Authentizität des Update-Pakets überprüfen können. Wenn Sie das Flag -o
an sign_target_files_apks
übergeben, wie im vorherigen Abschnitt gezeigt, wird das Testschlüsselzertifikat durch das Release-Schlüsselzertifikat aus Ihrem certs-Verzeichnis ersetzt.
Normalerweise werden im System- und im Wiederherstellungs-Image dieselben öffentlichen OTA-Schlüssel gespeichert. Wenn Sie einen Schlüssel nur dem Schlüsselsatz für die Wiederherstellung hinzufügen, können Sie Pakete signieren, die nur per Sideloading installiert werden können, vorausgesetzt, der Update-Downloadmechanismus des Hauptsystems führt die Überprüfung korrekt anhand von otacerts.zip durch. Sie können zusätzliche Schlüssel angeben, die nur bei der Wiederherstellung berücksichtigt werden sollen. Dazu legen Sie die Variable „PRODUCT_EXTRA_RECOVERY_KEYS“ in Ihrer Produktdefinition fest:
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 Datei mit den Wiederherstellungsschlüsseln, damit damit signierte Pakete installiert werden können. Der zusätzliche Schlüssel ist jedoch nicht in „otacerts.zip“ enthalten. Daher wird bei Systemen, die heruntergeladene Pakete korrekt überprüfen, keine Wiederherstellung für Pakete aufgerufen, die mit diesem Schlüssel signiert sind.
Zertifikate und private Schlüssel
Jeder Schlüssel besteht aus zwei Dateien: dem Zertifikat mit der Endung .x509.pem und dem privaten Schlüssel mit der Endung .pk8. Der private Schlüssel sollte geheim gehalten werden und ist zum Signieren eines Pakets erforderlich. Der Schlüssel kann selbst durch ein Passwort geschützt sein. Das Zertifikat enthält dagegen nur die öffentliche Hälfte des Schlüssels und kann daher weit verbreitet verteilt werden. Damit wird geprüft, ob ein Paket mit dem entsprechenden privaten Schlüssel signiert wurde.
Die Standard-Android-Builds verwenden fünf Schlüssel, die sich alle in
build/target/product/security
befinden:
- testkey
- Generischer Standardschlüssel für Pakete, die keinen Schlüssel angeben.
- Plattform
- Testschlüssel für Pakete, die zur Kernplattform gehören.
- geteilt
- Testschlüssel für Dinge, die im Zuhause/Kontakt-Prozess geteilt wurden
- 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. (Wenn diese Variable nicht festgelegt ist, wird testkey verwendet.) Sie können auch einen völlig anderen Schlüssel über den Pfad 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}
zum Signieren von SpecialApp.apk. Für den Build können nur private Schlüssel verwendet werden, die nicht passwortgeschützt sind.
Erweiterte Signaturoptionen
Ersatz des APK-Signaturschlüssels
Das Signatur-Script sign_target_files_apks
arbeitet mit den Zieldateien, die für einen Build generiert wurden. Alle Informationen zu Zertifikaten und privaten Schlüsseln, die zum Zeitpunkt des Builds verwendet wurden, sind in den Zieldateien enthalten. Wenn Sie das Signaturskript zum Signieren für die Veröffentlichung ausführen, können Signaturschlüssel basierend auf dem Schlüsselnamen oder APK-Namen ersetzt werden.
Verwenden Sie die Flags --key_mapping
und --default_key_mappings
, um die Schlüsselersetzung basierend auf Schlüsselnamen anzugeben:
- Das Flag
--key_mapping src_key=dest_key
gibt den Ersatz für einen einzelnen Schlüssel an. - Das Flag
--default_key_mappings dir
gibt ein Verzeichnis mit fünf Schlüsseln an, um alle Schlüssel inbuild/target/product/security
zu ersetzen. Das entspricht der fünfmaligen Verwendung von--key_mapping
, um die Zuordnungen anzugeben.
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 Flag --extra_apks apk_name1,apk_name2,...=key
, um die Signaturschlüsselersetzungen basierend auf APK-Namen anzugeben. Wenn key
leer bleibt, werden die angegebenen APKs vom Script als vorab signiert behandelt.
Für das hypothetische Produkt „Tardis“ benötigen Sie sechs passwortgeschützte Schlüssel: fünf, um die fünf in build/target/product/security
zu ersetzen, und einen, um den zusätzlichen Schlüssel device/yoyodyne/security/special
zu ersetzen, der im Beispiel oben von SpecialApp 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
Anschließend signieren Sie alle Apps so:
./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
Daraufhin wird Folgendes angezeigt:
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 Nutzer zur Eingabe von Passwörtern für alle passwortgeschützten Schlüssel aufgefordert wurde, signiert das Skript alle APK-Dateien im Eingabeziel-.zip
mit den Releaseschlüsseln neu. Bevor Sie den Befehl ausführen, können Sie für die Umgebungsvariable ANDROID_PW_FILE
auch einen temporären Dateinamen festlegen. Das Skript ruft dann den Editor auf, damit Sie Passwörter für alle Schlüssel eingeben können. So lassen sich Passwörter einfacher eingeben.
Ersatz des APEX-Signaturschlüssels
Mit Android 10 wird das APEX-Dateiformat für die Installation von Systemmodulen der unteren Ebene eingeführt. Wie unter APEX-Signatur erläutert, wird jede APEX-Datei mit zwei Schlüsseln signiert: einem für das Minidateisystem-Image in einem APEX und einem für das gesamte APEX.
Beim Signieren für die Veröffentlichung werden die beiden Signaturschlüssel für eine APEX-Datei durch Release-Schlüssel ersetzt. Der Schlüssel für die Dateisystemnutzlast wird mit dem Flag --extra_apex_payload
und der Schlüssel für die gesamte APEX-Dateisignatur mit dem Flag --extra_apks
angegeben.
Angenommen, Sie haben für das Tardis-Produkt 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"
Außerdem haben Sie die folgenden Dateien mit den Release-Schlüsseln:
vendor/yoyodyne/security/runtime_apex_container.x509.pem vendor/yoyodyne/security/runtime_apex_container.pk8 vendor/yoyodyne/security/runtime_apex_payload.pem
Mit dem folgenden Befehl werden die Signaturschlüssel für com.android.runtime.release.apex
und com.android.tzdata.apex
bei der Release-Signatur überschrieben. Insbesondere ist com.android.runtime.release.apex
mit den angegebenen Releaseschlüsseln signiert (runtime_apex_container
für die APEX-Datei und runtime_apex_payload
für die Nutzlast des Dateibilds).
com.android.tzdata.apex
wird als vorab signiert behandelt. Alle anderen APEX-Dateien werden von der Standardkonfiguration verarbeitet, 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 folgende Logs:
[...] 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) [...]
Sonstige Optionen
Das Signaturskript sign_target_files_apks
schreibt die Build-Beschreibung und den Fingerabdruck in den Build-Attributdateien neu, um anzugeben, dass der Build ein signierter Build ist. Das Flag --tag_changes
steuert, welche Änderungen am Fingerabdruck vorgenommen werden. Führen Sie das Script mit -h
aus, um die Dokumentation zu allen Flags aufzurufen.
Schlüssel manuell generieren
Android verwendet 2048-Bit-RSA-Schlüssel mit dem öffentlichen Exponenten 3. Sie können Zertifikats-/private Schlüsselpaare mit dem OpenSSL-Tool 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
Mit dem obigen Befehl „openssl pkcs8“ wird eine .pk8-Datei ohne Passwort erstellt, die für die Verwendung mit dem Build-System geeignet ist. Wenn Sie eine mit einem Passwort gesicherte .pk8-Datei erstellen möchten (was Sie für alle Release-Schlüssel tun sollten), ersetzen Sie das Argument -nocrypt
durch -passout stdin
. openssl verschlüsselt dann den privaten Schlüssel mit einem Passwort, das aus der Standardeingabe gelesen wird. Es wird kein Prompt ausgegeben. Wenn stdin also das Terminal ist, scheint das Programm hängenzubleiben, obwohl es nur auf die Eingabe eines Passworts wartet. Für das Argument "passout" können andere Werte verwendet werden, um das Passwort aus anderen Speicherorten auszulesen. Weitere Informationen finden Sie in der
Dokumentation zu openssl.
Die Zwischendatei „temp.pem“ enthält den privaten Schlüssel ohne Passwortschutz. Entfernen Sie sie daher sorgfältig, wenn Sie Release-Schlüssel generieren. Insbesondere ist das GNUshred-Dienstprogramm möglicherweise nicht effektiv bei Netzwerk- oder protokollierten Dateisystemen. Sie können beim Generieren von Schlüsseln ein Arbeitsverzeichnis auf einer RAM-Disk (z. B. eine tmpfs-Partition) verwenden, damit die Zwischendateien nicht unbeabsichtigt offengelegt werden.
Bilddateien erstellen
Wenn Sie signed-target_files.zip
haben, müssen Sie das Image erstellen, damit Sie es auf ein Gerät übertragen können.
Führen Sie den folgenden Befehl im Stammverzeichnis der Android-Struktur aus, um das signierte Image aus den Zieldateien zu erstellen:
img_from_target_files signed-target_files.zip signed-img.zipDie resultierende Datei
signed-img.zip
enthält alle .img
-Dateien.
So laden Sie ein Image auf ein Gerät:
fastboot update signed-img.zip