iOS APP签名机制

2,693

iOS APP签名机制

证书介绍

非对称加密

通常我们证书里面的签名都是基于非对称加密算法实现的。 非对称加密有两份密钥,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密。

主要的算法: RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。

简单说一下常用的非对称加密算法 RSA 的数学原理,理解数学原理,我们就可以理解非对称加密是怎么实现的,为什么会是安全的:

  1. 选两个质数 p 和 q,相乘得出一个大整数n,例如 p = 61,q = 53,n = pq = 3233
  2. 选 1-n 间的随便一个质数e,例如 e = 17
  3. 经过一系列数学公式,算出一个数字 d,满足: a.通过 n 和 e 这两个数据一组数据进行数学运算后,可以通过 n 和 d 去反解运算,反过来也可以。 b.如果只知道 n 和 e,要推导出 d,需要知道 p 和 q,也就是要需要把 n 因数分解。 上述的 (n,e) 这两个数据在一起就是公钥,(n,d) 这两个数据就是私钥,满足用私钥加密,公钥解密,或反过来公钥加密,私钥解密,也满足在只暴露公钥 (只知道 n 和 e)的情况下,要推导出私钥 (n,d),需要把大整数 n 因数分解。目前因数分解只能靠暴力穷举,而 n 数字越大,越难以用穷举计算出因数 p 和 q,也就越安全,当 n 大到二进制 1024 位或 2048 位时,以目前技术要破解几乎不可能,所以非常安全。

RSA算法原理参考: www.ruanyifeng.com/blog/2013/0…

非对称加密算法的特性:

  • 对于一个私钥,有且只有一个与之对应的公钥。生成者负责生成私钥和公钥,并保存私钥,公开公钥
  • 公钥是公开的,但不可能通过公钥反推出私钥,或者说极难反推,只能穷举,所以只要密钥足够长度,要通过穷举而得到私钥,几乎是不可能的
  • 通过私钥加密的密文只能通过公钥解密,公钥加密的密文只有通过私钥解密

摘要算法

摘要算法是指,可以将任意长度的文本,通过一个算法,得到一个固定长度的文本。 摘要算法具有以下重要特性:

  • 只要源文本不同,计算得到的结果,必然不同
  • 无法从结果反推出源 典型的摘要算法,比如MD5和SHA。

数字签名

数字签名使用了非对称加密和摘要算法,一般用于数据接收方(一般指客户端)验证数据发送发方(一般只指代服务器)发送的数据是否合法(是否经过第三方篡改)。

举个例子,A有一段文本要发给B,A为了防止文本在中途被恶意篡改。A找来C,C将文本内容通过摘要算法,得到摘要,再用C自己私钥对摘要加密得到密文,A将原文、密文一并发给B。接收方B收到数据以后用C的公钥(提前固化在系统中了)对密文进行解密,将文本用同样的算法得到摘要,两个摘要进行对比,如果相等那么一切正常,否则视为接收数据视为无效。 avatar

数字签名可以快速验证文本的完整性和合法性,已广泛应用于各个领域。

数字证书

数字证书就是通过数字签名实现的数字化的证书。苹果公司可以签发跟苹果公司有关的证书。

这里签发机构都称为CA(Certificate Authority)。

苹果开发者账号与证书对应关系: 账号类型价格可以发布AppStore?支持安装设备数量申请条件证书类型个人账号99可以100无限制Development,AdHoc,AppStore公司账号99可以100无限制Development, Ad Hoc, App Store公司账号99可以100DUNS编码Development, Ad Hoc, App Store企业账号299不可以无限制DUNS编码Development,AdHoc,InHouse教育账号299不可以无限制DUNS编码Development, Ad Hoc, In House教育账号0可以100教育机构Development, Ad Hoc, App Store 各个证书使用说明:

  1. Development:开发 App 时可以直接把开发中的应用安装进手机进行调试。
  2. In House: 企业内部分发,可以直接安装企业证书签名后的 APP。
  3. Ad Hoc:相当于企业分发的限制版,限制安装设备数量,较少用。
  4. AppStore:上传应用商店下载安装 证书申请过程 我们需要通过钥匙串生成一个CertificateSigningRequest.certSigningRequest文件来提交到苹果MC(Member Center)中,从而获取苹果证书。

certSigningRequest文件生成过程如下图: avatar

使用openssl解析文件中的内容如下图: avatar

certSigningRequest文件中包含信息:

  1. 申请者信息,此信息是用申请者的私钥加密的
  2. 申请者公钥,此信息是申请者使用的私钥对应的公钥
  3. 摘要算法(sha256)和公钥加密算法(rsa)

通过一系列在苹果开发者后台的操作后,得到苹果证书。 开发者证书例子如图: avatar

APP签名原理

