未来を形作るテクノロジーの深掘り記事。

中間CA侵害:信頼チェーンが壊れるとき

eMudhraの中間CA侵害から、弱い鍵がWeb PKIの信頼を崩す仕組みを解説。中間証明書の重要性と、クライアントの検証・修正方法をまとめました。

証明書チェーンを表した図。ルートとサーバーの間の中間リンクが割れている様子
中間CAが陥落すると、その配下のすべてのリーフ証明書も道連れになります。

一見逆説的に聞こえるかもしれませんが、最悪の認証局インシデントは、攻撃者が侵入してくるものではありません。最近のeMudhraの中間CA侵害がその証拠です。侵入の必要もなく、証明書そのものから中間CAの秘密鍵8本を復元できてしまいました。しかもCA自身の鍵生成セレモニーで作られた秘密鍵が極端に弱く、そのうちの1つは文字通り数値の「4」でした。誰かが鍵を盗んだわけではありません。最初から侵害された状態で生まれていたのです。これはどんな情報漏えいよりも恐ろしい故障モードです。認証情報をローテーションしてパッチを当てても直せません。信頼そのものが最初から欠陥品だったのですから。

ブラウザ以外でTLS接続を行うものを何か運用しているなら(ほぼ全員がそうです)、この件は注意を払う価値があります。ブラウザは数日以内に保護されました。しかし残りのエコシステム、つまりcronジョブのcurl呼び出し、certifiをピン留めしたPythonサービス、ルートストアを埋め込んだGoバイナリなどは、まだ追いついている途中です。まず何が実際に起きたのかを追い、中間CAの侵害がリーフ証明書の侵害よりなぜ本質的に深刻なのか、そして対応がばらついていることが現代のインターネットの失効(revocation)の現状について何を物語っているのかを見ていきましょう。

eMudhraで実際に何が起きたのか

Mozillaのインシデントトラッカーに掲載されたCA自身の暫定報告によると、話は痛々しいほど地味です。鍵生成セレモニーのスクリプト(CAが最も機微な鍵を作る、統制され監査された手順)が、鍵のラップ/アンラップ手順をエクスポート用にテストするため、承認済みの逸脱として改変されていました。その改変されたコードの欠陥によって、HSM上で2組目のECC鍵が生成され、それらの鍵が弱かったのです。「エントロピーが少し低い」程度の弱さではありません。公開証明書だけで簡単に復元できてしまうほどの弱さです。

これが何を意味するか考えてみてください。ECCの秘密鍵は本来ランダムな256ビットの数値であるべきです。この方式全体の安全性は離散対数問題に依存しています。公開鍵から秘密のスカラーを求めることが計算上不可能でなければなりません。しかし、その「ランダム」なスカラーが1バイトだったとしたら、公開鍵は生成点にそのバイト値を掛けたものにすぎず、ノートPCでも数マイクロ秒で256通りすべてを総当たりできてしまいます。報告によれば8本の鍵のうち1本は整数の4だったそうです。これは従来の意味での「侵害」ではありません。そもそも一度も安全ではなかった証明書が、Mozilla、Microsoft、Apple、Chromeが信頼するルートの下で発行されていたのです。

報告者であるWayne氏は、8本の秘密鍵それぞれでメッセージに署名し、その署名をルートプログラムに提出することで鍵の保有を証明しました。誰でもいくつかのOpenSSLコマンドで検証できます。各中間証明書から公開鍵を取り出し、メッセージの署名がそれに対して検証できるかを確認するだけです。暗号学的な鍵保有の証明がエレガントかつ恐ろしいのは、そこに曖昧さがないことです。「セキュリティを重視しています」といったPR的な霧はありません。数学が合うか合わないかのどちらかで、今回は合ってしまいました。

中間CAの侵害がリーフより悪い理由

リーフ証明書の秘密鍵が漏れた場合、たとえばapi.example.comの鍵が公開GitHubリポジトリに出てしまったとします。影響範囲はホスト名1つ、ワイルドカードならせいぜい数個です。証明書を失効させ、新しく発行し直せば終わりです。面倒ではあっても、存続に関わる問題ではありません。

中間CAの鍵はまったく別物です。Web PKIは署名の連鎖として機能しています。ルートCA(オフラインで保管され、核物質並みに守られています)が中間CAに署名し、中間CAが、サーバーが実際に提示するリーフ証明書に署名します。中間CAの秘密鍵を持つ者は、暗号学的な意味ではそのCA本人です。google.comや、あなたの銀行、社内SSOのドメインに対しても有効な証明書を発行でき、そのチェーンを信頼するクライアントはすべて文句なくそれを受け入れます。レート制限もなく、問い合わせ先の中央機関もなく、不正だが有効な署名と正当な署名を見分ける方法もありません。

