IOS 逆向開發(三)應用簽名

孔雨露發表於2020-04-05

@[TOC](IOS 逆向開發(三)應用簽名)

1. 數字簽名

  • 什麼是數字簽名?
  1. 數字簽名(digitally signed):先舉個例子:老外喜歡用支票,支票上面的簽名能夠證明這玩意是你的.那麼數字簽名顧名思義,就是用於鑑別數字資訊的方法.這個是個很形象的說法。在IOS app的數字簽名:就是將原始資料通過Hash演算法得到原始的hash值,然後通過非對稱加密演算法RSA加密hash值,得到最終的加密資料,這個過程就叫做數字簽名。
  2. 數字簽名(又稱公鑰數字簽名、電子簽章等)是一種類似寫在紙上的普通的物理簽名,但是使用了公鑰加密領域的技術實現,用於鑑別數字資訊的方法。一套數字簽名通常定義兩種互補的運算,一個用於簽名,另一個用於驗證。
  3. 數字簽名,就是隻有資訊的傳送者才能產生的別人無法偽造的一段數字串,這段數字串同時也是對資訊的傳送者傳送資訊真實性的一個有效證明。
  • 想要證明數字資訊(也就是二進位制資料,計算機裡面的任意資料)的有效性,那麼使用什麼方式最合適呢?
  1. 在上一篇部落格“IOS 逆向開發(二)密碼學 HASH” 中有講到HASH演算法專門用來做檔案資料的識別.那麼在網路資料傳遞的過程中,我們可以將明文資料,和資料的HASH值一起傳遞給對方.對方可以拿出HASH值來進行驗證.
  2. 但是在這個過程中,如何做到資料的保護呢? 明文資料和HASH值如果直接傳遞就有都被篡改的風險.所以這裡我們要對資料進行加密.明文資料有時會比較大,不適合使用RSA非對稱加密演算法,那麼資料的HASH值是比較小的.這個資料是用於校驗的,它完全可以使用RSA來加密.
  3. 所以在資料傳遞的時候,我們將明文資料加上通過RSA加密的校驗資料一併傳遞給對方.那麼這個通過RSA加密的校驗資料,我們稱之為簽名.
  • 通過下圖,可以弄明白數字簽名是個什麼過程?

數字簽名

1.1 數字簽名過程:

  1. 首先傳遞資料時會將原始的資料和數字簽名一起傳送
  2. 對方拿到資料後,先進行校驗.拿到原始資料,通過同樣的HASH演算法得到資料的HASH值.
  3. 然後通過非對稱加密,將數字簽名中的校驗HASH值解密出來.
  4. 最後對比兩個HASH值是否一致.這樣可以很好的判斷資料是否被篡改!
    數字簽名驗證過程
  • 數字簽名驗證過程

數字簽名技術是將摘要資訊用傳送者的私鑰加密,與原文一起傳送給接收者。接收者只有用傳送者的公鑰才能解密被加密的摘要資訊,然後用Hash函式對收到的原文產生一個摘要資訊,與解密的摘要資訊對比。如果相同,則說明收到的資訊是完整的,在傳輸過程中沒有被修改,否則說明資訊被修改過,因此數字簽名能夠驗證資訊的完整性。

1.2 客戶端,伺服器簽名驗證過程:

  • 如果客戶端向伺服器發生資料時不做任何處理,可能會遭到中間人的竊取攻擊,後果如何嚴重就不說了。那麼我們如何防止中間人攔截,或者檢查資料是否被篡改呢?

    傳送資料

  • 直接用RSA(RSA加密原理)進行加密應該是不滿足我們的需求,RSA只適合對小資料進行加密,我們知道驗證資料的完整性可以用Hash(Hash概述)來驗證,可以對資料進行Hash,把Hash值和原始資料一起打包傳送給伺服器,伺服器將原始資料進行Hash,得到的hash值和客戶端傳送的Hash值做對比,如果一致則保證資料有效性。但是這樣會有安全隱患,如果中間人篡改了客戶端傳送的資料,當然也可以修改客戶端傳送的Hash值,所以這樣操作不可行。

  • 這時我們可以用RSA來對hash值進行保護,此時客戶端傳送原始資料,和經RSA加密後的該資料的hash值。

