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形式)
- 長度前綴X.509
-
minSDK
(UINT32) -如果平台版本低於這個數這個簽名者應該被忽略。 -
maxSDK
(UINT32) -如果平台版本高於這個數這個簽名者應該被忽略。 - 的長度前綴長度前綴序列
additional attributes
:-
ID
(UINT32) -
value
(可變長度:附加屬性的長度- 4個字節) -
ID - 0x3ba06f8c
-
value -
驗證的旋轉結構
-
- 長度前綴的長度前綴序列
minSDK
(UINT32) -在簽約數據部分minSDK值的副本-用於跳過此簽名進行驗證,如果當前平台不在範圍內。必須匹配有符號的數據值。-
maxSDK
(UINT32) -用於跳過此簽名進行驗證,如果當前平台不在範圍內-在簽名的數據部分maxSDK值的副本。必須匹配有符號的數據值。 - 長度前綴的長度前綴序列
signatures
:-
signature algorithm ID
(UINT32) - 長度前綴
signature
在signed 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) -算法使用在先前的水平證書
- 長度前綴X.509
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形式)
- 長度前綴X.509
- 的序列
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。
圖1. APK簽名驗證處理
APK 簽名方案 v3 驗證
- 找到 APK 簽名塊並驗證:
- APK 簽名塊的兩個大小字段包含相同的值。
- ZIP 中央目錄後面緊跟著 ZIP 中央目錄記錄的結尾。
- ZIP 中央目錄結尾後面沒有更多數據。
- 在 APK 簽名塊中找到第一個 APK 簽名方案 v3 塊。如果V3塊存在,進入步驟3。否則,回落到驗證APK使用V2方案。
- 對於每一個
signer
在APK簽名方案V3塊以最小和最大SDK版本是在當前平台的範圍:- 選擇最強的支持
signature algorithm ID
從signatures
。強度排序取決於每個實現/平台版本。 - 驗證相應的
signature
從signatures
反對signed data
使用public key
。 (這是現在可以安全地解析signed data
。) - 驗證最小和最大SDK版本中簽名的數據匹配指定的
signer
。 - 驗證簽名算法ID的排序列表
digests
和signatures
是相同的。 (這是為了防止簽名剝離/添加。) - 計算的APK內容的摘要使用相同的摘要算法的摘要算法的簽名算法使用。
- 驗證所計算的摘要是等同於相應的
digest
從digests
。 - 驗證第一的是SubjectPublicKeyInfo進行
certificate
的certificates
是相同的public key
。 - 如果證明的旋轉屬性存在的
signer
驗證的結構是有效的,這個signer
是在列表中的最後一個證書。
- 選擇最強的支持
- 如果只有一個驗證成功
signer
在當前平台和第3步成功為的範圍內發現的signer
。
驗證
要測試設備支持V3正常,運行PkgInstallSignatureVerificationTest.java
在CTS測試cts/hostsidetests/appsecurity/src/android/appsecurity/cts/
。