labunix's blog

labunixのラボUnix

「openssl s_client」でSSLサーバのテストを行ってみる。

■「openssl s_client」でSSLサーバのテストを行ってみる。

$ lsb_release -d
Description:	Debian GNU/Linux 8.4 (jessie)

$ openssl version
OpenSSL 1.0.1k 8 Jan 2015

■公開サイトからのSSLテストを行う場合
 「普通は公開前にテストするよね!」という人はローカル方式を探すかと思います。

 SSL Server Test
 https://www.ssllabs.com/ssltest/

■ローカルサイトからのSSLテスト
 以下よりダウンロードして実行権を付与して実行

 SSLTest
 http://www.thegreycorner.com/p/ssltest.html

$ chmod +x ssltest.pl
$ perl -v | awk '/^This/'
This is perl 5, version 20, subversion 2 (v5.20.2) built for x86_64-linux-gnu-thread-multi

■下記はデフォルトではSSLv3+RC4がデフォルトで使えていた頃の話。
 有効にしようと思えば可能だが、脆弱になるのでお勧めしない。

 openssl ciphersのDEAFULTとapache2のssl.conf
 http://labunix.hateblo.jp/entry/20140211/1392048666

 FREAK Attack(CVE2015-0204)について
 http://labunix.hateblo.jp/entry/20150305/1425487029

$ sudo openssl ciphers -V 'HIGH:MEDIUM:!aNULL:!MD5' | awk '/RC4|SSLv2/'
          0xC0,0x11 - ECDHE-RSA-RC4-SHA       SSLv3 Kx=ECDH     Au=RSA  Enc=RC4(128)  Mac=SHA1
          0xC0,0x07 - ECDHE-ECDSA-RC4-SHA     SSLv3 Kx=ECDH     Au=ECDSA Enc=RC4(128)  Mac=SHA1
          0xC0,0x0C - ECDH-RSA-RC4-SHA        SSLv3 Kx=ECDH/RSA Au=ECDH Enc=RC4(128)  Mac=SHA1
          0xC0,0x02 - ECDH-ECDSA-RC4-SHA      SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=RC4(128)  Mac=SHA1
          0x00,0x05 - RC4-SHA                 SSLv3 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=SHA1
          0x00,0x8A - PSK-RC4-SHA             SSLv3 Kx=PSK      Au=PSK  Enc=RC4(128)  Mac=SHA1

■対象のWebサーバのバージョンと使用可能な暗号化方式(SSLCipherSuite)と、暗号通信方式(SSLProtocol)の確認。
 現在のWebサーバでは、デフォルトでRC4もSSLv2も使用しないし、SSLv3も除外されている。
 HIGHは128bit以上、aNULLは認証しないものなので、検査対象は28の暗号化方式のみ。
 また、TLSv1.0もTLSv1.1も無い。

$ dpkg -l apache2 | awk '/^ii/{print $2,$3}'
apache2 2.4.10-10+deb8u4

$ awk '/^\tSSL[CP][ri]/' /etc/apache2/mods-available/ssl.conf 
	SSLCipherSuite HIGH:!aNULL
	SSLProtocol all -SSLv3

$ sudo openssl ciphers -V 'HIGH:!aNULL' | awk '/RC4|SSLv2/'