伺服器簽名驗證過程

  • 伺服器對RSA加密的資料進行解密,得到原始資料的hash值,接下來對原始資料進行通過同樣的Hash演算法,將得到的Hash值和解密後的Hash值做對比,如果一致則保證資料有效性,整個過程中,如果解密的Hash值和原始的Hash值不一致,或者無法解密RSA的資料,說明資料被篡改了。

  • 驗證資料是否被篡改的過程如下:

    驗證資料是否被篡改

2. 程式碼簽名

  • 什麼是程式碼簽名?

程式碼簽名: 是對可執行檔案或指令碼進行數字簽名.用來確認軟體在簽名後未被修改或損壞的措施。和數字簽名原理一樣,只不過簽名的資料是程式碼而已.程式碼簽名就是用來校驗我們的可執行檔案的

  • 作為IOS開發人員,為什麼需要理解程式碼簽名的原理?
  1. iOS工程師用於從本地計算機上安裝的Xcode部署iOS應用程式的日子已經一去不復返了。公司正在採用DevOps和CI / CD來構建軟體,因此所有構建都需要自動化,無需任何人工或GUI互動。
  2. 由於Xcode的程式碼簽名失敗,開發人員試圖通過重新生成和修復證照和配置檔案來修復程式碼簽名問題,因此浪費了數千個開發人員時間。
  3. 像Fastlane這樣的第三方工具使iOS開發人員更容易構建指令碼。然而,在Apple對底層技術進行更改後,Fastlane不斷破壞,開發人員花費數小時,數天和數週來修復損壞的部署指令碼。在某些情況下,工程師必須等到Fastlane實施新的更改。
  4. 如果您是iOS開發人員/工程師,並希望一生成為iOS工程師,那麼您無需瞭解這些內容。但是,如果您想在職業生涯中成長,那麼您必須詳細瞭解底層工具,技術和整個iOS生態系統。如果您不瞭解這些底層技術,無論您的iOS開發技能有多好,您都不會獲得iOS技術主管,iOS技術架構師或類似角色。作為技術架構師,您應該能夠快速修復程式碼簽名或類似的基礎架構相關問題,而無需依賴Xcode或其他第三方工具。

2.1 簡單的程式碼簽名

  • 程式碼簽名的產生背景
  1. 在iOS出來之前,以前的主流作業系統(Mac/Windows)軟體隨便從哪裡下載都能執行,系統安全存在隱患,盜版軟體,病毒入侵,靜默安裝等等.
  2. 那麼蘋果希望解決這樣的問題,要保證每一個安裝到 iOS 上的 APP 都是經過蘋果官方允許的.
  3. 要做到上述目的,就需要程式碼簽名。
  • 怎樣保證安裝的每一個APP都是經過蘋果官方允許的?
  1. 如果要實現驗證.其實最簡單的方式就是通過蘋果官方生成非對稱加密的一對公私鑰.
  2. 在iOS的系統中內建一個公鑰,私鑰由蘋果後臺儲存,我們傳APP到AppStore時,蘋果後臺用私鑰對APP資料進行簽名,
  3. iOS系統下載這個APP後,用公鑰驗證這個簽名,若簽名正確,這個APP肯定是由蘋果後臺認證的,並且沒有被修改過,也就達到了蘋果的需求:保證安裝的每一個APP都是經過蘋果官方允許的.

蘋果程式碼簽名

  • 整個過程很簡單,這樣就保證了蘋果安裝的每一個APP都是經過蘋果官方允許的。對於大部分普通使用者而言,這樣一個數字簽名就解決了安全隱患問題,但是實際上iOS裝置安裝APP並不是只有App Store這一個渠道,比如對於我們iOSer來說,我們在開發APP時還在真機除錯,當然蘋果還開放了企業內部分發的渠道,這時就無法通過簡單的程式碼簽名來滿足這些需求了。
  • 要實現這些要求,需要一種更好的機制,這就是接下來要講的雙向程式碼簽名技術

2.2 iOS的雙層程式碼簽名

  • 雙層程式碼簽名的產生背景
  1. 如果我們iOS裝置安裝APP只從App Store這一個入口這件事就簡單解決了,沒有任何複雜的東西,一個數字簽名搞定.
  2. 但是實際上iOS安裝APP還有其他渠道.比如對於我們開發者iOSER而言,我們是需要在開發APP時直接真機除錯的.而且蘋果還開放了企業內部分發的渠道,企業證照籤名的APP也是需要順利安裝的.
  3. 蘋果需要開放這些方式安裝APP,這些需求就無法通過簡單的程式碼簽名來辦到了.
  4. 蘋果爸爸使用雙層簽名技術來實現以下需求: (1)安裝包不需要上傳到App Store,可以直接安裝到手機上. (2)為了保證系統的安全性,又必須對安裝的APP有絕對的控制權 (3)經過蘋果允許才可以安裝 (4)不能被濫用導致非開發APP也能被安裝

