コード署名
署名とは何か?
署名、もとい コード署名 とは、その名の通り あるアプリケーションコード に対して行われるものであり、以下が保証されていることを示す役割を持つ。
そのアプリケーションが、特定の発行元から提供されていること
そのアプリケーションが、最後に署名した時点から改変されていないこと
なぜ iOS アプリを実機インストールするためにこの署名が必要なのか?というと、iOS が署名されていないアプリケーションのインストールを受け付けていないから である。アプリケーションを iOS にインストールした時に、iOS はそのアプリケーションの署名をチェックする。したがって、署名されていない野良アプリケーションなどは iOS にインストールできないし、できたとしても使えない (はず)。
コード署名の仕組み
ガイドで説明されているが、基本的には一般的なデジタル署名と同様の仕組みとなっている。Apple におけるコード署名に登場する主な用語は、以下の3つ。
seal は、署名対象から生成されるチェックサム, ハッシュ値であり、変更があったかどうかの検証に利用する
digital signature は seal を暗号化したもの。公開鍵暗号方式によって seal の完全性を保証するために作成する
code requirements は、コード署名の検証のためのルール群
Apple のドキュメントの図で言うと、Message digest が seal であり、それを秘密鍵で暗号化したものが digital signature になる。Code-signed data は署名を検証する側に送られる。
検証側は、Cerificate から公開鍵を取り出し Digital signature を複合化して seal にする。さらに、Data を同一のアルゴリズムでハッシュ化し、その結果を複合化した seal と比較する。これで一致したなら、データは改ざんされていないこと、特定のユーザ (秘密鍵を保持したユーザ) によって署名されていること、が保証できる。
https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Art/code_signing.png
seal
seal は、署名対象を特定のハッシュアルゴリズムで変換した結果得られるハッシュ値。同じ入力に対して必ず同じ出力だが、出力から元の入力は推測できないようになっている。コードの署名を確認する側は、「ハッシュ化前のコード」と「seal」の2つを受け取る。署名時に利用したのと同一のハッシュアルゴリズムを「ハッシュ化前のコード」に適用すると、コードに改ざんがなければ手元の「seal」と内容が一致するはず。これを利用してコードが改ざんされていないか?保証する。ただし、この変更検知の信頼性は seal の信頼性に依存する。この信頼性の担保は digital signature で行う。
https://gyazo.com/9da1ecdb932d7cbfe86fcb9c2825247f
digital signature は、データの完全性の保証のために公開鍵暗号を利用する。署名側は seal を秘密鍵で暗号化し digital signature を作成する。署名の確認側は、digital signature を公開鍵で複合化し、その結果得られた seal と手元のコードのハッシュ化結果を比較すれば良い。秘密鍵を利用した暗号化は秘密鍵を保有する署名者しか行えないので、これによって秘密鍵を所有している人物によって署名されてから変更されていないことが保証できる。
https://gyazo.com/c0a3c6325c02d7a89f48ff32a77bb56d
Code requirements
通常のデジタル署名に追加して存在する概念として、Code requirements がある。これは、コード署名を評価する際に macOS が利用するルールで、例えば Gatekeeper は「アプリはその初回起動のために、Mac App Store もしくは Developer ID 証明書で署名されている必要がある」という Code requirements を持つ。他にも、アプリケーションはその利用する全てのプラグインが Apple によって署名されていなければならない、といったことを強制できる、といったものがある。
code requirements は署名者が定義でき、コード署名の一部 (internal requirements) として含めることができる。ただし、署名を検証を行うシステムはこれを利用するかどうかを選択できる。例えば、記述の例のような「プラグインは全て署名されているべき」という internal requirements があった時、それを適用するかどうかを判断するのはアプリに委ねられる。ポイントとしては、コード署名の仕組みのおかげで、この internal requirements が署名者による要求であることは保証されている。
最も重要な internal requirements は、Designated Requirement (DR) である。これは 対象のコードが同一とみなされるための要件 であり、この仕組みによって、同一アプリの別バージョンをリリースすることができる。例えば、Apple Mail の DR は「Apple nいよって署名されており、かつ識別子 com.apple.Mail を持つ」などになる。
通常、署名機能は DR を自動的に作成する。その際には Info.plist 内の CFBundleIdentifier が利用される。 そのほかの code requirements は、専用の言語で記述される (詳細は割愛)。