$ sudo openssl ciphers -V 'HIGH:!aNULL' | awk '!/SSLv3/{sum+=1;gsub("  *",",",$0);print}END{print sum}'
,0xC0,0x30,-,ECDHE-RSA-AES256-GCM-SHA384,TLSv1.2,Kx=ECDH,Au=RSA,Enc=AESGCM(256),Mac=AEAD
,0xC0,0x2C,-,ECDHE-ECDSA-AES256-GCM-SHA384,TLSv1.2,Kx=ECDH,Au=ECDSA,Enc=AESGCM(256),Mac=AEAD
,0xC0,0x28,-,ECDHE-RSA-AES256-SHA384,TLSv1.2,Kx=ECDH,Au=RSA,Enc=AES(256),Mac=SHA384
,0xC0,0x24,-,ECDHE-ECDSA-AES256-SHA384,TLSv1.2,Kx=ECDH,Au=ECDSA,Enc=AES(256),Mac=SHA384
,0x00,0xA3,-,DHE-DSS-AES256-GCM-SHA384,TLSv1.2,Kx=DH,Au=DSS,Enc=AESGCM(256),Mac=AEAD
,0x00,0x9F,-,DHE-RSA-AES256-GCM-SHA384,TLSv1.2,Kx=DH,Au=RSA,Enc=AESGCM(256),Mac=AEAD
,0x00,0x6B,-,DHE-RSA-AES256-SHA256,TLSv1.2,Kx=DH,Au=RSA,Enc=AES(256),Mac=SHA256
,0x00,0x6A,-,DHE-DSS-AES256-SHA256,TLSv1.2,Kx=DH,Au=DSS,Enc=AES(256),Mac=SHA256
,0xC0,0x32,-,ECDH-RSA-AES256-GCM-SHA384,TLSv1.2,Kx=ECDH/RSA,Au=ECDH,Enc=AESGCM(256),Mac=AEAD
,0xC0,0x2E,-,ECDH-ECDSA-AES256-GCM-SHA384,TLSv1.2,Kx=ECDH/ECDSA,Au=ECDH,Enc=AESGCM(256),Mac=AEAD
,0xC0,0x2A,-,ECDH-RSA-AES256-SHA384,TLSv1.2,Kx=ECDH/RSA,Au=ECDH,Enc=AES(256),Mac=SHA384
,0xC0,0x26,-,ECDH-ECDSA-AES256-SHA384,TLSv1.2,Kx=ECDH/ECDSA,Au=ECDH,Enc=AES(256),Mac=SHA384
,0x00,0x9D,-,AES256-GCM-SHA384,TLSv1.2,Kx=RSA,Au=RSA,Enc=AESGCM(256),Mac=AEAD
,0x00,0x3D,-,AES256-SHA256,TLSv1.2,Kx=RSA,Au=RSA,Enc=AES(256),Mac=SHA256
,0xC0,0x2F,-,ECDHE-RSA-AES128-GCM-SHA256,TLSv1.2,Kx=ECDH,Au=RSA,Enc=AESGCM(128),Mac=AEAD
,0xC0,0x2B,-,ECDHE-ECDSA-AES128-GCM-SHA256,TLSv1.2,Kx=ECDH,Au=ECDSA,Enc=AESGCM(128),Mac=AEAD
,0xC0,0x27,-,ECDHE-RSA-AES128-SHA256,TLSv1.2,Kx=ECDH,Au=RSA,Enc=AES(128),Mac=SHA256
,0xC0,0x23,-,ECDHE-ECDSA-AES128-SHA256,TLSv1.2,Kx=ECDH,Au=ECDSA,Enc=AES(128),Mac=SHA256
,0x00,0xA2,-,DHE-DSS-AES128-GCM-SHA256,TLSv1.2,Kx=DH,Au=DSS,Enc=AESGCM(128),Mac=AEAD
,0x00,0x9E,-,DHE-RSA-AES128-GCM-SHA256,TLSv1.2,Kx=DH,Au=RSA,Enc=AESGCM(128),Mac=AEAD
,0x00,0x67,-,DHE-RSA-AES128-SHA256,TLSv1.2,Kx=DH,Au=RSA,Enc=AES(128),Mac=SHA256
,0x00,0x40,-,DHE-DSS-AES128-SHA256,TLSv1.2,Kx=DH,Au=DSS,Enc=AES(128),Mac=SHA256
,0xC0,0x31,-,ECDH-RSA-AES128-GCM-SHA256,TLSv1.2,Kx=ECDH/RSA,Au=ECDH,Enc=AESGCM(128),Mac=AEAD
,0xC0,0x2D,-,ECDH-ECDSA-AES128-GCM-SHA256,TLSv1.2,Kx=ECDH/ECDSA,Au=ECDH,Enc=AESGCM(128),Mac=AEAD
,0xC0,0x29,-,ECDH-RSA-AES128-SHA256,TLSv1.2,Kx=ECDH/RSA,Au=ECDH,Enc=AES(128),Mac=SHA256
,0xC0,0x25,-,ECDH-ECDSA-AES128-SHA256,TLSv1.2,Kx=ECDH/ECDSA,Au=ECDH,Enc=AES(128),Mac=SHA256
,0x00,0x9C,-,AES128-GCM-SHA256,TLSv1.2,Kx=RSA,Au=RSA,Enc=AESGCM(128),Mac=AEAD
,0x00,0x3C,-,AES128-SHA256,TLSv1.2,Kx=RSA,Au=RSA,Enc=AES(128),Mac=SHA256
28