2.2.1 雙層程式碼簽名原理

  • 首先這裡有兩個角色.一個是iOS系統 還有一個就是我們的Mac系統.因為iOS的APP開發環境在Mac系統下.所以這個依賴關係成為了蘋果雙層簽名的基礎.

  • 我們使用的xcode只需要有一個證照,就可以幫我們把ipa安裝到手機中。

  • xcode 在申請證照的時候,在Mac系統中生成非對稱加密演算法的一對公鑰\私鑰(你的Xcode幫你代辦了).這裡稱為公鑰M 私鑰M . M = Mac

Mac電腦的公鑰私鑰

  • 蘋果自己有固定的一對公私鑰,跟之前App Store原理一樣,私鑰在蘋果後臺,公鑰在每個iOS系統中.這裡稱為公鑰A , 私鑰A. A=Apple,

私鑰存放

  • 把公鑰M 以及一些你開發者的資訊,傳到蘋果後臺(這個就是CSR檔案),用蘋果後臺裡的私鑰 A 去簽名公鑰M。得到一份資料包含了公鑰M 以及其簽名,把這份資料稱為證照

證照生成

通過CSR檔案申請證照過程

  • 如上圖所示,證照雙向簽名驗證流程:
  1. 我們Xcode找蘋果伺服器去要證照,這個過程利用了一個csr檔案,其中這個csr檔案中有個核心的東西叫公鑰M 。xcode通過csr檔案將mac電腦裡的公鑰M 傳送給蘋果伺服器。
  2. 蘋果伺服器收到csr檔案後,對公鑰M進行簽名,也就是使用蘋果伺服器自己的私鑰A進行非對稱RSA加密。本身這個公鑰M就不大,所以不會很耗時。加密後就得到一個證照。這個證照就是被私鑰A加密過後的一個檔案,裡面包含公鑰M 。這個證照就是我們的開發者證照。
  3. Xcode通過Mac電腦上的私鑰M 對我們的app進行簽名。只要我們通過xcode 進行command + B 進行bulid就會有這麼一個過程。本地的私鑰m也就是我們的p12檔案。
  4. Xcode幫我們打包簽名的時候,會同時將證照一起打包。
  5. 在我們安裝ipa包的時候,蘋果會檢查證照,檢視證照的頒發機構是否是蘋果。如果不是蘋果頒發的證照,就不能安裝。
  6. iphone手機用證照裡面攜帶的蘋果伺服器給的公鑰A對ipa包裡面的證照進行解密。如果能夠成功解密,說明是蘋果頒發的證照,如果不是蘋果頒發的,則肯定無法進行解密。
  7. 接下來就需要驗證app,用公鑰A解密證照得到公鑰M。這樣用公鑰M就能對app進行驗證了。
  • 在開發時,編譯完一個 APP 後,用本地的私鑰 M(今後你匯出的P12) 對這個 APP 進行簽名,同時把第三步得到的證照一起打包進 APP 裡,安裝到手機上。

證照安裝

  • 在安裝時,iOS 系統取得證照,通過系統內建的公鑰 A,去驗證證照的數字簽名是否正確。

  • 驗證證照後確保了公鑰 M 是蘋果認證過的,再用公鑰 M 去驗證 APP 的簽名,這裡就間接驗證了這個 APP 安裝行為是否經過蘋果官方允許。(這裡只驗證安裝行為,不驗證APP 是否被改動,因為開發階段 APP 內容總是不斷變化的,蘋果不需要管。)

驗證證照

  • 雙層程式碼簽名總的流程圖

    雙層程式碼簽名總的流程圖

  • 上面的雙向程式碼簽名的過程,已經可以保證開發者的認證,和程式的安全性了。但是,你要知道iOS的程式,主要渠道是要通過APP Store才能分發到使用者裝置的,如果只有上述的過程,那豈不是隻要申請了一個證照,就可以安裝到所有iOS裝置了?

  • 上面的流程能驗證安裝的ipa是蘋果允許的,但是無法驗證ipa的安裝行為。

  • 為了防止濫用,蘋果再加了幾個限制,主要是通過描述檔案來限制安裝的裝置數量。

  • 接下來我們需要了解一下什麼描述檔案。

