Kevinlma的博客

物来顺应,未来不迎,当时不杂,既过不恋

0%

iOS程序证书和签名机制Tips

基本概念

涉及的算法

  1. 非对称加密算法,一般是RSA加密算法。一对私钥和公钥。用私钥加密后,只能用公钥解密。知道公钥无法破解出私钥。
  2. 摘要算法,也是哈希算法。相同的数据,哈希值肯定相同。哈希值不同,数据肯定不同。 根据哈希值无法反推出数据是什么

签名算法:

发送方:

  1. 把原始数据计算hash
  2. 将hash使用私钥加密后获得加密后数据,叫做签名
  3. 将明文同签名一起发送给接收方。

接收方:

  1. 收到后使用公钥解密签名,获得原始数据的hash值。
  2. 自己对原始数据计算hash值。
  3. 将计算得出的hash和解密后的hash进行比较,就可以知道明文是否被篡改过。

证书

接收方如果要接收多个来源的数据,就需要保存多个来源的公钥,管理非常不便。所以一般会把公钥也放在发送的数据中。但这样一来,对于收到的公私是否是真的,接收方就不能确定了。为了解决这个问题,一般会使用一个可信的第三方机构,通过第三方机构对用到的公钥也做一次签名。这个第三方机构叫做证书颁发机构(Certification Authority),也就是CA。公钥及其相关签名信息整个放在一个文件里,叫做证书。

接受者一般保存CA的公钥就可以,之后验证接收的公钥合法性,再验证接收的数据的合法性。CA有时候也会有多个,形成链条。

开发者证书

只有通过iOS系统的签名校验,才能安装到手机上。开发阶段需要频繁修改文件,安装测试等,不能每次都是请求Apple进行签名才能安装。所以需要一种开发者可以给自己签名的机制,同时又能保证安全。

申请创建

一般是通过KeyChain里的证书助理,填写邮箱和名称后,创建一个.certSigningRequest文件,之后保存到磁盘上。这时在KeyChain里已经生成好了一对公钥和私钥。

提交Apple验证

之后我们会在Apple的网站上,上传这个request文件。Apple生成一个.cer证书文件,我们下载到本地后,双击安装,就可以在KeyChain里看到安装的证书。
查看安装的证书信息。

  1. 证书信息,App根据我们的账号生成
  2. 颁发机构信息
  3. 使用的的算法
  4. 公钥信息

现在开发者就具有私钥+证书。证书里包含了公钥以及苹果对公钥的签名。打包签名的过程中,就使用开发者的私钥对文件进行签名。我理解可以把开发者视为数据的发送方,Apple是第三方的证书颁发机构。CA是可以一级一级形成链条。设备上安装ipa时,系统通过Apple的签名确定公钥的合法性,最终确定安装包的合法性。

开发者证书

一般有Develop、adhoc、distribution、inhouse。不同证书运行原理是一样的,区别在Provisioning Profile文件中

除了证书外,还要两个文件会被打进包里, provisioning profileentitlements

entitlements

这个文件与沙盒运行机制有关。iOS系统里每个App只能运行在自己的沙盒环境中,对资源的访问,只能限定在自己的沙盒中,比如磁盘文件的访问。并且对每个App使用权限做了严格的限制,只要是App用到的系统权限,必须在这个entitlements文件里做声明,否则运行时会直接Crash。

provisioning profile

这个文件是我们再Apple的网站上生成的,在构建时会被打进安装包,并重命名为 embedded.mobileprovision 。这个文件起到了的作用是,将签名的证书,与开发者账号、运行的设备、以及使用的权限做一个绑定。(在Apple网站上我们创建这个文件时,需要选择cer证书、设备、entitlements)。

这是一个处理过的plist文件,使用一些工具(比如python的PyMobileProvision库)就可以看到这个文件里至少包含以下信息:

  1. 账号信息

    1
    2
    'AppIDName': 'testapp',
    'ApplicationIdentifierPrefix': ['TeamID'],
  2. 证书

    1
    DeveloperCertificates': [Common Name: iPhone Distribution: xxxxx, SHA256: 9B766E84FC3C4FC587BBB433866110A82C6B59871214B84A07DA5321FAE315C2],
  1. Entitlements列表

    1
    2
    3
    4
    5
    6
    7
    8
    'Entitlements': {'application-identifier': 'xxxx.com.test.testapp',
    'aps-environment': 'production',
    'com.apple.developer.applesignin': ['Default'],
    'com.apple.developer.associated-domains': '*',
    'com.apple.developer.team-identifier': '{TeamID}',
    'com.apple.security.application-groups': ['group.com.test.testapp.appgroup'],
    'get-task-allow': False,
    'keychain-access-groups': ['TeamID.*']},
  2. ProvisionedDevices。注册过的设备

    1
    2
    3
    4
    5
    'ProvisionedDevices': ['201f303409994384c1916d12e0a069fb86962ead',
    'b6f474870760ccffbec436cb8aceb8f80c814602',
    '00008006-0004929A36E2002E',
    '85b3d893b249672891ed360a02e179be6174dfa8',
    ...

    企业版可以安装在任意的设备上,它的Provisioning profile里没有描述注册设备的字段,而是这样的

    1
    'ProvisionsAllDevices': True,

    签名相关文件的处理

    证书在构建时,会一起打进安装包里,会重命名为 certificate.cer 。provisitioning profile文件会被重命名为 embedded.mobileprovision

构建时签名过程

每一次build中都会涉及签名过程,包括framework和主项目二进制。使用的证书是provisioning profile里配好的。比如

在生成的安装包中, 还会生成一个文件夹

里面是一个plist格式的文件,包含了所有资源文件的md5值。

二进制制的签名信息会嵌入到二进制文件里,包括主项目和framework。二进制里会增加一个段

验证

在App安装,启动,运行等不同阶段,系统会进行一些合法性校验。有了前面的各种铺垫,我们大概可以了解,系统从证书颁发机构的合法性校验开始(Root CA的公钥是内置在设备系统里的,所以证书校验链条最上层的公钥不需要提供),逐步验证证书的合法性、公钥的合法性,直到App包里文件的合法性。

关于商店包

关于商店包会有几个疑问:

  1. 我们的证书都是有一年期限的,过期之后就不能使用,过期后不能安装用该证书签名的App。但是商店包没有这个影响。
  2. 商店包里没有embedded.mobileprovision和certificate.cer

原因bang在他的博客里提到,是因为Apple在安装包上传之后,Apple用自己的私钥对安装包做了重签名。所以我们自己的证书,profile文件就没有用处了。同时也就没有证书有效期的限制了。

参考

主要是参考了这篇博客,讲解的很深入
http://xelz.info/blog/2019/01/11/ios-code-signature/
http://blog.cnbang.net/tech/3386/