LibreSSL TLS1.3 対応状況（2019年12月時点）

# はじめに

[LibreSSL](https://www.libressl.org/) は [OpenBSD プロジェクト](https://www.openbsd.org/) によってメンテナンスされている TLS 通信用ライブラリです。
2016年に [「LibreSSL の意義」](https://qiita.com/kinichiro/items/3108e950b056963c33ad) 、2018年に [「LibreSSL の現在（2018年2月時点）」](https://qiita.com/kinichiro/items/c06692d81c175516e3cf)という文書を書きました。
今回は LibreSSL の TLS1.3 の対応状況について説明し、現状確認可能な TLS1.3 機能についてテストをしてみたいと思います。

# LibreSSL の TLS1.3 開発状況

2019年12月時点で LibreSSL はまだ TLS1.3 を正式にサポートしていません。
開発状況としては、クライアント機能は動作を確認できる程度になされていますがサーバー機能についてはまだこれからです。
このためデフォルトの状態では TLS1.3 対応のソースコードは有効にされていません。
現在の最新安定版バージョンは 3.0.2 ですが、TLS1.3 が完全にサポートされるのはもう少し先になると思われます。

# 今回のテストのためのディレクトリ構成

以下に今回のテストを行うために使用するディレクトリの構成を示します。

```
$HOME
    |- libressl/
        |- portable/              # GitHub レポジトリのクローン先
        |- libressl-3.0.2/        # 生成した tarball の展開先
        |- local/                 # make install でのインストール先
            |- bin/               # openssl(1) コマンドのある場所
```

# TLS1.3 を有効にして LibreSSL をビルドする手順

この章ではまだ公式サポートされていない LibreSSL の TLS1.3 を試してみるための方法を説明します。
LibreSSL で TLS1.3 を有効にするには、`LIBRESSL_HAS_TLS1_3` を #define してビルドする必要があります。また今回は KeyUpdate を試してみるために current のソースコードを使いたいと思ってます。
以下にその手順を示します。

## 1. portable を git clone

current のソースコードを使うため通常の[ダウンロードサイト](https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/)から tarball をダウンロードするのではなく、GitHub レポジトリをローカルにクローンします。
今回のクローン先はホームディレクトリ配下の libressl/ であるとします。

```shell-session
$ cd
$ mkdir libressl
$ git clone https://github.com/libressl-portable/portable.git
Cloning into 'portable'...
remote: Enumerating objects: 46, done.
remote: Counting objects: 100% (46/46), done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 5437 (delta 14), reused 30 (delta 10), pack-reused 5391
Receiving objects: 100% (5437/5437), 1.48 MiB | 1.05 MiB/s, done.
Resolving deltas: 100% (3364/3364), done.
Updating files: 100% (180/180), done.
$
```

これで $HOME/libressl/portable/ に GitHub のレポジトリがクローンされました。

## 2. tarball(tar.gz)の生成

クローンしたレポジトリを使ってビルド用の tarball(tar.gz)を生成します。
私は dist.sh をコピーして dist2.sh を作り、以下のように変更して tarball を生成させてます。

```bash:$HOME/libressl/portable/dist2.sh
#!/bin/sh
set -e

rm -f man/*.[35] include/openssl/*.h
./autogen.sh
./configure
make dist
```

一番最後の行の `make -j2 distcheck` を `make dist` に変更しています。

この dist2.sh を実行すると tarball が生成されます。

```shell-session
$ cd $HOME/libressl/portable/
$ ./dist2.sh
pulling upstream openbsd source
...
if test -d "libressl-3.0.2"; then  find "libressl-3.0.2" -type d ! -perm -200 -exec chmod u+w {} ';'  && rm -rf "libressl-3.0.2"  || { sleep 5 && rm -rf "libressl-3.0.2"; };  else :; fi
$
```

これで tarball が生成されました。現時点(2019年12月)では libressl-3.0.2.tar.gz というファイル名となります。

## 3. tarballを展開してビルド

生成した tarball を展開し、コメントアウトされている `LIBRESSL_HAS_TLS1_3` を有効にしてビルドを行います。

tarballを展開します。ここでは $HOME/libressl/ 直下に展開します。

```shell-session
$ cd $HOME/libressl/
$ tar zxf portable/libressl-3.0.2.tar.gz
```

tarball を展開すると $HOME/libressl/libressl-3.0.2/ というディレクトリができるのでここに移動します。

```shell-session
$ cd $HOME/libressl/libressl-3.0.2/
```

次にエディタで opensslfeatures.h を編集してコメントアウトされている `LIBRESSL_HAS_TLS1_3` を有効にします。

```shell-session
$ vi include/openssl/opensslfeatures.h
```

以下のように include/openssl/opensslfeatures.h の `LIBRESSL_HAS_TLS1_3` 定義のコメントアウトを外します。

```cl:include/openssl/opensslfeatures.h
/*
 * Feature flags for LibreSSL... so you can actually tell when things
 * are enabled, rather than not being able to tell when things are
 * enabled (or possibly not yet not implemented, or removed!).
 */
#define LIBRESSL_HAS_TLS1_3
...
```

そしてビルドを実行します。インストール先として $HOME/libressl/local/ を指定しています。

```shell-session
$ ./configure --prefix=$HOME/libressl/local/
$ make check
$ make install
```

現時点(2019年12月)では回帰テストの clienttest がエラーになりますが無視しておきます。
以上の手順で TLS1.3 を有効にした LibreSSL をビルドできました。

# TLS1.3 で接続確認

TLS1.3 が有効になった openssl(1) コマンドが使えるようになったので s_client を使って TLS1.3 で接続ができるサイトに接続してみます。

```shell-session
$ $HOME/libressl/local/bin/openssl s_client -connect tls13.cloudflare.com:443 -msg
...
---
New, TLSv1/SSLv3, Cipher is AEAD-AES256-GCM-SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : AEAD-AES256-GCM-SHA384
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Start Time: 1575985038
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---
```

上記のように TLS1.3 で接続ができることを確認できました。

# OpenSSL 1.1.1d サーバーとの KeyUpdate 確認

次に OpenSSL 1.1.1d の s_server に LibreSSL の s_client で接続し、ハンドシェイク完了後の KeyUpdate の動作を確認してみます。(KeyUpdate の仕様については [RFC 8446 の 4.6.3. Key and Initialization Vector Update](https://tools.ietf.org/html/rfc8446#section-4.6.3) を参照)

今回私は OpenBSD6.6(AMD64)で確認を行っています。OpenBSD では OpenSSL 1.1.1d を `pkg_add openssl` でインストールできるようになっており、該当するコマンドは /usr/local/bin/openssl11 となっています。
このため以後、OpenSSL 1.1.1d の実行は eopenssl11 と表記します。

またテスト用の証明書として LibreSSL の回帰テスト用の ca.pem と server.pem を利用しています。

まず OpenSSL 1.1.1d の s_server を端末で起動します。

```shell-session:terminal-A
$ cd $HOME/libressl/libressl-3.0.2/tests/
$ eopenssl11 s_server -4 -CAfile ca.pem -cert server.pem -msg
Using default temp DH parameters
ACCEPT
```

次に別端末で LibreSSL の s_client を起動して s_server に接続します。

```shell-session:terminal-B
$ cd $HOME/libressl/libressl-3.0.2/tests/
$ $HOME/libressl/local/bin/openssl s_client -CAfile ca.pem -connect localhost:4433 -msg -debug
...
---
New, TLSv1/SSLv3, Cipher is AEAD-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : AEAD-AES256-GCM-SHA384
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Start Time: 1575985744
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---
...
read R BLOCK
```

次に OpenSSL 1.1.1d の s_server 側の端末で 'K' とキーボード入力します。'K' は s_server のコマンドで KeyUpdate のメッセージをクライアントに送信し、クライアントからも KeyUpdate の送信を要求するものです。

```shell-session:terminal-A
K
```

すると以下のように KeyUpdate が出来ることを確認できました。

OpenSSL 1.1.1d の s_server 側の出力

```shell-session:terminal-A
>>> ??? [length 0005]
    17 03 03 00 16
>>> TLS 1.3 [length 0001]
    16
>>> TLS 1.3, Handshake [length 0005], KeyUpdate
    18 00 00 01 01
SSL_do_handshake -> 1
<<< ??? [length 0005]
    17 03 03 00 16
<<< TLS 1.3 [length 0001]
    16
<<< TLS 1.3, Handshake [length 0005], KeyUpdate
    18 00 00 01 00
Read BLOCK
```

LibreSSL の s_client 側の出力

```shell-session:terminal-B
read from 0x87031d42680 [0x8709af0e770] (5 bytes => 5 (0x5))
0000 - 17 03 03 00 16                                    .....
read from 0x87031d42680 [0x870a7897025] (22 bytes => 22 (0x16))
0000 - 9d 71 5d 02 44 30 d2 a9-f0 bd 49 9a 4b c4 5b 04   .q].D0....I.K.[.
0010 - 91 11 e4 71 f7 b3                                 ...q..
write to 0x87031d42680 [0x87002eb7520] (27 bytes => 27 (0x1B))
0000 - 17 03 03 00 16 86 68 c1-ab 04 2a 7b 2f 9f 11 b1   ......h...*{/...
0010 - a8 87 ad e5 c3 4d 0c 15-03 5c 6d                  .....M...\m
read R BLOCK
```

# まとめ
今回は LibreSSL の TLS1.3 対応状況を説明し、正式サポート前の TLS1.3 クライアント機能を使って通信が行えることを確認しました。
現状、TLS1.2 にセキュリティ上の問題がないこともあり、TLS1.3 の導入については急ぐ必要がなく慎重に丁寧に実装を進めていける状況です。とはいえ TLS1.3 対応の要求は高まっており、今後のサーバー機能の実装など含め TLS1.3 の公式サポートが期待されています。

OpenBSD プロジェクトは寄付を募ってます。
メールアドレス指定で日本からでもPayPalでの寄付ができます。
詳しくはこちら： https://www.openbsd.org/donations.html