3. 描述檔案

3.1 描述檔案(Provisioning Profile)

  • 什麼是描述檔案?
  1. 蘋果官方Xcode對Provisioning Profile的解釋是解釋是:A provisioning profile is a collection of digital entities that uniquely ties developers and devices to an authorized iPhone Development Team and enables a device to be used for testing.
  2. 描述檔案(Provisioning profile)一般包括三樣東西:證照、App ID、裝置。當我們在真機執行或者打包一個專案的時候,證照用來證明我們程式的安全性和合法性 Provisioning Profile在這裡就起到了一個對裝置和開發者授權的作用,他將開發者賬號、證照、entitlements檔案以及裝置進行了繫結。
  3. 在開發過程中,Xcode 8及後續版本預設情況下會自動幫我們管理Provisioining Profile,自動下載的Provisioning Profile都被存放在~/Library/MobileDevice/Provisioning\ Profiles/路徑下,以UUID格式命名。直接拖拽下圖中的齒輪圖示到Finder中也可以將其複製出來。
  • 前面我們講到了,通過簡單的程式碼簽名的方式,是無法解決蘋果的安全需求的,那麼蘋果是如何做到防止申請一個證照可以安裝到所有裝置上這個問題的呢?
  1. 蘋果加了兩個限制: (1)在蘋果後臺註冊過的裝置才可以安裝. (2)簽名只能針對某一個具體的APP.
  2. 蘋果還想控制App裡面的iCloud/PUSH/後臺執行/偵錯程式附加這些許可權,所以蘋果把這些許可權開關統一稱為Entitlements(授權檔案).
  3. 此外蘋果將這個Entitlements檔案放在了一個叫做**Provisioning Profile(描述檔案)**檔案中.描述檔案是在AppleDevelop網站建立的(在Xcode中填上AppleID它會代辦建立),Xcode執行時會打包進入APP內.
  4. 作為IOS開發者都知道一個規則:使用CSR申請證照時,我們還要申請一個東西: 就是描述檔案
  • 在xcode工程裡面,我們要真機除錯肯定需要通過xcode從蘋果伺服器下載描述檔案,如下圖:

    Xcode檔案中的描述檔案

  • 描述檔案除了包含appid等資訊外,還包含了蘋果伺服器用私鑰A加密的證照,證照裡面含有mac傳給伺服器的公鑰M .

  • 生成描述檔案的流程

生成描述檔案的流程

  • 生成的這個描述檔案裡面就是 可以安裝的裝置有哪些.. APP的ID是什麼.. 許可權是些什麼!
  • 在開發時,編譯完一個 APP 後,用本地的私鑰M對這個APP進行簽名,同時把從蘋果伺服器得到的 Provisioning Profile 檔案打包進APP裡,檔名為embedded.mobileprovision,把 APP 安裝到手機上.

通過CSR檔案申請證照流程

  • 我們可以利用$security cms -D -i embedded.mobileprovision命令檢視Provisioning profile內容,這些Xcode建立的Profile檔案都存放在~/Library/MobileDevice/Provisioning Profiles/目錄下

命令列檢視描述檔案
描述檔案存放路徑

  • 我們可以通過MachOView檢視我們mach-o可執行檔案
    code Signature
  • 我們可以在終端用 security cms -D -i + [名稱]命令檢視描述檔案裡面的資訊,我們會發現,描述檔案是一個plist檔案

