openssl s_client
とは?TLS/SSL接続テスト・証明書確認方法の徹底解説
はじめに:なぜ openssl s_client
を知る必要があるのか?
現代のインターネットにおいて、TLS/SSLプロトコルは通信のセキュリティを確保する上で不可欠です。ウェブサイトへのアクセス、電子メールの送受信、VPN接続、API連携など、様々な場面でTLS/SSLによる暗号化と認証が行われています。
サーバー管理者、ネットワークエンジニア、開発者、あるいはセキュリティに関心を持つ技術者にとって、これらのTLS/SSL接続が正しく機能しているか、想定通りの設定になっているかを確認することは非常に重要です。接続が確立できない、古いTLSバージョンを許可している、脆弱な暗号スイートが使われている、証明書に問題があるなど、様々なトラブルやセキュリティリスクが存在します。
これらの問題を診断し、確認するための強力なツールが、OpenSSLプロジェクトが提供するコマンドラインツールセットの一部である openssl s_client
です。
openssl s_client
は、指定したサーバーに対してクライアントとしてTLS/SSL接続を確立し、その過程や結果に関する詳細な情報を表示します。これにより、サーバーがどのTLS/SSLバージョンをサポートしているか、どのような暗号スイートを提供しているか、サーバー証明書は有効か、証明書チェーンは正しいか、相互認証は機能するか、といった多岐にわたる確認を行うことができます。
この記事では、openssl s_client
の基本的な使い方から、詳細なオプション、具体的なテストシナリオ、出力の見方、そしてよくあるエラーとそのトラブルシューティングまでを網羅的に解説します。これを読めば、あなたも openssl s_client
を使いこなせるようになり、TLS/SSL接続に関する様々な問題を解決できるようになるでしょう。
OpenSSLとは
openssl s_client
は、OpenSSLというプロジェクトの一部です。OpenSSLとは、SSL/TLSプロトコルのオープンソースによる実装であり、暗号化、証明書管理、鍵生成など、広範な暗号関連機能を提供するC言語ライブラリおよびコマンドラインツールキットです。
Linux、macOS、Windowsなど、ほとんどのオペレーティングシステムで利用可能であり、多くのソフトウェアやデバイスに組み込まれています。ウェブサーバー(Apache, Nginx)、メールサーバー、VPNソフトウェアなど、セキュリティを必要とする様々なアプリケーションでOpenSSLライブラリが利用されています。
openssl
コマンドは、このOpenSSLライブラリの機能にアクセスするためのインタフェースを提供します。証明書の生成・管理、秘密鍵の操作、暗号化・復号、ハッシュ計算など、様々な用途に使われます。openssl s_client
は、その中でも特にTLS/SSLクライアントとしての接続機能に特化したサブコマンドです。
openssl s_client
の基本
openssl s_client
コマンドの最も基本的な役割は、指定したホストとポートに対してTLS/SSL接続を試みることです。接続が成功すれば、TLS/SSLハンドシェイクの過程で交換される情報や、確立されたセッションの詳細、サーバー証明書の情報などを表示します。
基本書式
bash
openssl s_client [options] -connect host:port
[options]
: コマンドの挙動を制御するための様々なオプションを指定します。-connect host:port
: 必須オプションです。接続先のホスト名またはIPアドレスと、ポート番号を指定します。TLS/SSL接続が通常使用するポートはHTTPSなら443、LDAPSなら636などです。
最小限の実行例
例えば、www.google.com
のHTTPSポート(443)に接続する場合、最もシンプルなコマンドは以下のようになります。
bash
openssl s_client -connect www.google.com:443
このコマンドを実行すると、以下のような処理が行われます。
www.google.com
のIPアドレスをDNSで解決します。- 解決されたIPアドレスのポート443に対してTCP接続を確立します。
- TCP接続が確立された後、TLS/SSLハンドシェイクを開始します。
- ハンドシェイクが成功すると、TLS/SSLセッションが確立されます。
openssl s_client
は、確立されたセッションの詳細情報、サーバーから提示された証明書、証明書検証の結果などを標準出力に表示します。- その後、標準入力からの入力をサーバーに送信し、サーバーからの応答を受信できる状態になります(インタラクティブモード)。
GET / HTTP/1.1\nHost: www.google.com\n\n
のようにHTTPリクエストを入力して、ウェブサーバーの応答を確認することも可能です。 - サーバー側から接続が切断されるか、標準入力が閉じられる(Ctrl+Dなど)と、
openssl s_client
は終了します。
基本的な出力の見方(成功例)
成功した場合の出力は、OpenSSLのバージョンや設定、サーバーの設定によって多少異なりますが、主要な部分は以下のようになります。
“`
CONNECTED(00000003) # TCP接続が成功したことを示す
— TLSハンドシェイクの開始 —
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com
verify return:1 # 証明書チェーンの検証が成功したことを示す (深度0からルートまで)
— サーバー証明書の情報 —
Certificate chain
0 s:C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com # サーバー証明書
i:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3 # 発行者 (中間CA)
1 s:C = US, O = Google Trust Services LLC, CN = GTS CA 1C3 # 中間CA証明書
i:C = US, O = Google Trust Services LLC, CN = GTS Root R2 # 発行者 (ルートCA)
2 s:C = US, O = Google Trust Services LLC, CN = GTS Root R2 # ルートCA証明書
i:O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA # 発行者 (さらに上のルート、または自己署名)
OpenSSLのバージョンによっては、信頼ストアの証明書まで表示されないこともあります。
Server certificate # 深度0の証明書の詳細 (省略されることが多い)
証明書の詳細情報 (Subject, Issuer, Validity, Public Keyなど)
subject=/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com
issuer=/C=US/O=Google Trust Services LLC/CN=GTS CA 1C3
No client certificate requested # サーバーがクライアント証明書を要求しなかった
SSL-Session: # 確立されたTLSセッションの詳細
Protocol : TLSv1.3 # 使用されたTLS/SSLバージョン
Cipher : TLS_AES_256_GCM_SHA384 # 使用された暗号スイート
Session-ID: …
Session-ID-ctx:
Master-Key: …
Keying Material Export: …
PSK identity: None
PSK identity hint: None
Start Time: …
Timeout : 7200 (sec)
Verify return code: 0 (ok) # 最も重要 証明書検証の結果。0は成功を意味する。
Extended master secret: yes
“`
この出力から、以下の重要な情報が得られます。
- 接続が成功したこと (
CONNECTED
)。 - サーバー証明書チェーンが検証され、信頼できるものであること (
verify return code: 0 (ok)
)。 - 使用されたプロトコルバージョン (
Protocol: TLSv1.3
)。 - 使用された暗号スイート (
Cipher: TLS_AES_256_GCM_SHA384
)。 - サーバー証明書のSubject (
CN=*.google.com
など) や発行者 (Issuer
) の情報。 - サーバーがクライアント証明書を要求したか (
No client certificate requested
)。
基本的な接続テストでは、CONNECTED
が表示されること、そして最も重要な Verify return code: 0 (ok)
が表示されることを確認します。Verify return code
が0以外の値の場合、証明書の検証に何らかの問題があることを示しています。
openssl s_client
の主要なオプションと使い方
openssl s_client
の真価は、豊富なオプションを組み合わせることで、様々な条件での接続テストや詳細情報の取得が可能になる点にあります。ここでは、特によく使われる重要なオプションをカテゴリ別に解説します。
接続先指定
-connect host:port
: 接続先を指定します。ホスト名はFQDN(完全修飾ドメイン名)でもIPアドレスでも構いません。ポート番号は必須です。- 例:
-connect www.example.jp:443
,-connect 192.168.1.100:8443
- 例:
TLS/SSLバージョンの指定
サーバーがサポートするTLS/SSLバージョンを確認したり、特定のバージョンでの接続を強制したりするために使用します。古いバージョン(SSLv2, SSLv3, TLSv1.0, TLSv1.1)には既知の脆弱性があるため、これらを無効化する設定が推奨されます。
-ssl2
: SSLv2での接続を試みます(非推奨、ほとんどのサーバーで無効)。-ssl3
: SSLv3での接続を試みます(非推奨、POODLE脆弱性など)。-tls1
: TLSv1.0での接続を試みます(非推奨)。-tls1_1
: TLSv1.1での接続を試みます(非推奨)。-tls1_2
: TLSv1.2での接続を試みます(広く使用されているバージョン)。-tls1_3
: TLSv1.3での接続を試みます(最新のバージョン)。
これらのオプションは、指定したバージョンのみを許可します。例えば -tls1_2
を指定すると、サーバーがTLSv1.2をサポートしていない場合はハンドシェイクエラーになります。
特定のバージョンを無効化するには、-no_ssl2
, -no_ssl3
, -no_tls1
, -no_tls1_1
, -no_tls1_2
, -no_tls1_3
オプションを使用します。
- 例:
-no_ssl3 -no_tls1 -no_tls1_1
(TLSv1.2以上を強制したい場合)
OpenSSL 1.1.1以降では、より柔軟な指定が可能な -min_tls
および -max_tls
オプションが導入されました。
-min_tls version
: 許可するTLSの最小バージョンを指定します (tls1.2
,tls1.3
など)。-max_tls version
: 許可するTLSの最大バージョンを指定します (tls1.2
,tls1.3
など)。- 例:
-min_tls tls1.2 -max_tls tls1.3
(TLSv1.2またはTLSv1.3のみ許可)
- 例:
歴史的背景とセキュリティ上の注意:
* SSLv2, SSLv3: 重大な脆弱性があり、完全に無効化すべきです。
* TLSv1.0, TLSv1.1: これらにもいくつかの脆弱性が発見されており、PCI DSSなどのセキュリティ基準では無効化が求められています。特別な理由がない限り、TLSv1.2以上を使用すべきです。
* TLSv1.2: 現在最も広く互換性があり、十分に安全とされているバージョンです。
* TLSv1.3: TLSの最新バージョンで、ハンドシェイクの高速化やセキュリティの強化が図られています。TLSv1.2に比べて、より強力な暗号スイートのみをサポートします。
暗号スイート(Cipher Suite)の指定
TLS/SSLハンドシェイクでは、クライアントとサーバー間で合意した暗号スイートを使用して通信を暗号化します。暗号スイートは、鍵交換アルゴリズム、認証アルゴリズム、共通鍵暗号アルゴリズム、ハッシュアルゴリズムなどの組み合わせを定義します。
脆弱な暗号スイートを許可しているサーバーはセキュリティリスクを高めます。-cipher
オプションを使うことで、クライアントが提示する暗号スイートのリストを制御し、サーバーがどの暗号スイートを選択するかを確認できます。
-cipher cipherstring
: 使用する暗号スイートを指定します。cipherstring
はOpenSSL独自の形式で記述します。
Cipherstring の書式:
cipherstring
は、複数の暗号スイート名やキーワードを :
で区切って並べたものです。演算子を使って、リストの操作や特定のスイートの追加/除外が可能です。
:
: 区切り文字。リスト内のスイートを順番に評価します。+
: スイートをリスト内の指定位置に移動します。!
: 指定したスイートをリストから除外します。-
: 指定したスイートをリストの末尾に移動します。
よく使われるキーワード:
* ALL
: OpenSSLが知っている全ての暗号スイート。
* HIGH
: 鍵長が128ビット以上の暗号化を使用するスイート。通常はこちらを使用推奨。
* MEDIUM
: 鍵長が40ビット以上128ビット未満の暗号化を使用するスイート(非推奨)。
* LOW
: 鍵長が40ビット未満の暗号化を使用するスイート(非推奨)。
* eNULL
: 暗号化を行わないスイート(非推奨、デバッグ用)。
* aNULL
: 認証を行わないスイート(非推奨、デバッグ用)。
* RC4
: RC4を使用するスイート(非推奨、脆弱性あり)。
* 3DES
: 3DESを使用するスイート(非推奨)。
* SHA1
: ハッシュ関数にSHA1を使用するスイート(非推奨)。
指定例:
* HIGH:!aNULL:!eNULL
: 認証なし (aNULL
) や暗号化なし (eNULL
) を除く、強力な暗号スイートのみを許可する。これは一般的な安全な設定です。
* AES256-SHA256
: 特定の暗号スイートのみを試す。
* ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384
: 特定の暗号スイートのリストのみを提示する。
サーバーがサポートする暗号スイートを特定するには、クライアント側で広い範囲のスイートを許可しておき、OpenSSLの出力 (Cipher:
の行) で確認します。あるいは、様々な-cipher
指定で接続を試み、成功するかどうかで判断する方法もあります。
証明書関連オプション
サーバーから提示された証明書を確認したり、クライアント証明書を提示したりするために使用します。
-showcerts
: サーバーが提示した証明書チェーン全体を表示します。これにより、サーバー証明書だけでなく、中間CA証明書も確認できます。証明書チェーンが完全であるかどうかの確認に役立ちます。-cert file
: クライアント証明書ファイル(PEM形式)を指定します。サーバーがクライアント認証(相互認証)を要求する場合に使用します。-key file
: クライアント証明書に対応する秘密鍵ファイル(PEM形式)を指定します。-CAfile file
: 信頼できるCA証明書が含まれるファイルを指定します。システムデフォルトの信頼ストアではなく、指定したファイルのみを使ってサーバー証明書を検証する場合などに使用します。-CApath directory
: 信頼できるCA証明書が複数ファイルに分かれて格納されているディレクトリを指定します。各証明書ファイルは、OpenSSLのc_rehash
コマンドなどでハッシュ化されている必要があります。-verify depth
: 証明書チェーンの検証深度を指定します。例えば-verify 1
とすると、サーバー証明書が直接信頼できるCAによって署名されているかのみを検証し、中間CAは検証しません。通常はデフォルトのままで良いですが、特定の検証シナリオで役立ちます。-verify_return_code
: (OpenSSL 1.0.2以前) 証明書検証の結果コードを表示します。OpenSSL 1.1.0以降ではデフォルトで表示されるため不要です。-servername name
: SNI (Server Name Indication) を指定します。一つのIPアドレスで複数のHTTPSサイトを運用している場合(仮想ホスト)、このオプションでホスト名を指定しないと、意図した証明書やサイトにアクセスできないことがあります。host
がIPアドレスの場合や、-connect
でIPアドレスを指定しつつ特定のホスト名に対応する証明書を確認したい場合に特に重要です。- 例:
-connect 192.168.1.100:443 -servername www.example.com
- 例:
出力制御オプション
コマンドの出力内容を調整します。
-quiet
: TLS/SSLセッション情報や証明書検証結果などの詳細な出力を抑制し、最小限の情報のみを表示します。スクリプトなどでの使用に適しています。接続の成功/失敗のみをチェックしたい場合などに便利です。-ign_eof
: サーバーからのEOF(接続終了)を無視して、接続を維持します。これにより、ハンドシェイク完了後も手動でHTTPリクエストなどを送信し続けることができます。インタラクティブなデバッグに便利です。-debug
: デバッグ情報を表示します。TLSレコードのやり取りなど、より低レベルな情報が出力されます。トラブルシューティングの際に役立つことがあります。-msg
: TLSプロトコルのメッセージ(ClientHello, ServerHello, Certificateなど)の詳細を表示します。-debug
よりもプロトコルメッセージに特化した情報が得られます。-state
: TLSセッションの状態遷移を表示します。
プロトコルテスト関連オプション
特定のプロトコル(特にHTTP)との連携をテストする際に役立ちます。
-crlf
: 標準入力から読み込んだ各行の末尾にCRLF (\r\n
) を追加します。HTTP/1.1などのテキストベースのプロトコルでは行末にCRLFが必要なため、手動でHTTPリクエストを送信する際に便利です。-ign_eof
と組み合わせてよく使われます。
セッション再開関連オプション
TLSセッションの再開(Session Resumption)のテストに使用します。セッション再開は、二回目以降の接続でハンドシェイクの一部を省略し、接続確立を高速化する仕組みです。
-sess_out file
: 確立したセッション情報をファイルに保存します。-sess_in file
: 指定したファイルからセッション情報を読み込み、セッション再開を試みます。-hit
: セッション再開が成功したか(キャッシュにヒットしたか)を表示します。成功すればSession-ID: ... reused
のような表示になります。
その他の便利なオプション
-host name
:-connect
でIPアドレスを指定した場合に、仮想ホスト名(通常はSNIと同じ目的)を指定します。OpenSSLのバージョンによって動作が異なることがあります。一般的には-servername
が推奨されます。-uri uri
: OCSP (Online Certificate Status Protocol) ステープリングなど、証明書に関連するURIをテストするために使用できます。-status
: OCSPステープリングのテストを有効にします。サーバーが証明書の失効情報をOCSPで提供しているか確認できます。
具体的なテストシナリオと出力の読み方
ここからは、実際のコマンド実行例とその出力の詳細な読み方を見ていきましょう。
1. 基本接続とセッション情報の確認
目的: サーバーへのTLS/SSL接続が成功するか、使用されたTLSバージョンと暗号スイート、証明書検証結果を確認する。
bash
openssl s_client -connect example.com:443
出力例(重要部分抜粋):
“`
CONNECTED(00000003)
… (証明書チェーン検証の情報) …
Certificate chain
0 s:/CN=example.com # サーバー証明書のSubject
i:/C=US/O=Let’s Encrypt/CN=R3 # 発行者(中間CA)
1 s:/C=US/O=Let’s Encrypt/CN=R3 # 中間CA証明書
i:/O=Digital Signature Trust Co./CN=DST Root CA X3 # 発行者(ルートCA)
Server certificate
サーバー証明書の詳細情報 (Subject, Issuer, Validity, Public Key, Extensionsなど)
…
Validity
Not Before: Jan 1 00:00:00 2023 GMT # 有効開始日
Not After : Dec 31 23:59:59 2023 GMT # 有効終了日
…
Subject Alternative Name: # SANs (一つの証明書で複数のホスト名をカバーする場合)
DNS:example.com, DNS:www.example.com
…
No client certificate requested
SSL-Session:
Protocol : TLSv1.2 # 使用されたプロトコル
Cipher : ECDHE-RSA-AES128-GCM-SHA256 # 使用された暗号スイート
Session-ID: …
Start Time: …
Timeout : 300 (sec)
Verify return code: 0 (ok) # 証明書検証結果。0は成功。
ハンドシェイク完了後、標準入力から入力可能になる
GET / HTTP/1.1
Host: example.com
Connection: close
サーバーからの応答が表示される
… (HTTP応答ヘッダーやコンテンツ) …
“`
読み方:
CONNECTED
: TCP接続は成功。depth=X verify return:Y
: 証明書チェーンの検証過程。depth
はチェーンの深さ(0が末端のサーバー証明書)。verify return:1
はその証明書までのチェーンが有効であることを示す(ただし最終的な検証結果ではない)。Certificate chain
: サーバーが提示した証明書のリスト。0がサーバー証明書、1が中間CA証明書、… と続きます。s:
はSubject(その証明書の主体)、i:
はIssuer(その証明書を発行したCA)を示します。このリストがシステムの信頼ストアのルートCAまで繋がっている必要があります。Server certificate
: 深度0の証明書の詳細。Subject
: 証明書が発行されたエンティティ。Common Name (CN=...
) が主な識別名ですが、Subject Alternative Name
(SAN) フィールドの方がより正確にホスト名を識別します。Issuer
: 証明書を発行したCA。Validity
: 証明書の有効期間。Not Before
からNot After
まで有効です。現在日時がこの期間外だと検証エラーになります。Subject Alternative Name
: この証明書が有効なホスト名(やIPアドレスなど)のリスト。ブラウザやopenssl s_client
はこのフィールドを見て、接続しようとしているホスト名と証明書が一致するか検証します。
SSL-Session
: 確立されたセッションの詳細。Protocol
: 最終的に合意されたTLS/SSLバージョン。Cipher
: 最終的に合意された暗号スイート。Verify return code
: 最重要。証明書チェーン全体の検証結果。0 (ok)
ならば、証明書は有効で、信頼できるCAによって署名されており、ホスト名も一致し、有効期限内であることを示します。
Verify return code
の一般的なエラーコード:
0 (ok)
: 検証成功。2 (unable to get issuer certificate)
: 中間CA証明書が見つからない(証明書チェーンが不完全)。3 (unable to get certificate CRL)
: 証明書失効リスト(CRL)を取得できない。6 (certificate signature failure)
: 証明書の署名が不正。7 (certificate rejected)
: 証明書が拒否された(ポリシー違反など)。9 (certificate is not yet valid)
: 有効期限開始前。10 (certificate expired)
: 有効期限切れ。18 (self signed certificate)
: 自己署名証明書(信頼できるCAに署名されていない)。20 (unable to get local issuer certificate)
: システムまたは指定されたCAファイル/パスに、チェーン上のCA証明書が見つからない。21 (unable to verify the first certificate)
: チェーンの最初の証明書(サーバー証明書)を検証できない。通常は署名検証失敗、期限切れ、または信頼できない発行者。22 (certificate has unsupported critical extension)
: サポートされていないクリティカルな拡張が含まれている。23 (certificate has unsupported critical extension)
: サポートされていないクリティカルな拡張が含まれている。24 (certificate purpose not supported)
: 証明書の用途が適切でない (e.g. サーバー認証にクライアント認証用証明書を使おうとしている)。26 (unsupported certificate purpose)
: サポートされていない証明書の用途。27 (certificate not trusted)
: 証明書が信頼されていない(指定された用途に対して)。48 (invalid hostname)
: 接続しようとしているホスト名と証明書のSAN/CNが一致しない。
検証エラー (Verify return code
が0以外) の場合は、そのコードとOpenSSLのドキュメントを照らし合わせ、原因を特定します。特に 18
, 20
, 21
, 48
はよく遭遇するエラーです。
2. 証明書チェーン全体の確認
目的: サーバー証明書だけでなく、中間CA証明書やルートCA証明書まで含めたチェーン全体を確認する。
bash
openssl s_client -showcerts -connect example.com:443
-showcerts
オプションを使うと、Certificate chain
のセクションにリストされた各証明書(0から順番に)の詳細が、---BEGIN CERTIFICATE---
から ---END CERTIFICATE---
の形式で表示されます。
“`
…
Certificate chain
0 s:/CN=example.com
i:/C=US/O=Let’s Encrypt/CN=R3
—–BEGIN CERTIFICATE—–
… (サーバー証明書のPEMデータ) …
—–END CERTIFICATE—–
1 s:/C=US/O=Let’s Encrypt/CN=R3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
—–BEGIN CERTIFICATE—–
… (中間CA証明書のPEMデータ) …
—–END CERTIFICATE—–
… (SSL-Session情報など) …
“`
読み方:
表示されたPEM形式の証明書データをコピーし、以下のコマンドで詳細を確認できます。
“`bash
サーバー証明書の詳細を確認
echo “—–BEGIN CERTIFICATE—–
… (サーバー証明書のPEMデータ) …
—–END CERTIFICATE—–” | openssl x509 -text -noout
中間CA証明書の詳細を確認
echo “—–BEGIN CERTIFICATE—–
… (中間CA証明書のPEMデータ) …
—–END CERTIFICATE—–” | openssl x509 -text -noout
“`
これにより、各証明書のSubject, Issuer, Validity, Public Key, Extensions (SAN, AIA, CDPなど) を詳細に確認できます。チェーンが途中で切れていないか(発行者 i:
と次の証明書の主体 s:
が一致するか)、ルートCAがシステムの信頼ストアにあるかなどを手動で確認する際に役立ちます。
3. 特定のTLSバージョンでの接続テスト
目的: サーバーが特定のTLSバージョン(例: TLSv1.2またはTLSv1.3)をサポートしているか確認する。
“`bash
TLSv1.2のみで接続を試みる
openssl s_client -tls1_2 -connect example.com:443
“`
出力の Protocol
が TLSv1.2
になっていれば成功です。接続が失敗し alert handshake failure
のようなエラーが出力される場合は、サーバーがTLSv1.2をサポートしていない、または他の原因(暗号スイートの不一致など)でハンドシェイクに失敗したことを意味します。
“`bash
TLSv1.3のみで接続を試みる
openssl s_client -tls1_3 -connect example.com:443
“`
同様に、出力の Protocol
が TLSv1.3
になれば成功です。
“`bash
古いバージョン(SSLv3, TLSv1.0, TLSv1.1)を無効にして接続を試みる (推奨設定の確認)
openssl s_client -no_ssl3 -no_tls1 -no_tls1_1 -connect example.com:443
“`
このコマンドで接続が成功し、Protocol
が TLSv1.2
または TLSv1.3
になれば、サーバーは古いバージョンを許可していないことが確認できます。もし接続が失敗する場合、サーバーがTLSv1.2以上のバージョンをサポートしていないか、または古いバージョンを無効化しているにも関わらずクライアント(openssl s_client)が提示する暗号スイートとサーバーの許可する暗号スイートに互換性がない可能性が考えられます。
4. 特定の暗号スイートでの接続テスト
目的: サーバーが特定の暗号スイートをサポートしているか確認する。あるいは、脆弱な暗号スイートを許可していないか確認する。
“`bash
脆弱なRC4暗号スイートを強制して接続を試みる
openssl s_client -cipher ‘RC4’ -connect example.com:443
“`
このコマンドで接続が成功し、Cipher
が RC4-SHA
や RC4-MD5
のようになる場合、サーバーはRC4を許可しています。これはセキュリティ上のリスクがあるため、サーバー側でRC4を無効化することを検討すべきです。
“`bash
認証なし(aNULL)や暗号化なし(eNULL)のスイートを強制して接続を試みる
openssl s_client -cipher ‘aNULL’ -connect example.com:443
openssl s_client -cipher ‘eNULL’ -connect example.com:443
“`
これらが成功する場合も、サーバーの設定に問題があります。
“`bash
高セキュリティな暗号スイートのみを許可して接続を試みる
openssl s_client -cipher ‘HIGH:!aNULL:!eNULL:!LOW:!3DES:!RC4:!MD5:!SHA1’ -connect example.com:443
“`
このコマンドで接続が成功し、Cipher
が ECDHE/DHE + AES-GCM/CHACHA20 + SHA256/SHA384 のような強力なスイートになっていれば、サーバーは安全な暗号スイートをサポートしていることが確認できます。
サーバーがサポートする暗号スイートの列挙:
openssl s_client
にはサーバーがサポートする全ての暗号スイートを直接列挙するオプションはありません。しかし、クライアントが提示する暗号リストを一つずつ変えながら接続を試みるスクリプトを作成することで、サーバーが優先する順序やサポートしているスイートをある程度特定できます。これはより高度なテストであり、例えばSSL LabsのSSL Server Testのようなサービスが自動で行っています。
5. SNI (Server Name Indication) のテスト
目的: 同じIPアドレスで複数のHTTPSサイトを運用しているサーバーで、指定したホスト名に対応する証明書が提示されるか確認する。
まず、テスト対象のサーバーのIPアドレスを特定します。
“`bash
例: www.example.com のIPアドレスを調べる
dig +short www.example.com
または
host www.example.com
“`
例えばIPアドレスが 192.0.2.1
だったとします。
SNIを指定しない場合(IPアドレスで直接接続):
bash
openssl s_client -connect 192.0.2.1:443
この場合、サーバーはSNI情報がないため、デフォルトの証明書を返したり、ハンドシェイクに失敗したりする可能性があります。
SNIを指定する場合:
bash
openssl s_client -servername www.example.com -connect 192.0.2.1:443
このコマンドを実行すると、サーバーはSNIで受け取った www.example.com
に対応する証明書を返します。出力される証明書のSubjectやSANsが www.example.com
と一致するか確認します。
SNIが正しく機能しているか確認することは、仮想ホスト環境で非常に重要です。証明書検証エラー(Verify return code: 48 (invalid hostname) など)の原因が、SNIの指定漏れであることもよくあります。
6. クライアント証明書認証(相互認証)のテスト
目的: サーバーがクライアント証明書認証を要求するように設定されているか、手持ちのクライアント証明書と秘密鍵で認証が成功するか確認する。
事前にクライアント証明書ファイル (client.crt
) と秘密鍵ファイル (client.key
) をPEM形式で用意しておく必要があります。
bash
openssl s_client -cert client.crt -key client.key -connect secure.example.com:443
コマンドを実行すると、TLSハンドシェイク中にサーバーがクライアント証明書を要求します。openssl s_client
は指定された client.crt
をサーバーに提示します。
出力のポイント:
Client Certificate Types:
: サーバーが受け入れるクライアント証明書のタイプ(RSA, ECDSAなど)が表示されます。Certificate Authorities:
: サーバーが信頼するクライアントCAのリストが表示されることがあります。No client certificate requested
: サーバーがクライアント証明書を要求しなかった場合。SSL-Session
のセクションに、クライアント証明書認証が成功したかどうかの情報が含まれる場合があります。- サーバーによっては、クライアント証明書認証の成否によって、ハンドシェイクが続行されるか、
alert handshake failure
になるか、あるいは特定のHTTPステータスコード(401 Unauthorizedなど)を返すかで判断できます。
認証が成功しない場合、以下の原因が考えられます。
- サーバーがクライアント証明書認証を要求する設定になっていない。
- 提示したクライアント証明書がPEM形式でないか、破損している。
- 指定した秘密鍵が証明書と一致しない。
- クライアント証明書がサーバーが信頼するCAによって発行されていない。
- クライアント証明書が失効している、または有効期限切れ。
7. 証明書検証の詳細(CAファイル/パスの指定)
目的: システムの信頼ストアではなく、特定のCA証明書ファイルやディレクトリを使用してサーバー証明書を検証する。
“`bash
信頼できるCA証明書を単一ファイルで指定
openssl s_client -CAfile my-custom-ca.crt -connect example.com:443
“`
my-custom-ca.crt
は、検証に使用したいルートCAや中間CAの証明書をPEM形式で連結したファイルです。
“`bash
信頼できるCA証明書をディレクトリで指定
openssl s_client -CApath /path/to/ca/certs -connect example.com:443
“`
/path/to/ca/certs
は、複数のCA証明書ファイルが格納されたディレクトリで、OpenSSLの c_rehash
コマンドなどでハッシュ化インデックスが作成されている必要があります。
これらのオプションは、独自のPKI環境や、システムの信頼ストアにまだ含まれていない新しいCAチェーンをテストする際に役立ちます。Verify return code
を見て、指定したCAファイル/パスを使って検証が成功するか確認します。
8. HTTPS以外のTLSサービスへの接続
目的: HTTPS (443) 以外のTLS/SSLを使用するサービスへの接続をテストする。
TLS/SSLは様々なプロトコルに適用可能です。代表的な例としては以下のポートがあります。
- LDAPS: 636
- SMTPS (submission): 587 (STARTTLS) または 465 (Implicit TLS)
- POP3S: 995
- IMAPS: 993
- FTPS: 990 (Implicit TLS)
openssl s_client
はデフォルトでImplicit TLS(接続開始直後からTLSハンドシェイクを行う)に対応しています。
“`bash
LDAPSサーバーへの接続テスト
openssl s_client -connect ldap.example.com:636
POP3Sサーバーへの接続テスト
openssl s_client -connect pop.example.com:995
Implicit FTPSサーバーへの接続テスト
openssl s_client -connect ftp.example.com:990
“`
STARTTLSを使用するサービス(SMTP 587, POP3 110, IMAP 143, FTP 21など)の場合、まず平文で接続し、対応するコマンド(STARTTLS
)を送信してTLSハンドシェイクを開始する必要があります。openssl s_client
には STARTTLS
オプションがあり、これにより自動でSTARTTLSコマンドを送信し、その後のハンドシェイクを行います。
“`bash
SMTPS (STARTTLS on 587) への接続テスト
openssl s_client -starttls smtp -connect mail.example.com:587
IMAPS (STARTTLS on 143) への接続テスト
openssl s_client -starttls imap -connect mail.example.com:143
FTPS (Explicit TLS on 21) への接続テスト
openssl s_client -starttls ftp -connect ftp.example.com:21
“`
-starttls
オプションを使用する場合、指定するプロトコル名(smtp
, pop3
, imap
, ftp
など)はOpenSSLが対応している必要があります。コマンドの出力を見て、TLSハンドシェイクが正常に行われたか、証明書検証結果はどうかなどを確認します。
9. インタラクティブなHTTPリクエスト送信
目的: TLS接続確立後、手動でHTTPリクエストを送信し、サーバーの応答を確認する。
これは特に、TLS接続は成功するがアプリケーション層(HTTPなど)で問題が発生している場合に役立ちます。
bash
openssl s_client -connect example.com:443 -ign_eof -crlf
-ign_eof
: サーバーからのEOFで接続を閉じずに維持。-crlf
: 標準入力からの入力にCRLFを追加。
コマンドを実行し、TLSハンドシェイクが完了して SSL-Session
情報などが表示された後、カーソルが点滅している状態になります。ここでHTTP/1.1リクエストを入力し、Enterキーを2回押してリクエストを送信します。
“`
GET / HTTP/1.1
Host: example.com
Connection: close
Enterキーを2回押す
サーバーからのHTTP応答が表示される
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
…
“`
Connection: close
ヘッダーを含めることで、サーバーは応答を返した後に接続を閉じます。接続が閉じられると read:errno=0
のようなメッセージが表示され、openssl s_client
が終了します。
よくあるエラーとトラブルシューティング
openssl s_client
の実行中に遭遇する可能性のある一般的なエラーメッセージとその原因、対処法について解説します。
-
connect: Connection refused
- 原因: 指定したホストやポートでTCP接続自体が拒否されています。TLS/SSLハンドシェイク以前の問題です。
- 考えられる理由:
- サーバーが起動していない。
- 指定したポートでサービスが待ち受けていない。
- ファイアウォールによって接続がブロックされている(クライアント側、サーバー側、または中間ネットワーク機器)。
- 指定したホスト名やIPアドレスが間違っている。
- 対処法:
- サーバーの状態を確認する。
- サービスが正しいポートで待ち受けているか確認する (
netstat -tulnp
など)。 - ファイアウォールの設定を確認する。
- ホスト名やIPアドレス、ポート番号が正しいか再確認する。
ping
コマンドなどでホストへの基本的な到達性を確認する。
-
connect: operation timed out
- 原因: TCP接続を確立しようとしたが、タイムアウトしました。
- 考えられる理由:
- ホストが存在しない、またはネットワークから到達不能。
- ファイアウォールによって接続要求がフィルタリングされ、拒否応答も返ってこない。
- ネットワーク遅延が大きい。
- 対処法:
ping
などでホストへのネットワーク到達性を確認し、ファイアウォールの設定を再確認する。
-
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
- 原因: TLS/SSLハンドシェイクの初期段階で失敗しました。クライアント(
openssl s_client
)とサーバーの間で、共通のTLSバージョンまたは暗号スイートが見つからなかった可能性が高いです。 - 考えられる理由:
- サーバーがサポートするTLSバージョンが、クライアントが許可しているバージョンと一致しない(例: クライアントはTLSv1.2のみ許可しているが、サーバーはTLSv1.0/1.1しかサポートしていない)。
- クライアントが提示する暗号スイートリストと、サーバーが許可する暗号スイートリストに共通のものが一つもない。
- サーバー側でSSL/TLS設定に問題がある。
- SNIが必要なのに指定していない (
-servername
オプション)。 - クライアント証明書が必要なのに提示していない。
- 対処法:
-tls1_2
,-tls1_3
,-no_ssl3
などのバージョン指定オプションを調整して試す。特定のバージョンで成功するか確認する。-cipher
オプションを調整して試す。ALL
など広い範囲を許可して成功するか確認する。成功すれば、どの暗号スイートが使われたか見て、サーバーが許可しているスイートを特定する。-servername
オプションが適切か確認する。- クライアント証明書が必要なサービスであれば、
-cert
,-key
オプションを正しく指定する。 - サーバー側のTLS/SSL設定(サポートバージョン、暗号スイート、SNI設定、クライアント証明書要求設定など)を確認する。
- 原因: TLS/SSLハンドシェイクの初期段階で失敗しました。クライアント(
-
error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
- 原因: サーバーから提示された証明書の検証に失敗しました。
- 考えられる理由:
- 証明書が自己署名である (
Verify return code: 18
)。 - 証明書チェーンが不完全(中間CA証明書が足りない) (
Verify return code: 2
)。 - 証明書がシステムの信頼ストアまたは指定したCAファイル/パスで信頼されていない (
Verify return code: 20
)。 - 証明書の有効期限が切れている (
Verify return code: 10
) またはまだ有効でない (Verify return code: 9
)。 - 接続しようとしているホスト名と証明書のSAN/CNが一致しない (
Verify return code: 48
)。 - 証明書が失効している(CRLやOCSPで確認)。
- 証明書の署名が不正 (
Verify return code: 6, 21
)。
- 証明書が自己署名である (
- 対処法:
- 出力の
Verify return code
を確認し、具体的なエラーコードの意味を調べる。 -showcerts
オプションで証明書チェーンを確認し、発行者と主体が一致しているか、チェーンがルートまで繋がっているか、中間CA証明書が含まれているかを確認する。openssl x509 -text -noout
コマンドで各証明書の詳細(特にValidity, SAN, Issuer)を確認する。- 接続しているホスト名が正しいか、
-servername
オプションが必要か確認する。 - システムの信頼ストアに証明書チェーン上のCA証明書が含まれているか確認する。必要に応じて
-CAfile
や-CApath
でカスタムのCA証明書を指定する。
- 出力の
-
alert certificate_unknown
またはalert unknown_ca
- 原因: サーバー証明書チェーンの検証中に、クライアントが信頼できないCA証明書に遭遇しました。
- 考えられる理由:
- 発行元のCAがシステムの信頼ストアにない。
- 中間CA証明書が不足しており、チェーンが途中で切れている。
- 対処法:
certificate verify failed
と同様、-showcerts
でチェーンを確認し、信頼ストアに不足しているCA証明書がないか確認する。
-
alert protocol_version
- 原因: クライアントとサーバーの間で、互換性のあるTLS/SSLバージョンが見つからなかった。
- 考えられる理由:
- クライアントがサポートしているバージョンが、サーバーがサポートしているバージョンと完全に重複していない。
- クライアント側で特定のバージョンを無効化している (
-no_...
) が、サーバーはそのバージョンしかサポートしていない。 - サーバー側でサポートバージョンが限定されすぎている。
- 対処法: バージョン指定オプションを調整する。まずはオプションなしで接続を試み、サーバーがサポートするバージョンを確認する。
スクリプトでの活用例(アイデア)
openssl s_client
はコマンドラインツールであるため、シェルスクリプトなどから呼び出して自動化することも可能です。例えば、以下のスクリプトは、サーバーがTLSv1.3をサポートしているか簡易的に確認するものです。
“`bash
!/bin/bash
HOST=$1
PORT=${2:-443} # ポート指定がなければ443
if [ -z “$HOST” ]; then
echo “Usage: $0
exit 1
fi
echo “Checking TLSv1.3 support for $HOST:$PORT…”
-tls1_3 で接続を試み、Protocol行があるかチェック
grepでProtocol行をフィルタし、head -n 1で最初の行を取得
wc -l で行数をカウント (0なら失敗、1なら成功)
RESULT=$(openssl s_client -connect “$HOST:$PORT” -tls1_3 2>&1 | grep -E ‘Protocol[[:space:]]+:’ | head -n 1 | wc -l)
if [ “$RESULT” -eq 1 ]; then
echo “TLSv1.3 is likely supported.”
else
# エラーメッセージにハンドシェイク失敗が含まれるか確認
ERROR_MSG=$(openssl s_client -connect “$HOST:$PORT” -tls1_3 2>&1 >/dev/null | grep -E ‘alert handshake failure’)
if [ -n “$ERROR_MSG” ]; then
echo “TLSv1.3 support check failed (handshake failure).”
# 詳細なエラーを確認したい場合は上記エラーメッセージを表示するなど
else
echo “TLSv1.3 support check failed (other error).”
fi
fi
“`
(注: 上記はあくまで簡単な例であり、実際のスクリプトではより詳細な出力解析やエラー処理が必要です。特に証明書検証エラーなども考慮する必要があります。また、grep
の正規表現はOpenSSLのバージョンによって調整が必要な場合があります。)
同様に、サーバー証明書の有効期限をチェックするスクリプトや、特定の暗号スイートリストでの接続を試すスクリプトなども作成可能です。
まとめ
openssl s_client
は、TLS/SSL接続のテスト、デバッグ、およびサーバー設定の確認を行うための非常に強力で柔軟なツールです。その豊富なオプションを理解し、出力される情報の意味を正しく読み解くことで、以下のような様々な作業が可能になります。
- サーバーがTLS/SSLで正しく応答するか確認する。
- 使用されているTLS/SSLバージョンや暗号スイートを特定する。
- サーバー証明書が有効か、信頼できるか、ホスト名と一致するか確認する。
- 証明書チェーンが完全か確認する。
- SNIやクライアント証明書認証の設定をテストする。
- TLS接続に関する様々な問題を診断し、原因を特定する。
- HTTPS以外のTLSを使用するサービスをテストする。
TLS/SSLは複雑なプロトコルですが、openssl s_client
を活用することで、その内部動作をある程度可視化し、問題発生時の切り分けを効率的に行うことができます。サーバー管理者や開発者にとって、これはまさに必須のツールと言えるでしょう。
この記事で解説した基本的な使い方や主要オプション、具体的なテストシナリオ、そして出力の読み方を参考に、ぜひあなたの環境で openssl s_client
を実際に使ってみてください。実践を通じて、このツールの強力さと便利さを実感できるはずです。そして、TLS/SSLに関する理解も一層深まることでしょう。