Android 作業系統映像檔會在兩處使用加密編譯簽章:
- 圖片中的每個
.apk
檔案都必須經過簽署。Android 的 Package Manager 會以兩種方式使用.apk
簽名:- 應用程式替換後,必須使用與舊版應用程式相同的金鑰進行簽署,才能存取舊版應用程式的資料。無論是透過覆寫
.apk
更新使用者應用程式,還是在/data
下安裝新版系統應用程式,這項原則都適用。 - 兩個或多個應用程式想要共用使用者 ID (以便彼此共用) 資料等),就必須使用相同的金鑰簽署。
- 應用程式替換後,必須使用與舊版應用程式相同的金鑰進行簽署,才能存取舊版應用程式的資料。無論是透過覆寫
- OTA 更新套件必須使用 或安裝程序將拒絕這些要求
發布金鑰
Android 樹狀結構包含 test-keys
build/target/product/security
。建構 Android 作業系統映像檔
使用 make
簽署所有 .apk
檔案時,系統會使用
測試金鑰由於測試金鑰是公開資訊,因此任何人都能簽署自己的測試金鑰
金鑰相同的 .apk 檔案,可能會使檔案更換或綁架系統
內建的應用程式因此,請務必簽署
公開發布或部署的 Android 作業系統映像檔
發布金鑰。
如要產生專屬的版本鍵組合,請在 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
做為輸入值,然後會在 .zip
中
所有 .apk
檔案皆已使用新的金鑰簽署。而
已簽署的圖片位於 IMAGES/
signed-target_files.zip
。
簽署 OTA 套件
已簽署的目標檔案 ZIP 檔案可轉換成已簽署的 OTA 更新 ZIP 檔案 按照下列程序操作:ota_from_target_files \
-k (--package_key)
signed-target_files.zip \
signed-ota_update.zip
簽章和側載
側載不會略過復原程序的一般套件簽名驗證機制。在安裝套件之前,復原程序會驗證套件是否使用與儲存在復原分區中的公開金鑰相符的私密金鑰簽署,就像透過無線方式傳送的套件一樣。
從主要系統接收的更新套件通常會驗證兩次:
透過 kubectl 指令
RecoverySystem.verifyPackage()
方法呼叫
以及災難復原RecoverySystem API 會檢查簽名是否與主要系統中儲存的公開金鑰相符,該系統位於 /system/etc/security/otacerts.zip
檔案中 (預設)。復原程序會依據儲存的公開金鑰檢查簽章
復原分區 RAM 磁碟中的 /res/keys
。
根據預設,建構產生的目標檔案 .zip
會設定
與測試金鑰相符的 OTA 憑證。在已發布的映像檔上,必須使用其他憑證,才能讓裝置驗證更新套件的真實性。將 -o
標記傳送至
如上一節所示,將 sign_target_files_apks
取代為
含有憑證中發布金鑰憑證的測試金鑰憑證
目錄。
系統映像檔和還原映像檔通常會儲存相同的 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 不會包含額外金鑰,因此正確驗證下載的套件時,系統不會針對使用此金鑰簽署的套件叫用復原程序。
憑證和私密金鑰
每個金鑰都會提供兩個檔案:憑證 (副檔名為 .x509.pem) 和私密金鑰 (副檔名為 .pk8)。私密金鑰應妥善保密,且必須用於簽署套件。金鑰本身可能受到密碼保護。憑證中 僅包含金鑰的公開一半,因此可將 可用來確認套件是否已由相應的 私密金鑰
標準 Android 版本使用五組金鑰,所有金鑰都位於
build/target/product/security
中:
- 測試金鑰
- 適用於未指定金鑰的套件的一般預設金鑰。
- 平台
- 核心平台中套件的測試金鑰。
- 已分享
- 在住家/聯絡人程序中共用物品的測試金鑰。
- 媒體
- 媒體/下載系統中套件的測試金鑰。
個別套件會設定 LOCAL_CERTIFICATE,藉此指定其中一個鍵 將其儲存在 Android.mk 檔案中(如未設定這個變數,系統會使用 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
標記 會一次取代一個金鑰。--default_key_mappings dir
旗標會指定 並在目錄中使用五組金鑰取代build/target/product/security
;等同於使用--key_mapping
五次指定對應。
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
使用
--extra_apks apk_name1,apk_name2,...=key
標記
,根據 APK 名稱指定簽署金鑰替換項目。如果
key
留空,指令碼會處理指定的 APK
預先簽署的商標
假設您要開發 Tardis 產品,就需要六個受密碼保護的金鑰:五個用於取代 build/target/product/security
中的五個金鑰,另一個用於取代上述範例中 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 檔案 簽署了兩個金鑰:一個用於 APEX 中的迷你檔案系統映像檔,以及 整個 APEX 除外
簽署版本時,系統會替換 APEX 檔案的兩組簽署金鑰
。檔案系統酬載金鑰會使用 --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
會使用指定的發布金鑰進行簽署 (runtime_apex_container
用於 APEX 檔案,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 會使用 2048 位元 RSA 金鑰搭配公開指數 3。您可以產生 憑證/私密金鑰組 openssl.org:
# 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
上方指定的 opensl pkcs8 指令會建立一個 .pk8 檔案,但當中含有 no
適合與建構系統搭配使用的密碼建立以 .pk8 安全儲存的
使用密碼 (所有實際發布金鑰都應使用此密碼),將
-nocrypt
引數搭配 -passout stdin
;然後 Opensl
會使用從標準輸入讀取的密碼來加密私密金鑰。否
提示會顯示,因此如果 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