TLS通信の内容に迫る Lv2 (1)
前回の記事ではTLS通信の解説Lv1として盗聴、なりすまし、改ざん対策の概要を書きました。
realizeznsg.hatenablog.com今回はLv2ということで、もう少し詳細に迫っていきます。ただ、Lv2の内容を全て書くと記事がかなりの長さになるので、いくつかの記事に分割したいと思います。
TLSプロトコルの詳細はRFC5246に記載があります。重要と思ったのか、IPAが翻訳版を用意しているのでそちらを見るのも手です。IPAの翻訳版リンクは以下の通り。なお、TLSバージョン1.2のものになります。
https://www.ipa.go.jp/security/rfc/RFC5246-00JA.html
TLSプロトコルの概要
IPAが翻訳を用意しているとはいえ、それだけではこの記事の意味がないので詳細に迫ってみましょう。
TLSハンドシェイクプロトコルの概要
TLSハンドシェイクプロトコルではクライアントとサーバでTLS通信を行うための約束事や必要な情報の共有を事前に行います。TLSハンドシェイクプロトコルにはアプリケーションデータを格納する部分もあるので、例えばHTTPS通信をしたい場合、HTTP通信の実データをこの部分に格納し通信を行います。TLSハンドシェイクプロトコルではデータの暗号化は行われません。
TLSハンドシェイクプロトコルは以下の4個のプロトコルで構成されます。
暗号方式変更プロトコルは適切な訳語が思いつかなかったのか分かりませんが、IPAの翻訳ではChange Cipher Specプロトコルと書かれていました。それぞれのプロトコルの内容は別途記載します。
TLSレコードプロトコルの概要
TLSレコードプロトコルではTLSハンドシェイクプロトコルで合意した内容を使って実際に暗号化を行います。TLSレコードプロトコルにはTLSハンドシェイクプロトコルと違って小分類的なプロトコルはありません。
この前提の上で、HTTPSのサイトにアクセスした時に流れるパケットを追ってみましょう。テスト用にApacheを用意し、mod_sslを最低限設定し内部のopensslで発行したサーバ証明書を配置しました。mod_sslではSSLキャッシュを無効化するように以下の設定をしています。
SSLSessionCache none
このあたりの詳細も別の記事で触れます。証明書によるクライアント認証は行わない構成とします。
通信環境は以下の通りです。
ちなみに、今回はサーバ証明書がオレオレ証明書かつ使用したプライベート認証局を信頼済み認証局として設定していないのでHTTPSアクセスを行った際にTLSエラーが表示されます。この事象自体は今回の記事の趣旨とは関係ないので別の機会に触れます。
尚、TLSプロトコルの解説における前提として、TLS通信のパケットデータは攻撃者に常にパケットミラーリングのような手段により全て見られているというものがあります。実際のエンタープライズネットワークでは別の観点での対策もありうるということは理解しておくべきです。
TLSハンドシェイクプロトコル
TLSハンドシェイクプロトコルは4個のプロトコルで構成されることは前述の通りです。一つずつ見ていきましょう。余談ですが、TLSプロトコル自体はレイヤ5以上のプロトコルのため、TCPコネクションの確立はTLSプロトコルの動作前に行われます。当然ながらレイヤ4以下の情報は攻撃者に全て入手されるので勘違いしないように。
ハンドシェイクプロトコル
ハンドシェイクプロトコルは名前が似ていてややこしいですが、TLSハンドシェイクプロトコルの中で最も役割が多く重要なプロトコルと思われます。RFCをベースに一連の流れをまず箇条書してみます。クライアント認証を行う場合の処理等、今回の実演には含まれない要素も記載しますが、Lv2の記事で言及するものは赤字にしてあります。
- Hello Request (サーバ→クライアント)
- Client Hello (クライアント→サーバ)
- Server Hello (サーバ→クライアント)
- Certificate (サーバ→クライアント)
- Server Key Exchange (サーバ→クライアント)
- Certificate Request (サーバ→クライアント)
- Server Hello Done (サーバ→クライアント)
- Certificate (クライアント→サーバ)
- Client Key Exchange (クライアント→サーバ)
- Certificate Verify (クライアント→サーバ)
- Change Cipher Spec (クライアント→サーバ)
- Finished (クライアント→サーバ)
- Change Cipher Spec (サーバ→クライアント)
- Finished (サーバ→クライアント)
TLSプロトコルのパケットフォーマット
パケットキャプチャした内容をスムーズに理解するために、まずTLSプロトコルのパケットフォーマットを記載します。
全てのTLSパケットにはTLS Record Layerヘッダが格納されます。TLS Record LayerはType、Version、Lengthの3種類のフィールドで構成されます。TypeにはTLSハンドシェイクプロトコルの小分類にある4種類のプロトコルのいずれかが格納されます。ここで指定したTypeに応じた情報を、TLS Record Layerに続くTLS Messageに格納します。
Versionはクライアントが使用可能なTLSプロトコルバージョンの最大を格納するものです。あくまで最大のみです。LengthはTLSパケット全体の長さを格納します。
TLS1.2 Record Layerで始まっており、先程記載したパケットフォーマットに従ってデータが格納されているのが分かると思います。Versionの「0303」はTLS1.2に相当します。0301はTLS1.0、0302はTLS1.1を示します。
Type(Content Type)はHandshakeとなっているので、このパケットはTLSハンドシェイクプロトコルのうち、ハンドシェイクプロトコルのデータであることが分かります。
続いて、TLS MessageとしてハンドシェイクプロトコルのうちClient Helloが続きます。
Client Hello
TCPコネクション確立後のTLS通信が始まります。Clent Helloは相手のサーバに対して自分が会話可能なTLSセットを伝える通信です。先程の画像を見てもらうと、Client Helloで送信する内容が書かれています。たくさんありますが、最低限送信する必要のあるものは以下の通りです。
これは何なのと疑問が出てくると思います。Lv1の記事と連携して関係するのはランダムです。このランダムはサーバからも送られてくるので、両者を区別するために、Client Helloでのランダムをクライアントランダムと呼ぶことにします。クライアントランダムはクライアントが作成する乱数で、共通鍵、メッセージ認証コードを生成するための情報です。
少し先取りして書いてしまうと、これらの情報を生成するにあクライアントランダム、サーバランダムの他に、もう一つプレマスターシークレットという値が必要になります。クライアントランダムとサーバランダムは平文で送られますが、プレマスターシークレットはクライアントで暗号化(説明が不足していますがLv2ではあえてこう書きます)した上で送られます。プレマスターシークレット自体は攻撃者に入手されてはいけないものですが、平文で送ることはないのでプレマスターシークレットは攻撃者に漏れることはないと考えて良いです。
Client Helloを受け取ったサーバはクライアントが会話可能なTLSセットを知ることができます。
上記画像にはExtensionというフィールドが多数あります。これはTLSプロトコルの機能拡張に対応した実装です。詳細はだいぶ先の記事に譲ります。最低限のTLS通信を実現するためには必須ではありません。
Server Hello
Client Helloを受け取ったサーバは、自分が会話可能なTLSセットをクライアントに送ります。パケットフォーマットや内容は基本的にClient Helloと同じです。唯一違うのはランダムの部分がクライアントランダムではなく、サーバランダムであることです。Sever Helloではサーバ側の事情のみをクライアントに伝えるのではなく、Client Helloで受け取った内容に応じてメッセージを選択して送ります。余計なことはしゃべらない仕事人といった感じです。
Server Helloを受け取ったクライアントはサーバが会話可能なTLSセットを知ることができるわけです。パケットキャプチャの画像は省略します。
長くなってきたので今回の記事はここまでにします。