してみるテストロゴ
Apache 2.4系でHTTP/2サーバを構築してみるテスト。

TLSv1.3を設定してみた。

[2018年10月24日版] Apache 2.4.37がリリースされました。特別なことをしなくても、OpenSSL1.1.1とTLSv1.3に対応しています。

[2018年6月14日版] OpenSSL1.1.1-pre7では、TLSv1.3(draft 28)に対応しています。

[2018年6月21日版] OpenSSL1.1.1-pre8がリリースされました。

[2018年6月29日版] OpenSSL1.1.1-pre7以降は、TLSv1.3に対応するために、mod_sslの修正が必要です。これを追記しました。

[2018年9月12日版] OpenSSL1.1.1正式版がリリースされました。

互換性上の問題、バグ、制限もあるのですが、なんとかWebサーバで使えるところまでは来ている感じです。

そこで、Apache HTTPDサーバで、OpenSSL1.1.1のTLSv1.3を使ってみました。

mod_sslの修正

Apache 2.4.37以降、こちらの手順は必要ありません。

OpenSSL1.1.1-pre7以降のTLSv1.3に対応するためには、mod_sslの修正が必要です。

mod_sslを最新版にするには、

http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/

から、ソースコードを取ってきます。

まずは、mod_sslのフォルダに移動します。

# cd ~/src/http2.4.33/modules/ssl

ここに、さきほどのURLから、ダウンロードしたファイルを配置します。

取ってくるのは、以下の6ファイルです。

ssl_engine_config.c
ssl_engine_init.c
ssl_engine_kernel.c
ssl_engine_pphrase.c
ssl_private.h
ssl_util.c

取ってきたら再コンパイルします。

# cd ~/src/http2.4.33/
# make
# sudo make install

です。

Apache HTTPDサーバの設定例

一応、Apache HTTPD Webサーバのバージョンは 2018年3月26日現在の最新である2.4.33を使いました。

TLS1.3を使うために必要最低限な設定は以下のようになります。

 

まず、SSLProtocolディレクティブの行頭に#を付けてコメントアウトします。

バージョン2.4.37以降、以下の設定でもTLSv1.3が有効になります。(testtlnlsさん情報ありがとうございます。)

vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLProtocol All -SSLv3

SSLProtocolのかわりに、SSLOpenSSLConfCmdを使って、プロトコルの制限を設定することもできます。

たとえば、TLSv1.0以降を有効にする場合、以下のようにします。

vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLOpenSSLConfCmd MinProtocol "TLSv1.0"
SSLOpenSSLConfCmd MaxProtocol "TLSv1.3"

 

続いて、TLSv1.3で使う暗号スイートを設定します。

TLSv1.3以降の暗号スイートはSSLOpenSSLConfCmdディレクティブのCiphersuitesパラメータに設定します。

従来からある、暗号スイートを列挙したSSLCipherSuiteディレクティブとの違いですが、SSLCipherSuiteディレクティブには、TLSv1.2までの暗号スイートを設定します。

つまり、SSLCipherSuiteディレクティブの設定は、既にお使いのありものがあればそのままで良いです。

そして、列挙する暗号スイートにも違いがあります。

TLSv1.2までの暗号スイートは、使用する各暗号アルゴリズムを"-"(ハイフン)で区切りますが、TLSv1.3の暗号スイートは"_"(アンダースコア)で区切ります。

TLSv1.3で定義されている暗号スイートは以下の通りです。

  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256
  • TLS_AES_128_GCM_SHA256
  • TLS_AES_128_CCM_SHA256
  • TLS_AES_128_CCM_8_SHA256

となります。これらをまとめると、次のようになります。

--[2018年10月26日修正]--

バージョン2.4.37以降は、見慣れたSSLCipherSuiteディレクティブが拡張されて、TLSv1.3用の暗号スイートを設定できます。

SSLCipherSuiteディレクティブの第1パラメータが、"TLSv1.3"の場合、第2パラメータをTLSv1.3用の暗号スイートとして設定します。

第1パラメータが"TLSv1.3"以外の場合、従来と同じくTLSv1.2までの暗号スイートの設定ができます。

testtlnlsさん情報ありがとうございます。)

第1パラメータが"TLSv1.3"のSSLCipherSuiteディレクティブと、 第1パラメータが、"TLSv1.3"以外のSSLCipherSuiteディレクティブは共存可能です。

vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLCipherSuite TLSv1.3 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256" ←TLSv1.3の暗号スイートを列挙
SSLCipherSuite "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305" ←TLSv1.2以前の暗号スイートを列挙
(バージョン2.4.36以前)
vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLOpenSSLConfCmd Ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256" ←TLSv1.3の暗号スイートを列挙
SSLCipherSuite "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305"←TLSv1.2以前の暗号スイートを列挙

ちなみに、TLSv1.2の暗号スイートは、SSLOpenSSLConfCmdディレクティブのCipherStringパラメータに設定することもできます。

SSLCipherSuiteディレクティブの設定よりも、こちらが優先されるようです。

vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLOpenSSLConfCmd CipherString "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305" ←TLSv1.2までの暗号スイートを列挙

そしてECDHの設定を行います。

--[2018年5月10日修正]--

