基于《iOS App 签名的原理》整理。本文优先保留原 PDF 的推导逻辑:先从数字签名出发,再解释为什么 iOS 最终需要 Certificate、Provisioning Profile、Entitlements、App ID、设备列表和本地私钥。
1. iOS 为什么需要签名
iOS 签名机制的核心目标不是“加密 App”,而是建立一条可信授权链:
- Apple 要确认:这个 App 的安装/分发行为是否经过 Apple 允许。
- 系统要确认:App 或其签名数据没有被非法篡改。
- 开发调试场景还要限制:谁可以签、哪个 App 可以签、哪些设备可以安装、App 可以使用哪些能力。
因此可以把 iOS 签名理解成:
身份认证 + 完整性校验 + 安装范围控制 + Capability/Entitlements 权限授权
2. 基础:非对称加密与数字签名
非对称密码体系有一对密钥:
- 私钥(Private Key):签名者自己保存。
- 公钥(Public Key):提供给验证者。
数字签名并不是简单地“用私钥加密整个 App”。基本思想是先计算数据摘要,再用私钥对摘要进行签名;验证方用公钥验证签名,并将得到/验证的摘要与自己重新计算的数据摘要比较。
数字签名解决两个问题
- 完整性:数据发生变化,摘要也会变化。
- 身份可信性:只有持有对应私钥的人才能生成可由该公钥验证的签名。
PDF 使用 MD5 作为讲解数字摘要的例子。理解原理时可把它抽象成
Hash(data);现代实际签名体系不应把 MD5 当作安全签名摘要算法。
3. 最简单模型:Apple 直接给 App 签名
假设 iOS 只允许从 App Store 安装应用,那么架构可以非常简单:
Apple 保存私钥,iOS 设备内置可信公钥。App 经 Apple 私钥签名后,设备即可验证它确实经过 Apple 授权且内容未被修改。
为什么现实中不能只有这一层?
开发过程中,开发者必须能把尚未上传 App Store 的 App 直接装到真机调试。如果每次 Build 都上传 Apple 服务器重新签名,开发效率无法接受。
所以新的问题变成:
Apple 不直接给每个开发中的 App 签名,又怎样允许开发者本地签名,同时仍保持控制权?
4. 核心机制:双层信任链
PDF 用“公钥 L / 私钥 L(Local)”和“公钥 A / 私钥 A(Apple)”描述这个过程。
第一层:Apple 认证开发者的公钥
开发者 Mac:
Private Key L <---- 对 App 签名
Public Key L ----> 提交给 Apple
Apple 使用自己的 Private Key A 对开发者的 Public Key L 进行认证,形成开发者证书。
第二层:开发者给 App 签名
开发者使用 Private Key L 给 App 签名。
iOS 最终执行两级验证:
这形成了关键的信任关系:
Apple Root / Apple Trust
↓
Apple 认证开发者证书
↓
开发者公钥 L 被系统信任
↓
开发者私钥 L 签名 App
↓
iOS 用公钥 L 验证 App
因此 Apple 不需要亲自签每一次 Debug Build,只需要证明:
“这个用于签 App 的公钥,是我 Apple 批准的。”
5. 为什么只有 Certificate 仍然不够
如果 Apple 只认证开发者公钥,那么开发者可能用这个私钥给任意 App 签名,并装到任意设备。
因此 Apple 还需要控制:
- 哪些设备可以安装:Device UDID / Device IDs
- 签的是哪个应用:App ID
- App 可以使用什么能力:Entitlements
- 使用哪张开发者证书:Certificate
- 授权有效期等信息
这些信息最终集中到 Provisioning Profile。
6. Provisioning Profile 是整个体系的授权清单
可以把 Provisioning Profile 理解为:
Apple 签名过的一份“这个 App 可以怎样运行”的授权文件。
逻辑结构可简化为:
Provisioning Profile
├── Developer Certificate
│ └── Developer Public Key
├── App ID
├── Device IDs / UDIDs(某些分发类型)
├── Entitlements
├── 有效期等信息
└── Apple Signature
Apple 对 Profile 整体签名,因此开发者不能自行修改其中的 App ID、设备列表或权限。
7. 最终完整签名架构
8. 从创建证书到真机验证:完整过程
Step 1:Mac 生成本地密钥对
Keychain 中执行“从证书颁发机构请求证书”等操作,本质上是在本机建立与证书申请相关的密钥材料。
核心关系:
Mac
├── Private Key ← 最重要,不能泄漏
└── Public Key ← 用于向 Apple 申请证书
Step 2:向 Apple 申请开发者证书
开发者向 Apple 提交 CSR/公钥相关信息。
Apple 对开发者身份/公钥进行认证,生成 Developer Certificate。
Developer Public Key
↓
Apple CA / Developer Portal
↓ Apple 签名
Developer Certificate
Step 3:配置 App ID、设备和能力
Developer Portal 中配置:
Bundle/App Identity
+
Registered Devices
+
Capabilities / Entitlements
+
Developer Certificate
Step 4:生成 Provisioning Profile
Apple 将这些授权信息组合并签名:
Certificate
+ App ID
+ Devices
+ Entitlements
+ ...
↓
Apple Signature
↓
Provisioning Profile
Step 5:Xcode 本地签 App
Xcode 找到 Developer Certificate 对应的本地 Private Key,使用它对 App 进行代码签名。
同时将 Provisioning Profile 嵌入 App:
MyApp.app/
├── MyApp # Mach-O,可执行文件含代码签名信息
├── _CodeSignature/
│ └── CodeResources
└── embedded.mobileprovision
Step 6:iOS 验证 Apple 的授权
安装/运行时,系统首先确认 embedded.mobileprovision 等授权数据确实来自可信 Apple 签名链。
Step 7:iOS 验证 App
随后检查:
开发者证书是否合法?
↓
App 的代码签名能否由证书对应公钥验证?
↓
App ID 是否匹配?
↓
当前设备是否被允许?(适用时)
↓
App Entitlements 是否超出 Profile 授权?
↓
全部通过 → 安装 / 启动
9. Certificate、CSR、Private Key、p12、Profile 的关系
这是最容易混淆的一组概念。
| 对象 | 本质 | 谁生成/签发 | 主要作用 |
|---|---|---|---|
| Private Key | 私钥 | Mac 本地 | 对 App 进行签名 |
| Public Key | 公钥 | 与私钥成对生成 | 验证开发者签名 |
| CSR | 证书签名请求 | Mac | 向 CA/Apple 申请证书时提交的信息 |
| Developer Certificate | Apple 认证的开发者身份/公钥凭证 | Apple | 证明该签名身份得到 Apple 认可 |
.p12 |
通常用于导出/迁移证书和对应私钥的 PKCS#12 容器 | 开发者导出 | 将签名身份迁移到另一台 Mac/CI |
| Entitlements | App 权限声明 | App/Xcode + Apple 授权体系 | 声明 App 要使用的能力 |
| Provisioning Profile | Apple 签名的授权配置 | Apple | 将证书、App ID、设备、Entitlements 等约束关联起来 |
embedded.mobileprovision |
App 内嵌的 Profile | Xcode 打包 | 供设备验证授权范围 |
一句话记忆
Certificate:你是谁
Private Key:证明“你就是你”的秘密
App ID:你要签哪个 App
Entitlements:这个 App 能做什么
Devices:它能装到哪些设备
Provisioning Profile:Apple 对以上组合给出的授权证明
Code Signature:你用自己的私钥对实际 App 做出的签名
10. CSR → Certificate → p12 的关系图
关键点:
只有
.cer/ Certificate,而没有与其匹配的 Private Key,通常无法完成对应身份的代码签名。
这也是常见的:
No signing certificate
Certificate has no matching private key
一类问题的根源。
11. Entitlements 为什么必须同时校验
App 自己会携带签名后的 Entitlements,而 Provisioning Profile 里也包含 Apple 授权范围。
因此不是 App 自己声明:
com.apple.developer.xxx = true
就自动拥有能力。
逻辑上必须满足:
App 请求的 Entitlements
⊆
Provisioning Profile 允许的 Entitlements
否则签名/安装/运行验证可能失败。
12. 不同分发方式的架构对比
下表主要按照 PDF 的分类和解释整理。Apple 的产品名称、分发政策和现代签名实现会随平台版本演进,因此这里重点理解“信任链和限制条件”,而不是把旧资料中的名称当成最新政策文档。
| 场景 | 谁最终授权 | 是否限制设备 | Profile 的角色 | 典型用途 |
|---|---|---|---|---|
| Development | Apple + Developer 签名链 | 是 | 约束 App ID、设备、Entitlements、证书 | 真机开发调试 |
| Ad Hoc | Apple + Developer 签名链 | 是 | 指定允许安装的设备 | 小范围测试分发 |
| In-House / Enterprise(PDF 用语) | Apple 认可的企业签名体系 | PDF 描述为不按普通设备列表限制 | 用于企业分发授权 | 企业内部应用 |
| App Store | Apple 分发体系 | 不按开发测试 UDID 列表 | 上传阶段用于开发者身份/权限等校验;商店分发验证模型不同 | 正式公开分发 |
13. Development 与“最简单 App Store 模型”对比
本质差异
简单模型:
Apple → App
开发模型:
Apple → Developer Identity / Authorization → App
多出来的一层,就是为了让开发者能够离线、本地、高频地签 Debug Build,同时 Apple 仍掌握授权边界。
14. iOS 签名最值得记住的信任链
Apple 信任根
│
Apple 对证书/Profile签名
│
┌────────────┴────────────┐
│ │
Developer Certificate Provisioning Profile
│ ├─ App ID
│ ├─ Devices
│ └─ Entitlements
│
▼
Developer Public Key
▲
│ 对应
Developer Private Key
│
│ codesign
▼
App Binary
│
▼
iOS 验证
可以浓缩成一句:
Apple 不必直接信任每一个开发中的 App;Apple 信任一个受约束的开发者签名身份,iOS 再沿着这条信任链验证 App。
15. 常见签名错误如何从原理定位
① Certificate 存在,但没有 Private Key
Certificate ✓
Private Key ✗
结果:你有“身份证明”,但没有能够生成该身份签名的秘密密钥。
处理思路:检查 Keychain 中证书下是否有关联私钥;需要迁移时从原机器导出包含对应私钥的 p12。
② Provisioning Profile 与 Certificate 不匹配
Profile 允许 Certificate A
当前使用 Certificate B
→ 授权链断裂。
③ Bundle ID / App ID 不匹配
App Bundle ID
≠
Profile 授权的 App ID
→ Profile 并没有授权这个 App。
④ Device 不在 Profile 中
Development / Ad Hoc 等需要设备授权的场景:
Current UDID ∉ Provisioned Devices
→ 真机无法按该授权安装。
⑤ Entitlements 不匹配
App Requested Capability
>
Profile Granted Capability
→ App 请求了 Apple 没有在该 Profile 中授权的能力。
⑥ Profile / Certificate 过期或失效
签名不仅要“数学上正确”,相关凭证和授权本身也存在有效性条件。
16. 一套排查思维
遇到 Xcode Signing 问题时,不要只反复点击 “Automatically manage signing”,可以沿信任链逐层检查:
17. PDF 原文中需要带着“历史资料”视角理解的地方
这份 PDF 非常适合建立签名机制的概念模型,尤其是“双层签名 → 增加设备/App限制 → Provisioning Profile”的推导过程。
但学习时建议区分两层:
原理层:长期有效
- 公私钥与数字签名
- Apple 信任链
- Developer Certificate
- 本地 Private Key
- App Code Signature
- Provisioning Profile
- App ID / Entitlements 的授权约束
实现与政策层:可能随 iOS / Xcode / Apple Developer Program 更新
- 摘要算法的具体选择
- App Store 安装包内部细节
- Enterprise / In-House 的政策和验证机制
- Xcode 自动签名的具体行为
- Profile 是否/如何出现在不同现代分发产物中
因此排查现代 Xcode 问题时,应以 Apple 当前官方文档和实际 codesign / Profile 内容为准。
18. 最终速记版
1. Mac 生成 Private Key + Public Key
2. 用 CSR 向 Apple 申请 Developer Certificate
3. Apple 认证开发者签名身份
4. Developer Portal 配置:
Certificate
+ App ID
+ Devices
+ Entitlements
5. Apple 对这些授权信息签名
→ Provisioning Profile
6. Xcode 使用本地 Private Key 对 App codesign
7. Profile 作为授权信息参与打包/验证
8. iOS:
先信 Apple
→ 再信 Apple 批准的 Developer Certificate/Profile
→ 再验证 Developer 对 App 的签名
→ 再核对 App ID / Device / Entitlements
9. 全部满足后,App 才获得相应安装/运行授权
核心公式
Apple Trust
↓
Certificate + Provisioning Profile
↓
Developer Identity
↓
Code Signature
↓
App
签名体系的核心不是某一个 .cer 或 .mobileprovision 文件,而是整条可验证的信任链。
浙公网安备 33010602011771号