阅读:iOS App签名的原理

导语

  前几天在 Bugly 公众号上看到这篇 iOS App签名的原理,解决了我原来关于 iOS 开发的证书相关知识的一些模糊的地方。
    
  下面按使用的场景进行梳理。   

场景一: 指定 AppStore 安装

  1. App 打包上传到 AppStore ,苹果服务器用对应用进行加壳,签名,用私钥对签名加密
  2. iOSAppStore 下载应用,在安装时用公钥进行验证

.ipa 包里有一个 _CodeSignature 的文件夹,其中有个 CodeResources
文件,拖拽到 Sublime Text 中,发现其内容包括 4 个节点,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict>
...
</dict>
<key>files2</key>
<dict>
...
</dict>
<key>rules</key>
<dict>
...
</dict>
<key>rules2</key>
<dict>
...
</dict>
</dict>
</plist>

参考这篇文章,可以得到如下观点

  • rules 和 files 是为老版本准备的,而 files2 和 rules2是为新的第二版的代码签名准备的。最主要的区别是在新版本中你无法再将某些资源文件排除在代码签名之外。

  • 二进制的签名会被放到可执行文件中

参考数字签名的过程,整个流程应该这样的: 苹果后台对应用中的各项资源进行哈希并签名生成该表,用以标识这个应用,当要安装到 iOS 设备中时,先用公钥解密签名,同样对资源进行哈希然后进行匹配。如果匹配上的话,在当前场景下就可以证明应用没有被修改过,即代表是从 AppStore 上下载的,如果验证不通过,则无法安装。

二进制的签名

我找了 AppleCode Signing Guide

重新确定了下签名的部分

哪些文件参与的签名

Nested code , 比如 .a 静态库, .frameworks (先签名)
Mach-O executables , 二进制可执行文件
Resources , 资源文件,就是 CodeResources 的部分

To apply the signature, the codesign utility adds the signature directly to the executable file.

这句话确实证明了关于二进制的签名会直接被加到可执行文件中。

场景二 : 开发环境下安装应用

参考数字证书的过程

mac: 服务器
苹果服务器: CA
iOS 设备: 客户端

服务器向 CA 发送证书请求( .csr ),其中包含了本地生成的公钥,CA 签名后将证书发送回服务器并安装到服务器上,在进行应用安装时,用本地私钥签名并将证书一起安装到客户端

因为客户端有 CA 的公钥,所以可以解密证书的签名,然后通过计算验证公钥是否已被认证,若被认证,则使用其公钥来解密私钥加密的内容。

证书是附在后面安装提到的 embedded.moilbeprovision

场景三 : AdHoc/企业证书安装应用

为了保证权限(通知,IAP…),安装设备数量统一进行控制,引入了描述文件 (Provisioning Profile) 。

描述文件也用苹果服务器私钥签名,打包时,会把描述文件一起打包到到应用中,文件名为 embedded.mobileprovision

编译自己的任意一个工程,然后找到 Produce 的目录,里面有 .app 目录,进到里面即可发现 embedded.mobileprovision

可以用如下命令来查看

1
security cms -D -i embedded.mobileprovision
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AppIDName</key>
<string>XC Wildcard</string>
<key>ApplicationIdentifierPrefix</key>
<array>
<string>ZEY3XXXXXX</string>
</array>
<key>CreationDate</key>
<date>2017-03-08T06:25:32Z</date>
<key>Platform</key>
<array>
<string>iOS</string>
</array>
<key>DeveloperCertificates</key>
<array>
<data>MIIF...fA=</data>
<data>MIIF...94=</data>
</array>
<key>Entitlements</key>
<dict>
<key>keychain-access-groups</key>
<array>
<string>ZEY3XXXXXX.*</string>
</array>
<key>get-task-allow</key>
<true/>
<key>application-identifier</key>
<string>ZEY3XXXXXX.*</string>
<key>com.apple.developer.team-identifier</key>
<string>ZEY3XXXXXX</string>
</dict>
<key>ExpirationDate</key>
<date>2018-03-08T06:25:32Z</date>

<key>Name</key>
<string>iOS Team Provisioning Profile: *</string>
<key>ProvisionedDevices</key>
<array>
<string>2b8ffa94ec91d9ce9c94da9ad423b88888888888</string>
</array>
<key>TeamIdentifier</key>
<array>
<string>ZEY3XXXXXX</string>
</array>
<key>TeamName</key>
<string>Deliang Wang</string>
<key>TimeToLive</key>
<integer>365</integer>
<key>UUID</key>
<string>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</string>
<key>Version</key>
<integer>1</integer>
</dict>

可看到 embedded.moilbeprovision 中包含了应用的包名,证书,可安装设备,过期时间等等信息。

最后

关键点

  1. 数字签名的保证了应用的完整性且来自 AppStore
  2. 描述文件统一管理权限,包名,可安装的设备等信息。
  3. 非对称加密,私钥加密,公钥验证

附一张来自原文的图

14903246801530

That’s all

参考

  1. 数字签名
  2. 数字证书
  3. 漫谈iOS程序的证书和签名机制
  4. Apple - Code Signing Guide