苹果的需求

  1. APP安装保证是开发者提交的代码而不会被中途恶意修改。
  2. 苹果想要对安装的App有控制权,包括
  3. 经过苹果允许才可以这样安装。
  4. 不能被滥用导致非开发app也能被安装。
  5. 安装包不需要上传到App Store, 也可以直接安装到手机上.
  6. 开发APP时直接真机调试安装
  7. 企业内部分发的渠道,企业证书签名的APP也是需要顺利安装的

签名原理

这里以开发包为例,讲解下原理。 苹果这里使用的方案是双层签名,流程图:

avatar

流程说明:

  1. 在你的 Mac 开发机器生成一对公私钥,这里称为公钥L,私钥L。L:Local
  2. 苹果自己有固定的一对公私钥,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥A,私钥A。A:Apple
  3. 把公钥 L 传到苹果后台,用苹果后台里的私钥 A 去签名公钥 L。得到一份数据包含了公钥 L 以及其签名,把这份数据称为证书。
  4. 在苹果后台申请 AppID,配置好设备 ID 列表和 APP 可使用的权限,再加上第③步的证书,组成的数据用私钥 A 签名,把数据和签名一起组成一个 Provisioning Profile 文件,下载到本地 Mac 开发机。
  5. 在开发时,编译完一个 APP 后,用本地的私钥 L 对这个 APP 进行签名,同时把第④步得到的 Provisioning Profile 文件打包进 APP 里,文件名为 embedded.mobileprovision,把 APP 安装到手机上。
  6. 在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证 embedded.mobileprovision 的数字签名是否正确,里面的证书签名也会再验一遍。
  7. 确保了 embedded.mobileprovision 里的数据都是苹果授权以后,就可以取出里面的数据,做各种验证,包括用公钥 L 验证APP签名,验证设备 ID 是否在 ID 列表上,AppID 是否对应得上,权限开关是否跟 APP 里的 Entitlements 对应等。

上面的步骤对应到我们平常具体的操作和概念是这样的:

  1. 第 1 步对应的是 keychain 里的 “从证书颁发机构请求证书”,这里就本地生成了一对公私钥,保存的 CertificateSigningRequest 就是公钥,私钥保存在本地电脑里。
  2. 第 2 步苹果处理,不用管。
  3. 第 3 步对应把 CertificateSigningRequest 传到苹果后台生成证书,并下载到本地。这时本地有两个证书,一个是第 1 步生成的,一个是苹果后台下载回来的,keychain 会把这两个证书关联起来,因为他们公私钥是对应的,在XCode选择下载回来的证书时,实际上会找到 keychain 里对应的私钥去签名。这里私钥只有生成它的这台 Mac 有,如果别的 Mac 也要编译签名这个 App 怎么办?答案是把私钥导出给其他 Mac 用,在 keychain 里导出私钥,就会存成 .p12 文件,其他 Mac 打开后就导入了这个私钥。
  4. 第 4 步都是在苹果网站上操作,配置 AppID / 权限 / 设备等,最后下载 Provisioning Profile 文件。
  5. 第 5 步 XCode 会通过第 3 步下载回来的证书(存着公钥),在本地找到对应的私钥(第一步生成的),用本地私钥去签名 App,并把 Provisioning Profile 文件命名为 embedded.mobileprovision 一起打包进去。这里对 App 的签名数据保存分两部分,Mach-O 可执行文件会把签名直接写入这个文件里,其他资源文件则会保存在 _CodeSignature 目录下。 第 6 – 7 步的打包和验证都是 Xcode 和 iOS 系统自动做的事。

再总结一下这些概念:

  1. 证书:内容是公钥或私钥,由其他机构对其签名组成的数据包。

  2. Entitlements:包含了 App 权限开关列表。

  3. CertificateSigningRequest:本地公钥。

  4. p12:本地私钥,可以导入到其他电脑。

  5. Provisioning Profile:包含了 证书 / Entitlements 等数据,并由苹果后台私钥签名的数据包。

  6. mobileprovision:从苹果后台下载下来的Provisioning Profile描述文件

其他发布方式

前面以开发包为例子说了签名和验证的流程,另外两种方式 In-House 企业签名和 AD-Hoc 流程也是差不多的,只是企业签名不限制安装的设备数,另外需要用户在 iOS 系统设置上手动点击信任这个企业才能通过验证。

而 AppStore 的签名验证方式有些不一样,苹果在后台直接用私钥签名 App 就可以了,如果去下载一个 AppStore 的安装包,会发现它里面是没有 embedded.mobileprovision 文件的,也就是它安装和启动的流程是不依赖这个文件,验证流程也就跟上述几种类型不一样。

那为什么发布 AppStore 的包还是要跟开发版一样搞各种证书和 Provisioning Profile? 猜测因为苹果想做统一管理,Provisioning Profile 里包含一些权限控制,AppID 的检验等,苹果不想在上传 AppStore 包时重新用另一种协议做一遍这些验证,就不如统一把这部分放在 Provisioning Profile 里,上传 AppStore 时只要用同样的流程验证这个 Provisioning Profile 是否合法就可以了。 所以 App 上传到 AppStore 后,就跟你的 证书 / Provisioning Profile 都没有关系了,无论他们是否过期或被废除,都不会影响 AppStore 上的安装包。

