iOS 的 Code Signing 体系

iOS中的Code Signing体系很是复杂,对新手很是不友好,虽然目前网上已经存在大量文章对此进行比较透彻的分析,最核心的部分已经讲解得很是清楚,我阅读了这些文章后,确实从中学习到很多知识,但我始终仍是对Code Signing体系中不少相关的地方有着疑惑,因而决定认真地探究一番。本文会引用一些比较好的文章中的内容和图片,加上一些我我的的理解进行分析,有些内容本文再也不重复,有须要的请阅读本文最后的参考文章。html

概念

公开密钥加密、数字签名、证书这些通用的基本概念这里再也不多说,主要提一下iOS上特有的东西git

.certSigningRequest

点击mac OS钥匙串访问里的 证书助理 -> 从证书颁发机构请求证书,最后会建立出一个.certSigningRequest文件,其实这个过程就是建立了一对公私钥github

  • 其中.certSigningRequest文件保存着
    • 申请者信息申请者的公钥
    • 摘要算法
    • 公钥加密算法
  • 私钥保存在 keychain

证书

AppleWWDRCA

iOS 以及 mac OS(在安装 Xcode 时)将自动安装 AppleWWDRCA.cer 这个中间证书(Intermediate Certificates),它实际上就是 iOS(开发)证书的证书,即根证书(Apple Root Certificate)。objective-c

iOS App Development

iOS的开发证书,在开发阶段进行真机测试时须要用到的证书。能够在苹果开发网站上手动建立,须要上传.certSigningRequest文件;或者使用Xcode自动建立。算法

iOS Distribution

iOS的发布证书,能够用于进行 Ad Hoc 测试、打包上传到 App Store 或者打包成 Enterprisee(In-House) 类型供企业内部使用。能够在苹果开发网站上手动建立,须要上传.certSigningRequest文件;或者使用Xcode自动建立。bash

.p12

mac OS钥匙串访问里选择一张证书,右击该证书,选择导出"xxxxx",而后设置密码,能够导出该证书对应的.p12文件。.p12文件包含我的信息、公钥和私钥,也就是证书 + 私钥。iOS类型的每种证书同时存在数量有限制,而证书是依靠mac OS上的.certSigningRequest文件建立的,因此正常状况下,每种类型的证书只能在有限的Mac电脑上使用,若是须要在更多不一样的Mac电脑上进行App开发、测试、签名,能够导出对应.p12文件代替证书来使用。微信

Provisioning Profile

Provisioning Profile的文件格式为.mobileprovision,里面包含着app

  • 可使用的证书
  • App ID,由 TeamID 和 BundleID 组合而成,相似于 A1B2C3D4.com.domain.appName 形式
  • 可安装该App的设备列表的UDID
  • Entitlements,受权文件,列出了App能够进行哪些行为
  • 以上信息的签名

在苹果开发网站上手动建立,或者使用Xcode自动建立。dom

.ipa

.ipa文件是iOS上的App安装文件,其实它只是一个压缩包,等同于.zip格式,用mac OS自带的归档实用工具能够直接对它解压,能够看到里面的内容ide

用于上传App Store的.ipa文件

App Store下载的.ipa文件

对比两种状况的.ipa文件,能够看出它里面最主要的是Payload文件夹,而Payload文件夹里面放的就是该App对应的.app文件

.app

右击.app文件,选择显示包内容,能够看到里面的内容

用于上传App Store的.app文件

从App Store下载的.app文件

能够看出.app文件主要包含三部分:

  • Mach-O格式的二进制可执行文件,这个是一个App最重要的文件,咱们编写的Objective-CSwift代码都被编译在里面
  • 资源文件,包括:.bundle文件,.framework文件,.dylib文件,.nib文件,图片文件,音视频文件,字体文件等全部项目用到的文件
  • CodeResources,签名信息
  • embedded.mobileprovision文件,或者entitlements文件
    • 对于没有上传App Store的.app文件,里面会包含embedded.mobileprovision文件,没有entitlements文件
    • App Store下载的.app文件,里面会包含.entitlements文件,没有embedded.mobileprovision文件

