Android OS イメージでは、次の 2 つの場所で暗号署名が使用されます。
- イメージ内の
.apk
ファイルそれぞれに署名する必要があります。Android のパッケージ マネージャーは、次の 2 つの方法で.apk
署名を行います。- アプリを置き換える場合、古いアプリのデータにアクセスするために古いアプリと同じ鍵で署名しなければなりません。これは、
.apk
を上書きしてユーザーアプリを更新する場合にも、/data
にインストールされる新しいバージョンでシステムアプリをオーバーライドする場合にも当てはまります。 - 2 つ以上のアプリで(データを共有するなどの目的で)ユーザー ID を共有する必要がある場合は、同じキーで署名する必要があります。
- アプリを置き換える場合、古いアプリのデータにアクセスするために古いアプリと同じ鍵で署名しなければなりません。これは、
- OTA アップデート パッケージは、システムが想定している鍵で署名する必要があります。そうしないとインストール処理で拒否されます。
リリースキー
Android ツリーは build/target/product/security
にテストキーを含みます。make
を使用して Android OS イメージをビルドすると、テストキーを使用してすべての .apk
ファイルに署名します。テストキーは一般に知られているため、だれでも .apk ファイルに同じキーで署名できることになり、そのままでは OS イメージに組み込まれているシステムアプリの置き換えやハイジャックにつながる可能性があります。そのため公開またはデプロイする Android OS イメージには、自分だけがアクセスできる特別なリリースキーのセットを使用して署名する必要があります。
一意のリリースキーのセットを独自に生成するには、Android ツリーのルートから次のコマンドを実行します。
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
は、組織の情報を反映する値に変更します。任意のディレクトリを使用できますが、バックアップされていて安全な場所かどうかを確認してから選択してください。ベンダーによっては、秘密鍵を強力なパスフレーズで暗号化し、その暗号化された鍵をソース管理に格納したり、エアギャップ コンピュータなど別の場所にリリースキーをそのまま保存したりしています。
リリース イメージを生成するには、次のコマンドを使用します。
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
スクリプトは、ターゲット ファイルの .zip
を入力として、すべての .apk
ファイルが新しい鍵で署名された新規のターゲット ファイル .zip
を生成します。新たに署名されたイメージは、signed-target_files.zip
の IMAGES/
内にあります。
OTA パッケージへの書名
署名付きターゲット ファイル zip は、次の手順により署名付き OTA アップデート zip に変換できます。
ota_from_target_files \
-k (--package_key)
signed-target_files.zip \
signed-ota_update.zip
署名とサイドローディング
サイドローディングはリカバリのパッケージに対する通常の署名検証メカニズムをバイパスしません。無線(OTA)で送信されたパッケージと同様、リカバリはパッケージをインストールする前に、リカバリ パーティションに格納された公開鍵に対応する秘密鍵で署名されていることを確認します。
メインシステムから受け取ったアップデート パッケージに対しては、2 回検証が行われます。1 回目はメインシステムによる検証で、Android API の RecoverySystem.verifyPackage()
メソッドを使用して検証します。その後もう一度リカバリにより検証されます。RecoverySystem API は、メインシステムの(デフォルトでは)/system/etc/security/otacerts.zip
ファイル内に格納されている公開鍵と署名を照らし合わせます。リカバリは、リカバリ パーティションの RAM ディスクの /res/keys
ファイル内に保存されている公開鍵と署名を照らし合わせます。
デフォルトでは、ビルド時に作成されたターゲット ファイル .zip
によりテストキーに対応する OTA 証明書が設定されます。リリース イメージでは、アップデート パッケージの真正性をデバイスが確認できるように、別の証明書を使用する必要があります。これまで説明したように、sign_target_files_apks
へ -o
フラグを渡すと、テストキー証明書は証明書ディレクトリのリリースキー証明書に置き換えられます。
通常、システム イメージとリカバリ イメージが格納するのは同じ OTA 公開鍵のセットです。リカバリのキーセットだけにキーを追加して、サイドローディングのみでインストールできるパッケージに署名することができます(その場合、メインシステムのアップデート ダウンロード メカニズムで otacerts.zip との署名検証が正しく行われていることが前提条件となります)。リカバリにのみ追加するキーを指定するには、プロダクト定義で PRODUCT_EXTRA_RECOVERY_KEYS 変数を設定します。
vendor/yoyodyne/tardis/products/tardis.mk
[...] PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
これによりリカバリキーのファイルに公開鍵 vendor/yoyodyne/security/tardis/sideload.x509.pem
が含まれ、この鍵で署名されたパッケージのインストールが可能になります。追加のキーは otacerts.zip に含まれていないため、ダウンロードしたパッケージが正しく検証されると、システムはこのキーで署名されたパッケージのリカバリを呼び出しません。
証明書と秘密鍵
各鍵には 2 つのファイルがあり、証明書(拡張子は .x509.pem)と秘密鍵(拡張子は .pk8)です。 秘密鍵は秘密に保管してください。パッケージに署名する際に必要になります。鍵自体はパスワードで保護できます。一方、証明書には鍵の公開部分のみが含まれているため、広く配布できます。パッケージが対応する秘密鍵で署名されていることを検証するために使用されます。
標準的な Android ビルドでは、5 つのキーが使用され、このキーはすべて
build/target/product/security
内にあります。
- testkey
- キーが指定されていないパッケージにデフォルトで設定される汎用キー。
- platform
- コア プラットフォームの一部であるパッケージのテストキー。
- shared
- ホームプロセスまたは連絡先プロセスで共有されるもののテストキー。
- media
- メディア システムまたはダウンロード システムの一部であるパッケージのテストキー。
Android.mk ファイルで LOCAL_CERTIFICATE を設定して、個々のパッケージにこれらのキーのいずれか 1 つを指定します。この変数が設定されていない場合は、testkey が使用されます。次のようにまったく別のキーをパス名で指定することもできます。
device/yoyodyne/apps/SpecialApp/Android.mk
[...] LOCAL_CERTIFICATE := device/yoyodyne/security/special
このビルドでは、device/yoyodyne/security/special.{x509.pem,pk8}
キーを使用して SpecialApp.apk に署名します。このビルドで使用できるのは、パスワードで保護されていない秘密鍵だけです。
高度な署名オプション
APK 署名鍵の置換
署名スクリプト sign_target_files_apks
は、ビルド用に生成されたターゲット ファイルに対して処理を実行します。ビルド時に使用される証明書と秘密鍵のすべての情報が、ターゲット ファイルに含まれます。署名スクリプトを実行してリリースの署名を行う際に、キー名または APK 名に基づいて署名鍵を置き換えることができます。
キー名に基づいて鍵の置換を指定するには、次のように --key_mapping
と --default_key_mappings
フラグを使用します。
--key_mapping src_key=dest_key
フラグは、一度に 1 つのキーの置換を指定します。--default_key_mappings dir
フラグは 5 つのキーを含むディレクトリを指定して、build/target/product/security
にあるすべてのキーを置き換えます。これは--key_mapping
を 5 回使用してマッピングを指定するのと同じです。
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
APK 名に基づいて署名鍵の置換を指定するには、--extra_apks apk_name1,apk_name2,...=key
フラグを使用します。key
が空の場合、スクリプトは指定された APK を事前署名済みとして処理します。
仮の tardis プロダクトでは、パスワードで保護された 6 つのキーが必要です。5 つは build/target/product/security
の 5 つを置き換え、1 つは(上記の例で SpecialApp が要求する)追加のキー device/yoyodyne/security/special
を置換します。キーが次のファイルにある場合、
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
この場合、すべてのアプリに次のように署名します。
./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
これにより、次のようになります。
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.
このスクリプトは、パスワード保護された鍵のパスワードをすべて入力するようユーザーに求めた後、入力ターゲット ファイル .zip
内のすべての APK ファイルにリリースキーを使用して再署名します。コマンドを実行する前に ANDROID_PW_FILE
環境変数を一時ファイル名に設定しておくと、スクリプトの実行中にエディタが起動し、そこにすべてのキーのパスワードを入力できます(パスワードの入力にはこの方法のほうが便利でしょう)。
APEX 署名鍵の置換
Android 10 では、低レベルのシステム モジュールをインストールするための APEX ファイル形式が導入されています。APEX 署名で説明したように、各 APEX ファイルは 2 つのキーで署名されます。1 つは APEX 内のミニ ファイル システムのイメージ用、もう 1 つは APEX 全体用です。
リリース用に署名する場合、APEX ファイルの 2 つの署名鍵をリリースキーに置き換えます。ファイル システムのペイロードキーは、--extra_apex_payload
フラグを使用して指定され、APEX ファイル署名鍵全体は --extra_apks
フラグで指定されます。
架空の tardis プロダクトでは、com.android.conscrypt.apex
、com.android.media.apex
、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"
また、リリースキーを含む次のファイルがあるとします。
vendor/yoyodyne/security/runtime_apex_container.x509.pem vendor/yoyodyne/security/runtime_apex_container.pk8 vendor/yoyodyne/security/runtime_apex_payload.pem
次のコマンドは、リリース署名中に com.android.runtime.release.apex
と com.android.tzdata.apex
の署名鍵をオーバーライドします。詳しく説明すると、com.android.runtime.release.apex
は指定された 2 つのリリースキー(APEX ファイルを runtime_apex_container
で、ファイル イメージのペイロードを runtime_apex_payload
で)で署名され、com.android.tzdata.apex
は事前署名済みとして処理されます。その他の APEX ファイルはすべて、ターゲット ファイルのデフォルト構成に従って処理されます。
./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
上記のコマンドを実行すると、次のログが生成されます。
[...] 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) [...]
その他のオプション
sign_target_files_apks
署名スクリプトは、署名付きビルドであることを示すためにビルド プロパティ ファイルのビルドの説明とフィンガープリントを書き換えます。フィンガープリントに加えられる編集は、--tag_changes
フラグで制御できます。-h
を指定してスクリプトを実行すると、すべてのフラグの説明が表示されます。
鍵の手動生成
Android は 2,048 ビット RSA キーと公開指数 3 を使用します。openssl.org の openssl ツールを使用して、証明書と秘密鍵のペアを生成できます。
# 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
上記の openssl pkcs8 コマンドは、パスワードのない .pk8 ファイルを作成します。これはビルドシステムでの使用に適しています。実際のリリースキーで署名する場合は、パスワードで保護された .pk8 を作成することをおすすめします。それには、-nocrypt
引数を -passout stdin
で置き換えてください。openssl は標準入力からパスワードを読み取り、それを使用して秘密鍵を暗号化します。プロンプトは表示されないので、stdin がターミナルの場合はプログラムがただパスワードの入力を待つことになり、ハングしたように見えます。passout 引数に他の値を渡して、別の場所からパスワードを読み取らせることができます。詳細については、openssl のドキュメントをご覧ください。
temp.pem 中間ファイルにはパスワード保護のない秘密鍵が含まれているため、リリースキーを生成する際には気を付けて破棄してください。特に、GNUshred ユーティリティはネットワークやジャーナリングされたファイル システムでは有効でない場合があります。中間ディスクが誤って公開されないように、鍵を生成する際に RAM ディスク内の作業ディレクトリ(tmpfs パーティションなど)を使用できます。
イメージ ファイルの作成
signed-target_files.zip
を作成したら、デバイスに配置できるようにイメージを作成する必要があります。署名付きイメージをターゲット ファイルから作成するには、Android ツリーのルートから次のコマンドを実行します。
img_from_target_files signed-target_files.zip signed-img.zip生成されるファイル
signed-img.zip
にはすべての .img
ファイルが含まれます。イメージをデバイスに読み込むには、次のように fastboot を使用します。
fastboot update signed-img.zip