簽署要發布的版本

Android 作業系統映像檔會在兩處使用加密編譯簽章:

  1. 圖片中的每個 .apk 檔案都必須經過簽署。Android 套件管理員使用 .apk 簽章的方式有兩種:
    • 取代應用程式時,其簽署金鑰必須與 才能存取舊應用程式的資料。這項訴訟保留 這兩者都是透過覆寫 .apk 來更新使用者應用程式,以及 覆寫安裝較新版本的系統應用程式 /data
    • 兩個或多個應用程式想要共用使用者 ID (以便彼此共用) 資料等),就必須使用相同的金鑰簽署。
  2. 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 憑證。發布的映像檔會 憑證的真實性 update 套件。將 -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 中:

測試金鑰
適用於未指定金鑰的套件的一般預設金鑰。
平台
核心平台中的套件測試金鑰。
已分享
測試住家/聯絡人在住家成員的共用金鑰。
媒體
媒體/下載系統中的套件測試金鑰。
網路堆疊
為網路系統中的套件測試金鑰。 網路堆疊金鑰的作用是簽署二進位檔 模組化系統元件 。如果模組更新是單獨建構,並與預先建構整合 不需要在裝置映像檔中產生網路堆疊金鑰 Android 原始碼樹狀結構。

個別套件會設定 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 中的五個,以及 以取代其他索引鍵 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.apexcom.android.media.apexcom.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 key
openssl 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 key
openssl 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 key
openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt

# securely delete the temp.pem file
shred --remove temp.pem

上方指定的 opensl pkcs8 指令會建立一個 .pk8 檔案,但當中含有 no 適合與建構系統搭配使用的密碼建立以 .pk8 安全儲存的 使用密碼 (所有實際發布金鑰都應使用此密碼),將 -nocrypt 引數搭配 -passout stdin;然後 Opensl 會使用從標準輸入讀取的密碼來加密私密金鑰。否 提示會顯示,因此如果 stdin 是終端機,程式就會顯示停止運作 您真的正在等候您輸入密碼其他值可以是 用於-passout 引數從其他位置讀取密碼;的 請參閱 opensl 說明文件

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 檔案。 如要將映像檔載入裝置,請使用 Quickboot 如下:
fastboot update signed-img.zip