(九) 代码签名

1. 代码签名

代码签名并不是每一个iOS开发人员的首要任务,但是对代码签名工作原理的深入了解对于解决问题以及在开发团队中树立自己的形象非常有用。没有什么比一个可以重新签署过时的Swift 2.2 iOS应用程序的开发人员更“值得一提”了,而不是在时间不允许的情况下修复潜在的数千个Swift编译器错误。

下面会讲解代码签名工作原理的基本概述。在下面的链接找到开源iOS Wordpress v10.9应用程序:

在发送到iTunes Connect Store之前,我们会探索应用程序代码签名的各个阶段。此外,我们会重新签署Wordpress应用程序,以便它可以在我们自己的iOS设备上运行!

1.1 准备工作

我们需要一个合适的iOS苹果开发人员帐户来生成配置文件;需要一个真机来安装Wordpress iOS应用程序;还需要获取并安装mobdevim命令,可在此处获得:

这个小命令行工具可以做很多事情,包括在设备上安装应用程序、查询设备信息和连接到iOS设备时获取控制台日志。使用此工具可以更轻松地在设备上安装iOS应用程序,并在应用程序签名不正确时查找错误。

按照mobdevsim上的说明安装该工具。安装mobdevim后,连上iOS设备并进行测试运行。

mobdevim -f

1.2 专业用语

要真正了解代码签名的工作原理,我们需要了解三个关键组件:公钥/私钥、授权文件和配置文件。我们将从广度优先开始,然后深入到深度优先。

公钥/私钥用于签署我们的应用程序。这是我们的数字签名,苹果知道如何进行验证。私钥用于对应用程序及其授权文件进行密码签名。授权文件实际上只是嵌入在应用程序中的一个XML字符串,它表示应用程序可以做什么,不能做什么。

授权文件、已批准设备的列表和用于验证代码签名的公钥都捆绑在应用程序的配置文件中。所有信息都是通过私钥创建的签名强制执行的,并且可以通过公钥进行验证。

1.3 公钥/私钥

在学习代码签名过程时,这可能是最难理解的事情。因为公钥/私钥引入了密码学,不断深入将是个无底洞。

简单地说,有两种不同类型的密码学:对称加密和非对称加密。

  • 对称加密,是一种只包含一个密钥的密码。如果A试图向B发送一条秘密消息,他们都必须知道共享的秘密才能对该消息进行加密和解密。
  • 在非对称加密中,有两个密钥:公钥和私钥。A和B都有自己独特的私钥和独特的公钥。这样,他们就可以在任何人不知道对方私钥的情况下共享信息。

我们在设置Apple开发人员帐户时,已经完成了从证书颁发机构请求证书的过程。我们创建了一对公钥/私钥,将公钥发送到Apple服务器(通过.csr文件)。最终的结果是创建了一个由苹果签署的签名,这就是苹果如何唯一地识别你。这意味着苹果公司和我们都使用非对称加密技术来分发应用程序。

我们可以使用以下终端命令查看用于为应用程序签名的公钥/私钥对的名称或标识:

security find-identity -p codesigning -v

此命令查询macOS系统的keychain,查找包含私钥(-v)且其类型可以进行代码签名(-p代码签名)的有效标识。

此输出将显示有效的标识,这些标识可以生成代码签名的应用程序。如果我们查找包含短语“iPhone Developer”的标识,则该标识可能用于在设备上签名iOS应用程序。

请注意,我们有一个公钥或证书,以及下面的私钥。证书可以重新创建,但私钥的价值超过黄金。永远不要删除私钥!如果这样做了,你就要拿出你是你的证据,就需要通过苹果重新创造一个新的身份。

从这个意义上说,证书只是公钥。因此,如果要使用keychain访问来导出标识,并且希望将其格式化为.cer格式,那么我们将只会导出公钥。如果还要导出私钥,则必须使用PKCS12格式(.p12)正确导出完整标识、私钥和其他信息。

这一点很重要,因为我们需要知道是否要导出标识,以便另一个开发人员可以生成具有匹配分发标识的构建。但要小心:无论谁拥有私钥,都可以为那家公司承担全部身份,至少从苹果的角度来看是这样!

可以使用以下命令导出公共证书:

 security find-certificate -c ${name} -p

