安全な通信を実現するTLS 1.3のプロトコル概要をTCPクライアント/サーバーの拡張を例に紹介|翔泳社の本

安全な通信を実現するTLS 1.3のプロトコル概要をTCPクライアント/サーバーの拡張を例に紹介

2022/03/14 08:00

 暗号化された安全な通信を実現するための技術「SSL/TLS」の最新版「TLS 1.3」を詳細に解説した『徹底解剖 TLS 1.3』(翔泳社)。本書から「Chapter 1 TLSプロトコルの概要」を抜粋して紹介します。TLSのプロトコルについて、簡単なTCPクライアント/サーバープログラムをTLSによるクライアントとサーバーに拡張する例を用いて解説されています。

本記事は『徹底解剖 TLS 1.3』(古城隆、松尾卓幸、宮崎秀樹、須賀葉子)の「Chapter 1 TLSプロトコルの概要」を抜粋したものです。掲載にあたって一部を編集しています。

1.1 TCPクライアント/サーバー

 本章では、TLS(Transport Layer Security)のプログラムとプロトコルがどのように実現されているのかを、簡単なクライアント、サーバープログラムを通して見ていきます。

 このプログラムは、TCPないしTLS接続のあと、クライアントからサーバーへ、そしてサーバーからクライアントへという1往復のアプリケーションメッセージを送受信し、接続を解除するだけの単純なものですが、この中にTLSプロトコルを構成する主要な要素のほとんどを見ることができます。

 TLSプロトコルはすべて、TCPプロトコルによる接続の上に実現されます。図1.1にTCPだけを使ったネットワーク通信のためのクライアント/サーバーの簡単なプログラムの概略を示します。

図1.1 TCPプログラムとプロトコル
図1.1 TCPプログラムとプロトコル

 プログラム上の前処理などを省略すると、TCP通信ではまず、サーバー側でこのサーバーと通信したい相手(クライアント)からの接続要求を受け付けられるように待ち状態に入ります。今回のようなBSDソケットによるプログラムを例とすると、accept()関数を呼び出します。

 一方、クライアントは通信したい相手のサーバーに対して接続要求を出します。BSDソケットではconnect()関数の呼び出しです。この要求がサーバーに受け入れられるとTCP接続が成立し(図1.1①)、クライアントとサーバーの間でTCP通信ができるようになります。

 以降、この接続を使ってクライアントとサーバーの間でアプリケーションの必要に応じたメッセージ(アプリケーションデータ)の送信・受信を繰り返します(図1.1②)。

 最後に、必要なメッセージの送受信が完了したらTCP接続を切断します(図1.1③)。

1.2 TLS層を追加する

 それでは、このTCPクライアント/サーバーのプログラムにTLS層の処理を追加しましょう。図1.2はTLSの処理を追加したプログラムの概略です。

図1.2 TLCプログラムとプロトコル
図1.2 TLCプログラムとプロトコル

 TLSはすべての通信をTCPプロトコル上で行うので、TCPプログラムの接続(図1.2①)、切断処理(図1.2⑥)は図1.1とまったく変わりません。TLSのすべてのレコードはTCP接続されたクライアント、サーバー間のTCPレコードの上に載せて転送することになります。

 次に、サーバー側プログラムがTLSレイヤーの接続要求を待つためにSSL_accept()関数を呼び出します。これでサーバー側はクライアントからのTLS接続要求の待ち状態となります。一方、クライアント側プログラムでは接続要求のためにSSL_connect()関数を呼び出します(図1.2②、③)。

 この呼び出しにより、クライアントとサーバー間での一連のTLSハンドシェイクが実行されます。ハンドシェイクでは、TLS通信で使用する暗号スイート(暗号アルゴリズムの組み合わせ)を合意し、実際にTLSセッションで使用する暗号鍵を合意します。さらに、正当な相手方であることを認証するなど、安全な通信が確保できることを確認します。これらの手順がすべて正常に完了すればTLS接続が確立します。

 TLS接続が確立したら、目的とするアプリケーションデータの送受信を行います(図1.2④)。これはプログラム上ではAPIのSSL_read()/SSL_write()関数を呼び出すことで実現されます。アプリケーションが送信したい平文のメッセージはSSL_write()関数によって暗号化され、さらにSSL_read()関数によって復号されて相手方のアプリケーションに平文で引き渡されます。

 このとき、TLSプロトコル処理の一環として、受け取ったメッセージが送信元メッセージから改竄されていないこと、つまり「真正性のチェック」も行います。 最後に、アプリケーションデータの送受信が完了したらTLS、TCPの順に切断します(図1.2⑤、⑥)。

