代码签名探析

"用户会感激代码签名带来的好处" – Apple Developer Library: 酷炫的动画效果,便捷地进行Core
Data
 将数据安全的存储在本地。但是总有一天,你会碰上代码签名 (code signing) 和配置文件 (provisioning),大多数情况下,这会是你在心里问候某些人祖宗的开始。

如果你已经在 iOS 上开发过应用,那么你多半已经与代码签名或设备配置文件打过交道了。即使是 OS X 开发者,如果你想发布自己的应用到 Mac App Store 上去或者想参与苹果的开发者项目,那么也不得不开始为自己的代码进行签名。

大多数时候代码签名看上去像是一个难以理解的神秘黑盒。在这篇文章里我会尽可能揭示盒子内部的运作机理。

通常来说,我们无法直接看到代码签名的运作过程,它们隐藏在 iOS 系统内部和 SDK 之中。但我们可以通过观察设置代码签名所需工具的运作方式,来找出一些线索。除此之外,我们还可以参考 OS X 上的代码签名运作方式,毕竟 iOS 和 OS X 系出同源,我们可以从他们的对比之中得到很多有用的信息。

OS X 上代码签名技术和相应的 API 是在 Mac OS X Leopard 10.5 上首次出现的,这刚好是第一台 iPhone 发布的时候。这并非巧合,因为在 iOS 上,代码签名起到的作用更加重要。iPhone 是在众多游戏主机之后第一个大规模出售并且从头就开始使用代码签名的计算平台。只有在越狱之后,iOS 才能运行没有签名的代码。越狱使应用可以绕过代码签名和沙盒安全机制的全部限制,这会是一个非常危险的行为。

证书和密匙

作为一个 iOS 开发者,在你开发使用的机器上应该已经有一个证书,一个公钥,以及一个私钥。这些是代码签名机制的核心。像 SSL 一样,代码签名也依赖于采用 公开密钥加密

在 OS X 上,X.509 的基本组成部分(译者注:例如证书等)都是由一个叫钥匙串访问的工具来进行管理。打开你开发机器上的钥匙串访问应用,选择类别选项下的“我的证书(My Certificates)”,你可以看到所有你持有的私钥相对应的证书。要用一个证书设置代码签名,你必须拥有私钥,所以所有你拥有私钥的证书都会被列在这里。如果你拥有一个证书的私钥,你可以展开证书并将它的私钥显示出来:

如果你要导出证书,例如为了备份(强烈建议进行),一定要记得展开证书那一条显示出私钥并将两行都选中。

还有一种可以用来快速地显示出你的系统中能用来对代码进行签名的认证的方法,那就是利用用途广泛的命令行工具security

$ security find-identity -v -p codesigning
  1) 01C8E9712E9632E6D84EC533827B4478938A3B15 "iPhone Developer: Thomas Kollbach (7TPNXN7G6K)"

概括的讲,一个证书是一个公钥加上许多附加信息,这些附加信息都是被某个认证机构(Certificate Authority 简称 CA)进行签名认证过的,认证这个证书中的信息是准确无误的。对于 iOS 开发来说这个认证机构就是苹果的认证部门 Apple Worldwide Developer Relations CA。认证的签名有固定的有效期,这就意味着当前系统时间需要被正确设置,因为证书是基于当前时间进行核对。这也是为什么将系统时间设定到过去会对 iOS 造成多方面破坏的原因之一。

对于 iOS 开发来说,一般会有两个证书:一个带有前缀 iPhone Developer,另一个带有前缀 iPhone
Distribution
。前者用于使应用可以在你的测试设备上运行,后者是在提交应用到 APP store 时用到。一个证书的用途取决于它所包含的内部信息,在钥匙串访问中双击打开一个证书文件,你可以看到许多详细条目,拖动到最下面有一条标记着 Apple
Developer Certificate (Submission)
, 或者 Apple Developer Certificate (Development),具体你会看到哪一种,取决于你所打开的证书是哪一种类型,iOS
系统会利用这个信息来判断你的应用是运行在开发模式下还是发布模式,并据此判断以切换应用运行规则。

