@[TOC](IOS 逆向开发(三)应用签名)
1. 数字签名
- 什么是数字签名?
- 数字签名(digitally signed):先举个栗子:老外喜欢用支票,支票上面的签名能够证明这玩意是你的.那么数字签名顾名思义,就是用于鉴别数字信息的方法.这个是个很形象的说法。在IOS app的数字签名:就是将原始数据通过Hash算法得到原始的hash值,然后通过非对称加密算法RSA加密hash值,得到最终的加密数据,这个过程就叫做数字签名。
- 数字签名(又称公钥数字签名、电子签章等)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
- 数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
- 想要证明数字信息(也就是二进制数据,计算机里面的任意数据)的有效性,那么使用什么方式最合适呢?
- 在上一篇博客“IOS 逆向开发(二)密码学 HASH” 中有讲到HASH算法专门用来做文件数据的识别.那么在网络数据传递的过程中,我们可以将明文数据,和数据的HASH值一起传递给对方.对方可以拿出HASH值来进行验证.
- 但是在这个过程中,如何做到数据的保护呢?
明文数据和HASH值如果直接传递就有都被篡改的风险.所以这里我们要对数据进行加密.明文数据有时会比较大,不适合使用RSA非对称加密算法,那么数据的HASH值是比较小的.这个数据是用于校验的,它完全可以使用RSA来加密.- 所以在数据传递的时候,我们将明文数据加上通过RSA加密的校验数据一并传递给对方.那么这个通过RSA加密的校验数据,我们称之为签名.
- 通过下图,可以弄明白数字签名是个什么过程?
1.1 数字签名过程:
- 首先传递数据时会将原始的数据和数字签名一起发送
- 对方拿到数据后,先进行校验.拿到原始数据,通过同样的HASH算法得到数据的HASH值.
- 然后通过非对称加密,将数字签名中的校验HASH值解密出来.
最后对比两个HASH值是否一致.这样可以很好的判断数据是否被篡改!
- 数字签名验证过程
数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用Hash函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。
1.2 客户端,服务器签名验证过程:
-
如果客户端向服务器发生数据时不做任何处理,可能会遭到中间人的窃取攻击,后果如何严重就不说了。那么我们如何防止中间人拦截,或者检查数据是否被篡改呢?
直接用RSA(RSA加密原理)进行加密应该是不满足我们的需求,RSA只适合对小数据进行加密,我们知道验证数据的完整性可以用Hash(Hash概述)来验证,可以对数据进行Hash,把Hash值和原始数据一起打包发送给服务器,服务器将原始数据进行Hash,得到的hash值和客户端发送的Hash值做对比,如果一致则保证数据有效性。但是这样会有安全隐患,如果中间人篡改了客户端发送的数据,当然也可以修改客户端发送的Hash值,所以这样操作不可行。
这时我们可以用RSA来对hash值进行保护,此时客户端发送原始数据,和经RSA加密后的该数据的hash值。
服务器对RSA加密的数据进行解密,得到原始数据的hash值,接下来对原始数据进行通过同样的Hash算法,将得到的Hash值和解密后的Hash值做对比,如果一致则保证数据有效性,整个过程中,如果解密的Hash值和原始的Hash值不一致,或者无法解密RSA的数据,说明数据被篡改了。
-
验证数据是否被篡改的过程如下:
2. 代码签名
- 什么是代码签名?
代码签名: 是对可执行文件或脚本进行数字签名.用来确认软件在签名后未被修改或损坏的措施。和数字签名原理一样,只不过签名的数据是代码而已.代码签名就是用来校验我们的可执行文件的
- 作为IOS开发人员,为什么需要理解代码签名的原理?
- iOS工程师用于从本地计算机上安装的Xcode部署iOS应用程序的日子已经一去不复返了。公司正在采用DevOps和CI / CD来构建软件,因此所有构建都需要自动化,无需任何人工或GUI交互。
- 由于Xcode的代码签名失败,开发人员试图通过重新生成和修复证书和配置文件来修复代码签名问题,因此浪费了数千个开发人员时间。
- 像Fastlane这样的第三方工具使iOS开发人员更容易构建脚本。然而,在Apple对底层技术进行更改后,Fastlane不断破坏,开发人员花费数小时,数天和数周来修复损坏的部署脚本。在某些情况下,工程师必须等到Fastlane实施新的更改。
- 如果您是iOS开发人员/工程师,并希望一生成为iOS工程师,那么您无需了解这些内容。但是,如果您想在职业生涯中成长,那么您必须详细了解底层工具,技术和整个iOS生态系统。如果您不了解这些底层技术,无论您的iOS开发技能有多好,您都不会获得iOS技术主管,iOS技术架构师或类似角色。作为技术架构师,您应该能够快速修复代码签名或类似的基础架构相关问题,而无需依赖Xcode或其他第三方工具。
2.1 简单的代码签名
- 代码签名的产生背景
- 在iOS出来之前,以前的主流操作系统(Mac/Windows)软件随便从哪里下载都能运行,系统安全存在隐患,盗版软件,病毒入侵,静默安装等等.
- 那么苹果希望解决这样的问题,要保证每一个安装到 iOS 上的 APP 都是经过苹果官方允许的.
- 要做到上述目的,就需要代码签名。
- 怎样保证安装的每一个APP都是经过苹果官方允许的?
- 如果要实现验证.其实最简单的方式就是通过苹果官方生成非对称加密的一对公私钥.
- 在iOS的系统中内置一个公钥,私钥由苹果后台保存,我们传APP到AppStore时,苹果后台用私钥对APP数据进行签名,
- iOS系统下载这个APP后,用公钥验证这个签名,若签名正确,这个APP肯定是由苹果后台认证的,并且没有被修改过,也就达到了苹果的需求:保证安装的每一个APP都是经过苹果官方允许的.
- 整个过程很简单,这样就保证了苹果安装的每一个APP都是经过苹果官方允许的。对于大部分普通用户而言,这样一个数字签名就解决了安全隐患问题,但是实际上iOS设备安装APP并不是只有App Store这一个渠道,比如对于我们iOSer来说,我们在开发APP时还在真机调试,当然苹果还开放了企业内部分发的渠道,这时就无法通过简单的代码签名来满足这些需求了。
- 要实现这些要求,需要一种更好的机制,这就是接下来要讲的双向代码签名技术
2.2 iOS的双层代码签名
- 双层代码签名的产生背景
- 如果我们iOS设备安装APP只从App Store这一个入口这件事就简单解决了,没有任何复杂的东西,一个数字签名搞定.
- 但是实际上iOS安装APP还有其他渠道.比如对于我们开发者iOSER而言,我们是需要在开发APP时直接真机调试的.而且苹果还开放了企业内部分发的渠道,企业证书签名的APP也是需要顺利安装的.
- 苹果需要开放这些方式安装APP,这些需求就无法通过简单的代码签名来办到了.
- 苹果爸爸使用双层签名技术来实现以下需求:
(1)安装包不需要上传到App Store,可以直接安装到手机上.
(2)为了保证系统的安全性,又必须对安装的APP有绝对的控制权
(3)经过苹果允许才可以安装
(4)不能被滥用导致非开发APP也能被安装
2.2.1 双层代码签名原理
首先这里有两个角色.一个是iOS系统 还有一个就是我们的Mac系统.因为iOS的APP开发环境在Mac系统下.所以这个依赖关系成为了苹果双层签名的基础.
我们使用的xcode只需要有一个证书,就可以帮我们把ipa安装到手机中。
xcode 在申请证书的时候,在Mac系统中生成非对称加密算法的一对公钥\私钥(你的Xcode帮你代办了).这里称为公钥M 私钥M . M = Mac
- 苹果自己有固定的一对公私钥,跟之前App Store原理一样,私钥在苹果后台,公钥在每个iOS系统中.这里称为公钥A , 私钥A. A=Apple,
- 把公钥M 以及一些你开发者的信息,传到苹果后台(这个就是CSR文件),用苹果后台里的私钥 A 去签名公钥M。得到一份数据包含了公钥M 以及其签名,把这份数据称为证书。
- 如上图所示,证书双向签名验证流程:
- 我们Xcode找苹果服务器去要证书,这个过程利用了一个csr文件,其中这个csr文件中有个核心的东西叫公钥M 。xcode通过csr文件将mac电脑里的公钥M 发送给苹果服务器。
- 苹果服务器收到csr文件后,对公钥M进行签名,也就是使用苹果服务器自己的私钥A进行非对称RSA加密。本身这个公钥M就不大,所以不会很耗时。加密后就得到一个证书。这个证书就是被私钥A加密过后的一个文件,里面包含公钥M 。这个证书就是我们的开发者证书。
- Xcode通过Mac电脑上的私钥M 对我们的app进行签名。只要我们通过xcode 进行command + B 进行bulid就会有这么一个过程。本地的私钥m也就是我们的p12文件。
- Xcode帮我们打包签名的时候,会同时将证书一起打包。
- 在我们安装ipa包的时候,苹果会检查证书,查看证书的颁发机构是否是苹果。如果不是苹果颁发的证书,就不能安装。
- iphone手机用证书里面携带的苹果服务器给的公钥A对ipa包里面的证书进行解密。如果能够成功解密,说明是苹果颁发的证书,如果不是苹果颁发的,则肯定无法进行解密。
- 接下来就需要验证app,用公钥A解密证书得到公钥M。这样用公钥M就能对app进行验证了。
- 在开发时,编译完一个 APP 后,用本地的私钥 M(今后你导出的P12) 对这个 APP 进行签名,同时把第三步得到的证书一起打包进 APP 里,安装到手机上。
在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证证书的数字签名是否正确。
验证证书后确保了公钥 M 是苹果认证过的,再用公钥 M 去验证 APP 的签名,这里就间接验证了这个 APP 安装行为是否经过苹果官方允许。(这里只验证安装行为,不验证APP 是否被改动,因为开发阶段 APP 内容总是不断变化的,苹果不需要管。)
-
双层代码签名总的流程图
上面的双向代码签名的过程,已经可以保证开发者的认证,和程序的安全性了。但是,你要知道iOS的程序,主要渠道是要通过APP Store才能分发到用户设备的,如果只有上述的过程,那岂不是只要申请了一个证书,就可以安装到所有iOS设备了?
上面的流程能验证安装的ipa是苹果允许的,但是无法验证ipa的安装行为。
为了防止滥用,苹果再加了几个限制,主要是通过描述文件来限制安装的设备数量。
接下来我们需要了解一下什么描述文件。
3. 描述文件
3.1 描述文件(Provisioning Profile)
- 什么是描述文件?
- 苹果官方Xcode对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)一般包括三样东西:证书、App ID、设备。当我们在真机运行或者打包一个项目的时候,证书用来证明我们程序的安全性和合法性
Provisioning Profile在这里就起到了一个对设备和开发者授权的作用,他将开发者账号、证书、entitlements文件以及设备进行了绑定。- 在开发过程中,Xcode 8及后续版本默认情况下会自动帮我们管理Provisioining Profile,自动下载的Provisioning Profile都被存放在
~/Library/MobileDevice/Provisioning\ Profiles/
路径下,以UUID格式命名。直接拖拽下图中的齿轮图标到Finder中也可以将其复制出来。
- 前面我们讲到了,通过简单的代码签名的方式,是无法解决苹果的安全需求的,那么苹果是如何做到防止申请一个证书可以安装到所有设备上这个问题的呢?
- 苹果加了两个限制:
(1)在苹果后台注册过的设备才可以安装.
(2)签名只能针对某一个具体的APP.- 苹果还想控制App里面的iCloud/PUSH/后台运行/调试器附加这些权限,所以苹果把这些权限开关统一称为Entitlements(授权文件).
- 此外苹果将这个Entitlements文件放在了一个叫做Provisioning Profile(描述文件)文件中.描述文件是在AppleDevelop网站创建的(在Xcode中填上AppleID它会代办创建),Xcode运行时会打包进入APP内.
- 作为IOS开发者都知道一个规则:使用CSR申请证书时,我们还要申请一个东西: 就是描述文件
-
在xcode工程里面,我们要真机调试肯定需要通过xcode从苹果服务器下载描述文件,如下图:
描述文件除了包含appid等信息外,还包含了苹果服务器用私钥A加密的证书,证书里面含有mac传给服务器的公钥M .
生成描述文件的流程
- 生成的这个描述文件里面就是 可以安装的设备有哪些.. APP的ID是什么.. 权限是些什么!
- 在开发时,编译完一个 APP 后,用本地的私钥M对这个APP进行签名,同时把从苹果服务器得到的 Provisioning Profile 文件打包进APP里,文件名为embedded.mobileprovision,把 APP 安装到手机上.
- 我们可以利用
$security cms -D -i embedded.mobileprovision
命令查看Provisioning profile内容,这些Xcode
创建的Profile
文件都存放在~/Library/MobileDevice/Provisioning Profiles/
目录下
-
我们可以通过MachOView查看我们mach-o可执行文件
- 我们可以在终端用
security cms -D -i + [名称]
命令查看描述文件里面的信息,我们会发现,描述文件是一个plist文件
-
上述红框里面的就是可执行文件的
从上面分析可以看出描述文件是一个xml格式的plist文件,下面我们对关键一些属性做一些说明。
DeveloperCertificates: 允许使用的开发者证书,这是一个列表,一般包含生成这个Provisioning Profile文件时,当前开发者账号下所有有效的Development证书,以base64格式保存,使用base64解码之后就可以得到DER格式的开发者证书。通过计算每个证书的sha1值,可以看出,前文中新申请的证书,就在这个列表中
Entitlements: 允许使用的权限列表,实际在App中使用的权限必须是这个列表的子集,否则安装时会无法通过校验而失败。如果曾经开启过某个功能,Xcode自动更新了Provisioning Profile,后来又关闭它,Xcode并不会将其从Provisioning Profile中删去,如上图中的com.apple.developer.team-identifier。
ProvisionedDevices: 允许安装的设备列表,如果目标设备的UUID不在这个列表中,会安装失败。对于这一项,普通开发者证书和企业级开发者证书的待遇是不同的。普通开发者证书使用Provisioning Profile的方式安装App到设备,只是出于测试和调试的需要,因此Apple只允许最多注册100台用于测试的设备,否则开发者就可以以测试的名义任意任意分发自己的App了。而对于企业级开发者来说,本身就有任意安装的需求,因此在分发时,这一项会被ProvisionsAllDevices取代,代表授权任意设备。
这些信息中有任何变动的时候,比如开发者证书有新增或者失效,在Capabilities中启用了当前App从未使用过的新功能,或是将新的iPhone连接到Xcode用于测试,Xcode都会自动重新申请Provisioning Profile。
每次我们新建项目其实会生成一个描述文件,选择运行到手机上, 我们只需要编译一下,在APP包里面就可以看到.
- Provisioning Profile会被内置在App中,置于App根目录下的embedded.mobileprovision。安装App时如果签名校验通过,这个文件会自动被拷贝到iOS设备的/Library/MobileDevice/Provisioning\ Profiles/路径下。由于该文件已被Apple官方签名,系统可以无条件信任它,并用它来校验App的签名、权限,以及本机的UUID等是否满足来自官方的授权。通过这种方式,间接信任了使用开发者证书签名的App,让iOS设备可以运行非苹果官方签名的App。
- 假如你有一台越狱的设备,查看任意一个从AppStore上下载下来的App,里面都不会有embedded.mobileprovision这个文件,因为经过Apple重新签名以后,设备就不再需要它了。
其实我们开发过程中经常接触到代码签名,只是我们都是通过xcode帮我们自动完成了这些工作,所以一般对代码签名的原理不是很熟悉。
回想一下,当我们完成开发后,会使用 Xcode 的 Archive(存档) 的功能进行打包,当我们点击了 Archive 以后,Xcode 就会对我们的代码进行编译和链接,最终产生一个后缀为.app文件(严格意义上来说这是一个文件夹,是 Mac 上的包文件,终端里头是把这个文件当做文件夹对待的)。然后 Xcode 会把对应的mobileprovision文件拷贝到 APP 文件中(这个文件就是我们在前面配置 provision profile 后下载下来的文件),这一步的详情可以在 Archive 的 log 中的『Process product packaging』这一步中看到;再之后,Xcode 会使用codesign这个命令对 APP 文件进行签名。
如果我们有多个 Signing Identity,我们也可以在工程『Build Settings』选项中进行配置
-
一个没有被签名的 APP 文件的结构类似这样:
codesign 在对 APP 文件进行签名的时候,会把对应的签名直接添加到二进制文件的内部,而针对资源文件则是利用一个叫做 『CodeResources』的 plist 文件把对应的资源文件和数字签名进行记录。签名结束后的 APP 文件的内容如下:
- 完成签名后,我们可以使用 Xcode 打包生成对应的 ipa ,方便之后安装到设备上。
-
此外,我们可以通过Xcode来查看内容:
Provisioning profile
本身也是通过签名认证的,所以别想着你可以更改里面的东西来达到扩充权限\设备的目的.只有老老实实的去网站向Apple申请一份权限更多\设备更多的profile。
3.2 授权文件(Entitlements)
Entitlements
沙盒(Sandbox)技术是iOS安全体系中非常重要的一项技术,他的目的是通过各种技术手段限制App的行为,比如可读写的路径,允许访问的硬件,允许使用的服务等等,即使应用出现任意代码执行的漏洞,也无法影响到沙盒外的系统。
通常所说的Entitlements(授权文件),也就是指iOS沙盒的配置文件,这个文件中声明了app所需的权限,如果app中使用到了某项沙盒限制的功能,但没有声明对应的权限,可能运行到相关的代码时会直接Crash。
全新的iOS工程中是没有这个文件的,如果在Capabilities中开启了一些需要权限的功能之后,Xcode会自动(Xcode 8及之后的版本)生成Entilements文件,并将对应的权限声明添加到Entitlements文件中。
- 这个文件其实是xml格式的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>inter-app-audio</key>
<true/>
</dict>
</plist>
- 实际上,这个文件的内容并非是全部的授权内容,因为缺省状态下,App默认会包含以下与Team ID及App ID相关的权限声明:
<dict>
<key>keychain-access-groups</key>
<array>
<string>xxxxxxxxxx.*</string>
</array>
<key>get-task-allow</key>
<true/>
<key>application-identifier</key>
<string>xxxxxxxxxx.test.CodeSign</string>
<key>com.apple.developer.team-identifier</key>
<string>xxxxxxxxxx</string>
</dict>
- 其中get-task-allow代表是否允许被调试,它在开发阶段是必需的一项权限,而在进行Archive打包用于上架时会被去除。
- 进行代码签名时,会将这个Entitlements文件(如有)与上述缺省内容进行合并,得到最终的授权文件,并嵌入二进制代码中,作为被签名内容的一部分,由代码签名保证其不可篡改性。
4. 签名数据存放
- App 的签名数据保存分两部分:
- Mach-O 可执行文件会把签名直接写入文件里
- 其他资源文件则会保存在 _CodeSignature 目录下在APP包里。
-
Mach-O 可执行文件会把签名直接写入文件里
- 其他资源文件则会保存在 _CodeSignature 目录下在APP包里。
5. IOS 证书文件
5.1 证书文件相关概念
- 证书: 内容是公钥或者私钥,由认证机构对其签名组成的数据包!我们开发可以使用钥匙串访问看到.
- 证书分两种:开发者证书、发布者证书。前者开发时使用,后者发布使用.
- 模拟器调试无需代码签名;真机调试需开发者证书代码签名;发布时需发布证书签名
- 代码签名需要:证书+私钥,缺一不可
- 真机调试时要求在设备上安装描述文件(provision profile),该文件包含信息:调试者证书,授权调试设备清单,应用ID。一个应用对应一个描述文件.
- 开发者证书按用途可分为Development证书和Distribution证书:
(1) Development证书是用于开发及测试阶段使用的证书,它用于在设备安装上开发阶段的App后对App的完整性进行校验,一般证书名称为 iPhone Developer: xxxxxxx。如果是多人协作的开发者账号,任意成员都可以申请自己的Development证书。
(2) Distribution证书是用于提交AppStore的证书,一般命名为 iPhone Distribution: xxxxxxxxx,用于让AppStore校验提交上来的App的完整性,只有管理员以上身份的开发者账号才可以申请,因此可以控制提交权限的范围。同时,Distribution证书不能用于开
发及调试。
- 企业级开发者证书:
除了普通开发者证书(个人开发者账号和公司开发者账号使用的证书)外,还有一种特殊的企业级开发者证书,这种证书签名的App可以被直接安装在任意的iOS设备上,只要用户主动信任该证书即可。它的作用是方便企业给内部员工分发生产力工具,比如往往存在这样一些场景:企业内部无法访问互联网,自然也就无法通过AppStore安装应用,或是使用私有API,完成一些AppStore不允许的功能。前面所说的不需要苹果签名即可安装运行的机制同样适用于企业级开发者证书,并且是企业级开发者证书的基础。
- P12: 就是本地私钥,可以导入到其他电脑
- Entitlements: 权限文件,包含了APP一些权限的plist文件
- CertificateSigningRequest: CSR文件包含了本地公钥的数据文件
- Provisioning Profile: 描述文件,包含了证书/Entitlements等数据,并由苹果后台私钥签名的数据包.
- 团队开发中如何共用证书?
- 团队开发中,需要共享证书文件和私钥。若仅从provisioning portal下载证书文件而无私钥,xcode会提示出错:Unable to code design using identities in this team: no private keys available(无法在团队中进行代码签名:找不到有效的私钥)。
解决办法:
(1) 打开钥匙串程序,选择 ‘秘钥’ 种类。
(2) 右键点击(或按住control点击)与开发证书相配套的私钥(专用密钥),并点击 ‘导出’,保存为Personal Information Exchange (.p12) 文件格式.,将提示你创建一个密码,并需要管理员密码才可导出。
(3) 拷贝该p12文件到其他机子上,会提示你输入上一步输入的密码。
5.1.1 证书相关资源
钥匙串程序(常用工具->钥匙串),用于创建证书请求、安装证书、导出私钥等
IOS开发中心:https://developer.apple.com/devcenter/ios/index.action
IOS描述门户(IOS provisioning Portal),在此配置证书、描述文件、推送服务等:
https://developer.apple.com/ios/manage/overview/index.action,
- IOS程序发布:http://itunesconnect.apple.com/
5.2 开发证书生成流程
5.2.1 生成证书
-
第 1 步:对应的是 keychain 里的 “从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的 CertificateSigningRequest 里面就包含公钥,私钥保存在本地电脑里.
这个操作会产生一个名为CertificateSigningRequest.certSigningRequest 的签名请求文件,在生成这个文件之前其实Keychain已经自动生成了一对公、私钥
可以在Keychain中选中这个条目,右键选择导出,将密钥文件导出为p12文件,使用openssl查看其内容
$ openssl pkcs12 -in JustForTesting.p12 -out private_key.pem # 导出p12文件中的密钥
Enter Import Password: # 输入p12文件的密码
MAC verified OK
Enter PEM pass phrase: # 设定导出的密钥文件的密码
Verifying - Enter PEM pass phrase: # 确认密码
$ openssl rsa -in private_key.pem -noout -text # 查看密钥文件的内容
Enter pass phrase for private_key.pem: # 输入密钥文件的密码
Private-Key: (2048 bit)
modulus:
00:c2:98:f5:02:eb:dc:a6:fd:4b:12:4c:70:17:a6:
xx:xx:xx:xx:xx:xx:xx:...
publicExponent: 65537 (0x10001)
privateExponent:
00:a1:67:68:e1:51:6c:a4:fd:36:45:29:2d:58:10:
xx:xx:xx:xx:xx:xx:xx:...
prime1:
00:f3:91:5d:5b:dc:c1:de:d2:ab:7a:5f:b2:27:41:
xx:xx:xx:xx:xx:xx:xx:...
prime2:
00:cc:87:b5:c9:7e:81:39:94:13:c1:ff:3f:d7:7b:
xx:xx:xx:xx:xx:xx:xx:...
exponent1:
00:a5:a0:22:c0:f5:d3:eb:86:8c:4e:b1:c6:3e:85:
xx:xx:xx:xx:xx:xx:xx:...
exponent2:
00:8b:e1:00:85:a6:7c:10:79:e2:2d:5a:39:3a:51:
xx:xx:xx:xx:xx:xx:xx:...
coefficient:
7e:30:60:84:fc:47:6b:90:fe:e7:32:1a:2f:b0:c4:
xx:xx:xx:xx:xx:xx:xx:...
prime1/prime2
就是生成密钥所使用的两个超大的素数p, q
modulus
是这两个超大素数的乘积 n = p * q
publicExponent
是公钥因子,也就是前文中的e, 这里固定为 0x10001 (65535)
privateExponent
是私钥因子,即前文中的d
CSR
文件的内容其实就是个人信息、公钥(Modulus + PublicExponent),以及自签名(使用自己的私钥进行签名), 可通过openssl
命令查看其内容:
$ openssl req -in ~/Desktop/CertificateSigningRequest.certSigningRequest -text -noout
Certificate Request:
Data:
Version: 0 (0x0)
Subject: emailAddress=me@xelz.info, CN=JustForTesting, C=CN
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c2:98:f5:02:eb:dc:a6:fd:4b:12:4c:70:17:a6:
xx:xx:xx:xx:xx:xx:xx:...
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption
b7:11:aa:48:2f:b3:10:e9:71:c7:93:c3:ec:44:8d:0f:a0:5a:
xx:xx:xx:xx:xx:xx:xx:...
- 第 2 步: 向苹果申请对应把 CSR 传到苹果后台生成证书.
在苹果开发者网站,将CSR提交给Apple进行签名,Apple会返回一个签好名的证书文件,后缀名为cer。
先查看一下他的sha1值
$ shasum ios_development.cer
11447116f2c5521b057b9b67290f0fdadeadfa0a ios_development.cer
双击即可将其导入到Keychain中,Keychain会自动把它之前创建CSR时自动生成的密钥归为一组。无论是在证书列表中查看还是在密钥列表中查看,都能看到与之匹配的另一半。
可以从证书中得到几个关键信息:
- 证书的所有者,这部分信息并非由我们自行指定,而是签发者Apple根据我们的账号信息自动生成
- 证书的签发者,即前文所述的CA
- 证书的公钥信息,与之前生成的密钥文件及CSR完全一致
现在应该可以理解证书和密钥的关系了,密钥中保存了私钥和公钥,私钥用于签名,而证书里面有且只有公钥,并且是被第三方CA “认证” 过,用于解密和校验。
图中可以看到这个证书的签发者是Apple Worldwide Developer Relations Certification Authority,在Keychain中搜索这个名字, 可以看到它的证书详情。我们会发现,它的类型是中级证书颁发机构(中级CA),它也包含签名,并且是由另外一个叫做Apple Root CA的根证书颁发机构(根CA)进行签发的,这样就形成了一条证书链。而继续查看Apple Root CA的证书,会发现它是自签名的,因为它会被内置在设备中,设备无条件信任它,也就不需要其他的机构为其背书了。
这样的证书链机制可以简化根证书颁发机构的工作,同时提升证书管理的安全性。将颁发底层证书的工作分散给多个中级证书颁发机构进行处理,根证书颁发机构只需要对下一级机构的证书进行管理和签发,降低根证书颁发机构私钥的使用频率,也就降低了私钥泄露的风险。中级证书颁发机构各司其职,即使出现私钥泄露这样的重大安全事故,也不至于波及整个证书网络。
第 3 步:证书下载到本地.这时本地有两个证书.一个是第 1 步生成的私钥,一个是这里下载回来的证书,keychain 会把这两个证书关联起来,因为他们公私钥是对应的,在XCode选择下载回来的证书时,实际上会找到 keychain 里对应的私钥去签名.这里私钥只有生成它的这台 Mac 有,如果别的 Mac 也要编译签名这个 App 怎么办?答案是把私钥导出给其他 Mac 用,在 keychain 里导出私钥,就会存成 .p12 文件,其他 Mac 打开后就导入了这个私钥.
第 4 步:都是在苹果网站上操作,配置 AppID / 权限 / 设备等,最后下载 Provisioning Profile 文件。
- 第 5 步: XCode 会通过第 3 步下载回来的证书(存着公钥),在本地找到对应的私钥(第一步生成的),用本地私钥去签名 App,并把 Provisioning Profile 文件命名为 embedded.mobileprovision 一起打包进去。所以任何本地调试的APP,都会有一个embedded.mobileprovision(描述文件)从App Store下载的没有.
参考:https://www.jianshu.com/p/3c9e2055ae5b
https://segmentfault.com/p/1210000018014804/read