環境
事象
とあるダイナミックDNSサービスを長年愛用している。
自宅のIPアドレスが変更されたらcurlコマンドを叩き、そのダイナミックDNSサービスに通知する仕組みにしていた。
ところが、Ubuntu 18.04に上げてから error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
でcurlコマンドが失敗するようになった。
$ curl -v -s -o /dev/null https://XXXXXX.net/ * Trying XX.XX.XX.XX... * TCP_NODELAY set * Connected to XXXXXX.net (XX.XX.XX.XX) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs } [5 bytes data] * TLSv1.2 (OUT), TLS handshake, Client hello (1): } [210 bytes data] * TLSv1.2 (IN), TLS alert, Server hello (2): { [2 bytes data] * error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure * stopped the pause stream! * Closing connection 0
curlとOpenSSLのバージョン情報
$ curl --version curl 7.58.0 (arm-unknown-linux-gnueabihf) libcurl/7.58.0 OpenSSL/1.1.0g zlib/1.2.11 libidn2/2.0.4 libpsl/0.19.1 (+libidn2/2.0.4) nghttp2/1.30.0 librtmp/2.3 Release-Date: 2018-01-24 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL $ openssl version OpenSSL 1.1.0g 2 Nov 2017
原因
Webサーバ側が対応しているCipher Suiteが古くてセキュアではないものだった。 Ubuntu 18.04のcurl/OpenSSLでは、それらのCipher Suiteが非対応になっていた。
解決策
Webクライアント側でできることは何もない。 Ubuntu 18.04のcurl/OpenSSLで利用可能なCipher Suiteの中に、目的のWebサーバが対応しているものはなかったから。 SSLv3や脆弱な暗号化方式を有効にしてOpenSSLをコンパイルし直す手もあるが、セキュリティ的に良くないし、そこまで頑張る必要性もない。
だから、別のダイナミックDNSサービスに乗り換えよう…
原因究明の過程
いろいろなOSで試してみた
次の3通りのOS/バージョンで試してみたところ、すべて接続可能だった。
- Ubuntu 16.04.5 / curl 7.47.0 / OpenSSL 1.0.2g
SSL connection using TLS1.0 / RSA_3DES_EDE_CBC_SHA1
- macOS Sierra 10.12.6 / curl 7.54.0 / OpenSSL 0.9.8zh
TLS 1.0 connection using TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
- macOS Mojave 10.14.4 / curl 7.54.0 / LibreSSL 2.6.5
SSL connection using TLSv1.0 / EDH-RSA-DES-CBC3-SHA
Ubuntu 16.04.5 / curl 7.47.0 / OpenSSL 1.0.2g
$ curl -v -s -o /dev/null https://XXXXXX.net/ * Trying XX.XX.XX.XX... * Connected to XXXXXX.net (XX.XX.XX.XX) port 443 (#0) * found 148 certificates in /etc/ssl/certs/ca-certificates.crt * found 592 certificates in /etc/ssl/certs * ALPN, offering http/1.1 * SSL connection using TLS1.0 / RSA_3DES_EDE_CBC_SHA1 * server certificate verification OK * server certificate status verification SKIPPED * common name: XXXXXX.net (matched) * server certificate expiration date OK * server certificate activation date OK * certificate public key: RSA * certificate version: #3 * subject: CN=XXXXXX.net * start date: Fri, 21 Dec 2018 00:00:00 GMT * expire date: Thu, 18 Feb 2021 12:00:00 GMT * issuer: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=RapidSSL RSA CA 2018 * compression: NULL * ALPN, server did not agree to a protocol > GET / HTTP/1.1 > Host: XXXXXX.net > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Date: Fri, 03 May 2019 06:15:29 GMT < Server: Apache < Transfer-Encoding: chunked < Content-Type: text/html < { [6 bytes data] * Connection #0 to host XXXXXX.net left intact $ curl --version curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets $ openssl version OpenSSL 1.0.2g 1 Mar 2016
macOS Sierra 10.12.6 / curl 7.54.0 / OpenSSL 0.9.8zh
$ curl -v -s -o /dev/null https://XXXXXX.net * Rebuilt URL to: https://XXXXXX.net/ * Trying XX.XX.XX.XX... * TCP_NODELAY set * Connected to XXXXXX.net (XX.XX.XX.XX) port 443 (#0) * TLS 1.0 connection using TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA * Server certificate: XXXXXX.net * Server certificate: RapidSSL RSA CA 2018 * Server certificate: DigiCert Global Root CA > GET / HTTP/1.1 > Host: XXXXXX.net > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK < Date: Fri, 03 May 2019 05:40:26 GMT < Server: Apache < Transfer-Encoding: chunked < Content-Type: text/html < { [6 bytes data] * Connection #0 to host XXXXXX.net left intact $ curl --version curl 7.54.0 (x86_64-apple-darwin16.0) libcurl/7.54.0 SecureTransport zlib/1.2.8 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz UnixSockets $ openssl version OpenSSL 0.9.8zh 14 Jan 2016
macOS Mojave 10.14.4 / curl 7.54.0 / LibreSSL 2.6.5
$ curl -v -s -o /dev/null https://XXXXXX.net/ * Trying XX.XX.XX.XX... * TCP_NODELAY set * Connected to XXXXXX.net (XX.XX.XX.XX) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): } [218 bytes data] * TLSv1.2 (IN), TLS handshake, Server hello (2): { [74 bytes data] * TLSv1.0 (IN), TLS handshake, Certificate (11): { [3917 bytes data] * TLSv1.0 (IN), TLS handshake, Server key exchange (12): { [525 bytes data] * TLSv1.0 (IN), TLS handshake, Server finished (14): { [4 bytes data] * TLSv1.0 (OUT), TLS handshake, Client key exchange (16): } [134 bytes data] * TLSv1.0 (OUT), TLS change cipher, Client hello (1): } [1 bytes data] * TLSv1.0 (OUT), TLS handshake, Finished (20): } [16 bytes data] * TLSv1.0 (IN), TLS change cipher, Client hello (1): { [1 bytes data] * TLSv1.0 (IN), TLS handshake, Finished (20): { [16 bytes data] * SSL connection using TLSv1.0 / EDH-RSA-DES-CBC3-SHA * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=XXXXXX.net * start date: Dec 21 00:00:00 2018 GMT * expire date: Feb 18 12:00:00 2021 GMT * subjectAltName: host "XXXXXX.net" matched cert's "XXXXXX.net" * issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=RapidSSL RSA CA 2018 * SSL certificate verify ok. > GET / HTTP/1.1 > Host: XXXXXX.net > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK < Date: Fri, 03 May 2019 05:41:36 GMT < Server: Apache < Transfer-Encoding: chunked < Content-Type: text/html < { [6 bytes data] * Connection #0 to host XXXXXX.net left intact $ curl --version curl 7.54.0 (x86_64-apple-darwin18.0) libcurl/7.54.0 LibreSSL/2.6.5 zlib/1.2.11 nghttp2/1.24.1 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz HTTP2 UnixSockets HTTPS-proxy $ openssl version LibreSSL 2.6.5
SSL/TLSバージョンを指定してみた
TLS 1.0
オプションを付けてTLS 1.0を強制してみたが、結果は変わらず error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
が出てしまった。
$ curl --tlsv1.0 -v -s -o /dev/null https://XXXXXX.net/ * Trying XX.XX.XX.XX... * TCP_NODELAY set * Connected to XXXXXX.net (XX.XX.XX.XX) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs } [5 bytes data] * TLSv1.0 (OUT), TLS handshake, Client hello (1): } [136 bytes data] * TLSv1.0 (IN), TLS alert, Server hello (2): { [2 bytes data] * error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure * stopped the pause stream! * Closing connection 0
SSLv3
$ curl --sslv3 -v -s -o /dev/null https://XXXXXX.net/ * Trying XX.XX.XX.XX... * TCP_NODELAY set * Connected to XXXXXX.net (XX.XX.XX.XX) port 443 (#0) * OpenSSL was built without SSLv3 support * Closing connection 0
パケットキャプチャを見てみた
Ubuntu 18.04.2 / curl 7.58.0 / OpenSSL 1.1.0g
特にオプションを付けずに叩いたとき curl -v -s -o /dev/null https://XXXXXX.net
Client Helloの後、Webサーバから Handshake Failure
のAlertが返ってきていた。
Client HelloではTLS 1.2と28個のCipher Suiteを提示していた。
TLSv1.0を強制して叩いたとき curl --tlsv1.0 -v -s -o /dev/null https://XXXXXX.net/
Client Helloの後、Webサーバから Handshake Failure
のAlertが返ってきたのは同じ。
Client HelloではTLS 1.0と9個のCipher Suiteを提示していた。
Ubuntu 16.04.5 / curl 7.47.0 / OpenSSL 1.0.2g
特にオプションを付けずに curl -v -s -o /dev/null https://XXXXXX.net
を実行したときのパケットキャプチャを見る。
Client Helloの後、ちゃんとServer Helloが返ってきていた。
Client HelloではTLS 1.2と54個のCipher Suiteを提示していた。Ubuntu 18.04よりも多い!
Server HelloではTLS 1.0とCipher Suite TLS_RSA_WITH_3DES_EDE_CBC_SHA
が指定されていた。
OpenSSL 1.1.0g が対応しているCipher Suiteの一覧
Ubuntu 18.04.2のOpenSSL 1.1.0gが対応しているCipher Suiteは全部で57個ある。 Ubuntu 16.04.5のOpenSSL 1.0.2gでは97個だったので、だいぶ減った模様。
Ubuntu 16.04.5とmacOS Sierraで選択された SRP-RSA-3DES-EDE-CBC-SHA
と、 macOS Mojaveで選択された EDH-RSA-DES-CBC3-SHA
はこのリストの中にはない。
$ openssl ciphers -v ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD DHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=DH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256 ECDHE-ECDSA-AES256-SHA TLSv1 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 ECDHE-RSA-AES256-SHA TLSv1 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1 ECDHE-ECDSA-AES128-SHA TLSv1 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 ECDHE-RSA-AES128-SHA TLSv1 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1 RSA-PSK-AES256-GCM-SHA384 TLSv1.2 Kx=RSAPSK Au=RSA Enc=AESGCM(256) Mac=AEAD DHE-PSK-AES256-GCM-SHA384 TLSv1.2 Kx=DHEPSK Au=PSK Enc=AESGCM(256) Mac=AEAD RSA-PSK-CHACHA20-POLY1305 TLSv1.2 Kx=RSAPSK Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD DHE-PSK-CHACHA20-POLY1305 TLSv1.2 Kx=DHEPSK Au=PSK Enc=CHACHA20/POLY1305(256) Mac=AEAD ECDHE-PSK-CHACHA20-POLY1305 TLSv1.2 Kx=ECDHEPSK Au=PSK Enc=CHACHA20/POLY1305(256) Mac=AEAD AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD PSK-AES256-GCM-SHA384 TLSv1.2 Kx=PSK Au=PSK Enc=AESGCM(256) Mac=AEAD PSK-CHACHA20-POLY1305 TLSv1.2 Kx=PSK Au=PSK Enc=CHACHA20/POLY1305(256) Mac=AEAD RSA-PSK-AES128-GCM-SHA256 TLSv1.2 Kx=RSAPSK Au=RSA Enc=AESGCM(128) Mac=AEAD DHE-PSK-AES128-GCM-SHA256 TLSv1.2 Kx=DHEPSK Au=PSK Enc=AESGCM(128) Mac=AEAD AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD PSK-AES128-GCM-SHA256 TLSv1.2 Kx=PSK Au=PSK Enc=AESGCM(128) Mac=AEAD AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256 ECDHE-PSK-AES256-CBC-SHA384 TLSv1 Kx=ECDHEPSK Au=PSK Enc=AES(256) Mac=SHA384 ECDHE-PSK-AES256-CBC-SHA TLSv1 Kx=ECDHEPSK Au=PSK Enc=AES(256) Mac=SHA1 SRP-RSA-AES-256-CBC-SHA SSLv3 Kx=SRP Au=RSA Enc=AES(256) Mac=SHA1 SRP-AES-256-CBC-SHA SSLv3 Kx=SRP Au=SRP Enc=AES(256) Mac=SHA1 RSA-PSK-AES256-CBC-SHA384 TLSv1 Kx=RSAPSK Au=RSA Enc=AES(256) Mac=SHA384 DHE-PSK-AES256-CBC-SHA384 TLSv1 Kx=DHEPSK Au=PSK Enc=AES(256) Mac=SHA384 RSA-PSK-AES256-CBC-SHA SSLv3 Kx=RSAPSK Au=RSA Enc=AES(256) Mac=SHA1 DHE-PSK-AES256-CBC-SHA SSLv3 Kx=DHEPSK Au=PSK Enc=AES(256) Mac=SHA1 AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1 PSK-AES256-CBC-SHA384 TLSv1 Kx=PSK Au=PSK Enc=AES(256) Mac=SHA384 PSK-AES256-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=AES(256) Mac=SHA1 ECDHE-PSK-AES128-CBC-SHA256 TLSv1 Kx=ECDHEPSK Au=PSK Enc=AES(128) Mac=SHA256 ECDHE-PSK-AES128-CBC-SHA TLSv1 Kx=ECDHEPSK Au=PSK Enc=AES(128) Mac=SHA1 SRP-RSA-AES-128-CBC-SHA SSLv3 Kx=SRP Au=RSA Enc=AES(128) Mac=SHA1 SRP-AES-128-CBC-SHA SSLv3 Kx=SRP Au=SRP Enc=AES(128) Mac=SHA1 RSA-PSK-AES128-CBC-SHA256 TLSv1 Kx=RSAPSK Au=RSA Enc=AES(128) Mac=SHA256 DHE-PSK-AES128-CBC-SHA256 TLSv1 Kx=DHEPSK Au=PSK Enc=AES(128) Mac=SHA256 RSA-PSK-AES128-CBC-SHA SSLv3 Kx=RSAPSK Au=RSA Enc=AES(128) Mac=SHA1 DHE-PSK-AES128-CBC-SHA SSLv3 Kx=DHEPSK Au=PSK Enc=AES(128) Mac=SHA1 AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 PSK-AES128-CBC-SHA256 TLSv1 Kx=PSK Au=PSK Enc=AES(128) Mac=SHA256 PSK-AES128-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=AES(128) Mac=SHA1
SRP-RSA-3DES-EDE-CBC-SHA
と EDH-RSA-DES-CBC3-SHA
について調べてみた
共通鍵暗号方式の一種であるDESと、その後継の3DES (Triple DES)にはSweet32という脆弱性があるらしい。
TLS、SSH、IPSec およびその他プロトコルの製品で使用される DES および Triple DES 暗号は、約 40 億ブロックの birthday bound を持っているため、平文のデータを取得される脆弱性が存在します。
本脆弱性は、"Sweet32" 攻撃と呼ばれています。
JVNDB-2016-004511 - JVN iPedia - 脆弱性対策情報データベース より引用
そして、3DES (DES-CBC3) はOpenSSL 1.1.0からデフォルトでコンパイルされなくなったようだ。
For the 1.1.0 release, which we expect to release tomorrow, we will treat triple-DES just like we are treating RC4. It is not compiled by default; you have to use “enable-weak-ssl-ciphers” as a config option. Even when those ciphers are compiled, triple-DES is only in the “MEDIUM” keyword. In addition, because this is a new release, we also removed it from the “DEFAULT” keyword.
The SWEET32 Issue, CVE-2016-2183 - OpenSSL Blog より引用
だからOpenSSL 1.1.0を使っているUbuntu 18.04ではこれらのCipher Suiteが利用できない。