iOS证书签名机制

602 阅读4分钟

问题

相比安卓系统随便从哪里下载都能运行,系统安全存在许多隐患,例如盗版软件、病毒入侵、静默安装等等。苹果为了控制手机上的所有应用必须是经过授权的,规定正规应用只能在AppStore下载,同时对于调试阶段的安装、灰度测试和企业分发,苹果使用双重签名机制来控制应用权限并使其不被滥用

非对称加密

非对称加密则两份密钥,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密。正常情况下,公钥可以对外公开,而私钥需私密保存。我们常用公钥加密私钥解密的方式来进行加密防止数据明文传输,用私钥加密公钥解密的方式来签名确保数据的完整性防止被篡改。

数字摘要

将任意长度的源文本通过Hash函数计算得到一窜固定长度的文本,要保证不同源文本计算得到的值各不相同,且不能被反推得到源文本。常用的Hash算法有MD5和SHA。

数字签名

又称公钥数字签名,是非对称加密和数字摘要的结合,用于验证数据的完整性及不可抵赖性.发送方用接收方的公钥对摘要进行加密后和报文一起发送,接受方接受后用相同的Hash算法对报文进行摘要计算,接着用自己的私钥解密得到发送方的摘要,如果两个摘要相同则接收方就能确认该报文是对方发出的且未被篡改.

下面给出一些概念术语: 1576049725126335.png

APPStore签名

将APP提交审核后,苹果会用官方的私钥对我们提交的APP重签名,用户下载到手机后,iOS设备内置的公钥会对APP进行验证,验证成功即可正常使用 所以App上传到AppStore后,就跟我们本地的证书/Provisioning Profile 都没有关系了,无论是否过期或被废除,都不会影响 AppStore 上的安装包。

1576049732640575.png

Xcode安装&Adhoc&In-House

如果我们iOS设备安装APP只从APP Store这一个入口这件事就简单解决了,没有任何复杂的东西,一个数字签名搞定 但实际上iOS安装APP还有其他渠道,比如我们开发这ioser而言,我们是需要在开发APP时直接真机调试的,而且苹果还开发了企业内部分发的渠道,企业证书签名的APP也是需要顺利安装的.苹果需要开放这些方式安装APP,这些需求就无法通过简单的代码签名来办到了

先来分析以下苹果的需求:

  • 安装包不需要上传到App store,可以直接安装到手机上

  • 苹果为了保证系统的安全性,又可以对安装的APP有绝对的控制权

    1. 经过苹果允许才安装
    2. 不能被滥用导致非开发APP也能被安装

为了实现这些需求,iOS签名的复杂度也就开始增加了,苹果给出的方案是双层签名

对于非AppStore安装的应用苹果采用了双重签名的方式,用到了两对密钥,Mac电脑密钥对M,苹果官方密钥对A。

截屏2021-03-15 下午3.01.31.png

  • 我们在进行开发时,会从MAC的keychain里的“从证书颁发机构请求证书生成”CertificateSigningRequest(含有Mac的公钥M信息)文件上传到苹果后台,苹果会用其私钥A对公钥M签名,并生成一份包含公钥M信息和苹果签名信息的开发/发布正式cer,当我们将cer下载到MAC后,keychain会把CertificateSigningRequest和证书关联起来

  • 在苹果后台配置AppID,可用设备IDs(企业证书不需要)和Entitlements,用这些额外信息和证书再用私钥A签名,最后苹果将证书+额外信息+签名组成一个Provisioning Profile文件(mobileprovision后缀),下载到Mac上。

  • 在MAC上编译完一个App后,MAC会用私钥M对APP签名,并将Provisioning Profile文件也打包到App中,文件名为 embedded.mobileprovision。

  • 安装时,苹果通过内置在手机中的公钥A验证embedded.mobileprovision中的签名是否正确,接着验证证书中的签名是否正确。

  • 确保了embedded.mobileprovision 里的数据都是苹果授权以后,就可以取出里面的数据,做各种验证,包括用公钥 M 验证APP签名,验证设备ID是否在ID列表上,验证证书是否过期,AppID是否对应得上,权限开关是否跟App里的Entitlements 对应等等。

如果别的 Mac 也要编译签名这个 App,可以将私钥M导出给其他 Mac 用,在 keychain 里导出私钥,就会存成.p12 文件,其他 Mac 导入了这个私钥后便可用同一套苹果证书及Provisioning Profile文件。 In-House安装不限制设备ID数。