以前 Qiita に掲載していたものですが Qiita を使うのを辞めたのでこちらに転機。
AWS の脆弱性診断対応で各種プロトコルのチェックをする機会があったので、一通り curl
でテストしようと思ったら最近の OS に載っている OpenSSL ではそもそも SSLv2 が無効になっているためテスト出来なかった。
$ /usr/bin/curl --sslv2 https://example.com # macOS 標準 curl curl: (35) Your version of the OS does not support SSLv2 $ /opt/local/bin/curl --sslv2 https://example.com # MacPorts 版 curl curl: (4) OpenSSL was built without SSLv2 support
となるとシステム標準の OpenSSL は使えないので OpenSSL をソースからビルドする必要がありそう。これはちょっと面倒だなぁ…と思ってたら sslscan が OpenSSL のビルドとスタティックリンクに対応しているようだったので導入してみることにした。sslscan は各種パッケージマネージャからインストール出来るが Ubuntu の APT や MacPorts のバイナリはダイナミックリンクになっていて SSLv2 非対応の OpenSSL を使おうとするのでソースからビルドした。Ubuntu では特に問題なくコンパイル出来たが macOS の場合はエラーが起きたのでそのときのことをメモしておく。
sslscan って何?
GitHub - rbsec/sslscan: sslscan tests SSL/TLS enabled services to discover supported cipher suites
サポートしてる TLS のバージョンを調べたりすることができるツール。今回の要件では CloudFront や ELB/ALB の TLSv1.0 無効化対応をしなくてはならなかったので確認用として導入した。(この話はまた今度書こうかなと思っている)
実行してみると下記のように対応している Cipher や証明書の有効期限の確認などが出来る。
$ sslscan example.com Version: 1.11.11-rbsec-18-gef08e6f-static OpenSSL 1.0.2-chacha (1.0.2g-dev) Connected to 93.184.216.34 Testing SSL server example.com on port 443 using SNI name example.com TLS Fallback SCSV: Server supports TLS Fallback SCSV TLS renegotiation: Secure session renegotiation supported TLS Compression: Compression disabled Heartbleed: TLS 1.2 not vulnerable to heartbleed TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed Supported Server Cipher(s): Preferred TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256 Curve P-256 DHE 256 Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384 Curve P-256 DHE 256 Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA256 Curve P-256 DHE 256 Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA384 Curve P-256 DHE 256 Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.2 128 bits AES128-GCM-SHA256 Accepted TLSv1.2 256 bits AES256-SHA Accepted TLSv1.2 256 bits CAMELLIA256-SHA Accepted TLSv1.2 128 bits AES128-SHA Accepted TLSv1.2 128 bits CAMELLIA128-SHA Accepted TLSv1.2 128 bits SEED-SHA Preferred TLSv1.1 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 Accepted TLSv1.1 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.1 256 bits AES256-SHA Accepted TLSv1.1 256 bits CAMELLIA256-SHA Accepted TLSv1.1 128 bits AES128-SHA Accepted TLSv1.1 128 bits CAMELLIA128-SHA Accepted TLSv1.1 128 bits SEED-SHA Preferred TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 Accepted TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.0 256 bits AES256-SHA Accepted TLSv1.0 256 bits CAMELLIA256-SHA Accepted TLSv1.0 128 bits AES128-SHA Accepted TLSv1.0 128 bits CAMELLIA128-SHA Accepted TLSv1.0 128 bits SEED-SHA SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 2048 Subject: www.example.org Altnames: DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net Issuer: DigiCert SHA2 High Assurance Server CA Not valid before: Nov 3 00:00:00 2015 GMT Not valid after: Nov 28 12:00:00 2018 GMT
Homebrew で sslscan をインストールした場合
Homebrew では make static
でインストールされるようになっているので、macOS ユーザーで「sslscan を使いたい」かつ「Homebrew を導入している」ならこれでいいと思う。
$ /opt/hb/bin/sslscan --version 1.11.11-static OpenSSL 1.0.2f 28 Jan 2016
※openssl@1.1
を導入している場合はテストしていないので不明
MacPorts で sslscan をインストールした場合
依存関係にある openssl
パッケージで SSLv2 が無効になっているようなのでこちらは SSLv2 のテストが出来ない。特にバリアントの設定なども無いのでこれで固定なようだ。
$ /opt/local/bin/sslscan --version 1.11.11 OpenSSL 1.0.2p 14 Aug 2018 OpenSSL version does not support SSLv2 SSLv2 ciphers will not be detected
ソースコードから sslscan をインストールする
今回は下記の環境で検証しています。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.10.5 BuildVersion: 14F2511 $ git remote -v origin https://github.com/rbsec/sslscan (fetch) origin https://github.com/rbsec/sslscan (push) $ git branch * master $ git log -1 commit ef08e6ffaab20e9d144436715b2ab8b24ecae54f Author: rbsec <robin@rbsec.net> Date: Mon Aug 20 12:59:42 2018 +0100 Fix missing newline in SCSV output if server only supports TLSv1.0
ソースを https://github.com/rbsec/sslscan からクローンしてくる。
$ git clone https://github.com/rbsec/sslscan.git
README の通りに make static
すると OpenSSL のビルドは成功するが、sslscan のビルドで inet_ntop
部分でエラーが出る。
$ make static if [ -d openssl -a -d openssl/.git ]; then \ cd ./openssl && git checkout OpenSSL_1_0_2-stable && git pull | grep -q "Already up-to-date." && [ -e ../.openssl.is.fresh ] || touch ../.openssl.is.fresh ; \ else \ git clone --depth 1 -b OpenSSL_1_0_2-stable https://github.com/PeterMosmans/openssl ./openssl && cd ./openssl && touch ../.openssl.is.fresh ; \ fi M apps/Makefile M crypto/asn1/Makefile M crypto/chacha/Makefile M crypto/evp/Makefile M crypto/modes/Makefile D krb5.h M ssl/Makefile M test/Makefile Already on 'OpenSSL_1_0_2-stable' Your branch is up-to-date with 'origin/OpenSSL_1_0_2-stable'. true /Applications/Xcode.app/Contents/Developer/usr/bin/make sslscan STATIC_BUILD=TRUE cc -o sslscan -Wall -Wformat=2 -Wformat-security -L/tmp/sslscan/openssl/ -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/tmp/sslscan/openssl/include/ -I/tmp/sslscan/openssl/ -DVERSION=\"1.11.11-rbsec-18-gef08e6f-static\" sslscan.c -lssl -lcrypto -lz -ldl sslscan.c:3113:13: warning: implicit declaration of function 'inet_ntop' is invalid in C99 [-Wimplicit-function-declaration] inet_ntop(ai->ai_family, &options->serverAddress6.sin6_addr, options->addrstr, sizeof(options->addrstr)); ^ 1 warning generated.
inet.h
は /usr/include/arpa/inet.h
にあるが、inet.h
でリポジトリ内のソースを検索してみると sslscan.c
内で __linux__
が定義されていたら読み込むようになっているらしい。
$ grep -r /usr/include inet_ntop /usr/include/apr-1/apr_network_io.h: * used in inet_ntop... */ /usr/include/arpa/inet.h:const char *inet_ntop(int, const void *, char *, socklen_t); /usr/include/net-snmp/net-snmp-config.h:/* Define to 1 if you have the `inet_ntop' function. */ /usr/include/php/ext/standard/basic_functions.h:PHP_NAMED_FUNCTION(php_inet_ntop); /usr/include/php/main/php_config.h:/* Define to 1 if you have the `inet_ntop' function. */
#ifdef __linux__↩ #include <arpa/inet.h>↩ #endif↩
sslscan.c
を書き換えるか、CPPFLAGS="-D__linux__"
をセットするとビルドが通る。ただし、最初から CPPFLAGS="-D__linux__" make static
としてしまうと OpenSSL のビルドでエラーが起きるので make static
で OpenSSL のビルドを済ませ、sslscan のビルドでコケた後に CPPFLAGS
をセットして再度 make static
する。
$ CPPFLAGS="-D__linux__" make static if [ -d openssl -a -d openssl/.git ]; then \ cd ./openssl && git checkout OpenSSL_1_0_2-stable && git pull | grep -q "Already up-to-date." && [ -e ../.openssl.is.fresh ] || touch ../.openssl.is.fresh ; \ else \ git clone --depth 1 -b OpenSSL_1_0_2-stable https://github.com/PeterMosmans/openssl ./openssl && cd ./openssl && touch ../.openssl.is.fresh ; \ fi M apps/Makefile M crypto/asn1/Makefile M crypto/chacha/Makefile M crypto/evp/Makefile M crypto/modes/Makefile D krb5.h M ssl/Makefile M test/Makefile Already on 'OpenSSL_1_0_2-stable' Your branch is up-to-date with 'origin/OpenSSL_1_0_2-stable'. true /Applications/Xcode.app/Contents/Developer/usr/bin/make sslscan STATIC_BUILD=TRUE cc -o sslscan -Wall -Wformat=2 -Wformat-security -L/tmp/sslscan/openssl/ -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/tmp/sslscan/openssl/include/ -I/tmp/sslscan/openssl/ -D__linux__ -DVERSION=\"1.11.11-rbsec-18-gef08e6f-static\" sslscan.c -lssl -lcrypto -lz -ldl
もしくは make static
を手動で個別実行するか。make sslscan
の場合は STATIC_BUILD=TRUE
も必要になります。
$ make openssl/libcrypto.a && CPPFALGS="-D__linux__" make static または $ make openssl/libcrypto.a && CPPFLAGS="-D__linux__" make sslscan STATIC_BUILD=TRUE
バージョンを確認して SSLv2 が使用できないメッセージが表示されなければ OK。
$ ./sslscan --version 1.11.11-rbsec-18-gef08e6f-static OpenSSL 1.0.2-chacha (1.0.2g-dev)
余談: git pull して更新したらビルド出来なくなった
make openssl
側に変更があったりするようなので openssl
ディレクトリを一旦削除してから make static
すれば良い。
余談: CPPFLAGS
ではなく CFLAGS
をセットした場合
※これは make
に関するメモなので特に読む必要はない
CFLAGS="-D__linux__"
とした場合は書き方によって動きが変わる。いずれも OpenSSL のビルドは終わっている状態。
make static
の引数に CFLAGS="-D__linux__"
を与えた場合
Makefile で設定される CFLAGS
が最終的にコマンドラインで指定した -D__linux__
に置き換わるのでヘッダーが読み込まれずエラーになる。
$ make static CFLAGS="-D__linux__" : 中略 : /Applications/Xcode.app/Contents/Developer/usr/bin/make sslscan STATIC_BUILD=TRUE cc -o sslscan -Wall -Wformat=2 -Wformat-security -L/tmp/sslscan/openssl/ -D__linux__ -DVERSION=\"1.11.11-rbsec-18-gef08e6f-static\" sslscan.c -lssl -lcrypto -lz -ldl
環境変数で CFLAGS
をセットした場合
下記の4つの例ではそれぞれフラグや出来上がる実行ファイルが変わる。MacPorts ユーザでなければスタティックリンクになることもある。
### command: 1 (MacPorts ユーザはダイナミックリンクになる) ### $ CFLAGS="-D__linux__" make static /Applications/Xcode.app/Contents/Developer/usr/bin/make sslscan STATIC_BUILD=TRUE cc -o sslscan -Wall -Wformat=2 -Wformat-security -L/tmp/sslscan/openssl/ -D__linux__ -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/usr/local/include -I/usr/local/ssl/include -I/usr/local/ssl/include/openssl -I/usr/local/opt/openssl/include -I/opt/local/include -I/opt/local/include/openssl -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/tmp/sslscan/openssl/include/ -I/tmp/sslscan/openssl/ -DVERSION=\"1.11.11-rbsec-18-gef08e6f-static\" sslscan.c -lssl -lcrypto -lz -ldl ### command: 2 (フラグが余計に追加されるがスタティックリンクになる) ### $ CFLAGS="-D__linux__" make static STATIC_BUILD=TRUE /Applications/Xcode.app/Contents/Developer/usr/bin/make sslscan STATIC_BUILD=TRUE cc -o sslscan -Wall -Wformat=2 -Wformat-security -L/private/tmp/sslscan/openssl/ -D__linux__ -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/tmp/sslscan/openssl/include/ -I/tmp/sslscan/openssl/ -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/private/tmp/sslscan/openssl/include/ -I/private/tmp/sslscan/openssl/ -DVERSION=\"1.11.11-rbsec-18-gef08e6f-static\" sslscan.c -lssl -lcrypto -lz -ldl rbsec-18-gef08e6f-static\" sslscan.c -lssl -lcrypto -lz -ldl ### command: 3 (MacPorts ユーザはダイナミックリンクになる) ### $ CFLAGS="-D__linux__" make sslscan cc -o sslscan -Wall -Wformat=2 -Wformat-security -L/usr/local/lib -L/usr/local/ssl/lib -L/usr/local/opt/openssl/lib -L/opt/local/lib -D__linux__ -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/usr/local/include -I/usr/local/ssl/include -I/usr/local/ssl/include/openssl -I/usr/local/opt/openssl/include -I/opt/local/include -I/opt/local/include/openssl -DVERSION=\"1.11.11-rbsec-18-gef08e6f\" sslscan.c -lssl -lcrypto -ldl ld: warning: directory not found for option '-L/usr/local/ssl/lib' ld: warning: directory not found for option '-L/usr/local/opt/openssl/lib' ### command: 4 (正常。CPPFLAGS と同様) ### $ CFLAGS="-D__linux__" make sslscan STATIC_BUILD=TRUE cc -o sslscan -Wall -Wformat=2 -Wformat-security -L/tmp/sslscan/openssl/ -D__linux__ -D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -I/tmp/sslscan/openssl/include/ -I/tmp/sslscan/openssl/ -DVERSION=\"1.11.11-rbsec-18-gef08e6f-static\" sslscan.c -lssl -lcrypto -lz -ldl
これについては Makefile を見てみるとわかるが、make static
の場合は sslscan
の前に openssl/libcrypto.a
がある。このときにはまだ STATIC_BUILD
はセットされていないため FALSE
になり、else
側へ落ちる。そして定義済みである CFLAGS
には -I/usr/local/include -I/usr/local/ssl/include -I/usr/local/ssl/include/openssl -I/usr/local/opt/openssl/include -I/opt/local/include -I/opt/local/include/openssl
によって各種パラメータが追加される。
openssl/libcrypto.a
が終わって、sslscan
ターゲットが実行されるときには STATIC_BUILD=TRUE
がセットされているので今度は -I${PWD}/include/ -I${PWD}/
が CFLAGS
に追加され、優先するインクルードディレクトリの順番が狂って意図しない結果になる。
MacPorts ユーザであれば /opt/local
が優先されているのでそちらのヘッダーが読み込まれ、Homebrew ユーザであれば /usr/local
が優先されてそちらのヘッダーを読み込んでしまうかもしれない。(私は Homebrew を /opt/hb
にインストールしているので試してはいない)
# for static linking ifeq ($(STATIC_BUILD), TRUE) PWD = $(shell pwd)/openssl LDFLAGS += -L${PWD}/ CFLAGS += -I${PWD}/include/ -I${PWD}/ LIBS = -lssl -lcrypto -lz ifneq ($(OS), FreeBSD) LIBS += -ldl endif ifeq ($(OS), SunOS) LIBS += -lsocket -lnsl endif GIT_VERSION := $(GIT_VERSION)-static else # for dynamic linking LDFLAGS += -L/usr/local/lib -L/usr/local/ssl/lib -L/usr/local/opt/openssl/lib -L/opt/local/lib CFLAGS += -I/usr/local/include -I/usr/local/ssl/include -I/usr/local/ssl/include/openssl -I/usr/local/opt/openssl/include -I/opt/local/include -I/opt/local/include/openssl endif