描述檔案內容1

  • 上述紅框裡面的就是可執行檔案的

    描述檔案內容2

  • 從上面分析可以看出描述檔案是一個xml格式的plist檔案,下面我們對關鍵一些屬性做一些說明。

  • DeveloperCertificates: 允許使用的開發者證照,這是一個列表,一般包含生成這個Provisioning Profile檔案時,當前開發者賬號下所有有效的Development證照,以base64格式儲存,使用base64解碼之後就可以得到DER格式的開發者證照。通過計算每個證照的sha1值,可以看出,前文中新申請的證照,就在這個列表中

  • Entitlements: 允許使用的許可權列表,實際在App中使用的許可權必須是這個列表的子集,否則安裝時會無法通過校驗而失敗。如果曾經開啟過某個功能,Xcode自動更新了Provisioning Profile,後來又關閉它,Xcode並不會將其從Provisioning Profile中刪去,如上圖中的com.apple.developer.team-identifier。

  • ProvisionedDevices: 允許安裝的裝置列表,如果目標裝置的UUID不在這個列表中,會安裝失敗。對於這一項,普通開發者證照和企業級開發者證照的待遇是不同的。普通開發者證照使用Provisioning Profile的方式安裝App到裝置,只是出於測試和除錯的需要,因此Apple只允許最多註冊100臺用於測試的裝置,否則開發者就可以以測試的名義任意任意分發自己的App了。而對於企業級開發者來說,本身就有任意安裝的需求,因此在分發時,這一項會被ProvisionsAllDevices取代,代表授權任意裝置。

  • 這些資訊中有任何變動的時候,比如開發者證照有新增或者失效,在Capabilities中啟用了當前App從未使用過的新功能,或是將新的iPhone連線到Xcode用於測試,Xcode都會自動重新申請Provisioning Profile。

  • 每次我們新建專案其實會生成一個描述檔案,選擇執行到手機上, 我們只需要編譯一下,在APP包裡面就可以看到.

  1. Provisioning Profile會被內建在App中,置於App根目錄下的embedded.mobileprovision。安裝App時如果簽名校驗通過,這個檔案會自動被拷貝到iOS裝置的/Library/MobileDevice/Provisioning\ Profiles/路徑下。由於該檔案已被Apple官方簽名,系統可以無條件信任它,並用它來校驗App的簽名、許可權,以及本機的UUID等是否滿足來自官方的授權。通過這種方式,間接信任了使用開發者證照籤名的App,讓iOS裝置可以執行非蘋果官方簽名的App。
  2. 假如你有一臺越獄的裝置,檢視任意一個從AppStore上下載下來的App,裡面都不會有embedded.mobileprovision這個檔案,因為經過Apple重新簽名以後,裝置就不再需要它了。

描述檔案每次執行都生成

  • 其實我們開發過程中經常接觸到程式碼簽名,只是我們都是通過xcode幫我們自動完成了這些工作,所以一般對程式碼簽名的原理不是很熟悉。

  • 回想一下,當我們完成開發後,會使用 Xcode 的 Archive(存檔) 的功能進行打包,當我們點選了 Archive 以後,Xcode 就會對我們的程式碼進行編譯和連結,最終產生一個字尾為.app檔案(嚴格意義上來說這是一個資料夾,是 Mac 上的包檔案,終端裡頭是把這個檔案當做資料夾對待的)。然後 Xcode 會把對應的mobileprovision檔案拷貝到 APP 檔案中(這個檔案就是我們在前面配置 provision profile 後下載下來的檔案),這一步的詳情可以在 Archive 的 log 中的『Process product packaging』這一步中看到;再之後,Xcode 會使用codesign這個命令對 APP 檔案進行簽名。

  • 如果我們有多個 Signing Identity,我們也可以在工程『Build Settings』選項中進行配置

  • 一個沒有被簽名的 APP 檔案的結構類似這樣:

    未簽名的app結構

  • codesign 在對 APP 檔案進行簽名的時候,會把對應的簽名直接新增到二進位制檔案的內部,而針對資原始檔則是利用一個叫做 『CodeResources』的 plist 檔案把對應的資原始檔和數字簽名進行記錄。簽名結束後的 APP 檔案的內容如下:

簽名後的app結構

  • 完成簽名後,我們可以使用 Xcode 打包生成對應的 ipa ,方便之後安裝到裝置上。

  • 此外,我們可以通過Xcode來檢視內容:

    描述檔案內容

  • Provisioning profile本身也是通過簽名認證的,所以別想著你可以更改裡面的東西來達到擴充許可權\裝置的目的.只有老老實實的去網站向Apple申請一份許可權更多\裝置更多的profile。

3.2 授權檔案(Entitlements)

Entitlements 沙盒(Sandbox)技術是iOS安全體系中非常重要的一項技術,他的目的是通過各種技術手段限制App的行為,比如可讀寫的路徑,允許訪問的硬體,允許使用的服務等等,即使應用出現任意程式碼執行的漏洞,也無法影響到沙盒外的系統。