■私の環境ではSquidの内部用ブロックページとしか使っていないのですが。。。
 ところでデフォルトから従来の方法で「a2enmod ssl」しただけでは、
 「SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol」となる。

$ w3m -dump http://172.31.31.254:443
Deny Pages!

black

$ w3m -dump https://172.31.31.254:443
SSL error: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
w3m: Can't load https://172.31.31.254:443.

■上記は「a2ensite」を実行していないから。

$ head -4 /etc/apache2/ports.conf 
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf

$ sudo a2ensite default-ssl.conf 
Enabling site default-ssl.
To activate the new configuration, you need to run:
  service apache2 reload
$ sudo systemctl reload apache2.service 

■初回は少し詳しく出力してみる。
 証明書は組み込みの自己署名証明書なので、当然のログが出る。

$ wget -O /dev/null --debug --no-check-certificate --no-proxy https://172.31.31.254/
Setting --check-certificate (checkcertificate) to 0
Setting --proxy (useproxy) to 0
DEBUG output created by Wget 1.16 on linux-gnu.

URI encoding = `UTF-8'
--2016-05-31 22:50:01--  https://172.31.31.254/
Certificates loaded: 174
172.31.31.254:443 に接続しています... 接続しました。
Created socket 5.
Releasing 0x00000000024f0a10 (new refcount 0).
Deleting unused 0x00000000024f0a10.
警告: `172.31.31.254' の証明書は信用されません。
警告: `172.31.31.254' の証明書の発行者が不明です。
証明書の所有者の名前とホスト名 `172.31.31.254' が一致しません