这将把名字叫${name}的公共证书输出到stdout,并将其格式化为PEM格式。显示证书有两种方法:DERPEMPEM可以被终端读取(因为它是base64编码的;DER,用高度专业的编码术语来说,会产生官话并使终端发出很多哔哔声。

重复上述命令并将输出写入/tmp/public_cert.cer

 security find-certificate -c ${name} -p > /tmp/public_cert.cer

然后就可以在终端查看了。

cat /tmp/public_cert.cer
-----BEGIN CERTIFICATE-----
MIIFnDCCBISgAwIBAgIIFMKm2AG4HekwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
...

这就是我们怎么知道这个证书在PEM中。我们可以使用openssl命令查询公共的x509证书:

openssl x509 -in /tmp/public_cert.cer -inform PEM -text -noout
  • x509选项表示openssl命令应该使用x509证书。
  • 提供公共证书路径的-in,解码格式为PEM(-inform PEM)。
  • 希望证书采用可读的文本格式-text选项。
  • 指定不希望输出证书中带有-noout参数。

有关此公共证书的信息将显示在终端中。

记住这个openssl命令。当我们阅读到将这些公共证书嵌入其中的配置文件时,将重新接触到x509证书的概念。

1.4 授权文件

嵌入在几乎每个编译的应用程序中的是一组授权文件。这是嵌入在应用程序中的XML字符串,表示应用程序可以做什么和不能做什么。其他程序将检查授权文件中的权限,并相应地授予或拒绝请求。

其中许多权限检查是由其他检查程序权限的守护程序执行的。例如,App GroupsiCloud ServicesPush NotificationsAssociated Domains都将修改应用程序的授权信息。Xcode中显示的这些功能只是苹果平台上的一小部分权利,因为大多数功能都是苹果私有的,并通过代码签名来实现。

可能最重要的授权,是get-task-allow授权,可以在使用开发人员证书编译的所有软件上找到。它允许相关程序附着到调试器上。

在macOS上,可以通过为任何不具有get-task-allow: true的应用程序禁用SIP来解决缺少此权限的问题。在iOS上,我们将尝试调试不具有此权限的应用程序,除非通过越狱禁用了代码验证。

可以通过codesign命令查看应用程序的授权信息,比如Finder

codesign -d --entitlements :- /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder

-d选项表示在命令后面立即显示--entitlements选项。:-有两种作用:

  • -打印到stdout
  • :表示省略有信息和长度。

就像在Mach-O中一样,代码签名信息是用一个magic header和长度存储的。:表示从输出中删除此头信息,并且只显示实际的XML授权字符串。

1.5 配置文件

设置配置文件把公共x509证书、已批准设备的列表以及授权文件嵌入到一个文件中。

配置文件的默认位置可以在以下位置找到:

~/Library/MobileDevice/Provisioning Profiles/
// 通过ls命令查看文件夹下的所有证书
ls ~/Library/MobileDevice/Provisioning\ Profiles/

不幸的是,配置概要文件是由它们的UUID命名的,而不是由我们(或Xcode)为它们取的名称命名的。

幸运的是,我们可以再次使用security命令来显示原始信息。选择任何一个.mobileprovision文件并执行security命令,如下所示:

PP_FILE=$(ls ~/Library/MobileDevice/Provisioning\ Profiles/ *mobileprovision | head -1)
security cms -D -i "$PP_FILE"

第一个命令获取一个配置文件并将其分配给PP_FILE变量。PP_FILE变量被传递到security命令中。该命令对设置配置文件的加密消息语法cms格式进行-D解码,并通过-i选项指定输入路径。

下面将讨论某一个配置文件的输出。输出中有一些有意思的点:

  • AppIDName是绑定到此设置配置文件的ID的名称,可在https://developer.apple.com/account/ios/identifier/bundle上找到。
  • TeamIdentifier是Apple为团队标识提供的唯一团队标识。苹果将为付款的每个账户生成一个特定的团队ID。例如,对于应用商店版本,会有一个唯一的团队ID;而对于企业版本,会有一个不同的团队ID。
  • 授权包含应用程序使用此签名可以做什么和不能做什么。这通常是Xcode生成的配置文件出现问题的原因。因为Xcode需要更新App ID配置(本质上是授权),然后生成具有正确值的新配置文件。
  • IsXcodeManaged是一个布尔值。表明Xcode是否管理这个配置文件。整个代码签名过程给开发者带来了很多麻烦,苹果公司正试图在IDE上做更多的工作,包括用我们的发行证书为应用程序签名。这是一把双刃剑,让Xcode代为管理方便了我们,但是如果Xcode做了一些我们没有预料到的事情,那么潜在的错误可能更难追踪。
  • Name是在https://developer.Apple.com/account/ios/profile/limited上显示的用于标识配置文件的名称。
  • ProvisionedDevices授权设备的列表。
  • DeveloperCertificates是包含base64编码的x509证书的数组。这将包含先前通过security find certificate命令提取的相同公共证书。在对应用程序进行代码签名时,这些证书也被编码到实际的可执行文件中。

1.6 探索WordPress app

与iOS设备上的典型调试工作流一样,在将应用程序发送到Apple iTunes Connect之前,必须编译具有配置文件的应用程序。每个上架前的App都有一个名为embedded.mobileprovision的配置文件。正是这个配置文件告诉iOS应用程序是有效的,并且来自我们。

打开Pre App Store目录中的WordPress.app。为WORDPRESS.app的完整路径分配一个终端变量WORDPRESS,如下所示:

WORDPRESS="/full/path/to/WordPress.app/"
配置文件

WordPress应用程序中找到embedded.mobileprovision配置文件,并对其使用security命令。

security cms -D -i "$WORDPRESS/embedded.mobileprovision"

在这个特定的配置文件中,可以看到以下内容:

  • 苹果公司分配给Automattic, Inc.公司的团队标识是3TMU3BH3NK
  • Wordpress应用程序使用iCloud服务:在授权字典中有com.apple.developer.icloud键。它还希望使用某些扩展,如App Groups
  • get-task-allowfalse,意味着我们无法附着调试器。因为应用程序是使用分发签名标识签名的。

DeveloperCertificates密钥复制base64编码的数据。通过终端,将此值分配给名为CERT_DATA的变量:

CERT_DATA=MIIFozCCBIu...

变量CERT_DATA现在包含用于签署应用程序的base64编码x509证书。现在,解码这个base64数据并将其导出到/tmp/wordpress_cert.cer。之后执行openssl命令进行查看。

echo "$CERT_DATA" | base64 -D > /tmp/wordpress_cert.cerecho "$CERT_DATA" | base64 -D > /tmp/wordpress_cert.cer

openssl x509 -in /tmp/wordpress_cert.cer -inform DER -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 786948871528664923 (0xaebcdd447dc4f5b)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
        Validity
            Not Before: Jan 17 13:26:41 2018 GMT
            Not After : Jan 17 13:26:41 2019 GMT
        Subject: UID=PZYM8XX95Q, CN=iPhone Distribution: Automattic, Inc. (PZYM8XX95Q), OU=PZYM8XX95Q, O=Automattic, Inc., C=US
...

这意味着,在Automattic, Inc的工作人员的keychain上有一个名为“iPhone Distribution: Automattic, Inc. (PZYM8XX95Q)”的标识,用于签署此应用程序。

嵌入的可执行文件

如果应用程序包含扩展(即share扩展、today小部件或其他的),则在./Plugins目录中会找到更多签名的打包包,其中包含它们自己的应用程序标识符和embedded.mobileprovision配置文件。

这些功能为应用程序提供了应用程序之外的附加功能。

在深入./Plugins目录中的容器时,可以使用相同的安全命令来验证这一点,分别查看每个embedded.mobileprovision文件。

_CodeSignature文件夹

包含在真正的iOS应用程序包(不在模拟器中)中的是一个名为_CodeSignature的文件夹,其中包含一个名为CodeResources的文件。这是一个XML plist文件,它是该目录中找到的每个不可执行文件的校验和。例如:

cat "_CodeSignature/CodeResources" | head -10
<?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>files</key>
    <dict>
        <key>AboutViewController.nib</key>
        <data>
        rSZAWMReahogETtlwDpstztW6Ug=
        </data>

可以看到AboutViewController.nib文件的校验和
rSZAWMReahogETtlwDpstztW6Ug=

这个值可以通过openssl自己计算:

openssl sha1 -binary "AboutViewController.nib" | base64
rSZAWMReahogETtlwDpstztW6Ug=

苹果已经开始用Xcode 10为iOS应用程序从SHA-1校验和向SHA-256过渡,为两种算法生成校验和。

这个CodeResources文件本身有一个对文件执行的校验和,它被嵌入到了实际的WordPress应用程序中!这意味着,如果用户要修改任何文件,甚至在.app目录中添加一个目录而不重新签名WordPress应用程序,iOS应用程序都无法在用户手机上进行安装。

1.7 对WordPress app重新签名

我们可以使用Apple签名重新签名应用程序,将WordPress应用程序安装到iOS设备上。

从高层的角度来看,您需要执行以下操作:

  1. 将有效的配置文件复制到应用程序WordPress .app目录中的embedded.mobileprovision。
  2. Info.plistCFBundleIdentifier更改为新的配置文件中新的应用程序标识符。
  3. 使用适当的授权信息(也包括在配置文件中)通过嵌入的配置文件中包含的标识为WordPress应用程序重新签名。

如果你有一个有效的、未过期的、包含你的iOSUDID的配置文件。连接上iOS设备,通过执行mobdevim -f命令来获取设备的UDID

复制配置文件

无论是创建一个新的配置文件或使用现有的配置文件,我们将使用它来重新签名WordPress应用程序。用它覆盖WordPress.app文件夹下面的embedded.mobileprovision文件。

PP_PATH=~/Downloads/Code_Signing_Example_ProvisProfile_92618.mobileprovision

cp "$PP_PATH" "$WORDPRESS/embedded.mobileprovision"
删除插件

WordPress应用程序在主应用程序中嵌入了几个./Plugins目录中的扩展应用程序。每个配置文件都包含一个具有唯一应用程序标识符的唯一配置文件。我们可以为每个扩展本身提供一个唯一的配置文件进行签名。但这个太麻烦了,不是重点。我们不使用这些扩展,删除WordPress应用程序的整个插件目录。

修改Info.plist

希望你记住了配置文件的应用程序ID的名称,现在需要把它设置到Info.plist的键CFBundleIdentifier中。如果不记得,可以从配置文件中查询它。以下是获取这些信息的方法:

security cms -D -i "$PP_PATH" | grep application-identifier -A1
<key>application-identifier</key>
<string>H4U46V6494.com.selander.code-signing</string>

下面替换这个CFBundleIdentifier键中的值。

plutil -replace CFBundleIdentifier -string H4U46V6494.com.selander.code-signing "$WORDPRESS/Info.plist"

我们还可以更改它的显示名称:

plutil -replace CFBundleDisplayName -string "Woot" "$WORDPRESS/Info.plist"
提取授权信息

下一个任务是使用配置文件中的有效授权重新签名应用程序。

由于授权在配置文件中嵌入为字典而不是XML,因此可能更容易先从主可执行文件中提取权限,然后用配置文件中找到的新权限修补该文件。提取授权信息导出到/tmp/ent.xml

codesign -d --entitlements :/tmp/ent.xml "$WORDPRESS/WordPress"

可以通过cat进行查看:

cat /tmp/ent.xml

如果授权有效,则可以从当前配置文件中提取授权并将其放入这个新文件中。

首先,将配置文件XML写入名为/tmp/scratch的文件:

security cms -D -i "$PP_PATH" > /tmp/scratch

使用xpath命令只将权利信息提取到剪贴板。

 xpath /tmp/scratch '//*[text() = "Entitlements"]/following-sibling::dict' | pbcopy

现在剪贴板中有有效的授权信息。打开/tmp/ent.xml,删除包含的<dict>之间的内容并替换为剪贴板的内容。最终的/tmp/ent.xml文件应该如下所示:

<?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>keychain-access-groups</key>
    <array>
        <string>H4U46V6494.*</string>
    </array>
    <key>get-task-allow</key>
    <true />
    <key>application-identifier</key>
    <string>H4U46V6494.com.selander.code-signing</string>
    <key>com.apple.developer.team-identifier</key> 
    <string>H4U46V6494</string>
</dict>
</plist>
重新签名WordPress

我们已经执行了所有设置。我们有一个有效的签名标识;在embedded.mobileprovisionWordPress应用程序中嵌入了一个有效的配置文件;删除了插件目录;并且拥有在/tmp/ent.xml中找到的新配置文件的授权。

WordPress应用程序Frameworks目录中使用codesign命令和签名标识:

codesign -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$WORDPRESS"/Frameworks/*

然后对文件夹进行签名:

codesign --entitlements /tmp/ent.xml -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$WORDPRESS"

看看能否安装WordPress应用程序。在终端中,键入:

mobdevim -i "$WORDPRESS"

如果我们使用开发人员配置文件签署了应用程序。那么我们将拥有get-task-allow权限,这意味着我们可以调试这个WordPress应用程序。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容