APK 簽名方案 v3

Android的9支持APK密鑰輪換,這給應用程序,以改變他們的簽名密鑰的APK更新的一部分的能力。為了使輪換實用,APK 必須指明新舊簽名密鑰之間的信任級別。為了支持密鑰輪換,我們更新了APK簽名方案從V2到V3,以允許使用新的和舊密鑰。 V3 向 APK 簽名塊添加了有關支持的 SDK 版本的信息和旋轉證明結構。

APK 簽名塊

為了保持與 v1 APK 格式的向後兼容性,v2 和 v3 APK 簽名存儲在 APK 簽名塊中,緊鄰 ZIP 中央目錄之前。

第3版的APK簽名塊格式是一樣的V2 。 APK 的 v3 簽名存儲為 ID 值對,ID 為 0xf05368c0。

APK 簽名方案 v3 塊

第3版方案的設計是非常相似的V2方案。它具有相同的通用格式,並支持相同的簽名算法標識,按鍵尺寸和EC曲線。

但是,v3 方案添加了有關支持的 SDK 版本和旋轉證明結構的信息。

格式

APK簽名方案V3塊存儲的APK ID下簽名塊內0xf05368c0

APK 簽名方案 v3 塊的格式遵循 v2 的格式:

  • 長度前綴的長度前綴序列signer
    • 長度前綴signed data
      • 長度前綴的長度前綴序列digests
        • signature algorithm ID (4字節)
        • digest (長度前綴)
      • 的X.509長度前綴序列certificates
        • 長度前綴X.509 certificate (ASN.1 DER形式)
      • minSDK (UINT32) -如果平台版本低於這個數這個簽名者應該被忽略。
      • maxSDK (UINT32) -如果平台版本高於這個數這個簽名者應該被忽略。
      • 的長度前綴長度前綴序列additional attributes
        • ID (UINT32)
        • value (可變長度:附加屬性的長度- 4個字節)
        • ID - 0x3ba06f8c
        • value -驗證的旋轉結構
    • minSDK (UINT32) -在簽約數據部分minSDK值的副本-用於跳過此簽名進行驗證,如果當前平台不在範圍內。必須匹配有符號的數據值。
    • maxSDK (UINT32) -用於跳過此簽名進行驗證,如果當前平台不在範圍內-在簽名的數據部分maxSDK值的副本。必須匹配有符號的數據值。
    • 長度前綴的長度前綴序列signatures
      • signature algorithm ID (UINT32)
      • 長度前綴signaturesigned data
    • 長度前綴public key (SubjectPublicKeyInfo進行,ASN.1 DER形式)

輪換證明和自信任舊證書結構

輪換證明結構允許應用輪換他們的簽名證書,而不會在與其通信的其他應用程序上被阻止。為此,應用簽名包含兩個新數據:

  • 第三方斷言,無論其前身在哪裡,都可以信任應用程序的簽名證書
  • 應用程序本身仍然信任的舊簽名證書

簽名數據部分中的旋轉證明屬性由一個單向鍊錶組成,每個節點都包含一個用於簽署應用程序以前版本的簽名證書。此屬性旨在包含概念性的輪換證明和自信任舊證書數據結構。該列表按版本排序,其中最舊的簽名證書對應於根節點。輪轉證明數據結構是通過讓每個節點中的證書籤署列表中的下一個來構建的,從而為每個新密鑰注入證據,證明它應該與舊密鑰一樣受信任。

self-trusted-old-certs 數據結構是通過向每個節點添加標誌來構造的,這些標誌指示其在集合中的成員資格和屬性。例如,可能存在一個標誌,指示給定節點上的簽名證書是可信的,可以獲取 Android 簽名權限。此標誌允許由舊證書籤名的其他應用程序仍被授予由使用新簽名證書籤名的應用程序定義的簽名權限。由於整個證明的旋轉屬性駐留在V3的簽名的數據部分signer字段,它被用來簽署含APK的重點保護。

此格式排除了多個簽名密鑰和收斂不同祖先簽名證書的一個(多個起始節點到一個共同的接收器)。

格式

該證明的旋轉存儲在APK簽名方案V3座下的ID內0x3ba06f8c 。其格式為:

  • 長度前綴的長度前綴序列levels
    • 長度前綴signed data (由先前的證書-如果存在的話)
      • 長度前綴X.509 certificate (ASN.1 DER形式)
      • signature algorithm ID (UINT32) -算法使用在先前的水平證書
    • flags (UINT32) -標誌指示此證書是否應該在自我信任,老證書結構,以及哪些操作。
    • signature algorithm ID (UINT32) -必須從下一級簽名的數據部分中的一個相匹配。
    • 長度前綴signature超過上述signed data