为了让拥有公钥的证书起作用,我们需要有私钥。私钥是你在为组成应用的二进制文件进行签名时派上用场的。没有私钥,你就无法用证书和公钥对任何东西设置签名。

签名过程本身是由命令行工具 codesign 来完成的。如果你在 Xcode 中编译一个应用,这个应用构建完成之后会自动调用 codesign 命令进行签名,codesign 也正是给你提供了许多格式友好并且有用错误信息的那一个工具。你可以在
Xcode 的 project settings 中设置代码签名信息。

需要注意的是 Xcode 只允许你在有限的选项中进行选择,这些选项都是你既拥有公钥也拥有私钥的证书。所以如果在选项中没有出现你想要的那一个,那么你需要检查的第一件事情就是你是否拥有这个证书的私钥。在这里你需要区分开用于开发测试还是用于发布,如果你想要在机器上测试你的应用,你需要用用于开发测试的那一对密匙来进行签名,如果你是要发布应用,无论是给测试人员还是发布到 APP Store,你需要用用于发布的那一对密匙来进行签名。

一直以来,以上这些就是代码签名需要设置的全部,设置了这些就几乎完成了。

但是在 Xcode 6 的 project settings 中出现了设置配置文件的选项。如果你选择了某一个配置文件,你必须选择这个配置文件的证书中所包含的公钥所对应的那个密匙对,或者你可以选择让 Xcode 自动完成正确的设置。关于这方面我们稍后再详细说明,首先还是回到代码签名。

一个已签名应用的组成

一个已签名的可执行文件的签名包含在 Adding
Capabilities
 中提到的所有功能都是需要经过授权的。

授权信息会被包含在应用的签名信息中。如果你在这方面遇到了问题,可以尝试查看签名信息中具体包含了什么授权信息:$ codesign -d --entitlements - Example.app 会列出一个和前面的很像的
XML 格式的属性列表。你可以将这个文件的内容添加进一个脚本,每次构建应用时用脚本检查是否包含了推送服务的授权信息,以此确保推送服务工作正常。在这里推送服务只是一个例子,你使用的服务越多,这样的时候都添加推送通知的授权,以保证可以注册推送通知。在新版本的 Xcode 6 之后,授权信息列表会以 Example.app.xcent 这样的名字的文件形式包含在应用包中。在我看来,这么做是为了在出现配置错误时提供更加有用的错误信息。

配置文件

在整个代码签名和沙盒机制中有一个组成部分将签名,授权和沙盒联系了起来,那就是配置文件 (provisioning profiles)。

每一个 iOS 开发者可能都花费过相当的时间研究如何设置配置文件,这个环节也正是会经常出问题的地方。

一个配置文件中存放了系统用于判断你的应用是否允许运行的信息,这就意味着如果你的配置文件有问题,修复起来会相当烦人。

一个配置文件是一组信息的集合,这组信息决定了某一个应用是否能够在某一个特定的设备上运行。配置文件可以用于让应用在你的开发设备上可以被运行和调试,也可以用于内部测试 (ad-hoc) 或者企业级应用的发布。Xcode 会将你在 project setting 中选择的配置文件打包进应用。前面提到了,选择配置文件是 Xcode 6 才提供的功能,在 Xcode 5 或更早版本中,配置文件是 Xcode 根据你选择的签名证书来选择的。事实上同一个证书可以拥有多个不同的配置文件,因此让 Xcode 自行选择可能存在一些不确定性,最好的方式是你自主去选择,在
Xcode 6 中终于提供了这个功能。

我们下面来仔细研究一下配置文件。如果你要在自己的机器上找到配置文件,在这个目录下~/Library/MobileDevice/Provisioning Profiles。Xcode
将从开发者中心下载的全部配置文件都放在了这里。

不要惊讶,配置文件并不是一个 plist 文件,它是一个根据密码讯息语法 (Cryptographic Message Syntax) 加密的文件(下文中会简称 CMS,但不要用这个简写 Google,这不是一个很好的关键字)。如果你处理过 S/MIME 邮件或者证书你会对这种加密比较熟悉,详细信息可以查看互联网工程任务组 (IETF) 制定的 RFC
1848
) 格式的。要查看一个证书的详细内容,将编码过的文件内容复制粘贴到一个文件中去,像下面这样:

