ウェブサーバのTLS ChaCha20-Poly1305で通信させたい

以前にECDSAな証明書を作成したときにP-256を使ったけど、P-256は根拠は無いがなんか信用できないという人がいるのも確か。そこで来たるべくTLSv1.3時代を見据えてChaCha20-Poly1305やX25119にも対応させてみたい。速いらしいし。

サーバーOSは例によってFreeBSD、ウェブサーバはNginx、TLSに使うのはLibreSSLではなくOpenSSLとする。

OpenSSLの置き換え

X25519を使用するにはOpenSSL 1.1.0以上が必要だがFreeBSDのportsでOpenSSL(security/openssl)をインストールしている場合は1.0.xの筈なので非対応。security/openssl-devに変えなければならない。つい2ヶ月ほど前まではsecurity/openssl-devをインストールしようとすると多くの関連portsがビルドエラーになっていたが、急速に対応状況が改善していて2018年6月11日時点ではOpenSSLに依存しているportsの殆どがsecurity/openssl-dev対応になっている。一部非対応portsも残っているので油断はできないが。

/etc/make.conf(1行変更)
1
2
3
4
5
(変更前)
DEFAULT_VERSIONS+=ssl=openssl

(変更後)
DEFAULT_VERSIONS+=ssl=openssl-devel
OpenSSL ports置き換え手順 (portsツリー更新は省略)
### OpenSSLのオリジン替え
# portupgrade -o security/openssl-devel security/openssl
### 上のコマンドで反応しない場合はこちら、上で更新されたら↓の1コマンドは不要
# portupgrade -f -o security/openssl-devel security/openssl

### OpenSSLに依存しているportsを全て更新 (時間かかる)
# portupgrade -fr security/openssl-devel

Nginxの設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server {
    listen 443 ssl http2;
    listen [::]:443  ssl http2;
    server_name hoge.example.com;

中略

    #RSAの証明書
    ssl_certificate      /path/rsa.pem;
    ssl_certificate_key  /path/rsa-key.pem;

    #ECDSAの証明書
    ssl_certificate      /path/ecdsa.pem;
    ssl_certificate_key  /path/ecdsa.key;

    #DHパラメータファイル (この記事の設定的には不要な筈だが、無いとNginxがエラーになる筈)
    ssl_dhparam          /path/dhparam4096.pem;
    
    ssl_protocols        TLSv1.2;
    ssl_prefer_server_ciphers  on;
    ssl_ciphers          ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
    ssl_ecdh_curve       X25519:prime256v1;

中略

}

ECDSAの証明書が 無い or 使わない ならECDSA証明書の項目は削除でssl_cipherでECDSAを含む暗号スイートを削る。(半分になる)
今回は趣味でChaCha20-Poly1305を先頭に置いたが、サーバー側のCPUがIntelやAMDでAES-NIを効かせた処理速度を考えるとAESを優先させたいところ。逆にスマートフォンの閲覧者が多いサイトであれば(サーバー側が多少ツラくても) 非AES-NI環境で高速なChaCha20-Poly1305を優先してやると良いかも。
P-256が嫌いならssl_ecdh_curveから :prime256v1 を削るか別のに変える。

Nginxの再起動

###設定が致命的に間違っていないことを確認する
# service nginx configtest

###エラーが出ないならNginxを再起動する。
# service nginx restart

ブラウザで接続してみる

RSAの証明書のサイトでChaCha20-Poly1305 X25519 1
証明書がRSAなサイトでChaCha20-Poly1305 X25519な接続になるとブラウザではこのような表示。
(Chromeではページを表示して[F12]でデベロッパツールを開き[Security]タブを選択する)
ちなみに上の画像は「がとらぼ」をPC版のChromeで表示したもの。(2018年6月11日現在)

RSAの証明書のサイトでChaCha20-Poly1305 X25519 1
証明書がECDSAなサイトでChaCha20-Poly1305 X25519な接続になるとブラウザではこのような表示。
これは「がとらぼ」ではない別なサイトをECDHE-ECDSA-CHACHA20-POLY1305を最優先にして試したもの。

RSAの証明書のサイトでChaCha20-Poly1305 X25519 1
証明書がRSAなサイト(ここのこと)をQualysSSL LabsのSSL Server Testで見たもの。暗号スイートの優先順位も上の設定例で意図したとおりになっている。

ChaCha20って速いのかしら

###AES-NL有効化状態で計測
% openssl speed -elapsed -evp chacha20
% openssl speed -elapsed -evp aes-128-gcm
% openssl speed -elapsed -evp aes-256-gcm
% openssl speed -elapsed -evp aes-128-cbc

###AES-NL無効化状態で計測
% setenv OPENSSL_ia32cap "~0x200000200000000"      ←(tcsh用環境変数セット)
% openssl speed -elapsed -evp chacha20
% openssl speed -elapsed -evp aes-128-gcm
% openssl speed -elapsed -evp aes-256-gcm
% openssl speed -elapsed -evp aes-128-cbc

上のコマンドをIntel Pentium G630T 2.3GHzという非常に非力なPCで実行してで比較してみた。aes-128-cbcはAES-NLが効きやすいので有効化・無効化の差をはっきりと示す為の参考程度で。
逆に言うといまどきのセキュリティ重視な設定のウェブサーバ用途ではAES-NLは以前と違いあまり恩恵がない?ハードウエアの性能によるかしら。

速度比較AES-NLオン 1
AES-NLを有効化した計測結果。3秒で何回計算したかというもの。緑が参考値のaes-128-cbcだが、AES-NL有効でChaCha20とほぼ同じくらいを出せたのは16バイトのブロックの場合だけ。もっとaes-128-cbcが高い値になると思っていたので意外。
他のサイズではChaCha20が圧倒。ざっくり見てaes-128-gcmの3倍の値を出している。

速度比較AES-NLオン 2
AES-NLを有効化した計測結果。上のグラフの結果から計算回数とブロックの大きさを掛けて速度にしたもの。(実際にはコマンド実行で両方の数値が表示される)
効率からみると8192バイトのブロックが最も良い数値になるのかしら。こちらもaes-128-cbcがChaCha20と対等だったのは16バイトのブロックのときだけ。他はChaCha20が圧倒。そして、256バイト以上のサイズのブロックではaes128-gcm, aes-256-gcm, aes-128-cbcで大して変わらないことに。

速度比較AES-NLオフ 1
AES-NLを無効化した計測結果。3秒で何回計算したかというもの。AES-NLが効いてないので緑のaes128-cbcが1/3ほどに低下している。他のaes128-gcmやaes128-gcmも激減というほど酷くはないものの数値の低下はある。

速度比較AES-NLオフ 2
AES-NLを無効化した計測結果。上のグラフの結果から計算回数とブロックの大きさを掛けて速度にしたもの。(実際にはコマンド実行で両方の数値が表示される)
圧倒的な差を見せつけてChaCha20が勝利。

今回はCPUがショボイというのもあってか「がとらぼ」の中の人の思惑通りというか都合良くもChaCha20以外の選択肢はないだろというような圧倒的な結果になったが、サーバのマシンの性能によっては必ずこうなるとは限らない筈なのでウェブサーバで実際に試してみて安全で効率の良さそうな暗号スイートの優先度を上げるというのもアリかも。もちろん閲覧者の皆がメジャーブラウザの新しいバージョンを使っているとは限らないのでどうしても接続互換性重視ということであればChaCha20-Poly1305が最優先ということにはならないだろうけど。