APK 签名方案 v3
Android 9 新增了对 APK Signature Scheme v3 的支持。该架构提供的选择可以在其签名块中为每个签名证书加入一条轮转证据记录。 利用此功能,应用可以通过将 APK 文件过去的签名证书链接到现在签署应用时使用的证书,从而使用新签名证书来签署应用。
轮替签名证书世系或新签名序列的语法如下:
详细了解如何使用 apksigner 轮转密钥。
Android 9 支持 APK 密钥轮替 ,这使应用能够在 APK 更新过程中更改其签名密钥。为了实现轮替, APK 必须指示新旧签名密钥之间的信任级别。为了支持密钥轮替,我们将 APK 签名方案 从 v2 更新为 v3 ,以允许使用新旧密钥。 v3 在 APK 签名分块中添加了有关受支持的 SDK 版本和 proof-of-rotation 结构的信息。
为了保持与 v1 APK 格式的向后兼容性, v2 和 v3 APK 签名存储在 “APK 签名分块” 内紧邻 ZIP Central Directory 前面。
v3 APK 签名分块 的格式与 v2 相同。 APK 的 v3 签名会存储为一个 “ID-值” 对,其中 ID 为 0xf05368c0 。
“APK 签名分块” 的格式如下(所有数字字段均采用小端字节序):
在解析 APK 时,首先要通过以下方法找到 “ZIP 中央目录” 的起始位置:在文件末尾找到 “ZIP 中央目录结尾” 记录,然后从该记录中读取 “中央目录” 的起始偏移量。通过 magic 值,可以快速确定 “中央目录” 前方可能是 “APK 签名分块” 。然后,通过 size of block 值,可以高效地找到该分块在文件中的起始位置。
v3 方案的设计与 v2 方案 非常相似,它们采用相同的常规格式,并支持相同的 签名算法 ID 、密钥大小和 EC 曲线。
但是, v3 方案增添了有关受支持的 SDK 版本和 proof-of-rotation 结构的信息。
“APK 签名方案 v2 分块” 存储在 “APK 签名分块” 内, ID 为 0xf05368c0 。
“APK 签名方案 v3 分块” 采用 v2 的格式:
proof-of-rotation 结构允许应用轮替其签名证书,而不会使这些证书在与这些应用通信的其他应用上被屏蔽。为此,应用签名需包含两个新数据块:
签名数据部分中的 proof-of-rotation 属性包含一个单链表,其中每个节点都包含用于为之前版本的应用签名的签名证书。此属性旨在包含概念性 proof-of-rotation 和 self-trusted-old-certs 数据结构。该单链表按版本排序,最旧的签名证书对应于根节点。在构建 proof-of-rotation 数据结构时,系统会让每个节点中的证书为列表中的下一个证书签名,从而为每个新密钥提供证据来证明它应该与旧密钥一样可信。
在构造 self-trusted-old-certs 数据结构时,系统会向每个节点添加标记来指示它在组中的成员资格和属性。例如,可能存在一个标记,指示给定节点上的签名证书可信,可获得 Android 签名权限。此标记允许由旧证书签名的其他应用仍被授予由使用新签名证书签名的应用所定义的签名权限。由于整个 proof-of-rotation 属性都位于 v3 signer 字段的签名数据部分中,因此用于为所含 APK 签名的密钥会保护该属性。
此格式排除了 多个签名密钥 的情况和将 不同祖先签名证书 收敛到一个证书的情况(多个起始节点指向一个通用接收器)。
proof-of-rotation 存储在 “APK 签名方案 v3 分块” 内, ID 为 0x3ba06f8c 。其格式为:
Android 目前将使用多个证书签名的 APK 视为具有与所含证书不同的签名身份。因此,签名数据部分中的 proof-of-rotation 属性构成了一个有向无环图,最好将其视为单链表,其中给定版本的每组签名者都表示一个节点。这为 proof-of-rotation 结构(下面的多签名者版本)带来了额外的复杂性。排序成为一个特别突出的问题。更重要的是,无法再单独为 APK 签名,因为 proof-of-rotation 结构必须让旧签名证书为新的证书集签名,而不是逐个签名。
例如,如果希望由两个新密钥 B 和 C 签名的 APK 是由密钥 A 签名的,则它不能让 B 签名者仅包含 A 或 B 的签名,因为这是与 B 和 C 不同的签名身份。这意味着签名者必须在构建此类结构之前进行协调。
多个签名者 proof-of-rotation 属性
v3 方案也无法处理两个不同密钥轮替到同一个应用的同一签名密钥的情形。这不同于收购情形,在收购情形中,收购公司希望转移收购的应用以使用其签名密钥来共享权限。收购被视为受支持的用例,因为新应用将通过其软件包名称来区分,并且可以包含自己的 proof-of-rotation 结构。不受支持的用例是,同一应用有两个不同的路径指向相同的证书,这打破了在密钥轮替设计中做出的许多假设。
在 Android 9 及更高版本中,可以根据 APK 签名方案 v3、v2 或 v1 验证 APK 。较旧的平台会忽略 v3 签名而尝试验证 v2 签名,然后尝试验证 v1 签名。