iOS中的Code Signing
体系很是复杂,对新手很是不友好,虽然目前网上已经存在大量文章对此进行比较透彻的分析,最核心的部分已经讲解得很是清楚,我阅读了这些文章后,确实从中学习到很多知识,但我始终仍是对Code Signing
体系中不少相关的地方有着疑惑,因而决定认真地探究一番。本文会引用一些比较好的文章中的内容和图片,加上一些我我的的理解进行分析,有些内容本文再也不重复,有须要的请阅读本文最后的参考文章。html
公开密钥加密、数字签名、证书这些通用的基本概念这里再也不多说,主要提一下iOS
上特有的东西git
点击mac OS
的钥匙串访问
里的 证书助理 -> 从证书颁发机构请求证书
,最后会建立出一个.certSigningRequest
文件,其实这个过程就是建立了一对公私钥github
.certSigningRequest
文件保存着
keychain
中iOS
以及 mac OS
(在安装 Xcode 时)将自动安装 AppleWWDRCA.cer
这个中间证书(Intermediate Certificates),它实际上就是 iOS(开发)证书的证书,即根证书(Apple Root Certificate)。objective-c
iOS的开发证书,在开发阶段进行真机测试时须要用到的证书。能够在苹果开发网站上手动建立,须要上传.certSigningRequest
文件;或者使用Xcode自动建立。算法
iOS的发布证书,能够用于进行 Ad Hoc 测试、打包上传到 App Store 或者打包成 Enterprisee(In-House) 类型供企业内部使用。能够在苹果开发网站上手动建立,须要上传.certSigningRequest
文件;或者使用Xcode自动建立。bash
在mac OS
的钥匙串访问
里选择一张证书,右击该证书,选择导出"xxxxx"
,而后设置密码,能够导出该证书对应的.p12
文件。.p12
文件包含我的信息、公钥和私钥,也就是证书 + 私钥
。iOS类型的每种证书同时存在数量有限制,而证书是依靠mac OS
上的.certSigningRequest
文件建立的,因此正常状况下,每种类型的证书只能在有限的Mac电脑上使用,若是须要在更多不一样的Mac电脑上进行App开发、测试、签名,能够导出对应.p12
文件代替证书来使用。微信
Provisioning Profile
的文件格式为.mobileprovision
,里面包含着app
A1B2C3D4.com.domain.appName
形式在苹果开发网站上手动建立,或者使用Xcode自动建立。dom
.ipa
文件是iOS上的App安装文件,其实它只是一个压缩包,等同于.zip
格式,用mac OS
自带的归档实用工具
能够直接对它解压,能够看到里面的内容ide
用于上传App Store的.ipa
文件
App Store下载的.ipa
文件
对比两种状况的.ipa
文件,能够看出它里面最主要的是Payload
文件夹,而Payload
文件夹里面放的就是该App对应的.app
文件
右击.app
文件,选择显示包内容
,能够看到里面的内容
用于上传App Store的.app
文件
从App Store下载的.app
文件
能够看出.app
文件主要包含三部分:
Mach-O
格式的二进制可执行文件,这个是一个App最重要的文件,咱们编写的Objective-C
、Swift
代码都被编译在里面.bundle
文件,.framework
文件,.dylib
文件,.nib
文件,图片文件,音视频文件,字体文件等全部项目用到的文件CodeResources
,签名信息embedded.mobileprovision
文件,或者entitlements
文件
.app
文件,里面会包含embedded.mobileprovision
文件,没有entitlements
文件.app
文件,里面会包含.entitlements
文件,没有embedded.mobileprovision
文件正常状况下(非越狱),全部App想要安装到iOS设备上,只有如下几种方法
不管是哪种方法,都须要先把iOS项目编译成.app
文件,而后进行签名。按照惯例,须要分析一下Code Signing
对于非App Store得到的.ipa
文件,须要严格复杂的签名和验证流程
建立.certSigningRequest
文件,这时候会生成一对公私钥,这里称为公钥L
(L:Local),私钥L
。.certSigningRequest
文件保存着公钥L
iOS
以及 mac OS
上的AppleWWDRCA.cer
证书保存的就是苹果的公钥A
(A:Apple),而对应的私钥A
则在苹果的后台
在苹果开发者网站上建立证书的时候,上传.certSigningRequest
文件其实就是把公钥L
传到苹果后台,用苹果后台里的私钥A
去签名公钥L
,获得对应的证书,把证书下载回来双击安装,会跟对应的私钥L
绑定一块儿保存在keychain
中
除了证书,还须要对应的Provisioning Profile
。在苹果开发者网站上:
私钥A
把以上这些数据进行签名,组成一个Provisioning Profile
,格式为.mobileprovision
,下载回来双击安装,会保存在~/Library/MobileDevice/Provisioning Profiles
中,文件名为它的UUID当须要把一个App安装在iOS设备上时,都会先把iOS项目编译打包成.app
文件,而打包成可安装在iOS设备上的.app
文件的前提是,设置该App的Provisioning Profile
,最后使用合法的证书对源代码编译后的各类文件进行签名,步骤以下:
mac OS
里的公钥A
验证Provisioning Profile
,获取里面的信息Provisioning Profile
里面的信息验证App的Bundle ID是否对应,App的权限是否对应公钥A
验证Provisioning Profile
里面的证书,再判断是否有其中一张证书在这台Mac电脑里mac OS
的keychain
中取出符合条件且最新建立的证书,拿到对应的私钥L
.framework
文件、.dylib
文件、插件、watch目录下的extension,对它们分别进行签名Provisioning Profile
更名为embedded.mobileprovision
放在.app
文件里面私钥L
对整个.app
文件进行签名,获得签名信息CodeResources
也放会在.app
文件里面.ipa
文件,则会把.app
文件放在Payload
文件夹里,把Payload
文件夹和一些其余信息文件(非必要),一块儿压缩造成一个.ipa
文件把.ipa
文件或者.app
文件安装在iOS设备上时
公钥A
对.app
文件里面的embedded.mobileprovision
文件进行验证,获取里面的证书公钥A
对embedded.mobileprovision
文件里面存在的证书进行验证,取出一张对应的证书,获得公钥L
公钥L
对.app
里面全部签名信息进行验证,若是验证经过,证实该.app
文件是完整合法,没有被篡改的embedded.mobileprovision
文件里面的可安装该App的设备UDID列表,判断该iOS设备是否能够安装当须要在App Store发布App时,则先须要把.ipa
文件上传到App Store。苹果会用一种很是简单的方式进行从新签名,这是由于在把.ipa
文件上传到App Store以前,会先进行相似于上面步骤的一系列验证,只有经过验证才会上传成功,因此这已经进行过一次复杂的验证,表明苹果已经认同了这个.ipa
文件,而用户又是从App Store下载的,因此也保证了.ipa
文件来源是权威的,最后只须要在用户设备上进行简单的验证就能够
私钥A
对.app
文件里面须要签名的文件进行从新签名.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
不一样安装方式对应的证书类型
在iOS的项目中,只要不是运行在模拟器上,都会涉及到开发者账号、证书、Provisioning Profile
这些概念。
Provisioning Profile
有效期只有7天在Xcode 7以前,只有加入到Apple Developer Program(即付费)才能进行真机调试,Xcode 7以后苹果推出了Automatic signing
功能,只要在Xcode上登录Apple ID,就会自动管理证书和Provisioning Profile,同时没有加入Apple Developer Program的帐号也能进行真机调试。
在使用Xcode的Automatic signing
功能的时候,不管是什么类型的帐号,不管是直接Run
进行真机调试,仍是Archive
,Code 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
类型的证书,但这台电脑没有安装,须要先把那张证书Revoke
,Revoke
后会再次重复前面的步骤,生成新的证书和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怎么把App和证书、Provisioning Profile
绑定在一块儿呢?何时须要一张新的证书,何时须要一个新的Provisioning Profile
?
Bundle ID是App的惟一标识,App和证书、Provisioning Profile
绑定在一块儿,其实就是Bundle ID和证书、Provisioning Profile
绑定在一块儿,两种状况:
Bundle ID与开发者帐号绑定。使用Automatic signing
时,选择开发者帐号(Team)后,Xcode会根据开发者帐号去本地检索是否存在该帐号对应的Provisioning Profile
,再验证是否存在与该Bundle ID匹配的Provisioning Profile
,再根据Provisioning Profile
去本地检索是否存在对应的证书,都验证经过,则会设置成功。若是不存在Provisioning Profile
,则会判断该Bundle ID是否已经被其余帐号注册,若是已经被其余帐号注册,则整个流程失败,须要选择对应的帐号。若是该Bundle ID没有被其余帐号注册或者帐号已经对应上,则按照文章前面所说的步骤,最后生成Provisioning Profile
。
须要手动选择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有Run
、Archive
、Test
等几种项目构建方式,每一种能够指定不一样的Build Configuration
(默认有Debug
和Release
),而在Code Signing Identity
又须要指定每种Build Configuration
对应的配置,分别为iOS Developer
和iOS Distribution
,其实就是在设置Provisioning Profile
的类型是开发的仍是发布的
在使用Xcode的Automatic signing
功能的时候,Code Signing Identity
只能选择iOS Developer
,不然会报错
Run
和Archive
的时候已经对App完成签名。若是设置的Provisioning Profile
不是用于发布到App Store的,这时候把里面的.app
文件打包成.ipa
文件,能够利用Xcode或者其余工具直接安装到指定的iOS设备上。而点击Archives
界面中Distribute App
后,会再给你一次机会,选择其余证书和Provisioning Profile
进行重签名,用于将App发布到不一样的渠道
把App安装到iOS设备时,须要通过本文前面所说的验证,而打开App的时候,也须要验证:
使用付费帐号生成的Development
和AD-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设备上
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
文件,把其中两个值进行修改,分别是:
.app
文件用于哪一个App,在微信中为com.tencent.xin
,能够看出是跟微信的Bundle ID同样,因此须要把它改成跟Provisioning Profile
中的一致.app
文件本身的Bundle ID,在微信中为com.tencent.xin.watchapp
,能够看出它的前缀是微信的Bundle ID,因此须要把它的前缀改成跟Provisioning Profile
中的一致,后面的部分保持不变就能够.app
文件签名以上就是我我的对Code Signing
体系的观察和分析,你们能够看到相关的东西不少,须要注意的地方也不少,我尽可能地把这些细节都总结出来,而这方面官方文档确实没有写得很详尽(或许是我没找到),因此很难把全部特性和表现都彻底正确地总结出来,若是你们有发现文章中什么问题,请在评论中指出,我会及时验证、修改。
iOS Provisioning Profile(Certificate)与Code Signing详解