APK 簽署配置 v4

Android 11 支援透過 APK 簽署配置 v4 的串流相容簽署配置。這個 v4 簽章是根據 APK 的所有位元組計算而成的 Merkle 雜湊樹。它會完全遵循 fs-verity 雜湊樹狀結構 (例如,鹽值的零填充填補和最後一個區塊的零填充填補)。Android 11 會將簽章儲存在個別檔案中。<apk name>.apk.idsigA 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;
};
  1. merkle_tree 是 APK 的完整 Merkle 樹狀結構,計算方式如 fs-verity 說明文件所述。

生產者和消費者

apksigner 如果您使用預設參數執行 Android SDK 工具,現在會產生 v4 簽名檔案。您可以使用其他簽署配置的方式停用 v4 簽署。也可以驗證 v4 簽章是否有效。

adb 預期在執行 adb install --incremental 指令時,.apk.idsig 檔案會位於 .apk 旁邊
。預設情況下,它也會使用 .idsig 檔案嘗試逐步安裝,如果檔案遺失或無效,則會改為執行一般安裝作業。

建立安裝工作階段時,PackageInstaller 中的新串流安裝 API 會在將檔案新增至工作階段時,將「去除」的 v4 簽名做為獨立的引數。此時,signing_info 會以整個 blob 的形式傳遞至 incfs。Incfs 會從 blob 中擷取根雜湊。

當安裝工作階段正在提交時,PackageManagerService 會執行 ioctl 來從 incfs 擷取 signing_info blob,並剖析及驗證簽名。

增量資料載入器元件應透過資料載入器原生 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
圖 1:APK 驗證程序 v4

驗證和測試

使用功能單元測試和 CTS 驗證實作方式。

  • CtsIncrementalInstallHostTestCases
    • /android/cts/hostsidetests/incrementalinstall

測試簽名格式

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

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

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

如要使用 Android SDK 測試簽名格式,請設定開發環境,並確認您已完成 IncFS 的實作。接著,在目標實體裝置或模擬器上刷新版本。您必須產生或取得現有的 APK,然後建立偵錯簽署金鑰。最後,請從 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