前言
来讨论下让人模糊的证书相关的问题。
1.要证书干嘛?
第一个问题,要证书干嘛?
证书是给签名用的。
签名又是干嘛的?
签名表示我对数据做了标记,表明这是我的数据,没有经过篡改。苹果使用签名机制来限制App的分发。 如何知道数据没有被篡改过? 数据发送方A使用了一套摘要算法,对发送的数据生成一段摘要,摘要算法保证了只要数据修改,那么通过摘要算法算出来的结果一定改变。然后,A生成一对公/私钥,用私钥对这个摘要进行加密,然后和数据一起发送给B。B收到数据后,用公钥解密签名,得到摘要,然后根据同样的摘要算法对数据进行计算,将得到的结果与解密得到的摘要进行比较,如果得到的结果一致,说明数据没有被修改过。
什么是公钥私钥?
在密码学中有一个非对称加密,非对称加密需要两个密钥:公钥和私钥。私钥加密的只能用公钥解密,公钥加密的只能用私钥解密。
那和证书有什么关系?
上述流程有个问题,就是摘要算法怎么保证相同,还有就是公钥大家都有,我怎么知道这个公钥是谁的。如果B有公钥,C也有公钥,C把B的公钥替换成自己的,那么C就能伪装成B,和A进行通信,所以A必须确保这个公钥来自B,这时候我们通过证书来解决这个问题。
证书从哪来?
从一个权威的第三方来,也就是大名鼎鼎的CA机构(Certificate Authority),证书授权中心,又称证书授权机构。
证书里有什么?
签发者的公钥;签发者使用的摘要算法;证书的数字签名;到期时间等...
balabala...
所以到底为什么需要证书?
苹果需要控制App的分发,App(非越狱)要装在设备上需要保证两点:
- App来自Apple信任的开发者。
- 安装的设备是Apple允许的设备。 如果App被篡改过,那么是不被允许安装在苹果的设备上的。
为了知道App有没有被篡改,所以需要对App的数据进行摘要计算,得到一个摘要。接收方使用同样的摘要算法对App进行计算,如果两者计算的结果一致,说明App没有被篡改过。 为了对计算结果,也就是摘要进行保护,所以发送方对它进行了加密,使用的是非对称加密,公私钥来自CA机构颁发的证书,证书中还包含了发送者所使用的摘要算法等其他数据。 这就是需要证书的原因。
2.其他相关概念
列举一下相关的概念:
- CSR文件(Certificate Signing Request)
- Certificates
- Identifiers
- Devices
- Provisioning Profile
- p12
- Entitlements
首先是这个CSR文件,英文 Certficate Signing Request,证书签名请求。在Mac的keychain的证书助理可以向CA机构申请CSR:
然后再到苹果的后台,创建一份证书,在下图的 Certificates 中:
创建出来,download到本地的是一份 .cer
文件,这个就是开发用的证书。这份证书只包含了公钥,所以它不具备签名能力,私钥是保存在生成证书的那台机器的keychain里的,如果其他开发人员也需要使用这份证书,就需要从生成证书的机器中导出包含公钥以及私钥的p12文件(个人信息交换文件),团队成员将 p12 文件装到自己电脑的 keychain,这样的证书环境才是完整的。
Identifiers:一个 Bundle id 对应一个 Identifier,也就是一个 app 对应一个唯一标识。
Devices:Devices 是这个 app 支持哪些设备进行调整,用 UDID 来作为设备的唯一标识符。
Profiles:通过这个配置生成出来的是 Provisoning Profile 文件,是 .mobileprovision
类型的文件,这个文件就是将上面提到的几个信息(不包括p12),都打包在内,本质上是一个plist文件,包含到不只以下内容:
- AppIdName
- ApplicationIdentifierPrefix
- CreationDate
- DevelopCertificates
- Entitlements
- ExpiirationDate
- ProvisionedDevice
- UUID 可以通过命令行来查看:
security cms -D -i embedded.mobileprovision > result.plist
open result.plist
Entitlements:App 描述该 App 可以调用哪些服务的字符串,iOS 会检查这个文件,决定这个 App 是否可以调用相关功能,比如 iCloud 权限、推送、健康服务等。
3.打包和验证流程
在打包时,App会调用 codesign
对 Product.app 进行签名,创建一个额外的目录 _CodeSignature
以 plist 的方式存放安装包内的每一个文件签名。
代码签名会直接写入到 mach-o 的可执行文件里,值得注意的是签名是以(Page)为单位的,而不是整个文件签名。
App的安装验证流程:
- 从
embedded.mobileprovision
取出证书,验证证书是否来自 Apple 信任的开发者 - 证书验证通过后,从证书中取出 A 的公钥
- 读取
_CodeSignatire
中的签名结果,用 A 的公钥验证每个文件的签名是否正确 - 文件
embedded.mobileprovision
验证通过后,读取里面的设备 id 列表,判断当前设备是否可安装(App Store 和企业证书不做这步验证) - 验证通过后,安装 App
启动 App 的时候:
- 验证 bundle id、entitlements 和 embedded.mobileprovision 中的 Appid、entitlements 是否一致
- 判断 device id 包含在 embedded.mobileprovision 里
- App Store 和企业证书不做验证
- 如果是企业证书,验证用户是否信任企业证书
- App 启动后,当缺页中断(page fault)发生的时候,系统会把对应的 mach-o 页读入物理内存,然后验证这个 page 签名是否正确
- 以上验证都通过,App 才能正常启动