Code Signing

正常状况下(非越狱),全部App想要安装到iOS设备上,只有如下几种方法

  • 非App Store
    • 真机调试
    • Ad-Hoc
    • In-House
  • App Store

不管是哪种方法,都须要先把iOS项目编译成.app文件,而后进行签名。按照惯例,须要分析一下Code Signing

非App Store

对于非App Store得到的.ipa文件,须要严格复杂的签名和验证流程

  1. 建立.certSigningRequest文件,这时候会生成一对公私钥,这里称为公钥L(L:Local),私钥L.certSigningRequest文件保存着公钥L

  2. iOS 以及 mac OS上的AppleWWDRCA.cer 证书保存的就是苹果的公钥A(A:Apple),而对应的私钥A则在苹果的后台

  3. 在苹果开发者网站上建立证书的时候,上传.certSigningRequest文件其实就是把公钥L传到苹果后台,用苹果后台里的私钥A去签名公钥L,获得对应的证书,把证书下载回来双击安装,会跟对应的私钥L绑定一块儿保存在keychain

  4. 除了证书,还须要对应的Provisioning Profile。在苹果开发者网站上:

    1. 设置App的Bundle ID
    2. 设置可安装该App的设备UDID
    3. 设置该App的权限
    4. 设置可使用的证书
    5. 最后会使用私钥A把以上这些数据进行签名,组成一个Provisioning Profile,格式为.mobileprovision,下载回来双击安装,会保存在~/Library/MobileDevice/Provisioning Profiles中,文件名为它的UUID
  5. 当须要把一个App安装在iOS设备上时,都会先把iOS项目编译打包成.app文件,而打包成可安装在iOS设备上的.app文件的前提是,设置该App的Provisioning Profile,最后使用合法的证书对源代码编译后的各类文件进行签名,步骤以下:

    1. mac OS里的公钥A验证Provisioning Profile,获取里面的信息
    2. Provisioning Profile里面的信息验证App的Bundle ID是否对应,App的权限是否对应
    3. 公钥A验证Provisioning Profile里面的证书,再判断是否有其中一张证书在这台Mac电脑里
    4. 若是上面的验证都经过了,则会从mac OSkeychain 中取出符合条件且最新建立的证书,拿到对应的私钥L
      1. 若是有.framework文件、.dylib文件、插件、watch目录下的extension,对它们分别进行签名
      2. Provisioning Profile更名为embedded.mobileprovision放在.app文件里面
      3. 使用私钥L对整个.app文件进行签名,获得签名信息CodeResources也放会在.app文件里面
    5. 若是须要生成.ipa文件,则会把.app文件放在Payload文件夹里,把Payload文件夹和一些其余信息文件(非必要),一块儿压缩造成一个.ipa文件
  6. .ipa文件或者.app文件安装在iOS设备上时

    1. 先使用iOS设备上的公钥A.app文件里面的embedded.mobileprovision文件进行验证,获取里面的证书
    2. 再使用公钥Aembedded.mobileprovision文件里面存在的证书进行验证,取出一张对应的证书,获得公钥L
    3. 使用公钥L.app里面全部签名信息进行验证,若是验证经过,证实该.app文件是完整合法,没有被篡改的
    4. 获取embedded.mobileprovision文件里面的可安装该App的设备UDID列表,判断该iOS设备是否能够安装
    5. 若是前面的验证都经过,则App会安装在iOS设备上

App Store

