轉(zhuǎn)自 http://xelz.info/blog/2019/01/11/ios-code-signature-3/垃你,版權(quán)歸原作者所有
導(dǎo)航
- 一口氣讀完,大約需要40-60分鐘
- 分步閱讀
- 細(xì)說(shuō)iOS代碼簽名(一):簽名的作用及原理
- 細(xì)說(shuō)iOS代碼簽名(二):開(kāi)發(fā)者證書(shū)喂很、Entitlements惜颇、Provisioning Profile
- 細(xì)說(shuō)iOS代碼簽名(三):簽名的過(guò)程及代碼簽名的數(shù)據(jù)結(jié)構(gòu)
- 細(xì)說(shuō)iOS代碼簽名(四):簽名校驗(yàn)、越獄少辣、重簽名
0x05 CodeSign
萬(wàn)事具備凌摄,只欠東風(fēng)良姆,已經(jīng)具備了簽名所需的所有條件,接下來(lái)就可以開(kāi)始研究簽名的具體過(guò)程了垮媒。
在編譯iOS App時(shí)吮成,Xcode在編譯的打包的流程中會(huì)自動(dòng)進(jìn)行代碼簽名, 可以在編譯日志界面找到一個(gè)Sign
的步驟竹捉,內(nèi)部是調(diào)用了codesign
這個(gè)命令對(duì)app進(jìn)行簽名
codesign有幾個(gè)關(guān)鍵參數(shù)
-
--sign sign_identity
指定簽名所用的證書(shū),可以指定證書(shū)的名字,比如"iPhone Developer: xxx (xxx)"
也可以直接寫(xiě)證書(shū)文件的sha1值豪直,xcode中就是直接指定sha1值的。通過(guò)觀察圖中的sha1值可以看出xcode自動(dòng)選擇了剛申請(qǐng)的最新證書(shū)珠移。 -
--entitlements entitlements_file
指定簽名所需要的entitlements文件弓乙,這里的entitlements文件跟前面看到的并不是同一個(gè)文件末融,而是基于原有entitlements文件,補(bǔ)充上缺省權(quán)限后生成的臨時(shí)文件
<?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>application-identifier</key>
<string>xxxxxxxxxx.test.CodeSign</string>
<key>com.apple.developer.team-identifier</key>
<string>xxxxxxxxxx</string>
<key>get-task-allow</key>
<true/>
<key>inter-app-audio</key>
<true/>
</dict>
</plist>
如果想對(duì)比簽名前后的區(qū)別暇韧,可以在Build Settings
中找到Code Signing Identity
勾习,選擇Other
并將內(nèi)容清除(即設(shè)置為空),即可跳過(guò)代碼簽名懈玻。分別編譯一個(gè)不簽名的版本和簽名的版本巧婶,對(duì)比可以發(fā)現(xiàn)
- 簽名過(guò)的app中多了一個(gè)
_CodeSignature
文件夾,里面只有一個(gè)文件CodeResources
- 還多了一個(gè)
embedded.mobileprovision
文件 - 二進(jìn)制文件的內(nèi)容存在差異涂乌,并且簽名后體積變大了
其中embedded.mobileprovision
就是前文提到的Provisioning Profile文件艺栈,它直接被拷貝到了app的根目錄并重命名,在此不再贅述湾盒,重點(diǎn)研究下另外兩個(gè)不同點(diǎn)湿右。
_CodeSignature/CodeResources
首先是_CodeSingature/CodeResources
,這是一個(gè)plist文件罚勾,里面保存了app中每個(gè)文件(除了App的可執(zhí)行文件)的明文哈希值
<plist version="1.0">
<dict>
<key>files</key>
<dict>
<key>Base.lproj/Main.storyboardc/Info.plist</key>
<data>
MDrKFvFWroTb0+KEbQShBcoBvo4=
</data>
...
</dict>
<key>files2</key>
<dict>
<key>Base.lproj/Main.storyboardc/Info.plist</key>
<dict>
<key>hash</key>
<data>
MDrKFvFWroTb0+KEbQShBcoBvo4=
</data>
<key>hash2</key>
<data>
PpvapAjR62rl6Ym4E6hkTgpKmBICxTaQXeUqcpHmmqQ=
</data>
</dict>
...
</dict>
<key>rules</key>
...
<key>rules2</key>
...
</dict>
</plist>
files
和files2
分別是舊版本和新版本的文件列表毅人,而rules
與rules2
分別是與之對(duì)應(yīng)的規(guī)則說(shuō)明,里面描述了計(jì)算hash時(shí)需要被排除的文件以及每個(gè)文件的權(quán)重尖殃。
files
中保存的是每個(gè)文件的sha1值堰塌,而files2
中同時(shí)保存了sha1和sha256,因?yàn)閟ha1在計(jì)算機(jī)硬件高度發(fā)達(dá)的今天分衫,已經(jīng)相對(duì)沒(méi)有那么安全了场刑,因此最新的簽名算法中,引入了sha256蚪战。注意牵现,這里的hash值都是base64編碼的明文,有些文章說(shuō)這些值是使用私鑰加密的哈希邀桑,這是很不負(fù)責(zé)任的錯(cuò)誤說(shuō)法瞎疼,通過(guò)幾條簡(jiǎn)單的命令就可以進(jìn)行驗(yàn)證:
$ cat Base.lproj/Main.storyboardc/Info.plist | shasum -a 1
303aca16f156ae84dbd3e2846d04a105ca01be8e -
$ echo -n 'MDrKFvFWroTb0+KEbQShBcoBvo4=' | base64 -D | hexdump
0000000 30 3a ca 16 f1 56 ae 84 db d3 e2 84 6d 04 a1 05
0000010 ca 01 be 8e
$ # =========== 分割線 ===========
$ cat Base.lproj/Main.storyboardc/Info.plist | shasum -a 256
3e9bdaa408d1eb6ae5e989b813a8644e0a4a981202c536905de52a7291e69aa4 -
$ echo -n 'PpvapAjR62rl6Ym4E6hkTgpKmBICxTaQXeUqcpHmmqQ=' | base64 -D | hexdump
0000000 3e 9b da a4 08 d1 eb 6a e5 e9 89 b8 13 a8 64 4e
0000010 0a 4a 98 12 02 c5 36 90 5d e5 2a 72 91 e6 9a a4
_CodeSignature/CodeResources
文件的主要作用是保存簽名時(shí)每個(gè)文件的哈希值,而這些哈希值并不需要都進(jìn)行加密壁畸,因?yàn)榉菍?duì)稱加密的性能是比較差的贼急,全部都加密只會(huì)拖慢簽名和校驗(yàn)的速度。其實(shí)只需要確保這個(gè)文件沒(méi)有被篡改捏萍,自然也就可以確保每個(gè)文件都是簽名時(shí)的原始狀態(tài)太抓,這一點(diǎn)在后續(xù)的內(nèi)容中可以得到驗(yàn)證。
LC_CODE_SIGNATURE
使用otool -l
對(duì)比簽名前后的二進(jìn)制文件令杈,可以發(fā)現(xiàn)簽名后二進(jìn)制文件多了一個(gè)名為LC_CODE_SIGNATURE
的Load ?
$ otool -l TestCodeSign | tail -n 5
Load ? 21
cmd LC_CODE_SIGNATURE
cmdsize 16
dataoff 54016
datasize 19888
MachOView中查看如下
代碼簽名是一段純二進(jìn)制的數(shù)據(jù)走敌,可以在https://opensource.apple.com/source/Security/Security-55471/sec/Security/Tool/codesign.c.auto.html 看到一些結(jié)構(gòu)定義,結(jié)合數(shù)據(jù)定義來(lái)分析
// 紅色部分① Offset: 0xD300 = 54016 LC_CODE_SIGNATURE->dataoff
struct __SuperBlob {
uint32_t magic; /* 0xFADE0CC0 = CSMAGIC_EMBEDDED_SIGNATURE */
uint32_t length; /* 0x1A1E -> 6686 */
uint32_t count; /* 5 */
CS_BlobIndex index[]; /* 藍(lán)色部分 */
}
// 藍(lán)色部分② 5個(gè)BlobIndex
struct __BlobIndex {
uint32_t type; /* 0x0 -> Code Directory */
uint32_t offset; /* 0x34 -> 0xD300 + 0x34 = 0xD334 指向綠色③*/
}
struct __BlobIndex {
uint32_t type; /* 0x2 -> Requirements */
uint32_t offset; /* 0x221 -> 0xD300 + 0x221 = 0xD521 */
}
struct __BlobIndex {
uint32_t type; /* 0x5 -> Entitlements */
uint32_t offset; /* 0x2CD -> 0xD300 + 0x2CD = 0xD5CD */
}
struct __BlobIndex {
uint32_t type; /* 0x1000 -> Code Directory */
uint32_t offset; /* 0x475 -> 0xD300 + 0x475 = 0xD775 */
}
struct __BlobIndex {
uint32_t type; /* 0x10000 -> CMS Signature */
uint32_t offset; /* 0x746 -> 0xD300 + 0x746 = 0xDA46 */
}
這部分是典型的數(shù)據(jù)頭結(jié)構(gòu)逗噩,聲明了5個(gè)Blob掉丽,以及每個(gè)Blob的類型和相對(duì)簽名頭部的偏移量跌榔。接下來(lái)把每個(gè)部分分別提取出來(lái)進(jìn)行分析。
CodeDirectory
CodeDirectory是簽名數(shù)據(jù)中最終要的部分捶障,直譯過(guò)來(lái)就是代碼目錄僧须,其實(shí)里面是整個(gè)MachO文件的哈希值,這里的哈希并不是一次性對(duì)整個(gè)文件進(jìn)行哈希项炼,而是將MachO文件按照pageSize(一般是4k也就是4096字節(jié))進(jìn)行分頁(yè)皆辽,每一頁(yè)單獨(dú)計(jì)算哈希,并按照順序保存下來(lái)芥挣,就像目錄一樣驱闷。
細(xì)心的同學(xué)會(huì)發(fā)現(xiàn)上面的數(shù)據(jù)中出現(xiàn)了兩個(gè)CodeDirectory,type分別是0x0
和0x1000
空免,這也是歷史遺留問(wèn)題空另,0x0
對(duì)應(yīng)的是舊版本的代碼簽名,使用sha1算法進(jìn)行哈希值的計(jì)算蹋砚,而0x1000
是后來(lái)引入的扼菠,采用sha256作為哈希算法,除了算法和哈希的長(zhǎng)度不同之外坝咐,其他內(nèi)容基本是一樣的循榆。取第一個(gè)進(jìn)行分析:
// 綠色部分③ Offset: 0xD334
struct __CodeDirectory {
uint32_t magic; /* 0xFADE0C02 -> CSMAGIC_CODEDIRECTORY */
uint32_t length; /* 0x1ED -> 493 */
uint32_t version; /* 0x00020400 -> v2.4.0 */
uint32_t flags; /* 0 */
uint32_t hashOffset; /* 0xD5 -> 0xD334 + 0xD5 = 0xD409 指向⑤*/
uint32_t identOffset; /* 0x58 -> 0xD334 + 0x58 = 0xD38B 指向④*/
uint32_t nSpecialSlots; /* 5 */
uint32_t nCodeSlots; /* 0xE -> 14 */
uint32_t codeLimit; /* 0xD300 */
uint8_t hashSize; /* 0x14 -> 20bytes -> 160bits (sha1) */
uint8_t hashType; /* 0x01 (sha1) */
uint8_t spare1; /* unused (must be zero) */
uint8_t pageSize; /* 0x0C -> 2 ^ 0x0C = 0x1000 = 4096 */
uint32_t spare2; /* unused (must be zero) */
/* followed by dynamic content as located by offset fields above */
}
hashOffset就是"目錄"第一頁(yè)的偏移,從這個(gè)位置(0xD409)可以提取到一串20字節(jié)的sha1值(圖中黃色⑤):
9D452342F9ED06189E4F099BCA7CB68D6432F775
這個(gè)值代表的就是該文件第一頁(yè)的哈希值墨坚,通過(guò)以下命令計(jì)算文件前4096字節(jié)的sha1可進(jìn)行驗(yàn)證
$ dd bs=1 skip=0 count=0x1000 if=TestCodeSign 2>/dev/null | shasum -a 1
9d452342f9ed06189e4f099bca7cb68d6432f775 -
而緊接著的20個(gè)字節(jié)就是第二頁(yè)的哈希值秧饮,以此類推,直到原始文件的最后一頁(yè)泽篮。
由于文件不一定是pageSize的整數(shù)倍盗尸,最后一頁(yè)往往不足"一整頁(yè)"的大小,因此需要額外的字段codeLimit
記錄文件的實(shí)際大小帽撑,也就是需要簽名的數(shù)據(jù)的實(shí)際大小泼各,通過(guò)這個(gè)值計(jì)算出最后一頁(yè)的實(shí)際大小,并提取相應(yīng)數(shù)據(jù)計(jì)算最后一頁(yè)的簽名亏拉。例子中codeLimit=0xD300
扣蜻,很容易得出最后一頁(yè)大小為0x300
$ dd bs=1 skip=0xD000 count=0x300 if=TestCodeSign 2>/dev/null | shasum -a 1
9dc960fc86f803c1fa100f2a1145cf7cbe58e803 -
計(jì)算出最后一頁(yè)的sha1值與CodeDirectory中(圖中黃色⑥)一致。
nCodeSlots記錄了文件的總頁(yè)數(shù)14及塘,可通過(guò)0xD300 / 0x1000 = 13.1875
得出確實(shí)是14頁(yè)莽使。
細(xì)心的朋友已經(jīng)發(fā)現(xiàn)了,④ identifier和 ⑤ hashSlots 之間有一段多出的數(shù)據(jù)⑦磷蛹,并且CodeDirectory中還有一個(gè)奇怪的值nSpecialSlots=5
吮旅,整個(gè)文件的哈希值都已經(jīng)包含在⑤和⑥之間了溪烤,這多出來(lái)的數(shù)據(jù)是怎么回事呢味咳?
原來(lái)庇勃,在第一頁(yè)的前面,還有5個(gè)特殊的負(fù)數(shù)頁(yè)槽驶,用來(lái)保存這些額外信息的哈希值责嚷。
序號(hào) | 對(duì)應(yīng)內(nèi)容 |
---|---|
-1 | App根目錄的Info.plist文件 |
-2 | Requirements(代碼簽名的第二部分) |
-3 | Resource Directory (_CodeSignature/CodeResources文件) |
-4 | 暫未使用 |
-5 | Entitlements (代碼簽名的第三部分) |
同樣地,出于性能考慮掂铐,這些哈希值并未經(jīng)過(guò)任何加密罕拂,只需要確保這些哈希值未經(jīng)篡改,就可以說(shuō)明代碼本身沒(méi)有被篡改全陨。
Requirements
用于指定簽名校驗(yàn)時(shí)的一些額外的約束爆班,簽名時(shí)codesign命令會(huì)自動(dòng)生成這部分?jǐn)?shù)據(jù),但目前并沒(méi)有看到什么地方使用了它辱姨,就不深入分析了柿菩,官方文檔有對(duì)這部分內(nèi)容的詳細(xì)描述
Entitlements
通過(guò)頭部的偏移定位到數(shù)據(jù)的位置,顯然雨涛,這是一個(gè)Blob結(jié)構(gòu)
struct __Blob { /* Address: 0xD5CD */
uint32_t magic; /* 0xFADE7171 -> CSMAGIC_ENTITLEMENT */
uint32_t length; /* 0x1A8 -> 424 */
}
之前由Xcode生成的Entitlements文件被整個(gè)嵌入到簽名數(shù)據(jù)中枢舶。
CMS Signature
CMS是Cryptographic Message Syntax
的縮寫(xiě),是一種標(biāo)準(zhǔn)的簽名格式替久,由RFC3852定義凉泄。還記得Provisioning Profile的簽名嗎?它們是相同的格式蚯根。CMS格式的簽名中后众,除了包含前面我們推導(dǎo)出的加密哈希和證書(shū)之外,還承載了一些其他的信息颅拦。由于是二進(jìn)制格式吼具,不方便分析,可以將其內(nèi)容從MachO文件中剝離出來(lái)矩距,再找合適的工具進(jìn)行解析拗盒。根據(jù)偏移量定位到CMS Signature的位置0xDA46
struct __Blob { /* Address: 0xDA46 */
uint32_t magic; /* 0xFADE0B01 -> CSMAGIC_BLOBWRAPPER */
uint32_t length; /* 0x12D8 -> 4824 */
}
除去頭部的8個(gè)字節(jié),把對(duì)應(yīng)的內(nèi)容提取出來(lái)
$ dd bs=1 skip=0xDA4E count=0x12D0 if=TestCodeSign of=cms_signature
可以將導(dǎo)出的cms_signature文件上傳到在線ASN.1解析工具(支持CMS格式解析)進(jìn)行分析
文件被解析為樹(shù)狀結(jié)構(gòu)锥债,看起來(lái)還是不夠直觀陡蝇,因?yàn)檫@個(gè)工具只是按照數(shù)據(jù)格式把內(nèi)容進(jìn)行了格式化,但是并沒(méi)有標(biāo)注所有字段的確切含義哮肚。其實(shí)我們還可以使用openssl進(jìn)行查看登夫,但是因?yàn)镸ac上自帶的openssl以及通過(guò)HomeBrew安裝的openssl都是沒(méi)有開(kāi)啟cms支持的,所以可以將文件拷貝到linux機(jī)器上或者自行編譯openssl進(jìn)行查看允趟,具體方法在此不表恼策。
$ openssl cms -cmsout -print -inform DER -in cms_signature
CMS_ContentInfo:
contentType: pkcs7-signedData (1.2.840.113549.1.7.2)
d.signedData:
version: 1
digestAlgorithms:
algorithm: sha256 (2.16.840.1.101.3.4.2.1)
parameter: NULL
encapContentInfo:
eContentType: pkcs7-data (1.2.840.113549.1.7.1)
eContent: <ABSENT>
certificates:
... [stripped] Apple Worldwide Developer Relations Certification Authority
... [stripped] Apple Root CA
... [stripped] iPhone Developer: xxxxxxx
signerInfos:
version: 1
d.issuerAndSerialNumber:
issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
serialNumber: 1008862887770590428
digestAlgorithm:
algorithm: sha256 (2.16.840.1.101.3.4.2.1)
parameter: NULL
signedAttrs:
... [stripped]
SEQUENCE:
0:d=0 hl=2 l= 29 cons: SEQUENCE
2:d=1 hl=2 l= 5 prim: OBJECT :sha1
9:d=1 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:669421362B2F2B5303BCEBB47D793A75A6BBD32F
... [stripped]
signatureAlgorithm:
algorithm: rsaEncryption (1.2.840.113549.1.1.1)
parameter: NULL
signature:
0000 - 77 00 50 9c 5c 6d 50 1e-cb 4b ca b7 91 d3 5b w.P.\mP..K....[
000f - 2e 28 fe f3 5d 20 73 ef-0a 59 ac 2e ed bd 2a .(..] s..Y....*
... [stripped]
unsignedAttrs:
<EMPTY>
由于輸出內(nèi)容太多,將部分內(nèi)容做了刪減,可以觀察到簽名中主要包含了這些內(nèi)容
-
contentType涣楷, 表明消息的類型分唾,有6種取值,這里使用的是表示簽名的signedData類型
- Data
- SignedData
- EnvelopedData
- DigestedData
- EncryptedData
- AuthenticatedData
-
content狮斗,SignedData類型的數(shù)據(jù)
- version等:略
- certificates: 證書(shū)鏈绽乔,包含用于簽名的開(kāi)發(fā)者證書(shū)及所有上游CA的證書(shū)
- signerInfos:真正的簽名信息!
- version:版本號(hào)
- issuerAndSerialNumber:簽名者信息碳褒,根據(jù)簽名者的名稱找到證書(shū)鏈中對(duì)應(yīng)的證書(shū)折砸,使用證書(shū)中的公鑰即可驗(yàn)證簽名是否有效
- digestAlgorithm:哈希算法
- signedAttrs:需要簽名的屬性, 是可選項(xiàng),為空表示被簽名的數(shù)據(jù)是原始文件的內(nèi)容沙峻,如果不為空則至少要包含原始文件的類型以及其哈希值睦授,此時(shí)被簽名的數(shù)據(jù)就是signedAttrs的內(nèi)容
- signatureAlgorithm:簽名算法,這里指對(duì)哈希值進(jìn)行加密所使用的算法
- signature:加密后的哈希值
由于在Code Directory中已經(jīng)保存了所有資源及代碼的哈希值摔寨,那么我們只需要確保CodeDirectory不被篡改睹逃,即可確保整個(gè)app的完整性, 因此CMS Signature中只需要對(duì)CodeDirectory進(jìn)行簽名即可祷肯。而signedAttrs中支持這樣一種特性:可以先計(jì)算被簽名數(shù)據(jù)的哈希沉填,然后再對(duì)哈希值進(jìn)行簽名。聽(tīng)起來(lái)有點(diǎn)繞佑笋,不過(guò)仔細(xì)體會(huì)一下應(yīng)該不難理解翼闹。
我們把CodeDirectory的內(nèi)容摳出來(lái),計(jì)算其哈希值蒋纬,以第一個(gè)CodeDirectory為例猎荠,計(jì)算其sha1:
$ dd bs=1 skip=0xD334 count=0x1ED if=TestCodeSign 2>/dev/null | shasum -a 1
669421362b2f2b5303bcebb47d793a75a6bbd32f -
這個(gè)值叫做CDHash(Code Directory's Hash),對(duì)比前面從cms_signature中解析出的 signedAttrs蜀备,會(huì)發(fā)現(xiàn)這兩個(gè)值是一樣的关摇,也就是說(shuō)CodeDirectory的哈希值被放在了signerInfos->signedAttrs中,作為最終真正被簽名
(計(jì)算哈希并加密)的內(nèi)容碾阁。
至此输虱,我們已經(jīng)從頭到尾剖析了iOS代碼簽名的生成方式及數(shù)據(jù)結(jié)構(gòu),在這個(gè)過(guò)程中脂凶,至少存在4次計(jì)算哈希的行為宪睹,并且是環(huán)環(huán)相扣的
- _CodeSignature/CodeResources中對(duì)每個(gè)資源文件計(jì)算哈希
- Code Directory 中對(duì)MachO文件本身的每個(gè)分頁(yè),以及Info.plist蚕钦、CodeResources亭病、Entitlements等文件計(jì)算哈希
- CMS Signature的signedAttrs中對(duì)Code Directory計(jì)算哈希
- 對(duì)signedAttrs計(jì)算哈希并使用開(kāi)發(fā)者的私鑰加密
只有最后一步的哈希值是被加密的, 前面幾步的哈希值是否加密都不影響簽名的效果嘶居,只要任意內(nèi)容有變化罪帖,均會(huì)因某個(gè)環(huán)節(jié)的哈希不匹配而導(dǎo)致簽名校驗(yàn)的失敗。
jtool
相信上面的二進(jìn)制分析已經(jīng)讓你眼花繚亂了,不過(guò)已經(jīng)有大神做出了jtool這個(gè)工具整袁,它是一款強(qiáng)大的MachO二進(jìn)制分析工具菠齿,用來(lái)替代otool、nm葬项、segedit等命令泞当,也包括codesign的部分功能迹蛤。通過(guò)以下命令可以將代碼簽名解析為可讀的文本格式
$ jtool --sig -vv TestCodeSign
Blob at offset: 54016 (19888 bytes) is an embedded signature of 6686 bytes, and 5 blobs
Blob 0: Type: 0 @52: Code Directory (493 bytes)
Version: 20400
Flags: none (0x0)
CodeLimit: 0xd300
Identifier: test.CodeSign (0x58)
Team ID: xxxxxxxxxx (0x66)
Executable Segment: Base 0x00000000 Limit: 0x00000000 Flags: 0x00000000
CDHash: 669421362b2f2b5303bcebb47d793a75a6bbd32f (computed)
# of Hashes: 14 code + 5 special
Hashes @213 size: 20 Type: SHA-1
Entitlements blob: 19a92ca549e53593b384681245de14897df2a9dd (OK)
Application Specific: Not Bound
Resource Directory: fb7df05e17f3b347d6b64868f468def49feecf25 (OK)
Requirements blob: 9d58965211c9cd83b208fffd575d741881ff81e4 (OK)
Bound Info.plist: 89e1951413c3eb05fab8f6a5f06c13b48926eabe (OK)
Slot 0 (File page @0x0000): 9d452342f9ed06189e4f099bca7cb68d6432f775 (OK)
... [stripped]
... [stripped]
Blob 4: Type: 10000 @1862: Blob Wrapper (4824 bytes) (0x10000 is CMS (RFC3852) signature)
CA: Apple Certification Authority CN: Apple Root CA
... [stripped]
Time: 190122095805Z
Distribute App
在Xcode Organizer中導(dǎo)出或者提交App時(shí)民珍,Xcode會(huì)將Entitlements文件及embedded.mobileprovision文件替換為對(duì)應(yīng)的版本,并使用對(duì)應(yīng)的證書(shū)重新簽名盗飒,主要區(qū)別如下
類型 | Entitlements | Provisioning Profile | 證書(shū) |
---|---|---|---|
AppStore | 不可調(diào)試嚷量,推送為生產(chǎn)環(huán)境 | 無(wú)ProvisionedDevices | 發(fā)布證書(shū) |
Ad Hoc | 不可調(diào)試,推送為生產(chǎn)環(huán)境 | 允許安裝到已注冊(cè)的測(cè)試設(shè)備 | 發(fā)布證書(shū) |
Development | 可調(diào)試逆趣,推送為測(cè)試環(huán)境 | 允許安裝到已注冊(cè)的測(cè)試設(shè)備 | 開(kāi)發(fā)證書(shū) |
Enterprise | 不可調(diào)試蝶溶,推送為生產(chǎn)環(huán)境 | ProvisionAllDevices | 企業(yè)級(jí)發(fā)布證書(shū) |
本篇完。
下一篇:細(xì)說(shuō)iOS代碼簽名(四):簽名校驗(yàn)宣渗、越獄抖所、重簽名