细谈证书与Provisioning Profile

iOS程序员大多对证书和Provisioning Profile懵逼过吧,是时候整理一下思路了,把这个问题讲讲清楚。所有配置都在https://developer.apple.com,大家都可以上去摸索一下。

证书

打开钥匙串访问可以看到里面有证书我的证书两项,其中证书包含系统安装的所有证书,我的证书则仅包含电脑上有私钥的证书。

screenshot.png

证书的私钥是用来签名的,通过签名可以确保程序是没有被篡改的。其中私钥放在自己电脑上,公钥则放在苹果服务器上。

模拟器运行App是不需要签名的,真机调试和上传AppStore的包都需要签名,主程序、动态库、资源都要签名。

//模拟器也调用了codesign,但是没有选择证书。
CodeSign /Users/henshao/Library/Developer/Xcode/DerivedData/CloudConsoleApp-gszptqenpqtwraajgpawanvtjtny/Build/Products/Debug-iphonesimulator/CloudConsoleApp.app
    cd /Users/henshao/cloudconsole-iOS
    export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    
Signing Identity:     "-"

    /usr/bin/codesign --force --sign - --timestamp=none /Users/henshao/Library/Developer/Xcode/DerivedData/CloudConsoleApp-gszptqenpqtwraajgpawanvtjtny/Build/Products/Debug-iphonesimulator/CloudConsoleApp.app

//真机codesign选择了证书
CodeSign /Users/henshao/Library/Developer/Xcode/DerivedData/CloudConsoleApp-gszptqenpqtwraajgpawanvtjtny/Build/Products/Debug-iphoneos/CloudConsoleApp.app
    cd /Users/henshao/cloudconsole-iOS
    export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    
Signing Identity:     "iPhone Developer: 智杰 付 (WTLVCA9D68)"
Provisioning Profile: "iOS Team Provisioning Profile: a.b.c.d"
                      (e6dc1bc1-140c-4003-b91b-817535a46ae4)

    /usr/bin/codesign --force --sign AB9AB462D723988FB08AF1265BE1B574DD273DCB --entitlements /Users/henshao/Library/Developer/Xcode/DerivedData/CloudConsoleApp-gszptqenpqtwraajgpawanvtjtny/Build/Intermediates/CloudConsoleApp.build/Debug-iphoneos/CloudConsoleApp.build/CloudConsoleApp.app.xcent --timestamp=none /Users/henshao/Library/Developer/Xcode/DerivedData/CloudConsoleApp-gszptqenpqtwraajgpawanvtjtny/Build/Products/Debug-iphoneos/CloudConsoleApp.app

解压开ipa可以发现,里面有一个_CodeSignature/CodeResources文件,这是一个XML文件,打开可以看到里面的内容。

<key>Frameworks/AFNetworking.framework/AFNetworking</key>
<dict>
    <key>hash</key>
    <data>
    gF72IVSBtCx2WdGfkervPKcCmZw=
    </data>
    <key>hash2</key>
    <data>
    kySS3fap6mMdMztbVQ0BPcQqGHwDKowHON1fHzQ6P4k=
    </data>
</dict>
<key>Frameworks/AFNetworking.framework/Info.plist</key>
<dict>
    <key>hash</key>
    <data>
    6AnKOHTiBpi15MSyr4X4yhapLxc=
    </data>
    <key>hash2</key>
    <data>
    D5xPZO6XisdE1hSvSAioGQv9RHryi33o8j6GwaNOOT4=
    </data>
</dict>
<key>Frameworks/AFNetworking.framework/_CodeSignature/CodeResources</key>
<dict>
    <key>hash</key>
    <data>
    +eORwOY/EikcBmsFZfD7QEDo3Qw=
    </data>
    <key>hash2</key>
    <data>
    bqs1RQcVX2sq7r0OewcocgvkivH0PSm6hgcqh/99iDI=
    </data>
</dict>

有趣的是动态库也会拥有自己有的_CodeSignature/CodeResources,但是里面的内容非常简单,只有Info.plist的,签名结果跟外面的是一样的。AppStore里面所有动态库都要签名,加载的时候要检查签名,所以不可能实现下发动态库做升级或者hotpatch。但是企业证书可以这样做。

//AFNetworking.framework/_CodeSignature
<dict>
    <key>Info.plist</key>
    <data>
    6AnKOHTiBpi15MSyr4X4yhapLxc=
    </data>
</dict>

任何有效的证书都可以用来签名。所以这样不牢靠对不对?当年塞班时候,改签真的很容易,轻松安装各种程序。苹果要想的更加周到一些,比如下面要讲的Provisioning Profile。当然不遵守规则重签也是可以做到的,只是稍微增加了一些难度。

Provisioning Profile

解压开ipa文件,可以在Payload目录发现有一个embedded.mobileprovision文件。

[~/Downloads/CloudConsoleApp-Release/Payload]$ ll CloudConsoleApp.app/embedded.mobileprovision 
-rw-r--r-- 1 henshao staff 7.8K 10 21 03:01 CloudConsoleApp.app/embedded.mobileprovision

Provisioning Profile是一个很复杂的东西,包含了很多东西,可以在https://developer.apple.com里面试着生成一个Provisioning Profile,看看每个步骤都需要填些什么。Provisioning Profile包含了证书(公钥)、App ID、entitlements、device list等关乎App能否正常启动的所有信息。证书是给ipa签名的,在打包的时候起作用;而Provisioning Profile要打进ipa里面,在启动的时候起作用

