先週、私はグループで「学習報告」を行いました。実際には、グループで毎週行われる技術共有で、誰もが機会を持つものです。今回は私の番でした。では、チームの新人として、何を話すべきでしょうか?
考えを巡らせていると、以前からよく直面していた厄介な問題を思い出しました:実機で 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 インストール時に内蔵)によって発行され、中間証明書 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 Developer Program に参加する必要があります、$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 Developer Program への参加も強制されません。
a) Xcode で Apple アカウントにログインします:Xcode > Preference > Account > Apple IDs > 「+」。
b) ログインしてしばらくすると、キーチェーンに自動的に対応する証明書が追加されていることに気づくでしょう。
注意:もしあなたが開発者プログラムに参加していれば、Apple Developer のウェブサイトにも自動的にその証明書が追加されます。
iOS 署名 & パッケージング原理#
ついに iOS 署名の部分に来ました。前の内容はどのように理解できましたか?もしまだ少し混乱しているなら、署名の役割は送信されるデータの改ざんを防ぐことを覚えておけば、この記事の真髄を基本的に把握したことになります!
実際、iOS 署名を行う際には、証明書(公開鍵)を追加するだけではなく、証明書に対してもう一層の包装が必要です。それが私たちがよく知っている Provisioning Profile ファイルで、PP ファイル、説明ファイル、供給設定ファイルとも呼ばれます。
PP ファイル#
この重要な PP ファイルについて理解しましょう。これを証明書のアップグレード版と考えることができます。
生成方法#
- 開発者プラットフォームで申請;
- Xcode が自動生成:Xcode > Targets > Signing & Capabilities > Automatically manage signing をチェック。
ファイル構造#
- アプリ ID:
- Apple 開発者プラットフォームで登録;または Xcode > Targets > Signing & Capabilities で記入した Bundle ID に基づいて自動生成。
- Xcode > Targets > Signing & Capabilities で記入した Bundle Identifier はアプリ ID と一致またはマッチする必要があります。
- 権限:
- 使用可能な権限のリスト。実際にアプリで使用される権限はこのリストのサブセットでなければならず、Xcode > Targets > Signing & Capabilities で追加した Capabilities はその範囲を超えてはなりません。
- プロジェクトディレクトリにも.entitlements ファイル(権限ファイル)があり、これは Xcode > Targets > Signing & Capabilities で追加した Capabilities に基づいて自動生成されます。アプリがサンドボックス制限の機能を使用している場合、しかしその.entitlements ファイルが対応する権限を宣言していない場合、アプリが関連するコードに到達すると、アプリは直接クラッシュします。
- 証明書:iOS 開発者証明書で構成され、複数存在することができます。これらは上記で申請した iOS 証明書です。
- デバイス:iOS デバイスの UDID(Unique Device Identifier)で構成されたリストで、アプリの開発とデバッグが可能な iOS デバイスを制限します。
- 署名:PP ファイル生成時に Apple CA によって署名され、改ざんを防ぎます。
例#
PP ファイルはデフォルトで~/Library/MobileDevice/Provisioning\ Profiles
に保存されます。
以下は Xcode が自動生成した PP ファイルのプレビューです:
署名 & パッケージング#
iOS 署名とパッケージングプロセスは実際には Xcode によって制御されています。以下の図をご覧ください:
- まず、Xcode はアプリ内の bundle ID が PP ファイル内のアプリ ID と一致しているか、アプリ内の Entitlements (.entitlements) ファイルで宣言された権限が PP ファイル内の Entitlements で許可された権限の範囲内にあるかを確認します。いずれかの条件が否の場合、チェックは通過しません;
- 次に、Xcode はコンピュータのキーチェーン内で、PP ファイル内の証明書に一致するものがあるかを探します。一致するものが見つかった場合のみ、次のステップに進みます;
- その後、Xcode は一致した証明書が対応する秘密鍵にバインドされているかを確認します。もしそうでなければ、次の重要なステップ —— 署名を行うことができません;
- さあ、ハッシュアルゴリズムと秘密鍵を利用してアプリに署名を行います;
- 最終的に、アプリ、PP ファイル、署名をパッケージ化し、.ipa パッケージを生成します。
⚠️:上記では署名 C と署名 A の検証プロセスを省略しています。第 1 ステップで PP ファイルを使用する前と第 2 ステップで証明書が一致した後、CA 公開鍵を使用してそれに付随する署名 C と A を検証する必要があります。改ざんされていないことを確認します。誤りがあれば、指摘してください。
延長問題:
Q1: Xcode はアプリのどの内容に署名を行いますか?
A1: すべての内容です。しかし、署名プロセスは非常に複雑で、ここでは詳しく説明しません。簡単に言えば、署名の安全性と効率を考慮して、アプリの署名は 4 回のハッシュと 1 回の暗号化に分けられています。各ハッシュは連鎖的に関連しており、アプリの内容が改ざんされていないことを保証します。
具体的には細説 iOS コード署名 (三):署名のプロセス及びコード署名のデータ構造を参考にしてください。
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 コード署名 (四):署名検証、脱獄、再署名を参考にしてください。
正式パッケージ#
正式パッケージをインストールする際、実機の検証プロセスは大幅に簡略化されます。なぜなら、開発者証明書の検証プロセスは 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 + 秘密鍵)、PP ファイル(.mobileprovision)。
再度、私たちの問題を見てみましょう。上記の 2 つのものを見つけるだけで済みます:
- 実機で自分の iOS プロジェクトや iOS オープンソースライブラリを実行するにはどうすればよいですか?
- 秘密鍵を含む証明書:iOS 証明書申請方法のセクションを参照;
- PP ファイル:開発者プラットフォームで申請;または Xcode が自動生成、Targets > Signing & Capabilities > Automatically manage signing をチェック。
- 実機で会社の iOS プロジェクトを実行するにはどうすればよいですか?
- 秘密鍵を含む証明書:チームに要求し、ファイルの拡張子が.p12 であることに注意;
- PP ファイル:チームに要求し、担当者に開発者プラットフォームで自分の実機の UDID を PP ファイルに追加してもらうことを忘れないでください。
PS:
- テストパッケージでインストールしたアプリを実行する際、一般的に実機で証明書を信頼する必要があります:設定 > 一般 > VPN & デバイス管理。
- Xcode が自動生成した PP ファイル:
参考資料#
全体を把握する:iOS 証明書の背後にある原理——Blog
深く理解する:細説 iOS コード署名——Blog
その他、あなたが興味を持つかもしれないもの:
- iOS 証明書と説明ファイルの申請——DClound
- iOS アプリのリリース方法にはどのようなものがありますか?—— 知乎
- iOS 再署名の探求—— 簡書