当须要在App Store发布App时,则先须要把.ipa文件上传到App Store。苹果会用一种很是简单的方式进行从新签名,这是由于在把.ipa文件上传到App Store以前,会先进行相似于上面步骤的一系列验证,只有经过验证才会上传成功,因此这已经进行过一次复杂的验证,表明苹果已经认同了这个.ipa文件,而用户又是从App Store下载的,因此也保证了.ipa文件来源是权威的,最后只须要在用户设备上进行简单的验证就能够

  1. 苹果用私钥A.app文件里面须要签名的文件进行从新签名
  2. 用户下载App Store上面的.ipa文件进行安装时,用iOS设备上的公钥A.app文件里全部签名信息进行验证,若是验证经过,则会安装在iOS设备上

更多相关

以上就是Code Signing最核心的内容,但在iOS开发中其实还有不少相关的概念,不少须要注意的地方,接下来会讲解一下我我的的观察和分析

苹果开发者账号体系

Apple Developer:直接在Apple Developer登陆,赞成Apple Developer协议后的帐号,免费,只可使用Xcode进行真机调试,Xcode 7以后苹果推出的功能

Apple Developer Program:分我的和组织类型,费用都是每一年 99 美圆,可使用Xcode进行真机调试,打包Ad-Hoc测试,在App Store发布App

Apple Developer Enterprise Program:企业帐号,费用是每一年 299 美圆,可使用Xcode进行真机调试,打包Ad-Hoc测试,打包In-House App,但不能在App Store发布App

不一样安装方式对应的证书类型

  • 非App Store
    • Development(真机调试):iOS App Development
    • Ad Hoc:iOS Distribution (App Store and Ad Hoc)
    • Enterprise:iOS Distribution (In-House and Ad Hoc)
  • App Store:iOS Distribution (App Store and Ad Hoc)

在iOS的项目中,只要不是运行在模拟器上,都会涉及到开发者账号、证书、Provisioning Profile这些概念。

免费帐号的限制:

  • 建立的Provisioning Profile有效期只有7天
  • 在7天内最多注册10个Bundle Id
  • 只能同时注册3台iOS设备
  • 在同一台iOS设备上,只能同时安装3个使用免费帐号签名的App。当该设备上已经存在3个App,则没法安装任何免费帐号签名的任何App,就算是那3个App其中一个也不行,只能先把其中一个删除

Automatic signing

在Xcode 7以前,只有加入到Apple Developer Program(即付费)才能进行真机调试,Xcode 7以后苹果推出了Automatic signing功能,只要在Xcode上登录Apple ID,就会自动管理证书和Provisioning Profile,同时没有加入Apple Developer Program的帐号也能进行真机调试。

在使用Xcode的Automatic signing功能的时候,不管是什么类型的帐号,不管是直接Run进行真机调试,仍是ArchiveCode Signing Identity只能选用iOS Developer,只会使用iOS App Development类型的证书签名

若是不使用Automatic signing功能,则能够选择使用的是iOS App Development或者iOS Distribution证书进行签名

勾选Xcode中的AutoMatically manager signing,选择对应的Team后,不管是加入Apple Developer Program的帐号(即付费帐号)仍是Apple Developer的帐号(即免费帐号):

  • 若是Xcode没有帮该帐号自动生成过iOS App Development类型的证书, 不管在苹果后台是否已经存在其余iOS App Development类型的证书,都会生成一张新的iOS App Development类型证书,证书名称的格式是:开发者帐号名称(当前Mac电脑名称), 如:Brian Hui (Daniels的MacBook Pro),同时会保存在当前Mac电脑的keychain

  • 免费帐号没法进入苹果的管理证书后台,但能够猜想出在苹果后台也会存在该证书

  • 若是Xcode没有帮该App的Bundle ID自动生成过对应的Provisioning Profile,就会使用上面那张证书生成一个Provisioning Profile,保存在~/Library/MobileDevice/Provisioning Profiles,但在苹果后台则不会存在这个Provisioning Profile

  • 若是在钥匙串访问中删除了那张证书,Xcode会提示你的帐号有iOS App Development类型的证书,但这台电脑没有安装,须要先把那张证书RevokeRevoke后会再次重复前面的步骤,生成新的证书和Provisioning Profile

  • 若是在~/Library/MobileDevice/Provisioning Profiles里面,删除了该Provisioning Profile文件,Xcode会立刻从新生成Provisioning Profile