在這裡插入圖片描述
通常所說的Entitlements(授權檔案),也就是指iOS沙盒的配置檔案,這個檔案中宣告瞭app所需的許可權,如果app中使用到了某項沙盒限制的功能,但沒有宣告對應的許可權,可能執行到相關的程式碼時會直接Crash。 全新的iOS工程中是沒有這個檔案的,如果在Capabilities中開啟了一些需要許可權的功能之後,Xcode會自動(Xcode 8及之後的版本)生成Entilements檔案,並將對應的許可權宣告新增到Entitlements檔案中。
Xcode中檢視授權檔案

  • 這個檔案其實是xml格式的plist檔案,內容如下
<?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>
<!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;>
<plist version=&quot;1.0&quot;>
<dict>
  <key>inter-app-audio</key>
  <true/>
</dict>
</plist>
複製程式碼
  • 實際上,這個檔案的內容並非是全部的授權內容,因為預設狀態下,App預設會包含以下與Team ID及App ID相關的許可權宣告:
<dict>
    <key>keychain-access-groups</key>
    <array>
        <string>xxxxxxxxxx.*</string>
    </array>
    <key>get-task-allow</key>
    <true/>
    <key>application-identifier</key>
    <string>xxxxxxxxxx.test.CodeSign</string>
    <key>com.apple.developer.team-identifier</key>
    <string>xxxxxxxxxx</string>
</dict>
複製程式碼
  • 其中get-task-allow代表是否允許被除錯,它在開發階段是必需的一項許可權,而在進行Archive打包用於上架時會被去除。
  • 進行程式碼簽名時,會將這個Entitlements檔案(如有)與上述預設內容進行合併,得到最終的授權檔案,並嵌入二進位制程式碼中,作為被簽名內容的一部分,由程式碼簽名保證其不可篡改性。

4. 簽名資料存放

  • App 的簽名資料儲存分兩部分:
  1. Mach-O 可執行檔案會把簽名直接寫入檔案裡
  2. 其他資原始檔則會儲存在 _CodeSignature 目錄下在APP包裡。
  • Mach-O 可執行檔案會把簽名直接寫入檔案裡
    通過MachOView檢視Mach-O檔案
  • 其他資原始檔則會儲存在 _CodeSignature 目錄下在APP包裡。

_CodeSignature 目錄下簽名資源

5. IOS 證照檔案

5.1 證照檔案相關概念

  • 證照: 內容是公鑰或者私鑰,由認證機構對其簽名組成的資料包!我們開發可以使用鑰匙串訪問看到.
  1. 證照分兩種:開發者證照、釋出者證照。前者開發時使用,後者釋出使用.
  2. 模擬器除錯無需程式碼簽名;真機除錯需開發者證照程式碼簽名;釋出時需釋出證照籤名
  3. 程式碼簽名需要:證照+私鑰,缺一不可
  4. 真機除錯時要求在裝置上安裝描述檔案(provision profile),該檔案包含資訊:除錯者證照,授權除錯裝置清單,應用ID。一個應用對應一個描述檔案.
  5. 開發者證照按用途可分為Development證照和Distribution證照: (1) Development證照是用於開發及測試階段使用的證照,它用於在裝置安裝上開發階段的App後對App的完整性進行校驗,一般證照名稱為 iPhone Developer: xxxxxxx。如果是多人協作的開發者賬號,任意成員都可以申請自己的Development證照。 (2) Distribution證照是用於提交AppStore的證照,一般命名為 iPhone Distribution: xxxxxxxxx,用於讓AppStore校驗提交上來的App的完整性,只有管理員以上身份的開發者賬號才可以申請,因此可以控制提交許可權的範圍。同時,Distribution證照不能用於開 發及除錯。
  6. 企業級開發者證照: 除了普通開發者證照(個人開發者賬號和公司開發者賬號使用的證照)外,還有一種特殊的企業級開發者證照,這種證照籤名的App可以被直接安裝在任意的iOS裝置上,只要使用者主動信任該證照即可。它的作用是方便企業給內部員工分發生產力工具,比如往往存在這樣一些場景:企業內部無法訪問網際網路,自然也就無法通過AppStore安裝應用,或是使用私有API,完成一些AppStore不允許的功能。前面所說的不需要蘋果簽名即可安裝執行的機制同樣適用於企業級開發者證照,並且是企業級開發者證照的基礎。
  • P12: 就是本地私鑰,可以匯入到其他電腦

  • Entitlements: 許可權檔案,包含了APP一些許可權的plist檔案

  • CertificateSigningRequest: CSR檔案包含了本地公鑰的資料檔案

  • Provisioning Profile: 描述檔案,包含了證照/Entitlements等資料,並由蘋果後臺私鑰簽名的資料包.

  • 團隊開發中如何共用證照?

  1. 團隊開發中,需要共享證照檔案和私鑰。若僅從provisioning portal下載證照檔案而無私鑰,xcode會提示出錯:Unable to code design using identities in this team: no private keys available(無法在團隊中進行程式碼簽名:找不到有效的私鑰)。 解決辦法: (1) 開啟鑰匙串程式,選擇 ‘祕鑰’ 種類。 (2) 右鍵點選(或按住control點選)與開發證照相配套的私鑰(專用金鑰),並點選 ‘匯出’,儲存為Personal Information Exchange (.p12) 檔案格式.,將提示你建立一個密碼,並需要管理員密碼才可匯出。 (3) 拷貝該p12檔案到其他機子上,會提示你輸入上一步輸入的密碼。