eMudhraのインシデントは、これを8本の中間CAに拡大させました。一部はSectigoのルートを経由したクロス署名で、数十億台のデバイスに配布されるトラストストアにつながっています。欠陥のある証明書が作成されてから開示されるまでのおよそ1年半の間、これらの中間CAを信頼し、Certificate Transparencyを強制していないクライアントは、鍵を復元できた者なら誰にでもなりすまされた可能性がありました。これが問題の時間枠です。誰かが実際に悪用したかどうかは分かりませんし、CTログで運良く見つかるか攻撃が観測されない限り、おそらく永遠に分からないでしょう。

だからこそルートプログラムは、中間CAのインシデントを、リーフのインシデントでは決して与えられない深刻度で扱います。中間CAを不信頼にすると、それが発行したすべての証明書が無効になり、何千ものウェブサイトが一斉に壊れます。Symantecの不信頼化を巡る騒動は、数年かけて展開されましたが、CAの運用が信頼できないと判断された場合に完全な是正がどれほど痛みを伴うかの典型例です。仕組みは機能しています。ただし手術ではなく切断術のような機能の仕方です。

偶然のヒーローになったCertificate Transparency

この話でもっと注目されるべき点はこれです。Chrome、Safari、Firefox、Edgeは、問題があることが知られる前から保護されていたと言えます。失効の仕組みのおかげではなく、Certificate Transparencyのおかげです。

CTを強制するブラウザは、受け入れるすべての公的に信頼された証明書が、公開の追記専用CTログに記録されていることを要求します。侵害されたeMudhraの中間CAは、問題の期間についてCTログのエントリがありません。つまり、攻撃者がそれらの鍵で発行したリーフ証明書は、CTを強制するクライアントではどのみち拒否されたはずです。有効な署名付きタイムスタンプ(SCT)が付いていないからです。不正を信じさせるには公開しなければならず、公開すればすぐに露見していたでしょう。

CTは、事後に誤発行を検出し、不正な証明書を発見可能にするために設計されました。今回のインシデントでは、予防的な統制としても機能しました。ブラウザ利用者全体に対して、侵害された鍵をほぼ役に立たなくしたのです。大規模な傍受において最も価値の高い標的集団を守ったわけです。ほとんどのエンジニアが考えることのないインフラにとって、これは本当に良いニュースです。

ただし、ここで私の楽観論の限界を認めなければなりません。CTの強制は、本質的にはブラウザの贅沢品です。インターネット上のTLSクライアントの大多数はSCTを確認しません。あなたのcurlの実行もそうですし、Pythonのrequestsの呼び出しもそうです。ベンダーのクラウドにホームへ通信するIoT機器群もそうです。これらすべてにとって、唯一の防御は失効データがトラストストアに間に合って届くことでした。そして、ここから話がややこしくなります。

失効のギャップ:ブラウザとそれ以外

ブラウザベンダーはこの件をうまく処理しました。10年前に構築されたインフラには敬意を払うべきです。Mozillaは10年以上にわたり、中間証明書やルート証明書を不信頼にするためのプッシュ型の仕組みであるOneCRLを提供してきました。今回のインシデントに対しても、ブラウザのアップデートなしに数時間以内にFirefoxユーザーの対応を完了させました。ChromeのCRLSetsや、AppleのOS側の同等の仕組みも、数日以内に各プラットフォームで同様の対応を行いました。CAが中間CAを失効させ、ブラウザ利用者の視点から見れば、このインシデントは始まる前にほぼ終わっていたのです。

一方、ブラウザ以外の世界に目を向けると、対応リストはソフトウェアのサプライチェーンの棚卸しのように読めます。Ubuntu、Debian、Fedora、Alpine、Arch、Gentoo向けのca-certificatesパッケージ更新、新しいNSSリリース、新しいcurlのCAバンドル、Python用のcertifi、Rust用のrustls-webpkiとwebpki-roots、Goのポイントリリース、3つのリリースラインにわたるElectronのパッチ版、Composerのca-bundle、Elixirのcastore。どれも別々の成果物で、リリースサイクルも配布の仕組みも別々です。開示から数日経っても、まだ保留中のものもありました。