多個證書

Android 目前將使用多個證書籤名的 APK 視為具有獨立於組成證書的唯一簽名身份。因此,簽名數據部分中的旋轉證明屬性形成了一個有向無環圖,最好將其視為單鍊錶,給定版本的每組簽名者代表一個節點。這給旋轉證明結構(下面的多簽名者版本)增加了額外的複雜性。特別是,訂購成為一個問題。更重要的是,不再可以獨立簽署 APK,因為輪換證明結構必須有舊的簽名證書來簽署新的證書集,而不是一個一個地簽名。例如,由密鑰 A 簽名並希望由兩個新密鑰 B 和 C 簽名的 APK 不能讓 B 簽名者只包含 A 或 B 的簽名,因為這是與 B 和 C 不同的簽名身份。這將意味著簽名者必須在構建這樣的結構之前進行協調。

多簽名者輪換證明屬性

  • 的長度前綴長度前綴序列sets
    • signed data (按上一組-如果存在的話)
      • 的長度前綴序列certificates
        • 長度前綴X.509 certificate (ASN.1 DER形式)
      • 的序列signature algorithm IDs (UINT32) -一個用於從以前的組中的每個證書,以相同的順序。
    • flags (UINT32) -標誌指示此組證書是否不應該在自己信任的,舊的證書結構,以及哪些操作。
    • 長度前綴的長度前綴序列signatures
      • signature algorithm ID (UINT32) -必須從簽名的數據部分中的一個相匹配
      • 長度前綴signature超過上述signed data

旋轉證明結構中的多個祖先

v3 方案也不處理輪換為同一應用程序的同一簽名密鑰的兩個不同密鑰。這與收購的情況不同,收購公司希望將收購的應用程序移動到使用其簽名密鑰來共享權限。此次收購被視為受支持的用例,因為新應用程序將通過其包名稱進行區分,並且可以包含自己的旋轉證明結構。不受支持的情況,即同一個應用程序有兩條不同的路徑來獲得同一個證書,打破了密鑰輪換設計中的許多假設。

確認

在 Android 9 及更高版本中,可以根據 APK Signature Scheme v3、v2 方案或 v1 方案驗證 APK。較舊的平台忽略 v3 簽名並嘗試驗證 v2 簽名,然後是 v1。

APK簽名驗證流程

圖1. APK簽名驗證處理

APK 簽名方案 v3 驗證

  1. 找到 APK 簽名塊並驗證:
    1. APK 簽名塊的兩個大小字段包含相同的值。
    2. ZIP 中央目錄後面緊跟著 ZIP 中央目錄記錄的結尾。
    3. ZIP 中央目錄結尾後面沒有更多數據。
  2. 在 APK 簽名塊中找到第一個 APK 簽名方案 v3 塊。如果V3塊存在,進入步驟3。否則,回落到驗證APK使用V2方案
  3. 對於每一個signer在APK簽名方案V3塊以最小和最大SDK版本是在當前平台的範圍:
    1. 選擇最強的支持signature algorithm IDsignatures 。強度排序取決於每個實現/平台版本。
    2. 驗證相應的signaturesignatures反對signed data使用public key 。 (這是現在可以安全地解析signed data 。)
    3. 驗證最小和最大SDK版本中簽名的數據匹配指定的signer
    4. 驗證簽名算法ID的排序列表digestssignatures是相同的。 (這是為了防止簽名剝離/添加。)
    5. 計算的APK內容的摘要使用相同的摘要算法的摘要算法的簽名算法使用。
    6. 驗證所計算的摘要是等同於相應的digestdigests
    7. 驗證第一的是SubjectPublicKeyInfo進行certificatecertificates是相同的public key
    8. 如果證明的旋轉屬性存在的signer驗證的結構是有效的,這個signer是在列表中的最後一個證書。
  4. 如果只有一個驗證成功signer在當前平台和第3步成功為的範圍內發現的signer

驗證

要測試設備支持V3正常,運行PkgInstallSignatureVerificationTest.java在CTS測試cts/hostsidetests/appsecurity/src/android/appsecurity/cts/