ウェブサーバをOpenSSL 1.1.1でTLSv1.3に対応させる

2018年9月11日にようやくOpenSSL 1.1.1がリリースされた。これでOpenSSLでもTLSv1.3に正式に対応となる。
がとらぼの人は基本的にFreeBSDのportsが対応しないと動かないのでOpenSSL 1.1.1が早くportsにならないかなと思っていたら翌日には対応portsが出た。
事前にはOpenSSL 1.1.1がリリースされたら security/openssl か security/openssl-devel のどちらかになるのかなと思っていたのだが security/openssl111 という変なオリジンになった。これは今後1.1.1以降が出たらマズくない?臨時なのかしら?

2020年1月19日追記:
2020年1月1日にOpenSSL 1.1系のportsがsecurity/openssl111からsecurity/opensslに変更された。以下、この記事でsecurity/opessl111の部分はsecurity/opensslに読み替えて下さい。

インストール

すでにSSL/TLS系の暗号ライブラリを使用していなくてOpenSSLを新規インストールする場合
# パッケージでインストール
# pkg update  パッケージ情報の更新
# pkg install security/openssl111
または
# portsでインストール
# portsnap fetch update && portsdb -uU   portsの情報更新
# cd /usr/ports/security/openssl111
# make install
/etc/make.conf (追記1行)
DEFAULT_VERSIONS+=ssl=openssl111

既にOpenSSLを使っている、または他の暗号化ライブラリを使用している場合は以下(portsで)

/etc/make.conf
1
2
3
4
5
6
7
8
#コメント化または行削除
#DEFAULT_VERSIONS+=ssl=libressl       利用中がlibresslなら
#DEFAULT_VERSIONS+=ssl=libressl-devel 利用中がlibressl-develなら
#DEFAULT_VERSIONS+=ssl=openssl        利用中がsecurity/opensslなら
#DEFAULT_VERSIONS+=ssl=openssl-devel  利用中がsecurity/openssl-develなら

#追加1行
DEFAULT_VERSIONS+=ssl=openssl111

↓でportsのオリジン替えを行うので↑の/etc/make.confの変更を先に行っておく(重要)。

# portsnap fetch update && portsdb -uU   portsの情報更新
# portupgrade -f -o security/openssl111 security/openssl-devel     オリジン変更を伴う入れ替え
# portupgrade -fr openssl111   暗号化ライブラリに依存するportsを再ビルド

再ビルドしたportsを使用するサービスの全てを再起動する。または対象サービスが多くて面倒ならシステム再起動。

Nginxの設定変更

Nginxの設定ファイル (変更箇所のみ)
1
2
3
4
5
6
7
ssl_protocols   TLSv1.3 TLSv1.2;  #TLSv1.1, TLSv1.0はもうありえないよね
ssl_prefer_server_ciphers       on;       #これは既にある筈(そのまま)
ssl_ciphers     'TLS13:EECDH+CHACHA20:EECDH+AESGCM:ECDHE:!COMPLEMENTOFDEFAULT';
ssl_ecdh_curve     X25519:prime256v1;

# 参考 https://www.openssl.org/blog/blog/2018/02/08/tlsv1.3/        
# ssl_ciphers  'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384:ECDHE:!COMPLEMENTOFDEFAULT';

試してみた限りではTLSv1.3の暗号スイートはTLS13-AES-256-GCM-SHA384しか使われなかった。なのでTLSv1.3の順序指定は現状では無意味かなと思う。(今後は変わるだろうけど)
そこでTLSv1.3についてはTLS13だけを指定した。なお、OpenSSL 1.1.1を利用するNginxではTLS13の指定の有無に関わらずTLSv1.3が最優先で使用されるようなのでTLS13の指定自体不要かもしれない。
次にEECDH+CHACHA20を指定したのはTLSv1.3が使われずTLSv1.2の場合に再優先でChaCha20-Poly1305を使いたかったから。次に:EECDH+AESGCM:を優先した上で少し古めのブラウザとの互換性のためにECHDEを指定。最後に !COMPLEMENTOFDEFAULT で幾つかの余計なの(DEFAULT外)が外れる。

試行錯誤用 (例)
% openssl ciphers -s -v ECDHE:\!COMPLEMENTOFDEFAULT

ssl_ciphersで指定する暗号スイートを気に入る状態になるまで試すのが良いかと。なお、コマンド打ちでは除外の ! の直前に \ を付けること。