重签技术

使用场景:

  1. 证书过期或失效,不需要重新打包,直接使用新证书重签可以使用。
  2. App Store包使用企业证书重签,可以用于企业分发 企业证书签名因为限制少,在国内被广泛用于测试和盗版,fir.im / 蒲公英等测试平台都是通过企业证书分发,国内一些市场像 PP 助手,爱思助手,一部分安装手段也是通过企业证书重签名。通过企业证书签名安装的 App,启动时都会验证证书的有效期,并且不定期请求苹果服务器看证书是否被吊销,若已过期或被吊销,就会无法启动 App。对于这种助手的盗版安装手段,苹果想打击只能一个个吊销企业证书,并没有太好的办法。

准备材料:

  1. 需要重签的ipa包
  2. 证书
  3. 描述文件
  4. 非本机证书提供p12文件

IPA文件结构:

_CodeSignature:文件的hash列表。里面有一个文件 CodeResources 很重要,它是一个plist文件,包含所有文件及其对应的hash值。这个属性列表只有一项 files,这是一个字典,键是文件名,值通常是 Base64 格式的散列值。它的作用是用来判断一个应用程序是否完好无损,能够防止中途修改或损坏资源文件。

avatar

Info.plist :存储应用的相关配置、Bundle identifier 和 Executable file 可执行文件名等信息 可执行文件:Info.plist 中 Executable file 记录的名字所对应的文件 Frameworks:当前应用使用的三方 Framework 或 Swift 动态库 PlugIns:当前应用使用的 Extension Watch:手表一起使用的应用 资源文件:包括图片资源文件、配置文件、视频/音频,以及一些与本地化相关的文件。

重签步骤:

重签需要使用Xcode的命令 security 和 codesign 重签ipa文件。

  1. 添加p12证书
# Import items into a keychain.
$ security import inputfile [-k keychain] [-t type] [-f format] [-w] [-P passphrase] [options…]
$ security import /Users/htc/Desktop/distest.p12 -P '123456'
  1. 解压ipa包
$ unzip yourApp.ipa
# 查找 .app目录,删除系统临时文件
$ rm -rf ./Payload/yourAppName.app/.DS_Store
  1. 修改内容 修改Payload/yourName.app中的icon图标、Info.plist文件的信息等,如有需要也可以更改比如版本号,应用名称等。
  2. 删除之前的签名 _CodeSignature
$ rm -rf ./Payload/yourAppName.app/_CodeSignature
  1. 用包里的描述文件生成entitlements.plist文件
$ security cms -D -i "xxx.mobileprovision"
可以用管道命令 > 保存成 plist 文件:
$ security cms -D -i embedded.mobileprovision > entitlement_full.plist
如果只保留 Entitlements 属性内容,则可以使用PlistBuddy命令,我们重签只需要 Entitlements 属性:
$ /usr/libexec/PlistBuddy -x -c \'Print:Entitlements\' entitlement_full.plist > entitlement.plist
  1. 替换描述文件 把新的描述文件复制替换到解压后的目录中,这个需要看自己需要,旧包的描述权限与新证书的权限,是需要那些,上一步骤中 Entitlements 就是在重签时还可以在指定。
$ cp ./embedded.mobileprovision ./Payload/yourAppName.app/embedded.mobileprovision
如果需要查看系统中已经保存的描述文件:~/Library/MobileDevice/Provisioning\ Profiles/
  1. 给 MachO 文件添加执行权限
chmod +x ./Payload/yourAppName.app/yourAppName
  1. 获取证书内容
$ security find-identity -p codesigning -v

输出:本机所有可用证书列表 9. 重新签名 先重签名framework和dylib(不重签的话,就删除无法签名的插件文件: Framework、PlugIns 文件夹、Watch 文件夹)

$ /usr/bin/codesign --force --sign "iPhone Distribution:xxxxx" /Payload/XX.app/Frameworks/xxx.framework
再签名.app:
$ /usr/bin/codesign -f -s "iPhone Distribution:xxxxx"  --entitlements entitlements.plist ./Desktop/Payload/yourAppName.app
重签成功后提示:
./Payload/yourAppName.app: replacing existing signature.
  1. 压缩Payload 生成最终 .ipa 文件
$ zip -ry ABC.ipa Payload

其他工具使用:

fastlane: docs.fastlane.tools/actions/#co…

图形化工具:

dantheman827.github.io/ios-app-sig… github.com/maciekish/i…

参考资料

developer.apple.com/library/arc… developer.apple.com/library/arc… segmentfault.com/a/119000000… blog.cnbang.net/tech/3386/ ihtcboy.com/2019/07/30/…