Android-Betriebssystem-Images verwenden an zwei Stellen kryptografische Signaturen:
- Jede
.apk
Datei im Bild 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 die Aktualisierung 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 (damit sie Daten teilen können 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 die Aktualisierung von Benutzer-Apps durch Überschreiben der
- OTA-Update-Pakete müssen mit einem der vom System erwarteten Schlüssel signiert sein, sonst werden sie vom Installationsprozess abgelehnt.
Tasten loslassen
Der Android-Baum enthält Testschlüssel unter build/target/product/security
. Beim Erstellen eines Android-Betriebssystem-Images 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 und so möglicherweise in Ihr Betriebssystem-Image integrierte System-Apps ersetzen oder kapern. Aus diesem Grund ist es wichtig, jedes öffentlich veröffentlichte oder bereitgestellte Android-Betriebssystem-Image mit einem speziellen Satz von Freigabeschlüsseln zu signieren, auf die nur Sie Zugriff haben.
Um Ihren eigenen, einzigartigen 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 jedes beliebige Verzeichnis verwenden, achten Sie jedoch darauf, einen gesicherten und sicheren Speicherort auszuwählen. Einige Anbieter entscheiden sich dafür, ihren privaten Schlüssel mit einer starken Passphrase zu verschlüsseln und den verschlüsselten Schlüssel in der Quellcodeverwaltung zu speichern. 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
verwendet eine ZIP-Datei .zip
als Eingabe und erstellt eine neue ZIP-Datei .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
.
Signieren Sie OTA-Pakete
Eine signierte Zieldatei-ZIP-Datei kann mit dem folgenden Verfahren 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
Beim Querladen wird der normale Paketsignaturüberprüfungsmechanismus der Wiederherstellung nicht umgangen. Vor der Installation eines Pakets überprüft die Wiederherstellung, 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 Paket, das über die Wiederherstellungspartition geliefert wird -Luft.
Vom Hauptsystem empfangene Aktualisierungspakete werden in der Regel zweimal überprüft: einmal vom 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
gespeichert sind (standardmäßig). Die Wiederherstellung vergleicht die Signatur mit öffentlichen Schlüsseln, die auf der RAM-Disk der Wiederherstellungspartition in der Datei /res/keys
gespeichert sind.
Standardmäßig wird durch die vom Build erstellten .zip
-Zieldateien das OTA-Zertifikat so eingestellt, dass es mit dem Testschlüssel übereinstimmt. Auf einem freigegebenen 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 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 über Seitenladen 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 einbezogen 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 liegt in zwei Dateien vor: 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 zum Signieren eines Pakets benötigt. Der Schlüssel selbst kann durch ein Passwort geschützt sein. Das Zertifikat hingegen enthält nur die öffentliche Hälfte des Schlüssels und kann daher weit verbreitet werden. 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-/Kontakte-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 völlig anderen Schlüssel über den 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 Signierungsoptionen
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. Wenn Sie das Signaturskript zum Signieren zur Freigabe ausführen, können Signaturschlüssel basierend auf dem Schlüsselnamen oder dem 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 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--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 key
leer bleibt, behandelt das Skript die angegebenen APKs als vorsigniert.
Für das hypothetische Tardis-Produkt benötigen Sie sechs passwortgeschützte Schlüssel: fünf als Ersatz für die fünf in build/target/product/security
und einen als Ersatz für den zusätzlichen Schlüssel device/yoyodyne/security/special
von SpecialApp im obigen Beispiel benötigt wird. Wenn die Schlüssel in den folgenden Dateien wären:
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 im Eingabeziel .zip
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 Möglichkeit, Passwörter einzugeben).
Austausch des APEX-Signaturschlüssels
Android 10 führt das APEX-Dateiformat für die Installation untergeordneter Systemmodule ein. Wie unter APEX-Signierung erläutert, wird jede APEX-Datei mit zwei Schlüsseln signiert: einem für das Mini-Dateisystem-Image innerhalb eines APEX und dem anderen für das gesamte APEX.
Beim Signieren zur Freigabe werden die beiden Signaturschlüssel für eine APEX-Datei durch Freigabeschlüssel ersetzt. Der Dateisystem-Payload-Schlüssel wird mit dem Flag --extra_apex_payload
angegeben und der gesamte APEX-Dateisignaturschlüssel wird mit dem Flag --extra_apks
angegeben.
Gehen Sie für das Tardis-Produkt davon aus, dass Sie über die folgende Schlüsselkonfiguration für die APEX-Dateien com.android.conscrypt.apex
, com.android.media.apex
und com.android.runtime.release.apex
verfügen.
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 ist com.android.runtime.release.apex
mit den angegebenen Release-Schlüsseln signiert ( runtime_apex_container
für die APEX-Datei und runtime_apex_payload
für die Datei-Image-Nutzlast). com.android.tzdata.apex
wird als vorsigniert 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, werden die folgenden Protokolle angezeigt:
[...] 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 Signaturskript sign_target_files_apks
schreibt die Build-Beschreibung und den Fingerabdruck in den Build-Eigenschaftendateien um, 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.
Schlüssel manuell generieren
Android verwendet 2048-Bit-RSA-Schlüssel mit öffentlichem Exponenten 3. Sie können Zertifikat/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
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 mit einem Passwort gesicherte .pk8-Datei zu erstellen (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 hängen zu bleiben, obwohl es eigentlich 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; Einzelheiten finden Sie in der OpenSSL-Dokumentation .
Die Zwischendatei temp.pem enthält den privaten Schlüssel ohne jeglichen Passwortschutz. Entsorgen Sie ihn daher sorgfältig, wenn Sie Freigabeschlüssel generieren. Insbesondere ist das Dienstprogramm GNUshred möglicherweise nicht auf Netzwerk- oder Journaldateisystemen wirksam. Sie können beim Generieren von Schlüsseln ein Arbeitsverzeichnis auf einer RAM-Disk (z. B. einer tmpfs-Partition) verwenden, um sicherzustellen, dass die Zwischenprodukte nicht versehentlich offengelegt werden.
Bilddateien erstellen
Wenn Sie signed-target_files.zip
haben, müssen Sie das Bild 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 des Android-Baums 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