Nginxの設定確認と再起動
# nginx -t               設定の簡易チェック
または
# service nginx configtest

# service nginx restart  Nginx再起動

確認

まずはOpenssl 1.1.1をインストールした端末からコマンドで確認してみる。
% openssl s_client -connect www.example.com:443         プロトコルを指定しないで接続
% openssl s_client -tls1_3 -connect www.example.com:443  TLSv1.3を指定して接続
% openssl s_client -tls1_2 -connect www.example.com:443  TLSv1.2を指定して接続

ブラウザで確認する。

Chromeブラウザで確認 1
Chrome Dev版でTLSv1.3に対応させた「がとらぼ」を表示して[F12]でDevToolsを出した。(または右上のメニューボタン→その他のツール→デベロッパーツール or [Ctrl]+[Shift]+[i])
DevTools上部のタブから[Security]を選択。
TLSv1.3対応前と変わらずTLSv1.2で接続されている。
盛大に勘違いしていたのだが、ChromeのDev版,Canary版はバージョンがChrome71なので標準でTLSv1.3に対応しているのかと思っていた。それが大間違い。
ブラウザでの確認にChromeのDev, Canaryを設定触らずに使ったため、最初はTLSv1.3で全く接続できず頭の上にクエスチョンマークが3つくらい浮かんだ状態で暫く悩まされた。

Chromeブラウザで確認 2
ChromeのURL入力欄に chrome://flags/#tls13-variant を入力。
TLS1.3という項目が表示されるので、右の[Default] をクリック。
プルダウンメニューから[Enabled (Final)]を選択する。

Chromeブラウザで確認 3
念の為にボタンの表示が[Enabled (Final)]になっていることを確認。
右下の[RELAUNCH NOW]をでクリック。(ブラウザが再起動する)

Chromeブラウザで確認 4
TLSv1.3に対応させたサイトを再表示。DevToolsを出す。
DevTools上部のタブから[Security]を選択。
オリジンの混在するページの場合は左列のMain originで目的のウェブサイトのホスト名を選択。
右列の表示が変わり、プロトコルがTLS1.3、鍵交換グループがX25519、暗号スイートがAES_256_GCMになっている。 期待どおりなのでChromeでの確認は完了。

Firefoxブラウザで確認 1
FirefoxのDeveloper版でTLSv1.3に対応させた「がとらぼ」を表示した。
URL入力欄左の鍵アイコンをクリック。
ポップアップした窓の1行目の右端にある[ > ]をクリック。

Firefoxブラウザで確認 2
一番下の「詳細を表示」をクリック。

Firefoxブラウザで確認 3
上の画像の赤枠部分のように暗号スイートと鍵長とプロトコルが表示される。期待通りなのでFirefoxでの確認は完了。

最初にFirefox(の開発版)で確認すれば悩まずに済んだのね。

途中で触れたが、OpenSSL 1.1.1を利用するNginxでは暗号スイートの指定の有無に関わらずTLS13-AES-256-GCM-SHA384が使用される。(クライアント側がTLSv1.3の正式版に対応していたらだけど。)
それだけでなく、OpenSSL 1.1.1を利用するNginxでは ssl_protocols の指定にTLSv1.3を追記していないバーチャルホストであってもTLSv1.3が有効になるみたい。これは勝手な動作なのでちょっと困りモノ。Nginx側でそのうち直るかもだけど。

TLSv1.3はまだこれからなのでクライアント・サーバの両側ともにすぐに使えるという感じではないようだけど、どれくらいでTLSv1.3が当たり前の世の中になるかしら?

ちなみにSSL/TLSのテストサイトとして有名なQualysのSSL Server Testは2018年9月18日の時点でTLSv1.3のドラフト28までの対応なのでTLSv1.3の正式版は対応しておらず、テストしてもTLSv1.2までの表示となります。これからウェブサーバーをTLSv1.3の正式版に対応にさせようという人は勘違いなく。正しく設定できていてもテストするとTLSv1.2としか表示されないので「あれ?」ってなる。

Qualys Server Testで確認 3
2018年9月28日追記:
10日前にはドラフト28までの対応だったQualysのSSL Server TestがRFC8446対応になったみたい。
TLSv1.3対応の「がとらぼ」をテストしたところ、上の画像のように正しく評価して貰えた。