---request begin---
GET / HTTP/1.1
User-Agent: Wget/1.16 (linux-gnu)
Accept: */*
Host: 172.31.31.254
Connection: Keep-Alive

---request end---
HTTP による接続要求を送信しました、応答を待っています... 
---response begin---
HTTP/1.1 200 OK
Date: Tue, 31 May 2016 13:50:01 GMT
Server: Apache/2.4.10 (Debian)
Last-Modified: Sun, 11 Oct 2015 03:40:39 GMT
ETag: "36-521cbf9f6fa59"
Accept-Ranges: bytes
Content-Length: 54
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

---response end---
200 OK
Registered socket 5 for persistent reuse.
長さ: 54 [text/html]
`/dev/null' に保存中

/dev/null                         100%[=============================================================>]      54  --.-KB/s 時間 0s     

2016-05-31 22:50:01 (3.35 MB/s) - `/dev/null' へ保存完了 [54/54]

■上記を元にopensslコマンドでテストしてみる。
 ここから先は個別に細かく、ローカルでチェックしたい人向け。
 結果が気になると、その分調べる量が増える点に注意。

■12の暗号化方式で問題ないこと、16の暗号化方式で失敗したことを確認。

$ sudo openssl ciphers -V 'HIGH:!aNULL' | awk '!/SSLv3/{print $3}' | \
    for CIPHER in `xargs`;do \
      echo -e "GET / HTTP/1.0\n\n" | \
      openssl s_client -no_ssl2 -no_ssl3 -no_tls1 -connect 172.31.31.254:443 -cipher $CIPHER -msg 2>&1 | \
      grep '^New, (' | xargs echo $CIPHER; \
    done | awk '{if(/NONE/){NG+=1;print $1,"NG"}else{OK+=1;print $1,"OK"}}END{print "OK="OK,"NG="NG}'
ECDHE-RSA-AES256-GCM-SHA384 OK
ECDHE-ECDSA-AES256-GCM-SHA384 NG
ECDHE-RSA-AES256-SHA384 OK
ECDHE-ECDSA-AES256-SHA384 NG
DHE-DSS-AES256-GCM-SHA384 NG
DHE-RSA-AES256-GCM-SHA384 OK
DHE-RSA-AES256-SHA256 OK
DHE-DSS-AES256-SHA256 NG
ECDH-RSA-AES256-GCM-SHA384 NG
ECDH-ECDSA-AES256-GCM-SHA384 NG
ECDH-RSA-AES256-SHA384 NG
ECDH-ECDSA-AES256-SHA384 NG
AES256-GCM-SHA384 OK
AES256-SHA256 OK
ECDHE-RSA-AES128-GCM-SHA256 OK
ECDHE-ECDSA-AES128-GCM-SHA256 NG
ECDHE-RSA-AES128-SHA256 OK
ECDHE-ECDSA-AES128-SHA256 NG
DHE-DSS-AES128-GCM-SHA256 NG
DHE-RSA-AES128-GCM-SHA256 OK
DHE-RSA-AES128-SHA256 OK
DHE-DSS-AES128-SHA256 NG
ECDH-RSA-AES128-GCM-SHA256 NG
ECDH-ECDSA-AES128-GCM-SHA256 NG
ECDH-RSA-AES128-SHA256 NG
ECDH-ECDSA-AES128-SHA256 NG
AES128-GCM-SHA256 OK
AES128-SHA256 OK
OK=12 NG=16

■エラーの詳細はgrepを外して見て個別に調査するものとして。。。

$ sudo openssl ciphers -V 'HIGH:!aNULL' | awk '!/SSLv3/{print $3}' | \
    for CIPHER in `xargs`;do \
      echo -e "GET / HTTP/1.0\n\n" | \
      openssl s_client -no_ssl2 -no_ssl3 -no_tls1 -connect 172.31.31.254:443 -cipher $CIPHER -msg 2>&1 | \
      grep '^New, (' | xargs echo $CIPHER; \
    done | awk '{if(/NONE/){NG+=1;print $1,"NG"}else{OK+=1;print $1,"OK"}}END{print "OK="OK,"NG="NG}' | \
    grep NG | awk '{print $1}' | \
    for CIPHER in `xargs`;do \
      echo -e "GET / HTTP/1.0\n\n" | \
      openssl s_client -no_ssl2 -no_ssl3 -no_tls1 -connect 172.31.31.254:443 -cipher $CIPHER -debug 2>&1 ; \
    done | grep "^[0-9].*error"
140485668755088:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139997613799056:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140204113753744:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140306475337360:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139896995436176:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140571312961168:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140484783466128:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140225213290128:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140227260216976:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139897304012432:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140707123160720:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139740867552912:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139873656866448:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139968604477072:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139734951499408:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
139835136349840:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
140435192239760:error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl_lib.c:1295:

■例えばRC4が無効であることの確認。

$ sudo openssl ciphers -V | awk '/RC4/{print $3}' | \
    for CIPHER in `xargs`;do \
      echo -e "GET / HTTP/1.0\n\n" | \
      openssl s_client -no_ssl2 -no_ssl3 -no_tls1 -connect 172.31.31.254:443 -cipher $CIPHER -msg 2>&1 | \
      grep '^New, (' | xargs echo $CIPHER; \
    done | awk '{if(/NONE/){NG+=1;print $1,"NG"}else{OK+=1;print $1,"OK"}}END{print "OK="OK,"NG="NG}' 
ECDHE-RSA-RC4-SHA NG
ECDHE-ECDSA-RC4-SHA NG
ECDH-RSA-RC4-SHA NG
ECDH-ECDSA-RC4-SHA NG
RC4-SHA NG
RC4-MD5 NG
PSK-RC4-SHA NG
OK= NG=7