iOS 证书签名那些事

之前面试了很多 iOS 开发工程师,项目做的还可以,但是当聊起证书和签名这些的时候,没有几个能说的头头是道。作为一个iOS 开发工程师,每当你配置各种证书忙的焦头烂额的时候,有没有想过这 TM 到底是为了啥?本文就告诉你这TM 的是为了啥!

Why ?

玩儿苹果的都知道,通常情况下我们喜欢的 APP 是从 AppStore 上下载的。但是,苹果希望在 iOS 平台对第三方 APP 有绝对的控制权,一定要保证每一个安装到 iOS 上的 APP 都是经过苹果官方允许的,怎样保证呢?就是通过签名机制。

非对称加密

通常我们说的签名就是数字签名,它是基于非对称加密算法实现的。对称加密是通过同一份**加密和解密数据,而非对称加密则有两份**,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密。

简单说一下常用的非对称加密算法 RSA 的数学原理,理解简单的数学原理,就可以理解非对称加密是怎么做到的,为什么会是安全的:

选两个质数p和q,相乘得出一个大整数n,例如 p=61,q=53,n=pq=3233

选 1-n 间的随便一个质数e,例如 e = 17

经过一系列数学公式,算出一个数字d,满足:

a. 通过n和e这两个数据一组数据进行数学运算后,可以通过 n 和 d 去反解运算,反过来也可以。

b. 如果只知道n和e,要推导出d,需要知道p和q,也就是要需要把 n 因数分解。

上述的(n,e)这两个数据在一起就是公钥,(n,d)这两个数据就是私钥,满足用私钥加密,公钥解密,或反过来公钥加密,私钥解密,也满足在只暴露公钥(只知道n和 e)的情况下,要推导出私钥(n,d),需要把大整数n因数分解。目前因数分解只能靠暴力穷举,而n数字越大,越难以用穷举计算出因数p和q,也就越安全,当n大到二进制 1024 位或 2048 位时,以目前技术要**几乎不可能,所以非常安全。

数字签名

很多文章都与现实生活中的证件盖章做比喻,我认为不太恰当,容易误导初学者。数据的世界里,不可能像现实生活中那样简单。现在咱们一步一步分析什么是数字签名。
时间:某年某月某日
地点:地球任意有计算机的地方
人物:隔壁老王、东北老铁
事件:隔壁老王要给东北老铁发一个文件(O)。
经过:隔壁老王有一台电脑,这台电脑能够生成一对公钥和私钥。隔壁老王首先将文件(O)用摘要算法进行摘要,生成文件摘要(M)。然后用私钥对文件摘要(M)进行加密,也就是数字签名(以后统称为“签名”),生成一个签名文件(S)。然后隔壁老王将文件(O)、签名文件(S)、公钥一起发给了东北老铁。

东北老铁拿到这三样东西后,首先用公钥对签名文件(S)进行解密,生成文件摘要(m),然后用同样的摘要算法对文件(O)摘要,生成文件摘要(M)。东北老铁只需要对比 m 和 M 是否一样,就知道这个文件有没有被其他人改动。这就是数字加密的用途。
iOS 证书签名那些事

上图的理解:
1.首先用一种算法,算出原始数据的摘要。需满足 a.若原始数据有任何变化,计算出来的摘要值都会变化。 b.摘要要够短。这里最常用的算法是MD5。

2.生成一份非对称加密的公钥和私钥,私钥我自己拿着,公钥公布出去。

3.对一份数据,算出摘要后,用私钥加密这个摘要,得到一份加密后的数据,称为原始数据的签名。把它跟原始数据一起发送给用户。

4.用户收到数据和签名后,用公钥解密得到摘要。同时用户用同样的算法计算原始数据的摘要,对比这里计算出来的摘要和用公钥解密签名得到的摘要是否相等,若相等则表示这份数据中途没有被篡改过,因为如果篡改过,摘要会变化。

从 AppStore 下载 APP

iOS 证书签名那些事

上图说明的就是,苹果官方生成一对公私钥,在 iOS 里内置一个公钥,私钥由苹果后台保存,我们传 App 上 AppStore 时,苹果后台用私钥对 APP 数据进行签名,iOS 系统下载这个 APP 后,用公钥验证这个签名,若签名正确,这个 APP 肯定是由苹果后台认证的,并且没有被修改过,也就达到了苹果的需求:保证安装的每一个 APP 都是经过苹果官方允许的。

