
先週、私はチームで「学習報告」を行いました。実際には、チームで毎週行われる技術共有の一環で、誰もが機会を持つことができます。今回は私の番でした。では、チームの新人として、何を話すべきでしょうか?
考えを巡らせていると、以前からよく遭遇していた厄介な問題を思い出しました:実機で iOS プロジェクトを実行する際、プロジェクトがまだ起動していないのに、プロジェクト設定の署名(Targets > Signing & Capabilities)でエラーが出ることです。自分のプロジェクトでも、サードパーティのオープンソースライブラリでも、会社のプロジェクトでも同様です。
毎回 Google や同僚に尋ねれば答えを見つけることができましたが、なぜそれが解決できるのか、またなぜ実機で iOS プロジェクトを実行するために署名が必要なのか、自分ではそれらを半分理解しているだけで、混乱していました。
しかし、今ではその背後にある秘密を理解しました!もしあなたも同じような疑問を抱えているなら、読み進めてください。今回はあなたがそれを完全に理解できるように保証します ——iOS 署名の背後にある原理!
本文の目標#
この記事を読み終えると、以下の問題を簡単に解決できる能力を持つことができます:
- 実機で自分の iOS プロジェクトや iOS オープンソースライブラリを実行するにはどうすればよいですか?
 - 実機で会社の iOS プロジェクトを実行するにはどうすればよいですか?
 
さらに、この記事の最終目標は、iOS 署名に関連する問題に直面したときに、迅速に解決できるようになることです。
前提知識:デジタル署名 & デジタル証明書#
iOS 署名について話す前に、インターネットの世界における署名✒️と証明書📄についての 2 つの前提知識を理解する必要があります。
参考:デジタル署名とデジタル証明書とは?—— 阮一峰
デジタル署名#
デジタル署名は、送信されるデータに添付され、データの改ざんを防ぐために使用されます。
その基盤となるコアはハッシュ混乱アルゴリズムと非対称暗号技術(公開鍵 / 秘密鍵)です。
生成#
署名 Signature の生成は、通信中の送信者 Sender によって行われます。まず、送信するデータ Data に対してハッシュ Hash 混乱を行い、データの要約 Digest を得ます。その後、秘密鍵 Private Key で要約を暗号化し、これによりデータの署名が生成されます。

検証#
受信者 Receiver は、送信者からのデータと署名を受け取り、それぞれ次のように処理します:
- データ:送信者と同じハッシュアルゴリズムを使用してデータを混乱させ、データの要約 A を得ます;
 - 署名:送信者が使用した秘密鍵に対応する公開鍵 Public Key を利用して署名を復号し、データの要約 B を得ます。
 
要約 A と要約 B を比較し、等しい場合はデータが改ざんされていないことを示し、そうでない場合はデータに問題があることを示します。

署名の生成と検証のプロセスは、以下の図のようにまとめられています。自分で再分析することで理解を深めることができます。

問題を持って読み進めましょう:
Q1: iOS 署名と検証のプロセスを推測してみてください。アプリ開発者とアプリ使用者の中で、誰が送信者で、誰が受信者ですか?伝送されるデータは何ですか?
A1: アプリ開発者が送信者で、アプリ使用者が受信者です。伝送されるデータはアプリのインストールパッケージです。
Q2: 受信者はどのように復号に使用する公開鍵を取得するのですか?
このまま読み進めてください。
デジタル証明書#
デジタル証明書について理解する前に、送信者がデータと署名を送信する際に公開鍵を添付すれば、すべてが整うのではないかと思うかもしれません~以下の図のように:

しかし、これには新たな問題が生じます:
Q1: 受信者はどのようにして公開鍵が他の人によって悪意を持って置き換えられていないことを確認するのですか?つまり、公開鍵の身元が不明です。
この時、デジタル証明書が登場します。
構成内容#
デジタル証明書の構成内容を見てみましょう。証明書は、公開鍵、公開鍵の身元情報 Identity Info、およびそれらの署名 B で構成されています。

