Provisioning Profile & Entitlements

最近学习了一下iOS代码签名机制 ,这里做个笔记记录,整理思路,加深理解。
想了解更多iOS签名相关,强烈推荐去看看原文,写的太棒了。原文出处 深度长文:细说iOS代码签名

背景

沙盒(Sandbox)技术是iOS安全体系中非常重要的一项技术,他的目的是通过各种技术手段限制App的行为,比如可读写的路径,允许访问的硬件,允许使用的服务等等,即使应用出现任意代码执行的漏洞,也无法影响到沙盒外的系统。(图来自Apple开发者网站

sandboxing.png

Entitlements

通常所说的Entitlements(授权文件),也就是指iOS沙盒的配置文件,这个文件中声明了app所需的权限,如果app中使用到了某项沙盒限制的功能,但没有声明对应的权限,可能运行到相关的代码时会直接Crash。

授权机制也是按照 plist 文件格式来列出的。这个文件内部格式如下:

<?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>application-identifier</key>
        <string>7TPNXN7G6K.ch.kollba.example</string>
        <key>aps-environment</key>
        <string>development</string>
        <key>com.apple.developer.team-identifier</key>
        <string>7TPNXN7G6K</string>
        <key>com.apple.developer.ubiquity-container-identifiers</key>
        <array>
                <string>7TPNXN7G6K.ch.kollba.example</string>
        </array>
        <key>com.apple.developer.ubiquity-kvstore-identifier</key>
        <string>7TPNXN7G6K.ch.kollba.example</string>
        <key>com.apple.security.application-groups</key>
        <array>
                <string>group.ch.kollba.example</string>
        </array>
        <key>get-task-allow</key>
        <true/>
</dict>
</plist>

在 Xcode 的 Capabilities 选项卡下选择一些选项之后,Xcode 就会生成这样一段 XML。 Xcode 会自动生成一个 .entitlements 文件,然后在需要的时候往里面添加条目。当构建整个应用时,Xcode 会将这个文件作为 --entitlements 参数的内容传给 codesign ,作为应用所需要拥有哪些授权的参考。这些授权信息必须都在开发者中心的 App ID 中启用,并且包含在配置文件中,稍后我们会详细讨论这一点。在构建应用时需要使用的授权文件可以在 Xcode build setting 中的 code signing entitlements 中设置。

在这个应用中我启用了 iCloud 键值对存储 (key-value storage) (com.apple.developer.ubiquity-kvstore-identifier) ,以及 iCloud 文档存储 (com.apple.developer.ubiquity-container-identifiers)。另外我还将应用添加进了一个 App Group (比如说为了与扩展 (extensions) 共享数据,com.apple.security.application-groups), 最后开启了推送功能 (aps-environment)。这是一个开发版本,我会有将它连接到调试器的需求,这就需要将 get-task-allow 设为 true。另外,app id,也就是 bundle id 加上开发者 id,也被单独列出来了。

当然你并不能随心所欲的取得授权,你的应用能否得到某一项授权是有特定的规定的。举例来说,当 get-task-allow 被设定为 ture 时,应用只能在用于开发的证书签名下运行。你被允许使用的推送环境 (aps-environment) 也存在类似的限制。

实际上,这个文件的内容并非是全部的授权内容,因为缺省状态下,App默认会包含以下与Team ID及App ID相关的权限声明:

<dict>
    <key>get-task-allow</key>
    <true/>
    <key>application-identifier</key>
    <string>xxx.xxx.bundleID</string>
    <key>com.apple.developer.team-identifier</key>
    <string>xxxxxxxxxx</string>
</dict>

其中get-task-allow代表是否允许被调试,它在开发阶段是必需的一项权限,而在进行Archive打包用于上架时会被去除。

进行代码签名时,会将这个Entitlements文件(如有)与上述缺省内容进行合并,得到最终的授权文件,并嵌入二进制代码中,作为被签名内容的一部分,由代码签名保证其不可篡改性。

可以尝试查看签名信息中具体包含了什么授权信息:$ codesign -d --entitlements - Example.app

$ codesign -d --entitlements - CodeSignTest.app
Executable=/Users/bytedance/Downloads/iOS签名/sign/CodeSignTest.app/CodeSignTest
[Dict]
    [Key] application-identifier
    [Value]
        [String] JJHW9Jxxxx.com.xxxxxxx.xxxx
    [Key] com.apple.developer.applesignin
    [Value]
        [Array]
            [String] Default
    [Key] com.apple.developer.team-identifier
    [Value]
        [String] JJHW9Jxxxx
    [Key] get-task-allow
    [Value]
        [Bool] true

Provisioning Profile

这里引用一下苹果的原文解释

A provisioning profile is a collection of digital entities that uniquely ties developers and devices to an authorized iPhone Development Team and enables a device to be used for testing.

Provisioning Profile在这里就起到了一个对设备和开发者授权的作用,他将开发者账号、证书、entitlements文件以及设备进行了绑定。

在开发过程中,使用的 Provisioning Profile 都被存放在 ~/Library/MobileDevice/Provisioning\ Profiles/ 路径下,以 UUID 格式命名。

由于这个文件是被苹果签过名的,所以我们没有办法伪造或者修改这个文件,它使用的是标准的CMS(Cryptographic Message Syntax)格式,可以通过 security 命令查看它的签名信息:

$ security cms -D -i xxxxxxxxxxx.mobileprovision -h 1 -n  # 查看签名信息
SMIME:    level=1.2; type=signedData; nsigners=1;
      signer0.id="Apple iPhone OS Provisioning Profile Signing"; signer0.status=GoodSignature;
  level=1.1; type=data;

Provisioning Profile 统一都是由 Apple iPhone OS Provisioning Profile Signing 进行签名的,机构名称言简意赅。

profile_cer.png

通过 security 命令将文件的内容提取出来:

$ security cms -D -i ea8585cd-c2da-4b08-81c2-e32b28c34871.mobileprovision -o provision.plist # 将内容导出

<?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>xxxxx</string>
    ...
  <key>DeveloperCertificates</key>
  <array>
      <data>xxxxx</data>
      <data>xxxxx</data>
      <data>xxxxx</data>
  </array>
  <key>Entitlements</key>
  <dict>
      <key>get-task-allow</key>
      <true/>
      <key>application-identifier</key>
      <string>xxxxx.xxx.bundleID</string>
      <key>com.apple.developer.team-identifier</key>
      <string>xxxxx</string>
      <key>com.apple.developer.siri</key>
      <true/>
  </dict>
  <key>ExpirationDate</key>
  <date>2022-01-22T05:14:57Z</date>
  <key>Name</key>
  <string>iOS Team Provisioning Profile: xxxx</string>
  <key>ProvisionedDevices</key>
  <array>
      <string>xxxxx</string>
      <string>xxxxx</string>
      <string>xxxxx</string>
  </array>
  ...
</dict>
</plist>

明显可以看出这是一个xml格式的plist文件,里面的内容不难理解,最关键的是这几项

  • DeveloperCertificates:允许使用的开发者证书,这是一个列表,一般包含生成这个Provisioning Profile文件时,当前开发者账号下所有有效的Development证书,以base64格式保存。
  • Entitlements:允许使用的权限列表,这些授权信息是你在开发者中心下载配置文件时在 App ID 中设置的。实际在App中使用的权限必须是这个列表的子集,否则安装时会无法通过校验而失败。如果曾经开启过某个功能,Xcode自动更新了Provisioning Profile,后来又关闭它,Xcode并不会将其从Provisioning Profile中删去,如示例中的com.apple.developer.siri
  • ProvisionedDevices:允许安装的设备列表,如果目标设备的UUID不在这个列表中,会安装失败。对于这一项,普通开发者证书和企业级开发者证书的待遇是不同的。普通开发者证书使用Provisioning Profile的方式安装App到设备,只是出于测试和调试的需要,因此Apple只允许最多注册100台用于测试的设备,否则开发者就可以以测试的名义任意任意分发自己的App了。而对于企业级开发者来说,本身就有任意安装的需求,因此在分发时,这一项会被ProvisionsAllDevices取代,代表授权任意设备。

这些信息中有任何变动的时候,比如开发者证书有新增或者失效,在Capabilities中启用了当前App从未使用过的新功能,或是将新的iPhone连接到Xcode用于测试,Xcode都会自动重新申请Provisioning Profile。

Provisioning Profile会被内置在App中,置于App根目录下的 embedded.mobileprovision 。安装App时如果签名校验通过,这个文件会自动被拷贝到iOS设备的 /Library/MobileDevice/Provisioning\ Profiles/ 路径下。由于该文件已被Apple官方签名,系统可以无条件信任它,并用它来校验App的签名、权限,以及本机的UUID等是否满足来自官方的授权。

embed_profile.png

通过这种方式,设备间接信任开发者的身份,让iOS设备可以运行非苹果官方签名的App。

假如你有一台越狱的设备,查看任意一个从AppStore上下载下来的App,里面都不会有embedded.mobileprovision这个文件,因为经过Apple重新签名以后,设备就不再需要它来信任开发者了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容