5.1.1 證照相關資源

  • 鑰匙串程式(常用工具->鑰匙串),用於建立證照請求、安裝證照、匯出私鑰等

  • IOS開發中心:developer.apple.com/devcenter/i…

  • IOS描述門戶(IOS provisioning Portal),在此配置證照、描述檔案、推送服務等:

developer.apple.com/ios/manage/…

5.2 開發證照生成流程

5.2.1 生成證照

  • 第 1 步:對應的是 keychain 裡的 “從證照頒發機構請求證照”,這裡就本地生成了一對公私鑰,儲存的 CertificateSigningRequest 裡面就包含公鑰,私鑰儲存在本地電腦裡.
    儲存的 CertificateSigningRequest

這個操作會產生一個名為CertificateSigningRequest.certSigningRequest 的簽名請求檔案,在生成這個檔案之前其實Keychain已經自動生成了一對公、私鑰

可以在Keychain中選中這個條目,右鍵選擇匯出,將金鑰檔案匯出為p12檔案,使用openssl檢視其內容

$ openssl pkcs12 -in JustForTesting.p12 -out private_key.pem  # 匯出p12檔案中的金鑰
Enter Import Password:    # 輸入p12檔案的密碼
MAC verified OK
Enter PEM pass phrase:    # 設定匯出的金鑰檔案的密碼
Verifying - Enter PEM pass phrase:    # 確認密碼
$ openssl rsa -in private_key.pem -noout -text  # 檢視金鑰檔案的內容
Enter pass phrase for private_key.pem:   # 輸入金鑰檔案的密碼
Private-Key: (2048 bit)
modulus:
    00:c2:98:f5:02:eb:dc:a6:fd:4b:12:4c:70:17:a6:
    xx:xx:xx:xx:xx:xx:xx:...
publicExponent: 65537 (0x10001)
privateExponent:
    00:a1:67:68:e1:51:6c:a4:fd:36:45:29:2d:58:10:
    xx:xx:xx:xx:xx:xx:xx:...
prime1:
    00:f3:91:5d:5b:dc:c1:de:d2:ab:7a:5f:b2:27:41:
    xx:xx:xx:xx:xx:xx:xx:...
prime2:
    00:cc:87:b5:c9:7e:81:39:94:13:c1:ff:3f:d7:7b:
    xx:xx:xx:xx:xx:xx:xx:...
exponent1:
    00:a5:a0:22:c0:f5:d3:eb:86:8c:4e:b1:c6:3e:85:
    xx:xx:xx:xx:xx:xx:xx:...
exponent2:
    00:8b:e1:00:85:a6:7c:10:79:e2:2d:5a:39:3a:51:
    xx:xx:xx:xx:xx:xx:xx:...
coefficient:
    7e:30:60:84:fc:47:6b:90:fe:e7:32:1a:2f:b0:c4:
    xx:xx:xx:xx:xx:xx:xx:...
複製程式碼

prime1/prime2 就是生成金鑰所使用的兩個超大的素數p, q modulus 是這兩個超大素數的乘積 n = p * q publicExponent 是公鑰因子,也就是前文中的e, 這裡固定為 0x10001 (65535) privateExponent 是私鑰因子,即前文中的d