当初、OpenSSL 1.1.1のECDH設定にX25519を入れても動かないと書きましたが、動かす方法が見つかりました。

OpenSSL 1.1.1のECDH設定は、ECDHParametersにX25519を入れても、うまく動かない様です。

そこで、CurvesにX25519を明示して、 ECDHParametersは、Automaticにします。

これでなぜか動きます。

-----------------------

vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLOpenSSLConfCmd ECDHParameters Automatic
SSLOpenSSLConfCmd Curves X448:25519:secp384r1:prime256v1

最後に、使用する証明書の署名アルゴリズムを設定します。

--[2018年5月7日修正]--

署名アルゴリズムは、RSA+SHA256や、ECDSA+SHA256のように、公開鍵暗号方式と、ダイジェスト署名方式の組み合わせで指定します。

OpenSSL1.1.1では、署名アルゴリズムにRSA+SHA256の他に、RSA-PSS+SHA256といったRSA-PSS形式を、別の署名方式として分離して定義しています。

OpenSSL1.1.0までは、RSA-PSS+SHA256も、単にRSA+SHA256として分類されていました。OpenSSL1.1.1から分類が細分化したと言えます。

これは、証明書の内容を書き換えてから、パディング部分を調整することで、同一ハッシュ値となるように調整できてしまう脆弱性に対する対策と思われます。

Let's Encryptの発行するRSAを使った証明書は、2018年3月27日現在、RSA-PSS形式のようです。

当初、RSA+SHA256では、うまく動作しないと記載していたのですが、TLSv1.3の所定の動作ということでした。

訂正してお詫び申し上げます。

---------------------

RSAの証明書を禁止して、ECDSAの証明書だけを有効にしたければ、以下のようにしてください。

vi /usr/local/apache2/conf/extra/httpd-ssl.conf
SSLOpenSSLConfCmd SignatureAlgorithms "ECDSA+SHA256"

仕上げに、apachctl -tで、設定ファイルの間違いが無いことを確認の上、下記のように

# /usr/local/apache2/bin/apachctl -t
Syntax OK
# /usr/local/apache2/bin/apachctl stop
# /usr/local/apache2/bin/apachctl start

とします。Syntax OKと出なかった場合は、なにか間違ってますので、これまでの作業を見直してください。

OpenSSLクライアントから、TLSv1.3サーバへの接続

ChromeやEdgeなどのブラウザは、まだ、OpenSSL1.1.1-pre7が実装しているTLSv1.3のDraft28には、対応していないようです。

なので、コマンドラインから、OpenSSLを使って、TLSv1.3のサーバに接続してみます。

以下のように、-tls1_3オプションを付けると、OpenSSL1.1.1は、TLSv1.3を使って接続します。

# /usr/local/bin/openssl s_client -host http2.try-and-test.net -port 443 -tls1_3  -servername http2.try-and-test.net -crlf
CONNECTED(00000003)
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify error:num=20:unable to get local issuer certificate
---
Certificate chain
 0 s:CN = http2.try-and-test.net
   i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
   i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
(・・・省略・・・)
-----END CERTIFICATE-----
subject=CN = http2.try-and-test.net

issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: ECDH, P-384, 384 bits
---
SSL handshake has read 2807 bytes and written 637 bytes
Verification error: unable to get local issuer certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID:
    Session-ID-ctx:
    Master-Key: (・・・省略・・・)
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1521799948
    Timeout   : 7200 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
    Extended master secret: no
---
read R BLOCK
GET / HTTP/1.1
host: http2.try-and-test.net

HTTP/1.1 200 OK
(・・・省略・・・)

プロトコルが、TLSv1.3になっていればOKです。

X448/X25519の使い方は以下に書きました。

さて、これでアクセスログが書かれたはずです。

どんなログが出る?

さっそく、アクセスログも見て見ます。

アクセスログは、デフォルトのものでは、SSL関連の出力が甘いので、私は、以下のようなカスタムログを使って出力しています。

vi /usr/local/apache2/conf/extra/httpd-vhost.conf
CustomLog "|/usr/local/apache2/bin/rotatelogs -l /usr/local/apache2/log/access_log.%Y%m%d 86400 " "%
{remote}p@%h \"%{%F %T %z}t\" %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{pid}P %{H2_STREAM_TAG}e %u %m \"%U\" \"%q\" %H %>s %B \"%{Referer}
i\" \"%{User-agent}i\" %D \"%{H2_PUSHED}e\" %{H2_PUSHED_ON}e"	

上記カスタムログ設定だと、

tail /usr/local/apache2/log/access_log.YYYYMMDD
[PORT]@[IPv4] "YYYY-MM-DD XX:XX:XX +0900" TLSv1.3 TLS_AES_256_GCM_SHA384 42445 - - GET "/index.html" "" HTTP/1.1 200 66126 "-" "-" 9552125 "-" -

となります。

つまり、%{SSL_PROTOCOL}xに"TLSv1.3"と入ります。

また、%{SSL_CIPHER}xに、TLSv1.3の暗号スイート(今回は、TLS_AES_256_GCM_SHA384)がログに残ります。

NEXT >> トップページに戻る

©Copyrights 2015-2018, non-standard programmer

このサイトは、あくまでも私の個人的体験を、綴ったものです。 軽く参考程度にご利用ください。