
dtls-fuzzer は、DTLSサーバのプロトコル状態ファジングを実行するJavaツールです。具体的には、以下の機能をサポートしています:
dtls-fuzzer は TLS-Attacker を使用して、DTLSメッセージの生成/解析と状態の維持を行います。
そのために、TLS-Attacker はDTLSサポートのために拡張されています。
dtls-fuzzer は、DTLS拡張を実装した TLS-Attacker のバージョン3.0b に依存しています。
アーティファクトには以下が含まれます:
dtls-fuzzer のルートディレクトリで最も重要なフォルダは:
'experiments/results' には実験結果が含まれており、これが作業の主な出力です。特に、
出力フォルダは実験構成に基づいて命名されています。すなわち:
例として、フォルダ名 'jsse-12_rsa_cert_none_rwalk_incl' は、JSSE 12のDTLS実装での実験を示し、RSAハンドシェイクを実行するための入力を含むアルファベットを使用し、クライアント証明書認証は無効で、テストアルゴリズムはランダムウォーク、再送信が含まれています。
出力フォルダには以下が含まれます:
評価者は、たとえば 'included' 内の実験結果が表4に表示されているものと一致すること、または表2でテストされた構成が 'all_ciphers' にも現れることを確認できます。 論文に登場するモデルは大幅な枝刈り/トリミングの結果であるのに対し、出力フォルダに現れるモデルは未変更であることに注意してください。
dtls-fuzzer を評価するためには、以下の手順を実行する必要があります:
この評価セクションの後には、dtls-fuzzer の主なユースケースを紹介する使用方法ガイドがあります。
dtls-fuzzer は Ubuntu 18.04 および Debian 9 のLinuxディストリビューションでテストされています。 最近のLinuxディストリビューションであれば動作するはずです。 他のプラットフォームのサポートはテストされていません。 このガイドでは、Debianベースのディストリビューション('apt-get' があるもの)を使用することを前提としています。
Java 8 JDK(Java Development Kit)仮想マシン(VM)が必要です。 実験の実行に使用されたバージョンは1.8.0_222ですが、それ以降のJava 8バージョンでも動作するはずです。 このツールはJava 9以降ではビルドできないことに注意してください。 また、依存関係管理/デプロイのために maven('mvn' ユーティリティ)にも依存しています。
十分に強力なマシンを使用することをお勧めします。そうしないと、応答待機時間などのタイミングパラメータが低すぎて、論文で得られたものと異なる出力が生成される可能性があります。 さらに悪い場合、学習実験が失敗する可能性があります。 元の実験はマルチコアサーバで実行されましたが、i7プロセッサを搭載したデスクトップでも学習が可能であると期待されます(徹底的にはテストされていませんが)。 タイミングパラメータを適切に調整すれば、より弱いシステムでも学習は可能です。 最後に、.dotモデルを.pdfにエクスポートして可視化するには、graphvizライブラリのインストールが必要です。 graphvizが提供する 'dot' ユーティリティがシステムのPATHに配置されていることを前提とします。
要約すると、推奨される前提条件は次のとおりです:
dtls-fuzzer にはJava 8 JDK(Java Development Kit)が必要です。 Javaがインストールされていない場合は、OpenJDK実装を(Ubuntuでは 'apt-get' 経由で)インストールします。このサブセクションの残りはスキップできます。
> sudo apt-get install openjdk-8-jdk
Javaのバージョンがインストールされている場合、次のコマンドでバージョンを確認できます:
> java -version
バージョンコードは1.8で始まる必要があります(例:1.8.0_242)。仮想マシンは「Server VM」である必要があります(フルJDKがインストールされていることを示し、ランタイム環境のみではないことを示します)。 そうであれば、Javaに関しては完了です。 そうでない場合は、Java 8 JDKがプラットフォームにインストールされているが現在選択されていない可能性があります。インストールされているJava VMをリスト表示するには、次のコマンドを使用します:
> update-java-alternatives --list
Java 8 JDKが表示される場合は、同じコマンドを使用してJava 8 JDKをデフォルトのJava実装として構成できます。
> sudo update-java-alternatives --set java-1.8.0-openjdk-amd64
それ以外の場合は、冒頭で示した完全なインストールを実行する必要があります。 残念ながら、'update-java-alternatives' が成功しない場合があり、「error」メッセージが表示されます。 そのような場合は、'update-alternatives' を使用して、'java'(インタプリタ)と 'javac'(コンパイラ)で選択されるJava VMを対話的に構成できます。
> sudo update-alternatives --config java
> sudo update-alternatives --config javac
Java 8が設定されたら、他の依存関係(maven、graphviz、およびいくつかの一般的なSUT依存関係)をインストールします。 次に、dtls-fuzzer のリポジトリを選択したフォルダにクローンし、アーティファクトブランチをチェックアウトします。 最後に、そのフォルダを現在のディレクトリにします。
> sudo apt-get install maven graphviz autotools-dev automake libtool
> git clone -b usenix20-artifact https://github.com/assist-project/dtls-fuzzer.git ~/dtls-fuzzer
> cd ~/dtls-fuzzer
まず 'prepare.sh' スクリプトを実行します。これにより、dtls-fuzzer が依存するライブラリ(2つのローカル.jarとTLS-Attacker 3.0b)がインストールされます。 次に、ツール自体をインストールします。 POSIXシステムでの結果のコマンドは次のようになります:
> bash prepare.sh
> mvn clean install
これらの手順の後、'dtls-fuzzer.jar' を含む 'target' というディレクトリが構築されているはずです。 これが実行可能なライブラリです。 この時点以降、コマンドは dtls-fuzzer のルートディレクトリから実行されることを前提としています。
PSK(事前共有鍵)のみを使用してOpenSSL 1.1.1bのモデルを生成するとします。 dtls-fuzzer のクイックランは次のように進みます。
まず、'setup_sut.sh' スクリプトによって自動的にSUTをセットアップします。
> bash setup_sut.sh openssl-1.1.1b
次に、'args/openssl-1.1.1b' フォルダから引数ファイルを選択します。 いくつかの引数ファイルから選択できることに注意してください。具体的には:
learn_openssl-1.1.1b_all_cert_none_rwalk_incl
learn_openssl-1.1.1b_all_cert_nreq_rwalk_incl
learn_openssl-1.1.1b_all_cert_req_rwalk_incl
learn_openssl-1.1.1b_psk_rwalk_incl
対象の引数ファイルは 'learn_openssl-1.1.1b_psk_rwalk_incl' です。ファイル名がPSKを示しているためです。 したがって、それを選択し、ファザーを実行します。 さらに、学習時間を短縮するために、テスト数を200に制限します。 最後に、OpenSSLの場合、LD_LIBRARY_PATH を実装のディレクトリ ('suts/openssl-1.1.1b/') に設定する必要があります。 学習を実行する前に、セットアップが機能していることを確認するために簡単なテストを実行するとよいでしょう。 適切なテストは、ハンドシェイクを完了することです。 引数ファイルと、'examples/tests' からの対応するテストをパラメータとして指定します。
> LD_LIBRARY_PATH=suts/openssl-1.1.1b/ java -jar target/dtls-fuzzer.jar @args/openssl-1.1.1b/learn_openssl-1.1.1b_psk_rwalk_incl -test examples/tests/psk
すべてがうまくいけば、サーバは「This is a hello message」と出力するはずです。これはハンドシェイク完了後に送信するメッセージです。 セットアップが機能していることがわかったので、次のコマンドで学習を開始できます:
> LD_LIBRARY_PATH=suts/openssl-1.1.1b/ java -jar target/dtls-fuzzer.jar @args/openssl-1.1.1b/learn_openssl-1.1.1b_psk_rwalk_incl -queries 200
実験の出力ディレクトリ 'output/openssl-1.1.1b_psk_rwalk_incl/' が作成されたことに気づくでしょう。 このディレクトリを 'ls' して、実験の現在のステータス(生成された仮説の数など)を確認できます。
> ls output/openssl-1.1.1b_psk_rwalk_incl/
すべてがうまくいけば、20〜30分後に出力ディレクトリに 'learnedModel.dot' ファイルが含まれているはずです。 graphvizの 'dot' ユーティリティを使用してファイルを可視化し、.pdfにエクスポートして、お気に入りの.pdfビューアで開きます。
> dot -Tpdf output/openssl-1.1.1b_psk_rwalk_incl/learnedModel.dot > output/openssl-1.1.1b_psk_rwalk_incl/learnedModel.pdf
> evince output/openssl-1.1.1b_psk_rwalk_incl/learnedModel.pdf
最後に、'trim_model.sh' を使用して、より良い/トリミングされたバージョンのモデルを生成できます。次のように実行します:
> bash trim_model.sh --output output/openssl-1.1.1b_psk_rwalk_incl/nicerLearnedModel.dot output/openssl-1.1.1b_psk_rwalk_incl/learnedModel.dot
> dot -Tpdf output/openssl-1.1.1b_psk_rwalk_incl/nicerLearnedModel.dot > output/openssl-1.1.1b_psk_rwalk_incl/nicerLearnedModel.pdf
> evince output/openssl-1.1.1b_psk_rwalk_incl/nicerLearnedModel.pdf
これで、モデルを仕様と照合してシステムの適合性を判断できます...
出力ディレクトリを 'ls' すると 'error.msg' が見つかる場合があります。 それは実験が失敗し、学習が突然終了したことを示しています。 そのような場合、内容を表示すると失敗の理由が明らかになります。
> cat output/openssl-1.1.1b_psk_rwalk_incl/error.msg
ただし、最後に生成された仮説に対して適合性の確認を実行することは可能です。ただし、潜在的な発見はシステムに対して検証する必要があります(本来そうすべきですが)。
SUTをセットアップするためのスクリプトを提供しています。 このスクリプトは、ソースファイルをダウンロードし、いくつかの依存関係(jvm)をインストールし、SUTをビルドします。 自動セットアップが提供されているSUTを表示するには、次のコマンドを実行します:
> bash setup_sut.sh
たとえば、Contiki-NGのtinydtls実装をセットアップするには、次のコマンドを実行します:
> bash setup_sut.sh ctinydtls
スクリプトは dtls-fuzzer のルートディレクトリに2つのフォルダを生成します。
残念ながら、SUTセットアップの自動化は複雑なプロセスであるため、以下のショートカットを使用します。 Java SUT(JSSE、Scandium)の場合、実装をビルドせず、代わりに 'experiments/suts' ディレクトリからコンパイル済みの.jarを使用します。 これらのJava SUT(サーバアプリケーション)のソースコードはオンラインで公開されていることに注意してください。Scandium と JSSE を参照してください。PionDTLS についても同様です。 依存関係の自動インストールでは 'sudo' アクセスが求められる場合があります。 これは、GnuTLS(nettleなどの外部ライブラリに依存)やEclipseのTinyDTLS(autoconfに依存)で発生します。 最後に、NSSとPionDTLSについては、セットアップが非常に複雑なため、自動セットアップや引数ファイルは提供していません。
セットアッププロセスで問題が発生した場合は、'suts' フォルダ(またはSUT固有の 'suts/SUT' フォルダ)を削除してセットアップスクリプトを再実行すると問題が解決する場合があります。 また、ビルドに失敗した場合でも、実装のソースコードは 'suts' ディレクトリにダウンロードされているはずです。 回避策として、実装を手動でビルドします。 実装がビルドされていれば、セットアップは機能するはずです。
以下に、さまざまなSUTが持つ依存関係の不完全なツリーを示します。 イタリック体のものは、'setup_sut.sh' が 'sudo' アクセスを使用してインストールしようとする依存関係です。
これでSUT構成の学習を行う準備ができました。 さまざまなSUT構成の引数ファイルは、dtls-fuzzer のホームディレクトリにある 'args' ディレクトリに用意されています。 各引数ファイル名は、'experiments/results/' の出力フォルダ名で説明されているように、実験のセットアップ(SUT、アルファベット、認証)を表します。 引数ファイルを使用してSUTの学習を開始するには、次のコマンドを実行します:
> java -jar target/dtls-fuzzer.jar @args/sut_name/arg_file
出力フォルダは生成された 'output' ディレクトリに保存されます。
論文の実験と比較して、ハードウェア性能の低さへの適応として、いくつかのSUTの応答タイムアウトを増やしました。 学習時間を短縮するために、ランダムウォークアルゴリズムのテスト上限を20000から5000に減らすことをお勧めします。 これは次のように実行できます:
> java -jar target/dtls-fuzzer.jar @args/sut_name/arg_file -queries 5000
これにより、引数ファイルの上限設定が上書きされます。 GnuTLS、PionDTLS、JSSEを除き、この低い上限でも学習で同じモデルが生成されることが期待されます。
タイミングが問題になり、非決定性が発生し、その後情報提供の 'error.msg' ファイルで突然終了する可能性があります。 そのような場合、調整できる2つの調整ノブがあります:
これらのパラメータは、引数ファイルの対応する設定を(おそらくより高い値で)上書きすることで調整できます:
> java -jar target/dtls-fuzzer.jar @args/sut_name/arg_file -timeout new_response_timeout -runWait new_start_timeout
タイミングの問題を回避するために、十分に強力なマシンで実験を実行することをお勧めします。 非決定性の主な原因は、SUTの起動または応答の生成に時間がかかりすぎることです。 この可能性は、より多くの計算能力が提供されるにつれて減少します。
特に終了が予想されない実験については、一定期間後に実験を自動的に終了したい場合があります。 この期間の設定は、実験の実行が許可される最大期間を割り当てる時間制限パラメータを介して可能です。 この期間はISO 8601形式で指定します。 実験の実行時間を60分に制限するには、次のように実行します:
> java -jar target/dtls-fuzzer.jar @args/sut_name/arg_file -timeLimit "PT60M"
サーバが異なるポートでリッスンするように構成されている場合、複数の実験を同時に実行することが可能です。 各実験を別々のターミナルで起動することを選択できます。 あるいは、'disown' ユーティリティを使用して単一のターミナルで実験を起動することもできます:
> java -jar target/dtls-fuzzer.jar @args/ctinydtls/learn_ctinydtls_psk_rwalk 1>/dev/null 2>&1 & disown
ただし、数個(>2)を超えて実行すると、マシンに追加の負荷がかかります。 また、偶発的なポート競合による学習失敗の可能性が高まります。 ほとんどの構成では、サーバはlocalhost上のハードコードされたポートでリッスンするように構成されており、'args' で提供される構成は個別のハードコードされたポートを使用します。 JSSEおよびScandium構成では、セットアップが異なります。 テストごとに、SUTは動的に選択されたポートでリッスンするサーバを起動し、TCPソケットを介してポートを dtls-fuzzer に通知します。 これには、サーバがパケットを受信する準備ができたときに dtls-fuzzer に通知できるという利点があります(これがないと、dtls-fuzzer はサーバの起動を任意の時間盲目的に待機する必要があります)。 欠点は、割り当てられたポートが別の実験のハードコードされたポートと同じになる可能性があることです。特に、サーバスレッドが最近停止され、新しいスレッドがまだ開始されていない場合(つまり、ハードコードされたポートが動的割り当てで使用される可能性がある)に発生します。 この形式の競合を避けるために、ScandiumおよびJSSEの実験は他のすべての実験とは別に実行することをお勧めします。
自動ビルドが信頼性が高く、学習が速い、または興味深いバグが見つかった以下の構成をお勧めします。 提供されたコマンドを実行する前に、必ずSUTをセットアップしてください。 可能な限りPSK構成に焦点を当てていることに注意してください。 これは、小さなパスワードを使用したPSKは、他の暗号化メカニズムよりも大幅に少ない処理時間を必要とするためです。### OpenSSL 1.1.1b 任意の openssl-1.1.1b 設定(例えば 'args/openssl-1.1.1b/learn_openssl-1.1.1b_all_cert_req_rwalk_incl')を試すことができます。 実験は短時間(1日未満)で終了し、すべての鍵交換アルゴリズムを実行します。 すべての (PSK, RSA, ECDH, DH) 鍵交換アルゴリズムを使用したクライアント証明書必須設定のコマンド:
> LD_LIBRARY_PATH=suts/openssl-1.1.1b/ java -jar target/dtls-fuzzer.jar @args/openssl-1.1.1b/learn_openssl-1.1.1b_all_cert_req_rwalk_incl -queries 5000
注意: OpenSSL を学習する際は、LD_LIBRARY_PATH 変数をインストールディレクトリに設定する必要があります。
任意の mbedtls-2.16.1 設定を OpenSSL と同様の理由で使用できます。 SUT が低速なため、実験の完了にはより多くの時間がかかります。 すべての鍵交換アルゴリズムを使用し、クライアント証明書認証を無効にした設定のコマンド:
> java -jar target/dtls-fuzzer.jar @args/mbedtls-2.16.1/learn_mbedtls_all_cert_none_rwalk_incl -queries 5000
この設定で得られたモデルの編集版が付録に掲載されています。 入力アルファベットが小さいため、低いテスト制限値 2000 を使用でき、テストが容易になります。
> java -jar target/dtls-fuzzer.jar @args/ctinydtls/learn_ctinydtls_psk_rwalk -queries 2000
WolfSSL には PSK 設定を用意しており、学習は比較的早期に終了するはずです。
> java -jar target/dtls-fuzzer.jar @args/wolfssl-4.0.0/learn_wolfssl-4.0.0_psk_rwalk -queries 2000
分析した新しい GnuTLS バージョンでは、コンパクトで見やすいモデルが得られました。 残念ながら、クライアント認証を有効にすると、必要なテスト数が急増します。 学習時間を短縮するため、認証を無効にした設定を推奨します:
> java -jar target/dtls-fuzzer.jar @args/gnutls-3.6.7/learn_gnutls-3.6.7_all_cert_none_rwalk_incl -queries 2000
この設定で得られたモデルの編集版が論文に掲載されています。 そのモデルは重要なバグを露呈しますが、残念ながら実験には長い時間がかかります。 Scandium または JSSE を含まない実験と並行して実行しないでください。 コマンド:
> java -jar target/dtls-fuzzer.jar @args/scandium-2.0.0/learn_scandium-2.0.0_psk_rwalk -queries 2000
この設定で得られたモデルの編集版が論文に掲載されています。 そのモデルは重要なバグを露呈します。 Scandium または JSSE を含まない実験と並行して実行しないでください。 JSSE の学習は収束/完了せず、状態数が増え続ける仮説を構築することに注意してください。 そのため、JSSE 実験は 1 日後(論文では 2 日後)に自動終了するよう設定しています。 RSA 鍵交換のコマンド:
> java -jar target/dtls-fuzzer.jar @args/jsse-12/learn_jsse-12_rsa_cert_req_rwalk_incl
面倒な学習の代わりに、この設定で証明書メッセージを一切送信せずにハンドシェイクが完了できるかどうかを単純にテストしたい場合もあります。 これは次のように実行できます:
> java -jar target/dtls-fuzzer.jar @args/jsse-12/learn_jsse-12_rsa_cert_req_rwalk_incl -test examples/tests/rsa
学習が完了したら、出力ディレクトリで分析すべき項目は次のとおりです:
学習された .dot モデルは graphviz ライブラリを使用して .pdf に変換することで可視化できます:
> dot -Tpdf learnedModel.dot > learnedModel.pdf
残念ながら、モデルが大きくなるにつれて、この方法で生成された .pdf は読みにくくなります。 そこで、'trim_model.sh' からアクセスできる刈り込みスクリプトを開発/使用/インポートしました。 このスクリプトは、次のように実行することで使用法を表示します:
> bash trim_model.sh
最も基本的な形式でのスクリプトの使用をお勧めします:
> bash trim_model.sh learnedModel.dot
このスクリプトは:
(5) では、'experiments\scripts' にあるカスタム mypydot Python 3 ライブラリのインストールが必要です。 他のすべての手順では、プレーンな 'sed' と dot-trimmer Java ライブラリを使用します。 このライブラリの .jar は 'experiments\scripts' に含まれています。
実行:
> java -jar target/dtls-fuzzer.jar -help
オプションの数が多すぎるかもしれません。 DTLS サーバ実装を学習するには、"-connect ip_address:port"(実行中の DTLS サーバが listen しているアドレス)の数個のオプションを指定するだけで十分です。 他のすべてのオプション(アルファベットを含む)はデフォルト値に設定されます。
ポート 20000 で listen している既存のローカルサーバ実装の学習実行を開始するには、次のように実行します:
> java -jar target/dtls-fuzzer.jar -connect localhost:20000
このタイプの学習では問題が発生する可能性があります。 学習では、テストごとにサーバをリセットできる必要があります。 サーバによっては、あるテストから次のテストへ状態を引き継ぐものがあります。 これは学習中の非決定論につながる可能性があるため、より良い方法は、提供されたコマンドを使用してテストごとに新しいサーバスレッドを起動することです。 テストの実行後、サーバスレッドは強制終了され、適切なリセットが保証されます。 OpenSSL の例:
> java -jar target/dtls-fuzzer.jar -connect localhost:20000 -cmd "openssl s_server -accept 20000 -dtls1_2"
パラメータが多くなると、コマンドは非常に長くなります。 dtls-fuzzer は JCommander を使用して引数を解析し、ファイルからパラメータを読み取ることもできます。 引数の例については 'experiments/args' を参照してください。 dtls-fuzzer に引数ファイルを提供するには、"@" を前に付けてパラメータとして指定します。 また、コマンドに他の明示的な引数を追加することもできます(引数ファイル内のものを上書きします)
> java -jar target/dtls-fuzzer.jar @arg_file ...overwriting params...
バッチ学習実行を起動するには、'experiments/scripts' にある 'launcher.py' スクリプトを使用できます。 引数ファイルが含まれるディレクトリを指定すると、ツールは各引数ファイルに対して学習プロセスを起動します。
> python3 experiments/scripts/launcher.py --jar target/dtls-fuzzer.jar --args args_folder
学習実験を実行する前に、特にタイミングパラメータが正しく設定されているかを確認すると役立ちます。 そのために、dtls-fuzzer は SUT 上でカスタムテストスイート(テストの集合)を実行し、出力のサマリーを提供できます。 この機能は、失敗した学習実験の診断(何が問題だったかの特定)にも使用できます。
デフォルトのアルファベットを使用してサーバ上でテストスイートを実行するには、次のように実行できます:
> java -jar target/dtls-fuzzer.jar -connect localhost:20000 -test test_file
テストファイルの例については、'examples/tests' を参照してください。 テストファイルは、改行で区切られた入力のリストで構成されます。 テストは空行で区切られます。 各テストの終わりはファイルの終端または空行です。 "#" は行をコメントアウトするために使用します。
モデル/仕様がある場合は、テストスイートを実行し、その出力を仕様のものと比較することもできます。
> java -jar target/dtls-fuzzer.jar -connect localhost:20000 -test test_file -specification model
テストの実行回数は '-times' パラメータで設定可能で、デフォルトは 1 です。 高い値に設定すると、各テストの出力を比較することで学習設定の非決定論を検出するのに役立ちます。
> java -jar target/dtls-fuzzer.jar -connect localhost:20000 -test test_file -times 10
最後に、学習実験の引数ファイルがある場合は、必要なテスト引数を追加するだけで、対象の SUT に対してテストを実行できます:
> java -jar target/dtls-fuzzer.jar @learning_arg_file -test test_file