注意:暗号化された公開鍵データに使用される秘密鍵は、別の公開鍵 / 秘密鍵の組み合わせであり、権威ある認証機関(Certificate Authority、CA)によって発行されます。
公開鍵はデジタル証明書の中で伝送される#
これにより、送信者が送信する内容はデータ + 署名 +公開鍵から、データ + 署名 +証明書に変わります。

証明書には、受信者が署名 A を復号するために必要な公開鍵が含まれています。さらに、証明書には公開鍵の身元情報と署名 B も含まれています:
- 身元情報が存在することで、公開鍵の身元不明のリスクを排除できます;
 - そして、署名 B は公開鍵およびその身元情報が改ざんされていないことを保証します。
 
しかし、署名 B があるため、公開鍵を取得する際には、まず証明書内の署名 B を検証する必要があります:

注意:証明書内の署名 B を復号するために使用される公開鍵も CA によって発行されており、CA 証明書に存在します。
今、あなたは証明書の構成内容を覚えていると思います:公開鍵 + 公開鍵の身元情報 + それらの署名。
問題を持って読み進めましょう:
Q1: 受信者はこの CA 証明書をどこから取得するのですか?受信者はどのようにしてこの CA 証明書の署名を検証するのですか?無限ループに入ってしまったようです♻️。
このまま読み進めてください。
証明書の信頼チェーン#
CA 証明書は一般的にシステム / ソフトウェアをインストールする際に内蔵されており、私たちはそれを信頼するべきでしょう~
次に、証明書の信頼チェーンについて理解を深めましょう。
証明書が信頼チェーン内で占める位置に基づいて、証明書は 3 種類に分けられます:
- ルート証明書 Root Certificate(参考:Apple のオペレーティングシステムで利用可能な信頼されたルート証明書——Apple 公式)
 - 中間証明書 Intermediate Certificate
 - リーフ証明書 Leaf Certificate
 
例:私の開発者証明書 A(Apple Development)は、中間証明書 B(Apple Worldwide Developer Relations Certification Authority、Xcode インストール時に内蔵)の CA によって発行され、中間証明書 B はルート証明書 C(Apple Root CA、システム内蔵)の CA によって発行され、ルート証明書 C は自分の CA によって発行されています。C は信頼チェーンの頂点にあるため、自分で決定します。

前の質問に戻ります:この CA 証明書が信頼できることをどのように保証しますか?受信者が発行者の証明書を持っていれば、証明書内の公開鍵を使用して検証すればよいのです。たとえば、iPhone が私の開発したアプリをインストールする際、私の開発者証明書 A を受け取ると、携帯電話は発行者の証明書 B(Apple Worldwide Developer Relations Certification Authority、iOS システム内蔵)を探して A が信頼できるかどうかを検証します。
今、あなたは自分の Mac > キーチェーン Keychain ソフトウェア > 証明書 Certificates を見て、理解を深めることができます。
問題を持って読み進めましょう:
Q1: 暗号化された公開鍵およびその身元情報に使用される CA 秘密鍵は私たちのコンピュータにローカルにありますか?もしそうでない場合、どのようにして私たちの証明書を生成するのですか?
iOS 証明書申請原理 & 申請方法#
もちろん、そうではありません。これらの秘密鍵は CA が証明書を発行するための秘密の宝物です。たとえば、iOS 開発者証明書を申請したい場合、Apple 公式に助けを求める必要があります。Apple 公式は、上記で言及した中間証明書 CA の秘密鍵を使用して証明書を発行します。
申請原理#
自分の iOS 開発者証明書を申請するには、以下のステップに分かれます:
- 自分のコンピュータで公開鍵と秘密鍵のペアを生成し、公開鍵と秘密鍵の身元情報を記入します;
 - 公開鍵とその身元情報を Apple CA に送信します;
 - CA はハッシュアルゴリズムと CA 秘密鍵を使用してデータ(公開鍵とその身元情報)に署名し、データと署名が私たちが望む証明書を構成します;
 - 私たちは CA から証明書をダウンロードし、証明書をインストールすると、コンピュータは自動的に対応する秘密鍵を関連付けます。
 