在使用Xcode的Automatic signing功能的前提下,进行Archive,而后Distribute App的时候,选择非Development的选项,再选择AutoMatically manager signing

  • 若是本地存在iOS Distribution类型的证书,则会直接进行重签名

  • 若是没有存在iOS Distribution类型的证书,而苹果的后台有,则会告诉你,该帐号存在iOS Distribution类型的证书,但这台电脑没有安装,请联系建立人拿到备份(.p12文件)进行安装,当你安装了该证书(或者.p12文件),则会直接进行重签名

  • 若是没有存在iOS Distribution类型的证书,而苹果的后台也没有,则Xcode会询问你是否须要生成iOS Distribution类型的证书,若是选择须要,则会自动生成iOS Distribution类型的证书,而且建议你保存在本地,证书名称的格式是:Team Name, 如:Hutchison Telephone (Macau) Company Limited,同时使用这张证书生成一个Provisioning Profile,保存在~/Library/MobileDevice/Provisioning Profiles,但在苹果后台则不会存在这个Provisioning Profile

Xcode对Provisioning Profile的验证

Xcode怎么把App和证书、Provisioning Profile绑定在一块儿呢?何时须要一张新的证书,何时须要一个新的Provisioning Profile

Bundle ID是App的惟一标识,App和证书、Provisioning Profile绑定在一块儿,其实就是Bundle ID和证书、Provisioning Profile绑定在一块儿,两种状况:

Automatic signing

Bundle ID与开发者帐号绑定。使用Automatic signing时,选择开发者帐号(Team)后,Xcode会根据开发者帐号去本地检索是否存在该帐号对应的Provisioning Profile,再验证是否存在与该Bundle ID匹配的Provisioning Profile,再根据Provisioning Profile去本地检索是否存在对应的证书,都验证经过,则会设置成功。若是不存在Provisioning Profile,则会判断该Bundle ID是否已经被其余帐号注册,若是已经被其余帐号注册,则整个流程失败,须要选择对应的帐号。若是该Bundle ID没有被其余帐号注册或者帐号已经对应上,则按照文章前面所说的步骤,最后生成Provisioning Profile

没有使用Automatic signing

须要手动选择Provisioning Profile,当选择了其中一个Provisioning Profile时,则会分别验证Bundle ID是否对应、Provisioning Profile是否过时、是否存在对应的证书、App的权限是否对应、证书的类型和Code Signing Identity设置是否对应,若是都经过验证,则会设置成功。

结论

当你使用一台新的Mac电脑,进行开发、调试、发布某个开发者帐号注册的App时,就须要一张新的证书(或者.p12文件);当你使用新的证书或者新的App,就须要一张新的Provisioning Profile。一张证书对应一台Mac电脑,和一个开发者帐号里面全部App,而一个Provisioning Profile则是只能对应一个App。

检验Provisioning Profile是签名的第一步,那若是Provisioning Profile经过检验,而Provisioning Profile里面又存在证书,为何还须要单独安装证书呢?

答案是:Provisioning Profile里面证书的做用是验证本地是否有符合条件证书,而且在安装App的时候使用其中一张证书里面的公钥L来验证App的完整性和合法性。由于Provisioning Profile里面是有多张证书的,因此没法肯定用哪张证书对应的私钥L用来签名,因此这些证书只能用于判断Mac电脑里有没有符合条件的证书,若是Mac电脑里有多张符合条件的证书,则默认用其中最新的证书里面的私钥L进行签名,这样就能够限制了只有得到符合条件的证书的Mac电脑,才能进行签名。

Mac电脑中证书的做用:1. 证实这台电脑是合法的;2. 找到对应的私钥L来对.app文件进行签名

