これは、なにをしたくて書いたもの?
最近の通信はSSL/TLS上で行われることが多くなり、平文のものはあまり見かけなくなってきました。
平文の頃はtelnetコマンドやcurlのtelnet://
プロトコルでのアクセスでいろいろやっていましたが、SSL/TLSとなるとちょっと困ります。
こういう時はどうしたら?と思ったのですが、OpenSSLのクライアントコマンドを使うのが良さそうですね。
これからのことを考えると、openssl s_client
にもっと慣れ親しんだ方がいいのかもしれません。
openssl s_client
OpenSSLのオフィシャルサイトはこちら。
openssl s_clientコマンドのmanページはこちら。
openssl s_clientは、SSL/TLSを使ってリモートホストに接続するための汎用的なSSL/TLSクライアントを実装したコマンドです。
SSLサーバーの診断ツールとして便利だ、とされています。
This command implements a generic SSL/TLS client which connects to a remote host using SSL/TLS. It is a very useful diagnostic tool for SSL servers.
今回はこのコマンドを使っていろいろ試してみます。
環境
今回の環境は、こちら。Ubuntu Linux 22.04 LTSです。
$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy $ uname -srvmpio Linux 5.15.0-83-generic #92-Ubuntu SMP Mon Aug 14 09:30:42 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
OpenSSLのバージョン。
$ openssl version OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
また、Ubuntu Linux 22.04 LTSをもう1台用意して、こちらにSSL/TLSを有効化したApacheをインストールしておきます。
$ sudo apt install apache2 $ sudo systemctl enable apache2
$ sudo a2enmod ssl $ sudo a2ensite default-ssl $ sudo systemctl restart apache2
このApacheが稼働するサーバーのIPアドレスは、192.168.33.10とします。
ヘルプを見る
なにはともあれ、まずはヘルプから。
$ openssl s_client -help
SSL/TLSサーバーに接続する
-connect
の後に[host:port]
形式で、接続先を指定します。
$ openssl s_client -connect [host:port]
HTTPSでアクセスしてみる
HTTPSでアクセスしてみましょう。用意したApacheにアクセスしてみます。
$ openssl s_client -connect 192.168.33.10:443 -crlf
-crlf
オプションは、改行をCRLFで送信するものです。
証明書情報などがいろいろ出力されて、入力待ちになります。
CONNECTED(00000003) Can't use SSL_get_servername depth=0 CN = ubuntu2204.localdomain verify error:num=18:self-signed certificate verify return:1 depth=0 CN = ubuntu2204.localdomain verify return:1 --- Certificate chain 0 s:CN = ubuntu2204.localdomain i:CN = ubuntu2204.localdomain a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Sep 9 13:39:03 2023 GMT; NotAfter: Sep 6 13:39:03 2033 GMT --- Server certificate -----BEGIN CERTIFICATE----- MIIDHzCCAgegAwIBAgIUMZMUSvCr6TT7hGfk9OoJGFmmBgAwDQYJKoZIhvcNAQEL BQAwITEfMB0GA1UEAwwWdWJ1bnR1MjIwNC5sb2NhbGRvbWFpbjAeFw0yMzA5MDkx MzM5MDNaFw0zMzA5MDYxMzM5MDNaMCExHzAdBgNVBAMMFnVidW50dTIyMDQubG9j YWxkb21haW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgsQH1T4yX TpXXNQtC/KuSPpAGk+XpwSsdSQ21MrscFWojw7T+Hv/+tmKNvVI7/4i8w6sf56Jk tQwFnF+BsaVUwMe/kFRF6A98uUjMWsOmpnP4BP4U43eqaBwQSQG+ylsqSyiwMnM1 qkrGafrc4FAUM5Oi2X+dH9TbzEUJdgijGYEc5L06IozyS/M6hul6jbGupnNxHuKG EwWj07T77DhL/0oV5asu4S8CuYLn2IGcrqlU58Nqv0lt2n97OnSlcocnFlDcdVc7 4DQ/ThmVsXaZR2CghWdsgQaN5rTM/Fn3XJxnqOp/wBgSVrJAWtKMAaVFJPm0W1KJ UcaFGJQzHsZ9AgMBAAGjTzBNMAkGA1UdEwQCMAAwIQYDVR0RBBowGIIWdWJ1bnR1 MjIwNC5sb2NhbGRvbWFpbjAdBgNVHQ4EFgQUtgGicseT4uY5IR/zyIkyAfwJJE8w DQYJKoZIhvcNAQELBQADggEBAHG39cf00tFMNNInCY6Y39H3vjjL8zzvn085jaPs PVceDWWxHNU1tPlHKgPQVJEvpbd8SX7AG66b0/vvlAOOAE0E8gxrHkbZBQXqMVSN 3ILtYQ6byDk3QazwnPBNLHLG08M5X/ySuBHxDsqx07E2Fm1jTZ/zZBxbMwWyZbKT jIbMYe5GqiAW4mXwc0uxOQx559jhP/dpO9ncUyg7ScWuZEQeaMJn9q0YiJxSIlKD Lb3brYuDNq0N4kfXLKKcfd4jcmZsLYo7a+WUO5Sg5ZUxsjOXZEqXxdVfRULnob7C r/rE3QtTqdOH1hrclCMnKfkxnZju1tk/PSaLTlxtzxNYY/E= -----END CERTIFICATE----- subject=CN = ubuntu2204.localdomain issuer=CN = ubuntu2204.localdomain 〜省略〜 --- read R BLOCK
ちなみに、Apacheの証明書は自己署名証明書なのですが、特にエラーにならないようです。
HTTPリクエストを入力。
GET / HTTP/1.1 Host: 192.168.33.10
レスポンス。
GET / HTTP/1.1 Host: 192.168.33.10 HTTP/1.1 200 OK Date: Sat, 09 Sep 2023 13:49:48 GMT Server: Apache/2.4.52 (Ubuntu) Last-Modified: Sat, 09 Sep 2023 13:39:08 GMT ETag: "29af-604ed37b097b8" Accept-Ranges: bytes Content-Length: 10671 Vary: Accept-Encoding Content-Type: text/html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> 〜省略〜
最初の証明書情報を表示させたくない場合は、-quiet
オプションを指定します。
$ openssl s_client -connect 192.168.33.10:443 -crlf -quiet
表示内容は、これくらいに少なくなります。
Can't use SSL_get_servername depth=0 CN = ubuntu2204.localdomain verify error:num=18:self-signed certificate verify return:1 depth=0 CN = ubuntu2204.localdomain verify return:1
この後は入力待ちになります。
ちなみに、アクセス先がApacheの場合、-crlf
がないとBad Requestを返すようです。
GET / HTTP/1.1 HTTP/1.1 400 Bad Request Date: Sat, 09 Sep 2023 13:52:23 GMT Server: Apache/2.4.52 (Ubuntu) Content-Length: 315 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> <hr> <address>Apache/2.4.52 (Ubuntu) Server at ubuntu2204.localdomain Port 443</address> </body></html> closed
HTTPヘッダーを入力する前に弾かれてしまいます。
サーバーの証明書を取得する
サーバーの証明書を取得するには、以下のコマンドを実行します。
$ echo | openssl s_client -connect 192.168.33.10:443 2>&1 | \ perl -wn -e 'print if /-BEGIN CERTIFICATE-/ .. /-END CERTIFICATE-/' > server.crt
後半はPerl One Linerで、証明書の部分だけを切り取っています。使わない場合は、別の方法(エディタなど)で証明書の部分を
切り出しましょう。
このようなファイルが取得できました。
server.crt
-----BEGIN CERTIFICATE----- MIIDHzCCAgegAwIBAgIUMZMUSvCr6TT7hGfk9OoJGFmmBgAwDQYJKoZIhvcNAQEL BQAwITEfMB0GA1UEAwwWdWJ1bnR1MjIwNC5sb2NhbGRvbWFpbjAeFw0yMzA5MDkx MzM5MDNaFw0zMzA5MDYxMzM5MDNaMCExHzAdBgNVBAMMFnVidW50dTIyMDQubG9j YWxkb21haW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgsQH1T4yX TpXXNQtC/KuSPpAGk+XpwSsdSQ21MrscFWojw7T+Hv/+tmKNvVI7/4i8w6sf56Jk tQwFnF+BsaVUwMe/kFRF6A98uUjMWsOmpnP4BP4U43eqaBwQSQG+ylsqSyiwMnM1 qkrGafrc4FAUM5Oi2X+dH9TbzEUJdgijGYEc5L06IozyS/M6hul6jbGupnNxHuKG EwWj07T77DhL/0oV5asu4S8CuYLn2IGcrqlU58Nqv0lt2n97OnSlcocnFlDcdVc7 4DQ/ThmVsXaZR2CghWdsgQaN5rTM/Fn3XJxnqOp/wBgSVrJAWtKMAaVFJPm0W1KJ UcaFGJQzHsZ9AgMBAAGjTzBNMAkGA1UdEwQCMAAwIQYDVR0RBBowGIIWdWJ1bnR1 MjIwNC5sb2NhbGRvbWFpbjAdBgNVHQ4EFgQUtgGicseT4uY5IR/zyIkyAfwJJE8w DQYJKoZIhvcNAQELBQADggEBAHG39cf00tFMNNInCY6Y39H3vjjL8zzvn085jaPs PVceDWWxHNU1tPlHKgPQVJEvpbd8SX7AG66b0/vvlAOOAE0E8gxrHkbZBQXqMVSN 3ILtYQ6byDk3QazwnPBNLHLG08M5X/ySuBHxDsqx07E2Fm1jTZ/zZBxbMwWyZbKT jIbMYe5GqiAW4mXwc0uxOQx559jhP/dpO9ncUyg7ScWuZEQeaMJn9q0YiJxSIlKD Lb3brYuDNq0N4kfXLKKcfd4jcmZsLYo7a+WUO5Sg5ZUxsjOXZEqXxdVfRULnob7C r/rE3QtTqdOH1hrclCMnKfkxnZju1tk/PSaLTlxtzxNYY/E= -----END CERTIFICATE-----
SSL/TLS証明書を指定してアクセスする
$ openssl s_client -connect 192.168.33.10:443 -crlf
よく見るとアクセス時にverify error
が出力されていました。
CONNECTED(00000003) Can't use SSL_get_servername depth=0 CN = ubuntu2204.localdomain verify error:num=18:self-signed certificate verify return:1 depth=0 CN = ubuntu2204.localdomain verify return:1
証明書の検証にも失敗しています。
--- SSL handshake has read 1363 bytes and written 404 bytes Verification error: self-signed certificate ---
これでコマンドが止まったりはしないのですが。
ここで、先程取得したサーバー証明書を-CAfile
オプションで指定することで、このエラーが出ないようにすることができます。
$ openssl s_client -connect 192.168.33.10:443 -crlf -CAfile server.crt
今度は、証明書のエラーが出なくなりました。
CONNECTED(00000003) Can't use SSL_get_servername depth=0 CN = ubuntu2204.localdomain verify return:1
こちらもOKです。
--- SSL handshake has read 1359 bytes and written 373 bytes Verification: OK ---
証明書エラーになる場合に停止する
-verify_return_error
オプションを指定すると、証明書エラーになると処理を停止します。
$ openssl s_client -connect 192.168.33.10:443 -crlf -verify_return_error
ここで止まります。
CONNECTED(00000003) Can't use SSL_get_servername depth=0 CN = ubuntu2204.localdomain verify error:num=18:self-signed certificate 40671ED1CC7F0000:error:0A000086:SSL routines:tls_post_process_server_certificate:certificate verify failed:../ssl/statem/statem_clnt.c:1883: --- Certificate chain 0 s:CN = ubuntu2204.localdomain i:CN = ubuntu2204.localdomain a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Sep 9 13:39:03 2023 GMT; NotAfter: Sep 6 13:39:03 2033 GMT --- no peer certificate available --- No client certificate CA names sent Server Temp Key: X25519, 253 bits --- SSL handshake has read 999 bytes and written 300 bytes Verification error: self-signed certificate --- New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 18 (self-signed certificate) ---
有効な証明書を指定すると、動作するようになります。
$ openssl s_client -connect 192.168.33.10:443 -crlf -CAfile server.crt -verify_return_error
使用するプロトコルを指定する
-tlsXXX
オプションを使用します。
$ openssl s_client -connect 192.168.33.10:443 -crlf -tls1_3
$ openssl s_client -help 2>&1 | grep '\-tls1' -tls1 Just use TLSv1 -tls1_1 Just use TLSv1.1 -tls1_2 Just use TLSv1.2 -tls1_3 Just use TLSv1.3
サーバーがサポートしていないプロトコルを指定すると、エラーになります。
$ openssl s_client -connect 192.168.33.10:443 -crlf -tls1 CONNECTED(00000003) 40A7D6A9477F0000:error:0A0000BF:SSL routines:tls_setup_handshake:no protocols available:../ssl/statem/statem_lib.c:104: --- no peer certificate available --- No client certificate CA names sent --- SSL handshake has read 0 bytes and written 7 bytes Verification: OK --- New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 0 (ok) ---
このあたりは、以前こちらで確認しました。
サーバーが対応しているSSL/TLSプロトコルを確認する(openssl s_client、nmap) - CLOVER🍀
使いたくないプロトコルを-no_tlsXXX
で指定することもできます。
$ openssl s_client -connect 192.168.33.10:443 -crlf -no_tls1
このあたりが指定できますね。
$ openssl s_client -help 2>&1 | grep '\-no_tls1' -no_tls1 Just disable TLSv1 -no_tls1_1 Just disable TLSv1.1 -no_tls1_2 Just disable TLSv1.2 -no_tls1_3 Just disable TLSv1.3
暗号スイートを指定する
-ciphersuites
オプションで、TLSv1.3で使用する暗号スイートを指定できます。
$ openssl s_client -connect 192.168.33.10:443 -crlf -ciphersuites TLS_AES_128_GCM_SHA256
複数指定する場合は、:
で区切ります。
$ openssl s_client -connect 192.168.33.10:443 -crlf -ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
使用できる暗号スイートは、以下のようなコマンドでプロトコルごとに確認するとよいでしょう。
$ openssl ciphers -v -s -tls1_3
TLSv1.2以下の場合は、-cipher
で指定します。
$ openssl s_client -connect 192.168.33.10:443 -crlf -cipher 'HIGH:!aNULL:!MD5' -tls1_2
これについては、こちらにも書きました。
OpenSSLでの暗号スイートと指定方法を確認する(+Apache、nginxでのIPAガイド設定例含む)) - CLOVER🍀
プロキシサーバーを指定する
-proxy
オプションを指定することで、プロキシサーバーを介してアクセスします。
$ openssl s_client -connect [host]:[port] -proxy [proxy-host]:[proxy-port]
-connect
と合わせて使うことで、指定されたプロキシサーバーにHTTP CONNECTでアクセスします。
サーバー名を指定する
デフォルトでは、-connect
で指定された名前がサーバー名としてClientHelloメッセージで使われます。
これと異なる名前を指定する場合は-servername
オプションで指定します。
$ openssl s_client -connect 192.168.33.10:443 -crlf -servername ubuntu2204.localdomain
トラフィックをダンプする(デバッグする)
あまり使うことはないかもしれませんが、-debug
オプションを指定します。
$ openssl s_client -connect 192.168.33.10:443 -crlf -debug
おわりに
OpenSSLのs_clientコマンドについて、いろいろ調べてみました。
軽く試すくらいにするつもりが、オプションを眺めていたらけっこう増えてしまいましたが。
これからちゃんと使えていけたらいいなと思います。