1.3 TLSプロトコルを俯瞰する

 それでは、このサンプルプログラムの動作をTLSプロトコルレイヤーで見てみましょう。

  Wiresharkに代表されるパケットキャプチャツールを使うと、この様子を見ることができます。ここでは、TLSハンドシェイクだけに注目できるようにWiresharkのフィルターに「tls」を指定します(図1.3)。TLS 1.3では、ハンドシェイクの冒頭部分だけが平文で送受信され、残りはすべて暗号化されたやり取りとなるため、通常のパケットキャプチャでは冒頭の「Client Hello」「Server Hello」しか見ることができません。

図1.3 Wiresharkによる通常のパケットキャプチャ
図1.3 Wiresharkによる通常のパケットキャプチャ

 TLS 1.3のハンドシェイクでは「Client Hello」「Server Hello」のように名付けられた一連のメッセージのやり取りが行われます(図1.4)。

図1.4 TLS 1.3での通信の流れ
図1.4 TLS 1.3での通信の流れ

 この例のように、クライアントとサーバーが「通信相手に対する予備知識なしに」初めてTLS接続を確立する場合のハンドシェイクはフルハンドシェイクと呼ばれています。フルハンドシェイクは、

  • クライアント側から、サポートしている暗号アルゴリズムその他の方式に関する一連の一覧表を候補として示す
  • サーバー側がそれに合意し、それ以後の暗号化メッセージのやり取りのための共通鍵を合意する

 という流れとなっています。またその際、ピア認証(サーバー認証/クライアント認証)と呼ばれる、「通信の相手方が正当な相手であることの確認」を公開鍵証明書を使って行います。

 比較のため、同様の接続をTLS 1.2で実行した場合の通信の流れを図1.5に示します。TLS 1.2ではハンドシェイクの最終部分で暗号化が開始され、ハンドシェイク中は暗号化されません。また、その内容も暗号化方式の合意部分と鍵合意のパラメーターの授受、サーバー認証部分に分かれていて、メッセージの種類も多くなっていました。メッセージの往復回数もTLS 1.3ではほぼ1往復でハンドシェイクを完了できるようになったのに対して、TLS 1.2以前では2往復が必要でした。

図1.5 TLS 1.2での通信の流れ
図1.5 TLS 1.2での通信の流れ

 表1.1は、TLS 1.3のハンドシェイクにTLS 1.2までのハンドシェイクメッセージを重ね合わせて、TLS 1.3でどのようにメッセージが整理されたか対応を示しています。

表1.1 フルハンドシェイクのメッセージまとめ
表1.1 フルハンドシェイクのメッセージまとめ

 表からわかるように、TLS 1.2の「Client Hello」と「Server Hello」では暗号スイートと呼ばれる暗号化方式に関して合意するだけで、実際に暗号化に必要な情報は次の「Server Key Exchange」と「Client Key Exchange」で受け渡しを行うようになっていました。

 TLS 1.3では、古い暗号スイートを廃止・整理したおかげで、これらの情報を「Client Hello」と「Server Hello」の中で一度に受け渡すことが可能になりました。そのおかげで、ハンドシェイクの早い段階から暗号化を開始することができるようになるとともに、中間状態を示す「Server Hello Done」「Change Cipher Spec」のようなメッセージは不要になり、ハンドシェイクの終了を示す「Finished」に統一されてハンドシェイク全体が簡潔に整理されました。

 このようなハンドシェイクの整理が可能となった背景には、従来、鍵合意の方式として静的なRSA公開鍵を利用する方法とディフィー・ヘルマン系をベースとした方法の2つがあったのですが、TLS 1.3では静的RSA方式のセキュリティ上のリスク(完全前方秘匿性)が指摘されるようになり、RSA公開鍵を利用する方法は廃止されたことが挙げられます。それにより鍵合意方式がディフィー・ヘルマン系のみとなったことで、合意すべき暗号スイートも単純化され、整理が可能になったのです。

