自己署名VPN証明書:その意味と、何を信頼するのか
自己署名のVPN証明書でも通信は暗号化されます。変わるのは、誰にそれを信頼するよう伝えたか、どのストアがその信頼を受け取るか、そしてどの検査が残るかです。
ここで最も被害を生むのは二つの思い込みです。自己署名VPN証明書はトンネルが暗号化されていないという思い込みと、VPNクライアントが求めたものをインストールしてもVPNにしか影響しないという思い込みです。どちらも実際の導入に触れると成り立ちません。自己署名証明書は署名の関係を表すもので、安全性の判定ではありません。追加した信頼の及ぶ範囲は、それがどのストアに入るかで決まります。ヘルプデスクが警告を一つ黙らせるためにプロバイダーのルートをWindows機に取り込み、その後、無関係なポータルについてブラウザーが文句を言わなくなった理由を半日かけて説明したのを見たことがあります。この問いの二つの半分は一体なので、一つのものとして扱ってください。
証明書は信頼ストアではない
サーバーが提示するファイルには、公開鍵、サブジェクト名、発行者名、有効期間、拡張が含まれます。自己署名とは、サブジェクトと発行者が同じ実体であり、署名が証明書自身の鍵で検証されることを意味します。その定義のどこにも、接続が弱いとは書かれておらず、クライアントが受け入れるとも書かれていません。
受け入れは別のところから来ます。クライアントに指すCAファイル、手作業で照合するフィンガープリント、あるいはクライアントが読むストアにすでにあるルートです。導入が完全に健全でも、その証明書は公開の検査すべてに落ちるかもしれません。openssl verify はシステムバンドルに対して未知の発行者を報告しますが、その報告は欠陥ではなく正しいものです。
OpenVPNのcaオプションは、アプリに限定した信頼の最も明確な例です。このファイルはクライアントが受け入れるアンカーを指定し、一つのプライベートCA、あるいは小規模な導入ではサーバー自身の自己署名証明書を含むことがあります。バージョン2.6は、CAファイルを配布する代わりにSHA-256フィンガープリントを固定する--peer-fingerprintも受け付けます。WireGuardはさらに外側にあり、証明書を一切持たず、ピアごとの静的な公開鍵だけなので、自己署名という問いは当てはまりません。
信頼をどこにインストールするかで、誰がそれを継承するかが決まる
同じ証明書を三か所に置けば、三つの異なる影響範囲が得られます。VPNクライアントだけが読むバンドルは、そのクライアントに影響します。オペレーティングシステムのストアにあるルートは、そのストアを参照するすべてのプログラムに影響します。独自の信頼データベースを持つブラウザーは両方を無視することがあり、だからこそ、うまくいったように見えた取り込みの後でも警告が残ることがあります。
DebianやUbuntuでは、/usr/local/share/ca-certificates/ にファイルを置いてupdate-ca-certificates を実行するとシステム全体のバンドルが変わります。Windowsでは、certutil -addstore -f Root はマシンストアに書き込み、昇格したプロンプトが必要です。一方、-user を追加すると現在のユーザーのストアが対象になり、両者は交換できません。Firefoxは独自のNSSデータベースを保つので、OSレベルの取り込みがそこに現れないことがあります。
範囲が重要なのは、認証局が何をできるかによるからです。発行CAは関係のない名前にも署名できるため、そのストアを信頼するものはすべてその署名を受け入れます。固定された一枚のリーフにはそれはできず、ちょうど一つのピアの識別情報を認証します。目的が一つのVPNをつなぐことなら、アプリに限定したCAか固定したリーフで達成でき、マシン全体のルートは症状が必要とするよりはるかに大きな譲歩です。
公開CAがなくても暗号化はされている
TLSハンドシェイクは、ピア証明書がすでに信頼しているものにつながるかどうかに関係なく、セッション鍵を導出します。自己署名は平文を意味せず、通信が飛行中に読めるという意味でもありません。意味するのは、クライアントが、鍵が要求したサーバーのものだと信じる先験的な理由を持たないということです。
その隙間こそが実際の攻撃の住処です。検証設定を無効にしたか、一度押して忘れられた「とにかく信頼する」ボタンによって、あらゆる証明書を受け入れるよう構成されたクライアントは、応答する相手に喜んで暗号化します。傍受は認証の段階で起こり、アプリケーションのデータが動く前です。識別情報を確認しない暗号化は、受動的な観察者を締め出すだけで、それ以上のことはしません。
発行者を信頼しても名前の検査は飛ばせない
チェーンの検証、名前の照合、証明書の目的は別々の判断です。チェーンが有効でも名前が間違っていることがあり、名前が一致していても証明書が別の役割のために発行されていることがあります。RFC 5280 はそれらの制約を運ぶフィールドを定義しており、クライアントがどれだけ厳格に適用するかはアプリケーションごとの問題です。
OpenVPNはその分離を可視化します。verify-x509-name はname、name-prefix、またはsubject の照合を通じて期待するサブジェクトを固定します。remote-cert-tls server はピア証明書がサーバー証明書として使えることを要求し、発行者が信頼されていてもクライアント専用の証明書を拒否します。どちらの設定もCAファイルを送ることで置き換えられるものではありません。
何かを決める前に証明書を調べてください:
openssl x509 -in server.crt -noout -subject -issuer -dates -ext subjectAltNameは、誰が、どの名前のために、いつまで発行したかを示します。openssl verify -CAfile ca.crt server.crtは、送ろうとしているチェーンが実際にリーフを検証するかを確かめます。openssl s_client -connect vpn.example.net:443 -servername vpn.example.net -CAfile ca.crt -verify_return_errorはウェブポータルのようなTLSエンドポイントで機能します。1194番のOpenVPNプロトコルは通常のTLSストリームではないため、そのテストはそこでは当てはまりません。
期限切れの日付、接続する名前のsubjectAltNameがない、またはserverAuthの用途がない証明書は、アンカーがどれほど丁寧にインストールされていても失敗します。
受け入れる前の五つの検査
修復しようとしている接続ではない経路でフィンガープリントを比較します。コンソール、すでに持っているインストーラー、署名済みの構成ファイルです。サーバー上のopenssl x509 -in server.crt -noout -fingerprint -sha256 とクライアントログの同じ値だけで、一つのオブジェクトを見ていると分かります。
次に、一枚のリーフか、さらに発行できる認証局かという、何をインストールするかを決めます。次にそれがどこへ行くかを決め、そのストアを読むアプリケーションを名指しします。忘れないうちに削除手順を書き留めてください。「信頼して先へ進む」が、一時的な取り込みを恒久化する道だからです。
最後に、変更を計画します。固定した証明書やフィンガープリントは、証明書がローテーションするときに同じ信頼経路で更新する必要があり、プライベートCAには独自の発行と失効のライフサイクルがあります。秘密鍵が漏れたら、同じ証明書のコピーを再び信頼しても何も直りません。識別情報を置き換える必要があります。
警告が五つの検査すべてを生き延びたなら、有用な問いはどのボタンがそれを黙らせるかではなく、クライアントが実際にどのストアを読み、そのルートがどこから来たかです。それに答えれば、これから行う取り込みは反射ではなく判断になります。