//使用这个命令可以解开文件看看里面的内容
security cms -D -i embedded.mobileprovision
screenshot.png
screenshot.png
screenshot.png

Provisioning Profile是被苹果签名的,里面的内容不能被修改。如果要对App做重签,需要构造一份新的Provisioning Profile。找一些iOS重签名的文章:iOS重签名探索,可以发现,重签名之前,要把自己的mobileprovision拷贝到ipa指定目录里面。

Team

Xcode为了简化配置,设计了一个team的概念。只要在https://developer.apple.com里面添加了Apple ID,然后该用户在Xcode里面登录一下。遇到签名的问题,直接fix issue就可以了。这个过程中把证书和Provisioning Profile相关的配置都做好了。

一个用户可能加入多个team,如何区分这个用户在不同team里面创建的App ID呢?为了解决这问题,苹果设计了Team IDTeam ID加上Bundle ID构成完整的App IDApp ID跟App的各种service有很大的关系,从https://developer.apple.com也可以看出来,service的配置都是在App ID里面的。

screenshot.png

带通配符的App ID可以表示一类App,Provisioning Profile使用这种App ID可用于team里面所有的App。Xcode fix issue喜欢创建这种类型的Provisioning Profile。

Paste_Image.png

推送证书

推送服务器跟苹果APNs发消息,是需要认证的。苹果提供下面两种认证的方式。

//目前还没有听说谁在用这种方式
Token-based connection trust A provider using the HTTP/2-based API can use JSON web tokens (JWT) to validate the provider’s connection with APNs. In this scheme, the provider does not require a certificate-plus-private key to establish connection. Instead, you provision a public key to be retained by Apple, and a private key which you retain and protect. Your providers then use your private key to generate and sign JWT authentication tokens. Each of your push requests must include an authentication token.

//一般都用这种方式
Certificate-based connection trust A provider can, alternatively, employ a unique provider certificate and private cryptographic key. The provider certificate, provisioned by Apple when you establish your push service in your online developer account, identifies the topics supported by the provider. Each topic is the bundle ID associated with one of your apps.
screenshot.png
screenshot.png

推送平台需要一个包含证书和私钥的p12文件,而只有当初生成推送证书的人才能正常导出p12文件。为了避免紧急情况下,找不到当事人,所以我们在App代码根目录下存放了一份p12文件,并且标明了过期时间,可确保万无一失。

$ tree CertificateExpireAt20170324 
CertificateExpireAt20170324
├── AliyunMobileApp-APNs-prod.p12
└── push.passwd

更多详细信息可以参看:Local and Remote Notifications Overview

推送测试

命令行

使用Houston给iOS APP推送信息,拿到证书和token就可以在命令行下面做一些自动化的推送工作。

图形化工具

Easy APNs Provider这款工具很不错,在Mac App Store可以下载到。证书直接用cer就好了。Houston需要把证书转换成pem格式才行。

Snip20161130_3.png

打包平台

大公司都会开发很多个App,因为苹果设备数量的限制,必须注册很多开发者账号,才能保证各个团队都能做真机测试。但是并不是每个团队都可以申请企业证书,这样就没法发布企业内测包了。

为了解决这个问题,公司会搭建一个打包的平台,用一个企业证书给所有的App签名,然后分发给PD、视觉、交互、测试扫描做测试和验收。这里的问题是一旦a.b.c.d这个Bundle ID被团队自己注册了,打包平台就不能用这个Bundle ID了,需要注册一个a.b.c.d.e这样的Bundle ID,还得去手动生成对应的Provisioning Profile,所以说做一个通用的打包平台也是一件麻烦事。

好在现在有一个工具:fastlane,可以使用脚本来生成证书和Provisioning Profile。可以通过fastlane来提高打包平台的自动化程度。

AppStore的特殊性

App提交苹果审核之后,苹果会对App重签名。通过codesign可以看到mtl打出来的包都是我们自己证书签名的,而AppStore的包签名的证书都是苹果的。

//企业包
[~/Downloads/CloudConsoleApp-Release/Payload]$ codesign -vv -d CloudConsoleApp.app/
Executable=/Users/henshao/Downloads/CloudConsoleApp-Release/Payload/CloudConsoleApp.app/CloudConsoleApp
Identifier=com.aliyun.wstudio.amc.AliyunMobileApp
Format=app bundle with Mach-O universal (armv7 arm64)
CodeDirectory v=20200 size=193958 flags=0x0(none) hashes=6053+5 location=embedded
Signature size=4737
Authority=iPhone Distribution: Alibaba Cloud Computing Ltd. (QBMN2BBW3K)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=2016年10月21日 上午3:02:00
Info.plist entries=40
TeamIdentifier=QBMN2BBW3K
Sealed Resources version=2 rules=13 files=1451
Internal requirements count=1 size=220

//AppStore包
[~/wechat]$ codesign -vv -d WeChat.app/
Executable=/Users/henshao/wechat/WeChat.app/WeChat
Identifier=com.tencent.xin
Format=app bundle with Mach-O universal (armv7 arm64)
CodeDirectory v=20200 size=191179 flags=0x0(none) hashes=9550+5 location=embedded
Signature size=3487
Authority=Apple iPhone OS Application Signing
Authority=Apple iPhone Certification Authority
Authority=Apple Root CA
Info.plist entries=43
TeamIdentifier=88L2Q4487U
Sealed Resources version=2 rules=13 files=3005
Internal requirements count=1 size=96

参考文章

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

推荐阅读更多精彩内容