1.3.1 Client Helloメッセージ

 ここからは、TLS 1.3のキャプチャについてもう少し詳しく見ていくことにしましょう。

 TLSプロトコルは、クライアントからサーバーへのClient HelloメッセージによるTLS接続要求で開始されます。このメッセージの中には、接続したいTLSのバージョン(図1.3の場合は「TLSv1.3」としてTLS 1.3が指定されている)、およびクライアントが使用できる暗号スイートの一覧が含まれています。特にTLS 1.3の場合には、残りのハンドシェイク部分から暗号化が可能なように、key_share拡張に鍵合意のためのクライアント側のパラメーター一式も含まれています。

 図1.6はClient Helloメッセージの一部を抜き出したものですが、Cipher Suitesにはクライアントがサポートしている暗号スイートのリストが、supported_versions拡張にはサポートしているTLSのバージョン、supported_groups拡張にはサポートしている楕円曲線暗号の曲線の種類やRSAの鍵長などが示されていることがわかります。

図1.6 Client Helloメッセージ(部分)
図1.6 Client Helloメッセージ(部分)

1.3.2 Server Helloメッセージ

 クライアントからのClient Helloメッセージに対して、サーバーからはServer Helloメッセージによって接続要求の受け付けが行われます。このメッセージの中には、クライアントが提示した暗号スイートの中からサーバー側が選択したスイートや、鍵合意のためのサーバー側のパラメーター一式などが含まれます。

 ここまではTLS 1.2以前とそれほど大きく変わらないのですが、TLS 1.3ではそれらに加えてkey_share拡張として鍵合意に必要なクライアント側の情報が格納されているのが特徴です。これに、対応するServer Helloメッセージのkey_share拡張の情報を合わせることで、この段階で鍵合意が成立して、暗号化が可能となります。これにより、以降のハンドシェイクメッセージは合意した共通鍵によってすべて暗号化されます。

図1.7 Server Helloメッセージ(部分)
図1.7 Server Helloメッセージ(部分)

1.3.3 Certificate/Certificate Verifyメッセージ

 サーバーからの補足情報が送られたあと、CertificateメッセージとCertificate Verifyメッセージにより「サーバーが正当なサーバーである」ことを示すためのサーバー証明書と検証情報が送られます。そしてこれらを受け取ったクライアント側では、自分の持っているCA証明書を使ってこのサーバーが正当なサーバーであることを確認します。

 TLSでは、サーバー認証とクライアント認証の双方向の認証方式について規定していますが、サーバー認証は必須、クライアント認証はオプション(省略可)とされています。そのためこの例では、サーバー認証だけを行っています。

1.3.4 Finishedメッセージ

 ここまでの処理が終了すると、両者はFinishedメッセージを送信してハンドシェイクの終了を宣言します。これにより以降はTLS接続が安全に確立したことになります。

1.3.5 Application Dataメッセージ

 TLS接続が確立したら、クライアント/サーバー間でアプリケーションデータをやり取りするために、Application Dataメッセージを送受信します。

1.3.6 Alertメッセージ

 最後に、TLS接続の終了を示すために、両者はAlert種別が「Close Notify」となるAlertメッセージを送信します。「Alert」というと異常状態を示すように見えますが、種別が「Close Notify」のものはTLSの正常な終了を示します。

 まとめると、TLS 1.3ではそれ以前と比較して以下の点が変更されています。

  • ハンドシェイクメッセージが整理され、1往復で終了できるようになった
  • Cleint Hello/Server Helloメッセージのあとのハンドシェイクメッセージも暗号化されるようになった
  • 鍵合意方式が(EC)DHEのみに整理されたことにより、上記が可能になった
徹底解剖 TLS 1.3

Amazon SEshop その他


徹底解剖 TLS 1.3

著者:古城隆、松尾卓幸、宮崎秀樹、須賀葉子
発売日:2022年3月7日(月)
定価:3,630円(本体3,300円+税10%)

本書について

TLS 1.3の基礎的なプロトコルの流れから、暗号化・認証の仕組み、アプリケーション実装のベストプラクティスを組み込みシステム向けの軽量&高機能なライブラリwolfSSLを例に解説します。