原文链接: https://www.jianshu.com/p/19aaa3586826
做IOS开发不多不少也有三年了,记得第一次接触IOS时,碰到的第一个问题就是这个证书,稀里糊涂的把拦路的问题搞定后,也没有进一步的去深入的探究下这个到底是什么东西,为什么要这样。
最近再搞那个使用动态库一键接入SDK的课题,再一次碰到了这个证书与签名的主题,翻阅了很多的资料,也只能说有了进一步的了解与认识,谈不上深刻,所以打算写一点东西,加深下记忆吧。说到正题之前有下面这样几个概念需要先行说明下:
1.对称加密
对称加密是密码学中一类加密算法的统称,这类算法在加密与解密时使用相同的密钥,或者使用两个可以简单的相互推算的密钥。常见的对称加密算法有DES、3DES、AES、RC5等。相比非对称加密算法,对称加密算法的优点是加解密的速度很快。
2.非对称加密
非对称加密是指加密密钥与解密密钥是成对出现的,其中一个对外公开,叫公钥,另一个末公开的叫私钥,几乎不能从一个密钥计算出另一个密钥。通过私钥加密的只能通过公钥解密,公钥加密的只能通过私钥解密。最著名的非对称加密算法是RSA算法。当然如此强大可靠的安全性是在牺牲加密速度的基础上得到的。
3.摘要算法
摘要算法可以将任意长度的信息(文本、字节等)通过算法转换成一个固定长度的文本。只要源信息不同,摘要算法得到的结果必然不同。且无法从摘要算法的结果反推得到源信息。比较典型的摘要算法有MD5与SHA等。
4.数字签名
数字签名实际上是非对称加密算法与摘要算法的结合。将要发布的源信息通过摘要算法得到摘要,再将得到的摘要通过非对称加密算法中的密钥进行加密,最后将源信息、加密后的摘要密文与解密公钥打包到一块发布。
接收方接收到信息后需要先通过公钥从摘要密文中解析出原摘要信息,然后通过摘要算法从源信息明文中再次计算出摘要信息,最后将两个接要进行比对,相等就认为一切正常。完整的流程见下图:
5.数字证书
数字证书就是通过数字签名实现的数字化证书。苹果的开发者证书就是这种东东,证书的签发机构(Certificate Authority)自然是Apple,证书的被签发人是企业(企业证书)或者个人开发者(个人开发证书),证书的验证方是IOS设备,IOS系统已经将整个验证流程固化到系统中,除非越狱,否则无法绕过。
接下来我们正式开始来了解IOS这个东西。还记得我们是如何向苹果申请证书的吗?不记得了得话Google下吧,一个步骤一个步骤说的非常详细。
CertificateSigningRequest.certSigningRequest
申请证书过程中苹果会要求我们从MAC电脑上上传一个后缀名为certSigningRequest的文件,见下图。
我们可以尝试通过openssl来查看下这个文件的内容,如下图:
可以看到这个文件大致包括三个方面的内容:申请者的相关信息、申请者的公钥、接要算法与公钥加密算法。
开发证书与生产证书
实际上苹果只关心这个文件中的公钥信息,它将这个公钥封装在将要分发给开发者的证书中,并进行数字签名,我们同样可以用openssl来查看证书的内容:
从上图签名内容的Data域中我们可以看到签名证书的相关信息,其中最重要的东西就是签名证书的公钥了。双击这个证书,MAC会自动将该证书导入到钥匙串应用中,与些同时MAC还会将本机对应的钥匙与这个证书中的公钥对应起来,因此我们在Keychain中查看证书时,可以看到证书自动的关联了私钥,如下图:
也正因为如此,在使用多台MAC开发机器的团队开发过程中,一般都是由一台机器申请证书后,再将证书与私钥同时导出共享给其它开发成员使用,导出截图如下图:
开发证书与发布证书有什么区别呢?这两种证书只是在用途上有所不同,开发证书用于开发调试应用,生产证书用于正式发布应用。本质上来说,只要这两个证书是使用同一个certSigningRequest文件生成的,他们都拥有着相同的私钥与公钥。
mobileprovision
在我们平常开发过程中除了与证书打交道外,还会碰到一个后缀为mobileprovision的文件,这个又是什么鬼呢?这个东西的中文名叫做IOS授权与描述文件。我们可以使用下面的命令来查看该文件的内容:
可以猜测到该文件主要包括这样几个方面的内容:App的相关信息(AppId、创建时间、面向平台等)、App所使用到的功能授权列表(正因为这个原因,我们把它称为授权与描述文件)、可以使用这个授权文件的证书列表(DeveloperCertificates这一项,使用了Base64编码,我尝试解码,也只是看到了一部分可读数据,还是有一部分的乱码文件,http://objccn.io/issue-17-2/这篇文章中说可以使用openssl x509 -text -in file.pem命令来解码,但我没有尝试成功)、可安装的设备列表(每次我们使用新的设备时,都必须先将设备UID添加到后台的设备列表中,然后重新更新该mobileprovision文件,幸运的是XCODE能够默默的为我们做到这一切,该配置只适用于开发证书)、苹果自己的签名(与上面的公钥、私钥没有关系,苹果用来验证mobileprovision文件自身的合法性)。
IPA****签名与解密
xcode在打包过程中会调用系统中的codesign命令使用账号中的私钥对应用的所有文件进行签名,并保存在ipa中的_CodeSignature文件夹下。
当App安装后,系统首先找到ipa包中的embedded.mobileprovision文件,验证这个文件自身的合法性,然后再通过该文件找到证书,再通过证书获取到解密用的公钥,解密所有经过数字签名的文件,并比较摘要是否一致。如果这些环节中的一个有问题,整个验证工作就宣告失败。
整个签名与解密的流程写的比较简略,只有一个大概的流程,究其原因还是网上很多资料对这一块言之过少,大都三言两语一带而过,希望后续自己能对其进行更进一步的补充。大致流程参见下图:
下面这些关于ipa签名的结论是我自己的猜测,不一定准确:
1.对于ipa包中的所有文件来说,苹果同样会获取这些文件的摘要信息,但随ipa包一块发布的却是这些文件的明文,这也是为什么我们将ipa解压后能直接读取info.plist等文件内容的原因。
3.对于所有获取的摘要信息,同样都使用私钥再次加密后保存在_CodeSignature文件夹下的CodeResources文件中。
4.苹果获取这些文件后,会对IPA包中的代码文件进行再一次的加密(用户从appstore上下载的ipa包文件中的可执行文件,使用class_dump无法正确的获取头文件,必须要使用手机执行应用,然后通过内存中的信息获取解密后的可执行文件),至于这上次的加密是否用开发者的私钥,这个我不太清楚。
4.解密时通过公钥还原摘要信息,然后根据不同的文件类型采用不同的方式获取最终的摘要信息,最后两相比较,确定文件是否发生过变更。