CSR檔案的內容其實就是個人資訊、公鑰(Modulus + PublicExponent),以及自簽名(使用自己的私鑰進行簽名), 可通過openssl命令檢視其內容:

$ openssl req -in ~/Desktop/CertificateSigningRequest.certSigningRequest -text -noout
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: emailAddress=me@xelz.info, CN=JustForTesting, C=CN
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:c2:98:f5:02:eb:dc:a6:fd:4b:12:4c:70:17:a6:
                    xx:xx:xx:xx:xx:xx:xx:...
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: sha256WithRSAEncryption
         b7:11:aa:48:2f:b3:10:e9:71:c7:93:c3:ec:44:8d:0f:a0:5a:
         xx:xx:xx:xx:xx:xx:xx:...
複製程式碼
  • 第 2 步: 向蘋果申請對應把 CSR 傳到蘋果後臺生成證照.

在蘋果開發者網站,將CSR提交給Apple進行簽名,Apple會返回一個簽好名的證照檔案,字尾名為cer。

先檢視一下他的sha1值

$ shasum ios_development.cer
11447116f2c5521b057b9b67290f0fdadeadfa0a  ios_development.cer
複製程式碼

雙擊即可將其匯入到Keychain中,Keychain會自動把它之前建立CSR時自動生成的金鑰歸為一組。無論是在證照列表中檢視還是在金鑰列表中檢視,都能看到與之匹配的另一半。

檢視證照

證照資訊

可以從證照中得到幾個關鍵資訊:

  1. 證照的所有者,這部分資訊並非由我們自行指定,而是簽發者Apple根據我們的賬號資訊自動生成
  2. 證照的簽發者,即前文所述的CA
  3. 證照的公鑰資訊,與之前生成的金鑰檔案及CSR完全一致

現在應該可以理解證照和金鑰的關係了,金鑰中儲存了私鑰和公鑰,私鑰用於簽名,而證照裡面有且只有公鑰,並且是被第三方CA “認證” 過,用於解密和校驗。

Root CA
圖中可以看到這個證照的簽發者是Apple Worldwide Developer Relations Certification Authority,在Keychain中搜尋這個名字, 可以看到它的證照詳情。我們會發現,它的型別是中級證照頒發機構(中級CA),它也包含簽名,並且是由另外一個叫做Apple Root CA的根證照頒發機構(根CA)進行簽發的,這樣就形成了一條證照鏈。而繼續檢視Apple Root CA的證照,會發現它是自簽名的,因為它會被內建在裝置中,裝置無條件信任它,也就不需要其他的機構為其背書了。

這樣的證照鏈機制可以簡化根證照頒發機構的工作,同時提升證照管理的安全性。將頒發底層證照的工作分散給多箇中級證照頒發機構進行處理,根證照頒發機構只需要對下一級機構的證照進行管理和簽發,降低根證照頒發機構私鑰的使用頻率,也就降低了私鑰洩露的風險。中級證照頒發機構各司其職,即使出現私鑰洩露這樣的重大安全事故,也不至於波及整個證照網路。

  • 第 3 步:證照下載到本地.這時本地有兩個證照.一個是第 1 步生成的私鑰,一個是這裡下載回來的證照,keychain 會把這兩個證照關聯起來,因為他們公私鑰是對應的,在XCode選擇下載回來的證照時,實際上會找到 keychain 裡對應的私鑰去簽名.這裡私鑰只有生成它的這臺 Mac 有,如果別的 Mac 也要編譯簽名這個 App 怎麼辦?答案是把私鑰匯出給其他 Mac 用,在 keychain 裡匯出私鑰,就會存成 .p12 檔案,其他 Mac 開啟後就匯入了這個私鑰.

  • 第 4 步:都是在蘋果網站上操作,配置 AppID / 許可權 / 裝置等,最後下載 Provisioning Profile 檔案。

  • 第 5 步: XCode 會通過第 3 步下載回來的證照(存著公鑰),在本地找到對應的私鑰(第一步生成的),用本地私鑰去簽名 App,並把 Provisioning Profile 檔案命名為 embedded.mobileprovision 一起打包進去。所以任何本地除錯的APP,都會有一個embedded.mobileprovision(描述檔案)從App Store下載的沒有.

參考:www.jianshu.com/p/3c9e2055a… segmentfault.com/p/121000001…

相關文章