-----BEGIN CERTIFICATE-----
MIIFnjCCBIagAwIBAgIIE/IgVItTuH4wDQYJKoZIhvcNAQEFBQAwgZYxCzA…
-----END CERTIFICATE-----`

然后让 OpenSSL 来处理 openssl x509 -text -in file.pem

回到配置文件中继续往下看,你可能会注意到在 Entitlements 一项中包含了你的应用的所有授权信息,键值就和之前在授权那节看到的一模一样。

这些授权信息是你在开发者中心下载配置文件时在 App ID 中设置的,理想的情况下,这个文件应该和 Xcode 为应用设置签名时使用的那一个同步,但这种同步并不能得到保证。这个文件的不一致是比较难发现的问题之一。

举例来说,如果你在 Xcode 中添加了 iCloud 键值对存储授权 (com.apple.developer.ubiquity-kvstore-identifier),但是没有更新,重新设置并下载新的配置文件,旧的配置文件规定你的应用并没有这一项授权。那么如果你的应用使用了这个功能,iOS
就会拒绝你的应用运行。这也是当你在开发者中心编辑了应用的授权,对应的配置文件会被标记为无效的原因。

如果你打开的是一个用于开发测试的证书,你会看到一项 ProvisionedDevices,在这一项里包含了所有可以用于测试的设备列表。因为配置文件需要被苹果签名,所以每次你添加了新的设备进去就要重新下载新的配置文件。

小结

代码签名和配置文件这一套大概是一个 iOS 开发者必须处理的仅次于编码的最复杂的问题之一。与在 Mac 或 PC 上直接的编译运行你的代码不同,处理这些问题会是非常不同的经历。

虽然了解每一个部分是怎么运作的很有帮助,但是要控制好所有这些设置和工具其实是一件很消耗时间的事情,特别是在一个开发团队中,到处发送证书和配置文件显然很不方便。虽然苹果在最近几次发布的 Xcode 中都尝试改善,但是我不是很确定每一项改动都起到了好的作用。处理代码签名是每个开发者必过的大坑。

虽然处理代码签名对于开发者来说非常繁琐,但不可否认正是它使得 iOS 对于用户来说是一个非常安全的操作系统。如果你注意安全相关的新闻,每一次出现号称能在 iOS 上运行的木马或者恶意软件,例如不怎么出名的 <a rel="nofollow" href="https://en.wikipedia.org/wiki/FinFisher" "="" style="box-sizing: border-box; color: rgb(45, 133, 202); text-decoration: none; background-color:
transparent;">FinFisher,仔细看看详细说明,都会写明 “需要越狱”。说实话我还没见过面向 iOS 的不需要越狱的病毒或者木马。

所以为代码签名和配置文件进行的这些麻烦设置并不是徒劳无功。

时间: 2024-09-17 04:40:23

代码签名探析的相关文章

浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入_javascript技巧

在<浏览器环境下JavaScript脚本加载与执行探析之defer与async特性>中,我们研究了延迟脚本(defer)和异步脚本(async)的执行时机.浏览器支持情况.浏览器bug以及其他的细节问题.而除了defer和async特性,动态脚本和Ajax脚本注入也是两种常用的创建无阻塞脚本的方法.总的来看,这两种方法都能达到脚本加载不影响页面解析和渲染的作用,但是在不同的浏览器中,这两种技术所创建的脚本的执行时机还是有一定差异,今天我们再来探讨一下通过动态脚本技术和Ajax注入的脚本在这些方

浏览器环境下JavaScript脚本加载与执行探析之defer与async特性_javascript技巧

defer和async特性相信是很多JavaScript开发者"熟悉而又不熟悉"的两个特性,从字面上来看,二者的功能很好理解,分别是"延迟脚本"和"异步脚本"的作用.然而,以defer为例,一些细节问题可能开发者却并不一定熟悉,比如:有了defer特性的脚本会延迟到什么时候执行:内部脚本和外部脚本是不是都能够支持defer:defer后的脚本除了会延迟执行之外,还有哪些特殊的地方等等.本文结合已有的一些文章以及MDN文档中对两个特性的阐述,对de

探析Windows下将gvim8配置为Python IDE的方法_win服务器

Windows下将gvim8配置为Python IDE大概分为以下四步,每步介绍的都非常详细,一起看看吧. 1.准备工作 将下面的安装包或者文件下载好 1) Python 2.7  http://www.python.org/ftp/python/2.7.2/python-2.7.2.msi 2) gvim8.0   http://www.vim.org/download.php 3) Exuberant Ctags http://ctags.sourceforge.net/ 4) Taglis

SAP MM 采购订单中&quot;Delivery Completed&quot; Indicator(”交货已完成”标记)之含义探析

SAP MM 采购订单中"Delivery Completed" Indicator("交货已完成"标记)之含义探析    "Delivery Completed" Indicator指定了该采购订单的项目行是否考虑关闭了,如果勾选了这个标记就意味着该item将不再收货了. 举例来说,假设采购订单的项目行有200件,已经对该采购订单项目行收货了180件,此时手工对该行的"Delivery Completed" Indicato

探析置换滤镜(“伸展以适合”置换规律的研究)之一

滤镜 重温置换原理: ps的帮助中有如下几点关于置换图的明说.注:[]中是作者加的.老外翻译的东西就是不好理解. 1."置换"滤镜使用置换图中的颜色值[其实就是按照指定的通道的灰度值]改变选区[像素的移动] - 0 是最大的负向改变值,255 是最大的正向改变值,灰度值 128 不产生置换. 2.如果置换图[只]有一个通道,则图像沿着由水平比例和垂直比例所定义的对角线改变[像素的移动]. 如果置换图有多个通道,则第一个通道控制水平[方向像素的]置换,第二个通道控制垂直[方向像素的]置换

为代码签名,供后人瞻仰或唾弃,你敢吗?

如何衡量代码质量的好坏,是否有一个标准,是否可以量化? 我认为答案是否定的.如果今年中央给各省下个死命令,要求年度GDP增长达到10%,我相信每个省一定都能完成任务.这几年,GDP增长都在8%以上,CPI增长不到4%,民族复兴完成了62%,这些都量化的,你是否满意? 回到开发的问题上来,有一些数字,比如bug的个数,reopen的次数能说明一定的问题,但不是全部.它只能描述系统的外在质量的一部分,这个外在质量可以由QA来保证.但是内部质量只能靠开发自己来保证,牺牲内部质量来保证功能和外在质量是不

网络渠道运营探析与对比

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 据不完全的数据报告获悉,按照国内绝大部分的"贴牌"制造业现状,大多仍处于传统商业模式的格局之内,这一反映基本上决定了行业扩展方式的走向.由口耳相传转为电话营销以及客户拜访的套路演变,显然易见的是传统销售方式正处于目前市场当中的绝对劣势. 针对细分行业网络市场与传统线下的对比之下,大多都是属于渠道运营与资源成本的优劣所在.由

全球通信监管体制改革走势探析

工信部电信研究院政策经济所 马源 为适应技术进步,推动通信市场竞争,自上世纪80年代以来全球各国不断探索如何推进通信监管体制改革,并逐步形成了各具特色的通信监管体制,挖掘这些监管体制的共性规律及其决定因素,对于探析我国监管体制改革走向具有重要意义. 一.全球通信体制改革历程概要 上世纪80年代起,全球多数国家的通信体制都经历了一场深刻变革,其关键词是"民营化",改革重点是企业产权多元化,实施政企分开.以英国为例,为降低财政负担,相继推动国有电信企业的政企分开.股份化.民营化改造.引入新

固件源代码残留:D-Link 不慎泄露了代码签名密钥

作为一家网络设备制造商,D-Link 因为设备固件遵循 GPL 开源许可,而在科技圈拥有不少忠实用户.不过一位名叫"bartvbl"的挪威开发者,却在浏览近期购买的 DCS-5020L 监控摄像头的固件时,找到了4个似乎是代码签名密钥的内容.随后,他用这些密钥进行了试验,通过自己创建的一款Windows应用程序,竟然真的验证了其中一个密钥. 目前看来,这些残留的密钥应该就是来自D-Link公司,不过另外三个密钥并未有效.据荷兰科技门户网站Tweakers报道,这项研究得到了安全公司Fo