APK 簽署配置 v4

Android 11 支援與串流相容的簽署配置,也就是 APK 簽署配置 v4。v4 簽章是根據針對 APK 所有位元組計算的 Merkle 雜湊樹狀結構產生。這個配置完全遵循 fs-verity 雜湊樹狀結構 (例如,以零填補鹽值,並以零填補最後一個區塊)。Android 11 會將簽章儲存在另一個檔案 <apk name>.apk.idsig 中。V4 簽章需要搭配 v2v3 簽章。

檔案格式

所有數值欄位都採用小端序。所有欄位佔用的位元組數量都與 sizeof() 完全相同,不會加入隱含的填補或對齊。

下列輔助結構可簡化定義:

template <class SizeT>
struct sized_bytes {
        SizeT size;
        byte bytes[size];
};

主要檔案內容:

struct V4Signature {
        int32 version; // only version 2 is supported as of now
        sized_bytes<int32> hashing_info;
        sized_bytes<int32> signing_info;
        sized_bytes<int32> merkle_tree;  // optional
};

hashing_info 是用於產生雜湊樹狀結構和根雜湊的參數:

struct hashing_info.bytes {
    int32 hash_algorithm;    // only 1 == SHA256 supported
    int8 log2_blocksize;     // only 12 (block size 4096) supported now
    sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max
    sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page
};

signing_info 是下列結構體:

struct signing_info.bytes {
    sized_bytes<int32> apk_digest; // used to match with the corresponding APK
    sized_bytes<int32> x509_certificate; // ASN.1 DER form
    sized_bytes<int32> additional_data; // a free-form binary data blob
    sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate
    int32 signature_algorithm_id; // see the APK v2 doc for the list
    sized_bytes<int32> signature;
};

apk_digest 是從 APK 的 v3 簽署區塊取得。如果沒有這個區塊,系統會從 v2 區塊取得 (請參閱 apk_digest)。

如要建立及驗證 signature 代碼,必須將下列資料序列化為二進位 BLOB,並做為「已簽署資料」傳遞至簽署和驗證演算法:

struct V4DataForSigning {
        int32 size;
        int64 file_size; // the size of the file that's been hashed.
        hashing_info.hash_algorithm;
        hashing_info.log2_blocksize;
        hashing_info.salt;
        hashing_info.raw_root_hash;
        signing_info.apk_digest;
        signing_info.x509_certificate;
        signing_info.additional_data;
};

merkle_tree 是 APK 的完整 Merkle 樹狀結構,計算方式請參閱 fs-verity 說明文件。

生產者和消費者

如果您使用預設參數執行 apksigner Android SDK 工具,系統會產生 v4 簽章檔案。停用 v4 簽署的方式與其他簽署機制相同。這項工具也能驗證 v4 簽章是否有效。

執行 adb install --incremental 指令時,adb 會預期 .apk.idsig 檔案位於 APK 旁邊。adb 預設也會使用 IDSIG 檔案嘗試增量安裝,如果檔案遺失或無效,則會改為一般安裝。

建立安裝工作階段時,PackageInstaller 中的新串流安裝 API 會在將檔案新增至工作階段時,接受已移除的 v4 簽章做為個別引數。此時,signing_info 會以整個 Blob 的形式傳遞至 IncFS。IncFS 會從 Blob 擷取根雜湊。

提交安裝工作階段時,PackageManagerService 會發出 ioctl 呼叫,從 IncFS 擷取 signing_info blob、剖析該 blob,並驗證簽章。

Incremental Data Loader 元件會透過資料載入器原生 API,串流簽章的 Merkle 樹狀結構部分。package 服務殼層指令 install-incremental 接受以 Base64 編碼的已移除 v4 簽章檔案,做為每個新增檔案的參數。對應的 Merkle 樹狀結構必須傳送至指令的 stdin

apk_digest

apk_digest 是第一個可用的內容摘要,順序如下:

  1. V3、1 MB 區塊、SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512)
  2. V3、4 KB 區塊、SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256)
  3. V3、1 MB 區塊、SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256)
  4. V2、SHA2-512
  5. V2、SHA2-256

請參閱 APK 簽署配置 v3 中的長度前置簽署者長度前置序列

驗證和測試

APK 驗證程序 v4 如下圖所示:

APK 驗證程序 v4

圖 1. APK 驗證程序 v4。

使用功能單元測試和 CTS 驗證實作項目:

  • CtsIncrementalInstallHostTestCases
  • /android/cts/hostsidetests/incrementalinstall

測試簽名格式

如要測試簽章格式,請設定建構環境,然後執行下列手動測試:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

使用 Android SDK (ADB 和 apksigner) 測試簽章格式

請按照下列程序,使用 Android SDK 測試簽章格式:

  1. 設定建構環境,並確認您已完成 IncFS 的實作。
  2. 在目標實體裝置或模擬器上刷入建構版本。
  3. 產生或取得現有 APK,然後建立偵錯簽署金鑰
  4. 從 build-tools 資料夾中,以 v4 簽署格式簽署並安裝 APK。

    簽署
    $ ./apksigner sign --ks debug.keystore game.apk

    安裝
    $ ./adb install game.apk

    如何查看這些測試
    /android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java