wolfSSLでDTLS1.3を試してみる

# 1. はじめに

DTLSはUDPのような安定性を保証しない軽量のデータグラム上でセキュリティを実現するためのプロトコルです。

プロトコル仕様の最新バージョンDTLS1.3は2022年4月に[RFC9147](https://datatracker.ietf.org/doc/rfc9147/)が正式発行となっています。このバージョンがβバージョンではあるけれど[wolfSSL](https://www.wolfssl.jp/)で動作するようになったので、試してみます。

DTLS1.3では、TLS1.3で実現した数々の強化、改善が同様に盛り込まれています。その内容については[「最終段階に入ったDTLS1.3」](https://www.wolfssl.jp/wolfblog/2022/03/29/dtls1-3_in_the_final_stage/)や[「DTLS1.3で何が変わったか」](https://qiita.com/kj1/items/d021170cdeb55f990ce1)で紹介しているので参照してください。

# 2. ダウンロード、ビルド

現在のところGithubレポジトリーのオープンソース版だけで提供されているので、こちらからダウンロード、configure, makeします。
configureオプションとして --enable-dtls --enable-dtls13を指定します。

"configure" コマンドでDTLSとDTLS1.3オプションが　"yes"　となっていることを確認します。
"make check"を実行すると一連のコンパイル、ライブラリ、サンプルプログラムなどが生成され、テストを完了します。

```
$ git clone --depth 1 https://github.com/wolfssl/wolfssl
$ cd wolfssl
$ ./autogen.sh
$ ./configure --enable-dtls --enable-dtls13
...
   * DTLS:                       yes
   * DTLS v1.3:                  yes
...
$ make check
...
============================================================================
Testsuite summary for wolfssl 5.3.0
============================================================================
# TOTAL: 7
# PASS:  7
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================
```

# 3. サンプルサーバ、クライアントを走らせる


ライブラリや一連のテストプログラムとともに "examples" ディレクトリーの下にサンプルサーバとクライアントも生成されているのでそれを動作させてみます。サーバとクライアントは同じパソコン上でも、別々のパソコン上でも動作させることができます。このサンプルはポート"11111" を使用するので、別々のパソコンで通信させてみるときはファイヤーウォールのポートを開けておきます。

まず、サーバ側を起動します。"-u"オプションでUDP(DTLS)を指定します。デフォルトではDTLS1.2で動作するので、まずは比較のためこれを見てみます。クライアント側を異なるパソコンで動作させるときは外からのアクセスを受け付けるように "-b" でポートバインドを指定します。"-d"を指定するとクライアント認証を行わないようにすることができます。

```
$ ./examples/server/server -u -b
```

パケットキャプチャーも見たい場合はWiresharkを起動しておきます。

次にクライアント側を起動します。同じように"-u" オプションでUDP(DTLS)を指定します。"-h" オプションでサーバ側のIPアドレスを指定します。同じパソコンの場合は"127.0.0.1"を指定します。

```
$ ./examples/client/client -u -h xxx.xxx.xxx.xxx
```

サンプルプログラムはDTLS接続したのち、１往復の簡単なアプリケーションメッセージ通信を行って終了します。プロトコルのバージョン、利用した暗号スイートなどの実行結果はサーバ側、クライアント側にそれぞれ表示されます。

サーバ側：
```
SSL version is DTLSv1.2
SSL cipher suite is TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
SSL curve name is SECP256R1
Client message: hello wolfssl!
```

クライアント側：
```
SSL version is DTLSv1.2
SSL cipher suite is TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
SSL curve name is SECP256R1
I hear you fa shizzle!
```


次に"-v"オプションでDTLS1.3を指定して同じようにサーバとクライアントを通信させてみます。

```
$ ./examples/server/server -u -b -v4
```

```
$ ./examples/client/client -u -h xxx.xxx.xxx.xxx  -v4
```

今度は、プロトコルバージョンにDTLS1.3、暗号スイートも1.3向けのものが選択されていることがわかります。

```
SSL version is DTLSv1.3
SSL cipher suite is TLS_AES_128_GCM_SHA256
SSL curve name is SECP256R1
```

# 4. パケットキャプチャーを見てみる

次にキャプチャーしたパケットの内容を見てみます。"udp"でフィルターしてみると、DTLS1.2のハンドシェークと暗号化されたアプリケーションデータの送受信、そして最後に切断のためのAlertパケットを見ることができます。

```
No.	Time	Source	Destination	Protocol	Length	Info
127	19.043368	192.168.10.6	xx.xx.92.191	DTLSv1.2	223 	Client Hello
128	19.152213	xx.xx.92.191	192.168.10.6	DTLSv1.2	102 	Hello Verify Request
129	19.152340	192.168.10.6	xx.xx.92.191	DTLSv1.2	255 	Client Hello
130	19.260560	xx.xx.92.191	192.168.10.6	DTLSv1.2	149 	Server Hello
131	19.261291	xx.xx.92.191	192.168.10.6	DTLSv1.2	1442	Certificate (Fragment)
132	19.261293	xx.xx.92.191	192.168.10.6	DTLSv1.2	1244	Certificate (Reassembled)
133	19.273196	xx.xx.92.191	192.168.10.6	DTLSv1.2	396 	Server Key Exchange
134	19.273198	xx.xx.92.191	192.168.10.6	DTLSv1.2	67  	Server Hello Done
135	19.275181	192.168.10.6	xx.xx.92.191	DTLSv1.2	133 	Client Key Exchange
136	19.275266	192.168.10.6	xx.xx.92.191	DTLSv1.2	117 	Change Cipher Spec, Encrypted Handshake Message
141	19.384603	xx.xx.92.191	192.168.10.6	DTLSv1.2	117 	Change Cipher Spec, Encrypted Handshake Message
142	19.384762	192.168.10.6	xx.xx.92.191	DTLSv1.2	93  	Application Data
147	19.491633	xx.xx.92.191	192.168.10.6	DTLSv1.2	101 	Application Data
148	19.491635	xx.xx.92.191	192.168.10.6	DTLSv1.2	81  	Encrypted Alert
149	19.491740	192.168.10.6	xx.xx.92.191	DTLSv1.2	81  	Encrypted Alert
```

次にDTLS1.3のほうを見てみます。今のところWiresharkがまだDTLS1.3に対応していないのでプロトコルとしては"DTLSv1.2" と表示されてしまいますが、実際にはDTLS1.3のプロトコルがやりとりされています。DTLS1.2とは異なり、最初の"Client Hello"と"Server Hello" のあとは暗号化されているようで単なるUDPパケットとして表示されますが、この部分もハンドシェークが続きます。ハンドシェークが完了すると、レコード419, 421に１往復のアプリケーションメッセージとレコード422, 424にAlertのやりとりがありますが、この部分も暗号化されているのでハンドシェークメッセージと区別がつきません。

このネットワーク環境ではUDPパケット１往復に100mSec前後かかっているようです。β版で性能チューニングはまだこれからですが、パケットの往復回数が少なくなっている分だけハンドシェークのスループットが数十パーセント改善しています。

```
No.	Time    	Source      	Destination  	Protocol	Length	Info
408	34.818207	192.168.10.6	xx.xx.92.191	DTLSv1.2	561 	Client Hello
409	34.931783	xx.xx.92.191	192.168.10.6	DTLSv1.2	186 	Server Hello
410	34.932970	xx.xx.92.191	192.168.10.6	UDP     	78  	11111 → 61219 Len=36
411	34.934768	xx.xx.92.191	192.168.10.6	UDP     	1425	11111 → 61219 Len=1383
412	34.934770	xx.xx.92.191	192.168.10.6	UDP     	1284	11111 → 61219 Len=1242
413	34.940562	xx.xx.92.191	192.168.10.6	UDP     	336 	11111 → 61219 Len=294
414	34.940564	xx.xx.92.191	192.168.10.6	UDP     	108 	11111 → 61219 Len=66
415	34.940755	192.168.10.6	xx.xx.92.191	UDP     	108 	61219 → 11111 Len=66
417	35.050175	xx.xx.92.191	192.168.10.6	UDP     	82  	11111 → 61219 Len=40
419	35.050367	192.168.10.6	xx.xx.92.191	UDP     	78  	61219 → 11111 Len=36
421	35.159991	xx.xx.92.191	192.168.10.6	UDP     	86  	11111 → 61219 Len=44
422	35.159992	xx.xx.92.191	192.168.10.6	UDP     	66  	11111 → 61219 Len=24
424	35.160128	192.168.10.6	xx.xx.92.191	UDP     	66  	61219 → 11111 Len=24

```

Client Helloパケットの詳細をみてみるとDTLS1.3のための拡張を見ることができます。

```
Handshake Protocol: Client Hello
    Handshake Type: Client Hello (1)
```

DTLS1.3ではプロトコルバージョン情報は　"Supported Version　” 拡張に格納されます。このサンプル実行ではDTLS1.3を示す"0xfefc"だけが格納されていますが、後方互換のためにDTLS1.2, 1.3のどちらの接続も受け入れるというような場合はこの拡張に複数のバージョンが指定されます。

```
        Extension: supported_versions (len=3)
            Type: supported_versions (43)
            Length: 3
            Supported Versions length: 2
            Supported Version: Unknown (0xfefc)
```

後方互換性のためにプロトコルバージョンのフィールドも残されていますが、こちらには ""Version: DTLS 1.2 (0xfefd)"が入れてあります。

```
Version: DTLS 1.2 (0xfefd)
```

暗号スイートフィールドにDTLS1.2向けの暗号スイートとともに、DTLS1.3(TLS1.3)の暗号スイートも格納されているのがわかります。DTLS1.3(TLS1.3)では鍵交換方式がディフィーヘルマン系に統一されたためそのフィールドがなくなり "TLS_"の後には共通鍵アルゴリズムが指定されます。

```
        Cipher Suites (27 suites)
            Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
            Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
            Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
```

DTLS1.3(TLS1.3)ではキーシェア拡張が設けられ、この中に鍵交換に関するアルゴリズと具体的なパラメータも送るようになりました。これによって、サーバ側はClient Helloを受け取っと段階で、また、クライアント側はServer Helloを受け取った段階で共有鍵を得ることができ、その後のハンドシェークを暗号化することができるようになりました。

```
        Extension: key_share (len=331)
            Type: key_share (51)
            Length: 331
            Key Share extension
                Client Key Share Length: 329
                Key Share Entry: Group: secp256r1, Key Exchange length: 65
                    Group: secp256r1 (23)
                    Key Exchange Length: 65
                    Key Exchange: 04028a5a671c4f00cf8eaa91a37f18eaf7ccdbda26ac75eba72c…
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　...
```



# 5.　　まとめ

今回は、wolfSSLのDTLS1.3サポートのβ版を使って、DTLS1.3の一番基本となるフルハンドシェークの内容を1.2と比較しながら見てみました。β版なので全ての機能がサポートされているわけではありませんがDTLS1.3の特徴的な動作を見ることができました。