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;
};
  1. merkle_tree是 APK 的整個 Merkle 樹,依照fs-verity文件中的描述計算。

生產者和消費者

如果您使用預設參數執行apksigner Android SDK 工具,現在會產生 v4 簽章檔。可以像其他簽章方案一樣停用 v4 簽章。它還可以驗證 v4 簽章是否有效。

執行adb install --incremental指令時, adb期望 .apk.idsig 檔案出現在 .apk 旁邊
預設情況下,它也會使用 .idsig 檔案嘗試增量安裝,如果該檔案遺失或無效,則會回退到常規安裝。

建立安裝工作階段後, PackageInstaller中的新串流安裝 API 會在向會話新增檔案時接受剝離的v4 簽章作為單獨的參數。此時, signing_info作為整個 blob 傳遞到 incfs 中。 Incfs 從 blob 提取根哈希值。

提交安裝會話時,PackageManagerService 會執行 ioctl 從 incfs 檢索簽章資訊 blob,對其進行解析並驗證簽章。

增量資料載入器元件預計將透過資料載入器本機 API 傳輸簽署的 Merkle 樹部分。
package service shell 指令install-incremental接受編碼為 base64 的剝離 v4 簽章檔案作為每個新增檔案的參數。對應的 Merkle 樹必鬚髮送到命令的stdin中。

apk_摘要

apk_digest是第一個可用的內容摘要(依序):

  1. V3,1MB 區塊,SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
  2. V3、4KB 區塊、SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256)、
  3. V3,1MB 區塊,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