そして、私を眠れなくさせるカテゴリがあります。CAのストアをバイナリ内に同梱しているソフトウェアです。昨年ビルドされた静的リンクのGoサービスは、そのルートをコンパイル済みの成果物の中に持っています。修正の唯一の方法は再ビルドして再デプロイすることです。パッチを当てるべきシステムパッケージがありません。これを、レジストリ内のすべてのコンテナイメージ(/etc/ssl/certsレイヤーが焼き込まれたもの)、すべてのデスクトップ上のすべてのElectronアプリ、接続されたすべてのデバイスのファームウェアイメージに掛け合わせると、問題の全体像が見えてきます。システムのトラストストアは簡単な部分です。組み込み機器やOT機器がセキュリティインシデントを数年がかりの泥沼に変えてしまうことについては以前も書きました。侵害された認証局はまさに、そうした機器が決して修正されないタイプの事件です。

暗い風景を横切る二本の分岐した光の道。一方は輝くゲートを通り、もう一方は霧の中で迷っている
正規の検証を通過してしまう不正な証明書を提供するホストに対してクライアントをテストすることだけが、確実に知る唯一の方法です。

誰も所有していないトラストストアの長い尾

このインシデントには、あまりにも見事な事例なので独立した段落に値する特別なケースがあります。macOSです。AppleのプラットフォームはOSレベルで侵害された中間CAを速やかにブロックしました。しかし、組み込みの/usr/bin/curlは、更新されていない/etc/ssl/cert.pemを基準に検証し、失効チェックも行いません。つまり、完全にパッチ適用されたMacでも、Safariは偽造証明書を拒否する一方で、同じマシンのcurlはそれを喜んで受け入れてしまうことがあるのです。同じマシン上で二つの信頼判断が、正反対の答えを出します。

この分断こそが本当の教訓です。私たちは「Web PKI」を一つのシステムであるかのように語りがちです。しかし実際には、性質が大きく異なる数十のシステムの集まりです。

  • ブラウザ:プッシュ型の失効(OneCRL、CRLSets)、CTの強制、自動更新。対応は数時間から数日。
  • OSのトラストストア:パッケージ管理による更新(ca-certificates、ca_root_nss)。対応は、ディストリビューションのリリースサイクルと、そのマシンが実際にパッチを当てられるかどうかに依存します。
  • 言語エコシステム:certifi、webpki-roots、Goの埋め込みルート、Node.jsに同梱されたMozillaストア。対応にはリリースを切り、数千のプロジェクトで依存関係の更新を待つ必要があります。
  • コンパイル済み成果物とイメージ:バイナリ、コンテナ、ファームウェア。対応には再ビルドと再デプロイが必要で、実際には数年に及ぶ脆弱な尾を引くことになります。
  • IoTと組み込み:更新経路が存在しないことが多いです。事実上の恒久的な露出です。

ブラウザは、まさにこのシナリオに対して10年かけて投資してきました。ほかにそこまで投資したところはほとんどありません。Mozilla側の上流のコメントは率直でした。ブラウザのエコシステムの外では、失効への投資がほぼゼロに近く、そうしたクライアントにとってこの種のインシデントは重大な問題だ、と。これは、私がインフラを運用してきて見てきたこととも一致します。クラウド認証のイベントがどのようにログに残らないのかという死角に取り組んだことがあれば、このパターンに見覚えがあるでしょう。重要な経路は十分に計測されている一方で、長い尾は暗闇の部屋なのです。

クライアントがまだ脆弱かどうかを確認する方法

理屈はさておき、実際にあなたの環境をテストするべきです。TLSの良い点は、経験的にテストできることです。コミュニティのメンバーが、侵害された中間CAで署名された証明書を提供するホストを立ち上げました。クライアントが証明書エラーなしで接続できるなら、そのクライアントはまだそれらを信頼しているということです。curlやその他のコマンドラインツールをテストする一般的なパターンは次のとおりです。

# A certificate error here means you're protected.
# A successful response means this client still trusts a compromised intermediate.
curl -v https://dv-g3b-emudhra.we-have-a-problem.com/
# You can also test whether a client will accept a forged cert for an
# arbitrary hostname by pointing it at a test server:
curl -v https://example.org --connect-to example.org::2.29.126.86:

重要なすべての環境から実行してください。開発者のノートPC、CIランナー、コンテナのベースイメージ、サーバー群です。結果は環境ごとに異なるでしょうし、その違いこそがポイントです。アップグレードが必要なものの簡易インベントリとしては次のとおりです。

  • Goのサービス:Go 1.27.3または1.26.10以降で再ビルドしてください。ルートがコンパイル時に組み込まれています。
  • Python:certifi 2026.10.19以降。pipとuvのバージョンも確認してください。これらも独自のバンドルを同梱しています。
  • Rust:rustls-webpki 0.103.16、webpki-roots / webpki-root-certs 1.0.10。
  • Node.jsとElectron:各リリースラインごとに保留中またはパッチリリース。出荷されている各成果物を確認してください。
  • システムストア:更新されたca-certificatesパッケージは、Ubuntu、Debian、Fedora、Alpine、Arch、Gentoo向けに提供されています。FreeBSDのca_root_nssは、執筆時点では保留中でした。