Provisioning Profile中证书的做用:1. 判断这台电脑是否能够进行签名,也就是判断这个台电脑的合法性;2. 安装App时检验.app文件

Xcode的Build Configuration和Code Signing Identity

Xcode有RunArchiveTest等几种项目构建方式,每一种能够指定不一样的Build Configuration(默认有DebugRelease),而在Code Signing Identity又须要指定每种Build Configuration对应的配置,分别为iOS DeveloperiOS Distribution,其实就是在设置Provisioning Profile的类型是开发的仍是发布的

在使用Xcode的Automatic signing功能的时候,Code Signing Identity只能选择iOS Developer,不然会报错

Xcode的Run、Archive和Distribute App

RunArchive的时候已经对App完成签名。若是设置的Provisioning Profile不是用于发布到App Store的,这时候把里面的.app文件打包成.ipa文件,能够利用Xcode或者其余工具直接安装到指定的iOS设备上。而点击Archives界面中Distribute App后,会再给你一次机会,选择其余证书和Provisioning Profile进行重签名,用于将App发布到不一样的渠道

iOS设备上打开App时的验证

把App安装到iOS设备时,须要通过本文前面所说的验证,而打开App的时候,也须要验证:

  • 使用付费帐号生成的DevelopmentAD-Hoc类型的.ipa文件,安装后打开对应的App时,不须要在iOS设备上进行信任开发者操做,每次打开都会验证证书和Provisioning Profile是否被Revoke或者过时,若是验证不经过,则没法打开

  • 使用免费帐号生成的Development和企业帐号生成的Enterprise类型的.ipa文件,安装后第一次打开App时,须要在iOS设备上作额外的信任开发者操做,每次打开都会验证证书和Provisioning Profile是否被Revoke或者过时,若是验证不经过,则没法打开

  • App Store下载的.ipa文件,安装后第一次打开App时,会验证当前登陆的App ID是否已经购买该App,若是验证经过,则之后均可以正常打开,若是验证不经过则没法打开

重签名

在彻底了解iOS中的Code Signing体系后,除了可让你在平常开发中遇到证书、签名等问题的时候解决起来驾轻就熟,还有一个重要的应用就是重签名。网上也有一大堆关于重签名的文章,大多数都只是说了怎么操做,可是不多会解释为何要这样操做。接下来我会结合本文前面的内容详细分析重签名的原理。

原理

  • 重签名顾名思义,就是把.ipa文件也就是.app文件进行从新签名。通过前面的分析,iOS的Code Signing体系是依靠两个文件来进行签名:证书和Provisioning Profile,它们是由苹果后台生成的,而且用私钥A进行签名,因此重签名的第一步就是须要准备有效合法、由苹果后台生成的证书和Provisioning Profile,它们必须是相对应而且没有被修改过的。须要注意的是,若是这证书不是由你的Mac电脑去请求生成的,是它没法跟它里面公钥L对应的私钥L绑定在一块儿,由于你的Mac电脑里根本没有对应的私钥L,因此这时候是须要它对应的.p12文件,安装.p12文件就会获得证书和对应的私钥L

  • 签名的时候,会拿到Provisioning Profile里面的信息验证App的Bundle ID是否对应,App的权限是否对应,因此要把进行重签名的App的Bundle ID改为跟Provisioning Profile记录的一致。而App的权限则须要直接从Provisioning Profile中导出entitlements.plist文件,最后在重签名的时候使用

  • 既然是对.app文件进行重签名,那么最后就是须要准备一个没有被加密的.app文件。在App Store下载.ipa文件里面的.app文件都是被加密,被加密的.app文件没法进行重签名

  • 准备工做已经完成,如今就能够开始重签名,步骤实际上是跟初次签名同样的。首先把准备好的Provisioning Profile更名为embedded.mobileprovision放在.app 文件中或者进行覆盖。使用准备好的证书,对.framework文件、.dylib文件、插件、watch目录下的extension分别进行签名,最后用证书和导出entitlements.plist文件再对整个.app文件签名

  • 关于证书的类型和App的安装限制:既然进行了重签名,那么这个App能够安装的iOS设备就会受到使用的证书和Provisioning Profile的限制,因此通常会使用企业帐号的发布证书和In House类型Provisioning Profile进行重签名,这样就可使App安装在任何iOS设备上