申請方法:2 種類#
具体的な申請方法は 2 つあります:1)CSR (CSR, Certificate Signing Request) ファイルをアップロードする方法、2)Xcode による自動申請方法、ここでは後者を推奨します。
1)CSR ファイルをアップロードする方法#
この方法は、iOS 証明書申請の原理を理解したいあなたに適しています。注意:この方法ではApple 開発者プログラムに参加する必要があります、$99 / 年。
a) キーチェーンを開き、Certificate Assistant > Request a Certificate From a Certificate Authority... を選択します:

b) 身元情報(メールアドレス、証明書名)を入力し、ローカルに保存することを選択できます。これにより、公開鍵とその身元情報を含む CSR (.certSigningRequest) ファイルが得られます。

あなたは、秘密鍵はどこにあるのかと尋ねるかもしれません。もしあなたが注意深ければ、キーチェーン > login > Keys の中に、あなたが命名した公開鍵と秘密鍵のペアがすでに追加されていることに気づくでしょう。
c) Apple Developerのウェブサイトにログインし、Certificates, Identifiers & Profiles セクションに入り、先ほど生成した CSR ファイルをアップロードすることで証明書(.cer ファイル)を生成できます。この時、証明書をローカルにダウンロードし、ダブルクリックすることでキーチェーンにインポートできます。キーチェーン > login > My Certificates の中にその証明書が表示されます。

もしあなたが注意深ければ、キーチェーン内のその証明書はすでに秘密鍵とバインドされていることに気づくでしょう。他の開発者と証明書を共有したい場合は、右クリックして私たちがよく知っている.p12 ファイルをエクスポートする必要があります。これには証明書と対応する秘密鍵が含まれています~
2)Xcode による自動申請方法(推奨)#
この方法では、面倒な CSR ファイルのアップロードや.cer 証明書のダウンロードプロセスは必要なく、Apple 開発者プログラムに参加することも強制されません。
a) Xcode で Apple アカウントにログインします:Xcode > Preference > Account > Apple IDs > 「+」。

b) ログインしてしばらくすると、キーチェーンに自動的に対応する証明書が追加されているのがわかります。

注意:開発者プログラムに参加している場合、Apple 開発者ウェブサイトにも自動的にその証明書が追加されます。
iOS 署名 & パッケージング原理#
ついに iOS 署名の部分に来ました。前の内容は理解できましたか?もしまだ少し混乱しているなら、署名の役割は伝送データの改ざんを防ぐことであることを覚えておけば、この記事の真髄を基本的に把握したことになります!
実際には、iOS 署名を行う際には、証明書(公開鍵)を追加するだけではなく、証明書に対してもう一層の包装が必要です。それが私たちがよく知っている Provisioning Profile ファイルで、PP ファイル、プロファイル、供給設定ファイルとも呼ばれます。
PP ファイル#
この重要な PP ファイルについて理解しましょう。これを証明書のアップグレード版と考えることができます。
生成方法#
- 開発者プラットフォームで申請;
 - Xcode が自動生成:Xcode > Targets > Signing & Capabilities > Automatically manage signing をチェック。
 
ファイル構造#
- App ID:
- Apple 開発者プラットフォームで登録;または Xcode > Targets > Signing & Capabilities で記入した Bundle ID に基づいて自動生成されます。
 - Xcode > Targets > Signing & Capabilities で記入した Bundle Identifier は、App ID と一致またはマッチする必要があります。
 
 - Entitlements:
- 使用を許可された権限のリスト。実際にアプリで使用される権限はこのリストのサブセットでなければならず、Xcode > Targets > Signing & Capabilities で追加した Capabilities はその範囲を超えてはなりません。
 - プロジェクトディレクトリにも.entitlements ファイル(権限ファイル)があり、これは Xcode > Targets > Signing & Capabilities で追加した Capabilities に基づいて自動生成されます。アプリがサンドボックス制限の機能を使用している場合、その.entitlements ファイルに対応する権限が宣言されていないと、アプリが関連するコードに到達したときに直接クラッシュします。
 
 - Certificates:iOS 開発者証明書で構成され、複数存在することができます。これらは上記で申請した iOS 証明書です。
 - Devices:iOS デバイスの UDID(Unique Device Identifier)で構成されたリストで、アプリの開発とデバッグが可能な iOS デバイスを制限します。
 - Signature:PP ファイル生成時に Apple CA によって署名され、改ざんを防ぎます。
 
例#
PP ファイルはデフォルトで~/Library/MobileDevice/Provisioning\ Profilesに保存されます。
以下は Xcode が自動生成した PP ファイルのプレビューです:

署名 & パッケージング#
iOS 署名とパッケージングプロセスは実際には Xcode によって制御されます。以下の図を見てください:

- まず、Xcode はアプリ内のバンドル ID が PP ファイル内の App ID と一致しているか、アプリ内の Entitlements (.entitlements) ファイルで宣言された権限が PP ファイル内の Entitlements で許可されている範囲内にあるかを確認します。どちらか一方が否の場合、チェックは通りません;
 - 次に、Xcode はコンピュータのキーチェーン内で、PP ファイル内の Certificates に証明書が一致するかどうかを探します。一致した場合のみ次のステップに進みます;
 - その後、Xcode は一致した証明書が対応する秘密鍵にバインドされているかどうかを確認します。もしそうでなければ、次の重要なステップである署名を行うことができません;
 - さあ、ハッシュアルゴリズムと秘密鍵を使用してアプリに署名を開始します;
 - 最後に、アプリ、PP ファイル、および署名をパッケージ化し、.ipa パッケージを生成します。
 
⚠️:上記では署名 C と署名 A の検証プロセスを省略しています。第 1 ステップで PP ファイルを使用する前と第 2 ステップで証明書が一致した後に、CA 公開鍵を使用してそれに付随する署名 C と A を検証する必要があります。改ざんを防ぐためです。誤りがあれば、指摘してください。
延長問題:
Q1: Xcode はアプリのどの内容に署名を行いますか?
A1: すべての内容です。しかし、署名プロセスは非常に複雑で、ここでは詳細には触れません。簡単に言えば、署名の安全性と効率を考慮して、アプリの署名は 4 回のハッシュと 1 回の暗号化に分かれています。各ハッシュは連鎖的に結びついており、アプリの内容が改ざんされていないことを保証します。

具体的には、iOS コード署名の詳細(3):署名プロセスとコード署名のデータ構造を参照してください。
iOS 検証原理#
iOS 署名について話した後、実機がアプリの署名をどのように検証するのかを見てみましょう。
まず、アプリのインストールパッケージはテストパッケージと正式パッケージに分かれ、両者の検証プロセスは異なります。
テストパッケージと正式パッケージの知識を補足します:
1)テストパッケージ:内部テストパッケージ、App Store にアップロードするためのリリースパッケージ、Ad Hoc リリースパッケージ、In-house 企業内部リリースパッケージの 4 種類があります。
2)正式パッケージ:App Store にアップロードされたインストールパッケージです。
⚠️:Xcode が作成したパッケージはすべてテストパッケージに該当します。
参考:iOS の異なるタイプのテストパッケージの紹介—— 搜狗テスト公式アカウント。
テストパッケージ#
テストパッケージをインストールする際、実機は完全な検証プロセスを行います。以下の図のように:

- まず、実機はシステム内蔵の CA 公開鍵を使用してPP ファイルおよびその署名 C の合法性を検証します;
 - 次に、実機はシステム内蔵の CA 公開鍵を使用して PP ファイル内の証明書およびその署名 A の合法性を検証します;(アプリ内には署名 B を生成するために使用された証明書情報が保存されているため、実機はどの証明書から公開鍵を取得すべきかを知っています)
 - その後、実機は証明書内の公開鍵を取り出してアプリおよびその署名 B の合法性を検証します;
 - 最後に、実機は自分の UDID が PP ファイルの Devices リストに存在するかどうかを確認し、存在する場合のみアプリのインストールを開始します。
 
⚠️:図では検証プロセスが簡略化されていますが、あなたはこのプロセスに非常に慣れているはずです。ハッシュ混乱、公開鍵復号、等価判定...
実際、署名の検証は一度で完了するわけではなく、インストール、起動、実行時に異なる検証ルールがあります。上記はそのプロセスを簡略化したもので、具体的には細説 iOS コード署名(4):署名検証、脱獄、再署名を参照してください。
正式パッケージ#
正式パッケージをインストールする際、実機の検証プロセスは大幅に簡略化されます。なぜなら、開発者証明書の検証プロセスは App Store に委ねられるからです。
1)リリースパッケージを App Store にアップロードします。

- あなたがリリースパッケージ(テストパッケージの一種)を App Store にアップロードすると、Apple 公式もリリースパッケージの検証を行います。そのプロセスは上記のテストパッケージの検証プロセスに似ています;
 - 検証が通過すると、App Store はアプリに再署名を行います。ここで使用されるのは開発者証明書に対応する秘密鍵ではなく、CA 秘密鍵です;
 - 最後に、App Store はアプリと新しい署名をパッケージ化し、.ipa パッケージを生成します。(⚠️:PP ファイルは含まれません)
 
2)実機が正式パッケージをインストールします。

デバイスが App Store からアプリをダウンロードすると、システム内蔵の CA 公開鍵を使用してアプリを検証し、検証が通過すればインストールされます。
練習してみましょう#
インターネット上には非常に良い図がいくつかありますので、番号に従ってプロセスを振り返り、この記事の内容を強化するために使用してください。

出典:iOS 証明書に関する事柄—— 掘金。

出典:iOS アプリ署名の原理——Blog。
目標に戻る:本文の目標#
最後に、記事の冒頭で提起した問題に戻り、それらの問題を解決する前に常に 2 つのものを心に留めておいてください:秘密鍵を含む証明書(.p12 = .cer + private key)、PP ファイル(.mobileprovision)。
私たちの問題を再確認しましょう。上記の 2 つのものを見つけるだけで済みます:
- 実機で自分の iOS プロジェクトや iOS オープンソースライブラリを実行するにはどうすればよいですか?
- 秘密鍵を含む証明書:iOS 証明書申請方法のセクションを参照;
 - PP ファイル:開発者プラットフォームで申請;または Xcode が自動生成、Targets > Signing & Capabilities > Automatically manage signing をチェック。
 
 - 実機で会社の iOS プロジェクトを実行するにはどうすればよいですか?
- 秘密鍵を含む証明書:チームに要求し、ファイルの拡張子が.p12 であることに注意;
 - PP ファイル:チームに要求し、責任者に自分の実機の UDID を PP ファイルに追加してもらうことを忘れないでください。
 
 
PS:
- テストパッケージでインストールしたアプリを実行する際、一般的に実機で証明書を信頼する必要があります:Settings > General > VPN & Device Management。
 - Xcode が自動生成した PP ファイル:
 

参考資料#
全体を把握する:iOS 証明書の背後にある原理——Blog
深く理解する:iOS コード署名の詳細——Blog
その他、あなたが興味を持つかもしれない:
- iOS 証明書とプロファイルの申請——DClound
 - iOS アプリの公開方法にはどのようなものがありますか?—— 知乎
 - iOS 再署名の探求—— 簡書