コンテンツへスキップ

コード署名の基礎 — Apple Notarization と Windows Authenticode は何を証明しているのか

配布用のデスクトップアプリをビルドしていると、macOS では「開発元が未確認のため開けません」という警告に、Windows では SmartScreen の「発行者不明の実行可能ファイルを実行しますか」という表示に遭遇することがある。これを避けるために署名や公証という手続きを踏むが、この署名が具体的に何を証明していて、何を証明していないのかは、実は誤解されやすい。Apple の Notarization(公証)と Windows の Authenticode という、似ているようで役割の違う2つの仕組みを整理する。

補足: コード署名(code signing)とは、実行ファイルに暗号学的な署名を付与し、「誰が作ったか」と「配布後に中身が改変されていないか」を検証可能にする仕組みの総称。OS はこの署名を検証したうえで、実行を許可したり警告を出したりする。

署名が証明すること・証明しないこと

まず押さえておきたいのは、コード署名が保証しているのは「身元(identity)」と「完全性(integrity)」の2点であって、「安全性(safety)」ではないという点である。

  • 身元: この実行ファイルは、証明書に記載された開発者・組織が作成したものである
  • 完全性: 署名された時点から、ファイルの中身は1バイトも改変されていない

逆に言えば、署名済みのアプリであっても、そのアプリ自体にバグや脆弱性がないことは何も保証しない。署名は「誰が作って、途中で誰にも書き換えられていないか」を機械的に検証するための仕組みであり、「中身が良いソフトウェアかどうか」の審査ではない。この違いを理解しておくと、後述する Notarization や SmartScreen の役割も整理しやすくなる。

Apple の仕組み:署名とNotarizationは別レイヤー

macOS の Gatekeeper が見ているのは、実は2つの独立した情報である。

  1. コード署名(codesign): 開発者が Apple から発行された Developer ID 証明書の秘密鍵を使い、ローカルでアプリに署名を埋め込む。この署名にはアプリ全体のハッシュ値が含まれるため、配布後に1バイトでも改変されると検証が失敗する
  2. Notarization(公証): 署名済みのアプリを Apple のサーバーにアップロードし、既知の不正パターンなどの自動スキャンを受ける。問題がなければ Apple から「公証チケット」が発行され、これをアプリ自体に埋め込む(ステープルする)ことで、ネットワークに繋がっていない環境でも Gatekeeper がオフラインで検証できるようになる

つまり Notarization は「署名の代わり」ではなく、「署名済みのアプリを Apple 側が別途チェックし、その結果をアプリに証跡として貼り付ける」もう1段階のプロセスである。Gatekeeper はこの両方(有効な署名 + 有効な公証チケット)が揃って初めて、警告なしでの起動を許可する。

バンドル内の署名は「内側から外側へ」

macOS の .app バンドルは、実行ファイル本体だけでなく、フレームワークやヘルパーツールなど複数の Mach-O バイナリを内部に含んでいることが多い。バンドル全体の署名は、その時点でのバンドル内容全体のハッシュを含めて計算されるため、内側のバイナリを先に個別署名し、そのあとで外側の .app バンドル全体を署名するという順序が必要になる。

この順序を逆にしてしまうと、外側の署名を計算した時点ではまだ内側のバイナリが署名前の状態だったことになり、検証時に内容不一致として弾かれる。「バンドルの中身を全部確定させてから、一番外側の封をする」というイメージで捉えると分かりやすい。

Windows の仕組み:Authenticode と証明書チェーン

Windows の Authenticode は、Apple の Developer ID とは発行の仕組みが異なる。Apple は自社が唯一の発行者だが、Windows のコード署名証明書は第三者の認証局(CA: Certificate Authority)が発行し、その証明書がさらに上位のルート証明書まで連鎖的にたどれることで、OS 側は「この発行者は信頼できる認証局に身元確認された組織である」と判断する。

証明書には大きく分けて OV(Organization Validation・組織の実在確認)と EV(Extended Validation・より厳格な身元確認)の2種類があり、要求される確認プロセスの厳しさが異なる。かつては EV 証明書だけが SmartScreen の信頼を即座に得られるという違いがあったが、この扱いは仕様変更を経ており、現在は単純に「EV なら即信頼、OV なら要注意」と言い切れるものではなくなっている。

タイムスタンプを付けないと、証明書の期限切れが過去の署名を道連れにする

署名の際にもう一つ重要なのが、タイムスタンプ局(TSA: Timestamp Authority)による時刻証明を一緒に埋め込むかどうかである。タイムスタンプを付けずに署名した場合、証明書の有効期限が切れた瞬間、その証明書で署名したすべてのバイナリ(過去に配布した古いバージョンも含めて)が無効な署名として扱われうる。

タイムスタンプを付与しておけば、「この署名は証明書が有効な期間内に行われた」という事実そのものが第三者機関によって記録されるため、証明書自体の有効期限が切れたあとも、署名済みバイナリの検証は有効なまま保たれる。macOS の codesign にも --timestamp オプションがあり、Windows の署名ツールにも同様のタイムスタンプサーバー指定オプションがある。配布物には基本的にタイムスタンプ付きで署名しておくのが安全である。

SmartScreen のレピュテーションは、署名そのものとは別の話

Authenticode 署名が証明するのは、あくまで「誰が作り、改変されていないか」だけである。ところが Windows の SmartScreen は、これとは別に「その発行者証明書がどれだけの実績(ダウンロード数や利用期間)を積んできたか」というレピュテーションを評価している。

このため、有効な証明書で正しく署名していても、新しく取得したばかりの証明書では実績がまだ蓄積されておらず、SmartScreen の警告が出ることがある。これは署名が壊れているのではなく、「発行者としての信頼の蓄積」がまだ足りていないだけであり、時間の経過とダウンロード実績とともに徐々に解消されていく性質のものである。署名の検証エラーとレピュテーション不足による警告は、原因も対処もまったく別物として区別して考える必要がある。

まとめ

用語 何を証明するか 補足
コード署名(codesign / Authenticode) 身元(誰が作ったか)と完全性(改変されていないか) 「安全な中身か」は証明しない
Apple Notarization Apple による自動スキャンを通過した証跡 署名とは別レイヤーのチェック。チケットをステープルしてオフライン検証を可能にする
バンドル署名の順序 内側のバイナリを先に、外側のバンドルをあとに署名する
証明書チェーン(Windows) 認証局による発行者の身元確認 ルート証明書までの連鎖で信頼される
タイムスタンプ 署名がいつ行われたか 証明書の有効期限切れ後も過去の署名を有効に保つ
SmartScreen レピュテーション 発行者としての実績の蓄積度合い 署名の正しさとは別の評価軸

「署名してあるから安全」ではなく、「署名は身元と完全性を機械的に検証する手段であり、それとは別にレピュテーションのような実績評価の仕組みが並走している」と捉えておくと、配布時に遭遇する警告の意味を切り分けて理解しやすくなる。