openssl s_clientで-servernameを指定するとSNI環境の証明書を個別に確認できる

  • openssl
  • TLS
  • SNI

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

やったこと

openssl s_client -connect example.com:443 -servername example.net -showcerts < /dev/null 2>&1

同一IP・同一ポートで複数ドメインの証明書を運用しているサーバ(1台で複数のバーチャルホストを捌いてるようなケース)で、指定したドメインの証明書だけをピンポイントで確認したいときに使うコマンド。

なぜ-servernameが要るか

TLSのSNI(Server Name Indication)拡張は、ハンドシェイクの中でクライアントが「どのホスト名向けの接続か」をサーバに伝える仕組み。サーバはこの値を見て、どの証明書を返すかを決める。

なので -connect example.com:443 でIP・ポートを指定しつつ、-servername example.net を付けると「example.comのIPに繋ぐけど、example.netの証明書をくれ」というリクエストになる。マルチドメイン構成のサーバでは、これを指定しないと意図した証明書が確認できない。

-servername を省略した場合は、SNI拡張なしで接続することになる。この場合サーバ側の実装次第だが、デフォルトで設定されている証明書や、SNI非対応クライアント向けのフォールバック証明書が返ってくることがある。狙ったドメインの証明書を確認したいなら省略しない方がいい。

各オプションの役割

必須の引数:

引数 役割
-connect example.com:443 接続先のIP(ホスト名でも可)とポート

オプション:

オプション 役割
-servername example.net SNIで送るホスト名。これで対象の証明書を選ばせる
-showcerts リーフ証明書だけでなく、中間証明書も含めたチェーン全体を表示する。付けないとリーフ証明書のみ

シェル側の処理:

記法 役割
< /dev/null s_clientはハンドシェイク後に標準入力待ちで止まるので、入力を/dev/nullにして即終了させる
2>&1 標準エラー出力も一緒に拾う

まとめると

複数ドメインを1つのサーバでホストしている環境の証明書確認は、-servername を付けるかどうかで返ってくる証明書が変わりうる。狙ったドメインの証明書を見たいなら明示的に指定する。