パッケージを待てない場合は、ほとんどのLinuxディストリビューションで、影響を受けるルートを手動で不信頼にできます。Debian/Ubuntuでは、/etc/ca-certificates.conf内の証明書に!の接頭辞を付けて、update-ca-certificatesを実行します。Fedora/RHELファミリーでは、ルートを/etc/pki/ca-trust/source/blocklist/に展開して、update-ca-trustを実行します。NixOSには、宣言的に扱える分かりやすいオプションがあります。

security.pki.caCertificateBlacklist = [
"Comodo AAA Services root"
"emSign ECC Root CA - G3"
];

これらの回避策で実際に不信頼にしているものに注意してください。それは、それらの中間CAが連鎖しているルートです。これがPKIの是正における鈍器的な現実です。ほとんどのトラストストアのツールには「この中間CAだけを不信頼にする」という機能がないため、ルートをブロックリストに入れ、無関係な証明書への巻き添えの被害を受け入れることになります。緊急時には正しい選択ですが、それはトレードオフなのです。

私の逆張り的な主張が崩れるところ

冒頭で、自分の鍵生成の失敗が侵害よりも悪いと論じました。その主張がどこで崩れるかを正直に述べましょう。従来型の侵害(DigiNotarを思い浮かべてください)は、攻撃者に出し抜かれるまでCAが有能に運用していたことを少なくとも示唆します。そして、システム全体が賭けているのは有能なCAなのです。「4」という秘密鍵を出力する鍵セレモニーは、監査された統制、HSMの手順、コンプライアンスのチェックリストのいずれも、CAが行う最も機微な操作の壊滅的な欠陥を捉えられなかったことを意味します。これは敵対者の問題ではなく、保証の問題です。そして保証こそ、CAが売っている商品のすべてなのです。

この主張が本当に破綻する点はこうです。侵害は防ぐのが難しく、より長く気づかれないままになりえます。慎重に中間CAの鍵を盗んだ攻撃者は、それを控えめに使って標的を絞った傍受だけを行い、CTを強制するクライアントには一度も触れないかもしれません。一方で弱い鍵は、公開証明書をスキャンすれば誰でも見つけられます。今回の件がまさにそうやって表面化したのです。「派手だが明白な大失敗は、地味で標的型の失敗より良い」という議論もあります。私はそれを完全には支持しませんが、否定することもできません。結局のところ、どちらの失敗モードも同じ場所にたどり着きます。不信頼にしなければならない中間CAと、何か月もその通知を受け取らない長い尾のクライアント群です。

実際に何をすべきか

Web PKIそのものを直すことはできません。しかし、次の失敗に対するあなたの露出を減らすことはできます。

  • 推測せず、テストする。侵害されたチェーンを提供するホストに対して、クライアントを検証してください。これは午後一つ分の作業で、きっと驚くはずです。
  • コンパイル済み成果物を再ビルドする。Goのバイナリやコンテナイメージは、トラストストアを一緒に抱え込んでいます。「ベースイメージにパッチを当てた」というだけでは、再デプロイするまで何の意味もありません。
  • トラストストアを棚卸しする。把握していないものは是正できません。certifiのコピー、ベンダーのバンドル、Electronアプリを数えてください。実際に重要なので、重要なものとして扱ってください。
  • 可能な限りシステムのトラストストアを使う。ベンダーがバンドルするたびに、出荷し忘れるパッチが一つ増えます。OSのストアに集約しても問題が消えるわけではありませんが、責任の所在が一つにまとまります。
  • CTと失効のエコシステムを追う。ブラウザ相当の失効をブラウザ以外のクライアントにもたらすことを目指すプロジェクトが存在し、支援に値します。このインシデントは、その資金獲得のための最良の論拠になるでしょう。
  • CAのインシデントをセキュリティインシデントとして扱う。漏えいした認証情報と同じように、担当者を呼び出し、棚卸しを実施し、文書化された記録を残すべきです。実際にそういうものなのですから。

率直にまとめると、Web PKIの緊急ブレーキは、最もそれを必要としないクライアントの中で見事に機能します。なぜならCTがすでにそれらを守っていたからです。ブレーキを必要としていたクライアント、つまりヘッドレス、組み込み、ベンダーバンドル、忘れられたもの、の多くはそもそもブレーキを持っていません。次の中間CAの侵害は「起きるかどうか」ではなく「いつ起きるか」の問題です。あなたが管理できる唯一の変数は、自社の環境がそれに気づけるかどうかです。