步骤

  • 准备合法完整的证书(或者.p12文件)和Provisioning Profile
  • 准备一个已经脱壳的.app或者.ipa文件,其中Bundle ID要跟Provisioning Profile中的一致
// 在.app文件中,把Info.plist的Bundle ID改成 com.xxx.xxx
/usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier com.xxx.xxx' "Info.plist"
复制代码
  • Provisioning Profile提取entitlements
// 从embedded.mobileprovision文件中提取出entitlements.plist权限文件
security cms -D -i embedded.mobileprovision > temp.plist
/usr/libexec/PlistBuddy -x -c 'Print :Entitlements' temp.plist > entitlements.plist
复制代码
  • Provisioning Profile更名为embedded.mobileprovision放在.app 文件中
  • 使用准备好的证书,对.framework文件、.dylib文件、PlugIns目录里的.appex文件、Watch目录里的.app文件分别进行签名,最后用证书和导出entitlements.plist文件再对整个.app文件签名
// 查看可用的证书
security find-identity -v -p codesigning

// 对.app内部的.framework文件、.dylib文件、PlugIns目录里的.appex文件、Watch目录里的.app文件分别进行签名
codesign -fs   证书ID   xxx.dylib

// 对.app文件进行签名
codesign -fs   证书ID  --entitlements entitlements.plist xxx.app
复制代码
  • 查看新的签名信息
codesign -d -vv xxx.app
复制代码
  • 打包成.ipa文件
zip -r xxx.ipa Payload/
复制代码

注意

  • 正常状况下.app的Bundle ID要跟Provisioning Profile中的一致,但实际操做发现,就算Bundle ID不一致也能够正常安装使用,但应该存在必定的隐患,因此建议仍是保持一致
  • 重签名的时候,为了方便,能够直接把.app 文件里面的PlugIns目录、Watch目录都删除,通常状况下不会用到。可是为了项目的完整性,以防出错,最好把它们也保留。PlugIns目录的文件能够直接用证书分别对它们进行签名。而在微信里,Watch目录里面是一个.app文件,我不肯定是否是全部App都是如此,以微信为例,对它进行签名前,须要进去打开内部的Info.plist文件,把其中两个值进行修改,分别是:
    • WKCompanionAppBundleIdentifier,这个key对应的值指定了Watch目录的.app文件用于哪一个App,在微信中为com.tencent.xin,能够看出是跟微信的Bundle ID同样,因此须要把它改成跟Provisioning Profile中的一致
    • Bundle identifier,这个key对应的值表示Watch目录的.app文件本身的Bundle ID,在微信中为com.tencent.xin.watchapp,能够看出它的前缀是微信的Bundle ID,因此须要把它的前缀改成跟Provisioning Profile中的一致,后面的部分保持不变就能够
    • 完成上面的修改后就能够用证书对Watch目录里面的.app文件签名

结语

以上就是我我的对Code Signing体系的观察和分析,你们能够看到相关的东西不少,须要注意的地方也不少,我尽可能地把这些细节都总结出来,而这方面官方文档确实没有写得很详尽(或许是我没找到),因此很难把全部特性和表现都彻底正确地总结出来,若是你们有发现文章中什么问题,请在评论中指出,我会及时验证、修改。

参考文章

黑幕背后的 Code Signing

iOS Provisioning Profile(Certificate)与Code Signing详解

iOS之从建立(Development、Distribution)证书到发布

iOS App 签名的原理

相关文章
相关标签/搜索