从其他途径安装 app

事情没有那么简单,实际上因为除了从 AppStore 下载,我们还可以有三种方式安装一个 App:

1.开发 App 时可以直接把开发中的应用安装进手机进行调试。

2.In-House 企业内部分发,可以直接安装企业证书签名后的 APP。

3.AD-Hoc 相当于企业分发的限制版,限制安装设备数量,较少用。

苹果要对用这三种方式安装的 App 进行控制,就有了新的需求,无法像上面这样简单了。

iOS 证书签名那些事

苹果的方案是双层签名,如下:
1.在你的 Mac 开发机器生成一对公私钥,这里称为公钥L,私钥L。L:Local

2.苹果自己有固定的一对公私钥,跟上面 AppStore 例子一样,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥A,私钥A。A:Apple

3.把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书。

4.在开发时,编译完一个 APP 后,用本地的私钥 L 对这个 APP 进行签名,同时把第三步得到的证书一起打包进 APP 里,安装到手机上。

5.在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证证书的数字签名是否正确。

6.验证证书后确保了公钥 L 是苹果认证过的,再用公钥 L 去验证 APP 的签名,这里就间接验证了这个 APP 安装行为是否经过苹果官方允许。(这里只验证安装行为,不验证APP 是否被改动,因为开发阶段 APP 内容总是不断变化的,苹果不需要管。)

限制安装设备,限制 APP

上述流程只解决了上面第一个需求,也就是需要经过苹果允许才可以安装,还未解决第二个避免被滥用的问题。怎么解决呢?苹果再加了两个限制,一是限制在苹果后台注册过的设备才可以安装,二是限制签名只能针对某一个具体的 APP。
iOS 证书签名那些事

可以想到把 允许安装的设备 ID 列表 和 App对应的 AppID 等数据,都在第三步这里跟公钥L一起组成证书,再用苹果私钥 A 对这个证书签名。在最后第 5 步验证时就可以拿到设备 ID 列表,判断当前设备是否符合要求。根据数字签名的原理,只要数字签名通过验证,第 5 步这里的设备 IDs / AppID / 公钥 L 就都是经过苹果认证的,无法被修改,苹果就可以限制可安装的设备和 APP,避免滥用。

到这里这个证书已经变得很复杂了,有很多额外信息,实际上除了 设备 ID / AppID,还有其他信息也需要在这里用苹果签名,像这个 APP 里 iCloud / push / 后台运行 等权限苹果都想控制,苹果把这些权限开关统一称为 Entitlements,它也需要通过签名去授权。

限制功能,比如推送

iOS 证书签名那些事

因为步骤有小变动,这里我们不辞啰嗦重新再列一遍整个流程:

1.在你的 Mac 开发机器生成一对公私钥,这里称为公钥L,私钥L。L:Local

2.苹果自己有固定的一对公私钥,跟上面 AppStore 例子一样,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥A,私钥A。A:Apple

3.把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书。

4.在苹果后台申请 AppID,配置好设备 ID 列表和 APP 可使用的权限,再加上第③步的证书,组成的数据用私钥 A 签名,把数据和签名一起组成一个 Provisioning Profile 文件,下载到本地 Mac 开发机。

5.在开发时,编译完一个 APP 后,用本地的私钥 L 对这个 APP 进行签名,同时把第④步得到的 Provisioning Profile 文件打包进 APP 里,文件名为embedded.mobileprovision,把 APP 安装到手机上。

6.在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证embedded.mobileprovision的数字签名是否正确,里面的证书签名也会再验一遍。

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

从证书颁发机构请求证书

钥匙串程序中,从证书颁发机构请求证书的过程,就是在电脑上生成一对公钥和私钥,文件CertificateSigningRequest里面保存的就是公钥。

证书

从苹果开发者平台下载到本地的证书,里面的内容就是公钥或私钥,由其他机构对其签名组成的数据包。

描述文件

Provisioning Profile,包含了 证书 / Entitlements 等数据,并由苹果后台私钥签名的数据包。

总结

请求证书就是
广大开发人员:“苹果爸爸,我想给手机安装一个 app 进行测试”。
苹果爸爸:“好的,爹给你颁发证书了,你到时候用这个证书签名就行了,记得把描述文件放到包里”。

感谢CocoaChina 的文章:http://www.cocoachina.com/ios/20170602/19427.html