这编文章主要是参考了Demystifying iOS certificate and provisioning files,本来是想翻译来着,不过因为我又加了许多自己的理解,所以就放个链接出来算是引用好了。

       文章用到了一些密码学的知识,比如公钥、私钥、数字签名、证书等等,这些知识我是从《计算机网络:自顶向下方法》计算机网络中的安全这一章了解到的,如果大家有不明白的地方可以参考一下。

证书

       下面进入正题,我们只讨论开发证书,其他的证书其实原理差不多。我们用开发证书的目的主要是想要把app部署到设备中,不然只能在模拟器中调试。证书无非就是证明这个人就是自己,在苹果的角度来看就是需要一个手段证明想要把程序部署到机器中的人已经付过费了。

       以我的开发证书为例,其中主要包含:我的公钥、苹果用它的私钥制作的数字签名、签名算法(我的证书中显示的是:带RSA加密的SHA-1,SHA-1用于生成摘要,RSA用于对摘要加密生成数字签名)。证书用来证明我的合法性,当我把我的证书出示给苹果看的时候,苹果首先要用证书中指定的生成摘要的算法生成摘要digest1,再用证书中指定的加密算法,用自己的公钥解密证书中的数字签名得到digest2,然后比较digest1和digest2,如果相等,则证明这个证书是合法的。

       刚刚一直在说怎么证明证书是合法的,那么证书到底用来做什么?我们build程序的时候会对几乎每一个放在bundle中的文件做如下操作:生成摘要->使用自己的私钥对摘要加密,这些操作的结果会保存到一个plist文件中。解密是有苹果做的,苹果也会用相同的摘要生成算法对这个文件生成摘要,然后再对plist中保存的加密过的数据进行解密,解密需要的是公钥,这个公钥就保存在证书中。最后对比两个值是否相同,相同则表示文件没有被修改过。大体上就是这样的逻辑,之后我们再来详细解释一下这些过程。

题外话:可能有人会问为什么不直接加密,而是先生成摘要再加密,这样不是比较简单?这样做主要是因为我们的加密算法是很慢的,对一个大的文件直接应用加密,速度非常慢,所以工程上都是先生成摘要再对摘要应用加密。

生成证书请求

       我们从申请证书说起,iOS申请证书可以从钥匙串中申请,钥匙串访问->证书助理->从证书颁发机构请求证书,填好自己的邮件地址和常用名称,选择存储到磁盘,然后继续,就完成了申请,这时候我们可以发现在钥匙串访问/种类/密钥中增加了两个密钥,分别是公共密钥和专有密钥,我们通常叫做公钥和私钥。我们保存在磁盘中的证书请求文件包含了我的信息(可能就是那个我们填写的邮件地址)、我的公钥和用我的私钥签名的数字签名,这样拿到这个证书的苹果就能够确保私钥的拥有者就是文件中声称的人。

生成证书

       下一步我们要将这个证书请求发送给苹果,苹果为我们生成开发证书,苹果用它的私钥为我们的证书签名,即生成数字签名。

Provisioning Profiles

       现在我们已经有了苹果颁发的开发证书了,那么我们就可以把程序部署到设备上了么,不要忘记苹果对开发设备是有限制的(如果是个人开发者的账号,最多支持的设备是100个),那么就需要有一个机制做到这一点,那就是provisioning profiles了。

       在苹果开发网站生成provisioning profiles (以下简称pp)的时候需要选择app id、证书和设备id。一个pp只能关联一个app id,不过这个app id是可以有通配符的,pp中包含了多个证书(不一定是证书本身,不过肯定是存在某种方式的联系,可以确定的是肯定有证书的公钥和标识证书id)和设备id的列表。在Xcode中,Build Settings->Provisioning profiles可以选择我们在网站生成的下载到本地的pp,然后在Code Signing Identify中选择我们要使用的开发证书,注意这里面的开发证书一定要是在生成pp时候被包含的证书。

       现在我们可以Build & Run我们的程序了,让我们看看在这个过程发生了什么。在Build过程中,XCode把所有我们需要的文件都放在了一个目录中,如果你打开并显示这个目录就可以看到除了一些程序的文件和资源文件外,还包含了我们的pp和一个目录(_CodeSignature),在这目录中有个文件叫做CodeResourses,它是一个plist文件,在这个文件中包含了所有文件的被加密过的摘要,正如我之前提到过的,这个文件是用来验证在生成我们的app之后,这个app文件中的所有文件都没有被修改过。

       我们的程序安装到设备中之后,iOS系统首先要确保pp是被苹果签名过的(这是一个前提,因为下面的步骤都是在确定pp是合法的前提下进行的),这就要求pp中包含一个苹果签名的数字签名;然后系统要检查每一个文件是否被篡改。在Demystifying iOS certificate and provisioning files中作者介绍还需要有一步是:“The last check happens when you run the app. iOS checks that the app hasn't been modified, and that you still have a provision file that matches the app you're trying to run. If you do not have one anymore, the app will crash.”,这里我没太弄明白作者要表达的意思,不过根据我的理解,系统还要检查当前的设备id是否在pp的设备列表中,还有在info.list中的app id是否符合pp中的app id(考虑到通配符的存在,不需要这两个app id一定要完全一样)。当然这个检测绝对不止我们提到过的这几项,不过我们说的这几个比较重要,其他的我也不大清楚了。

        最后,如果我们把一个pp打印出来看一下里面的结构,我们可以看到pp是一个xml格式的文件,上面主要是以键值对的结构表现的,我们可以看到证书的列表(DeveloperCertificates)、设备id的列表(ProvisionedDevices)、创建时间(CreationDate)、有效期限等等,下面的乱码部分我觉得应该是苹果的数字签名和苹果的证书的信息等等。


这边文章主要自己对证书和provisioning profiles的理解,如果有什么错误请在评论中指出,谢谢 :)