この記事は後半です。前半は Qiita にあります: eMudhraの秘密鍵が「4」だった理由を追う——8本の中間CAが一瞬で破られた背景
前半では、「P-384のはずの鍵が、実際には8ビット分しかなかった」という話を見た。ここで大事なのは、単に数が小さいのではなく、探索空間が 256 通りにまで落ちたことだ。Scott Helme が手元の端末で即座に復元できたのも、この極端な縮退が理由だった。
画像: github.com より
Mozilla のコメントでは、影響鍵は 2025年4月30日に作られた 24 本の中間 CA の一部で、B 系列と C 系列の P-384 鍵が該当するとされている。鍵は本来、1 から群の位数までのランダムな整数であるべきだが、今回の 8 本はすべて 256 未満だった。つまり、実質的には最後の 1 バイトだけに値が入っていた。
この状態だと、楕円曲線の逆算は「重い暗号」ではなく「公開鍵に合う候補を 1 から 255 まで試す作業」になる。baby-step giant-step のような手法も使えるが、そこまでしなくても、最初の 256 個の P-384 鍵を順に作れば足りる。Mozilla 側も、復元は「trivially」と表現している。
この事件が厄介なのは、証明書の外見上は壊れていないことだ。公開鍵は曲線上の正しい点として成立するし、証明書の構造も正しい。見た目の検査は全部通る。だから、証明書だけを眺めても異常には気づきにくい。
しかも問題は署名の失敗ではない。eMudhra の説明でも、装置そのものが壊れたというより、KGC スクリプトに欠陥があり、弱い鍵が誤って CSR に使われた可能性が示されている。公開鍵や証明書が正しく見えるので、異常は生成工程の内側にしかない。外からはまず分からない。
ここで「秘密鍵が盗まれた」のと話が変わってくる。盗難なら、どこかの時点で誰かが持ち去ったと考えられる。だが今回は、証明書が公開された時点ですでに鍵が弱かった。Mozilla の文面に従えば、2025年4月以降は、誰でも回収できた可能性がある。失効の有無だけでは足りず、どのくらい長く弱い鍵が晒されていたかが問題になる。
Chrome と Firefox は、この中間 CA を直接ブロックした。Chrome は CRLSet、Firefox は OneCRL を使っている。さらに Chrome は、証明書透明性が強制されるため、そもそもこの CA にぶら下がる TLS 証明書がログに載っていなかった以上、ブラウザ既定では偽造証明書が通らないと説明している。
ただし、そこで安心してはいけない。影響はブラウザの外に広がる。curl、Python、Node、Go、Java、git、パッケージマネージャー、CI/CD ランナー、組み込み機器。こうしたクライアントは、CA バンドルをディスクから信頼し、revocation を既定で見ず、CT も見ないことが多い。つまり、失効済みでも通る世界が残っている。
eMudhra のページが「多くのクライアントは revocation を消費しない」と強調しているのはここだ。たとえば更新スクリプトや self-updater が、この種の証明書を信じてしまえば、そのまま攻撃者のコードを取りに行く構図になる。CI/CD なら依存取得や署名、サーバー間通信なら API 秘密情報、組み込み機器なら更新経路そのものが狙われる。被害の中心は、Web ページの偽装にとどまらない。
この事件で一番気になったのは、鍵長そのものより、工程のどこで破綻したのかという点だった。HSM は FIPS 140-2 Level 3 対応とされている。だから装置そのものより、鍵をどう作り、どうラベル付けし、どの CSR をどこへ渡したかが怪しい。eMudhra 側は、弱い ECC 鍵が誤って CSR に使われた可能性や、似たラベルの取り違えに触れている。
私ならまず、鍵生成の自動化部分を疑う。次に、CSR 作成の直前で「この鍵は本当に期待した個体か」を機械的に突き合わせる。最後に、生成後の検査を儀式ではなく判定にする。人手の確認だけでは、今回のような失敗はすり抜ける。
この事故の教訓は、暗号理論の難しさより、運用の雑さがどれほど致命的かにある。P-384 を選んでも、鍵が 8 ビットなら意味がない。CA の世界では、その 8 ビットが「信頼の土台」を丸ごと支えることになる。