SSL/TLS とは、インターネット上で通信を暗号化して送信し、他の人に見られないように安全に通信を行うためのプロトコルです。SSL/TLS では、通信するデータの暗号化だけではなく、データの改ざん検知や通信相手の認証を行いながら、安全に信頼できる相手と通信を行うための仕組みが決められております。
現在、SSL/TLS 通信にて主流で利用されているバージョンは TLS 1.2 となります。
2018 年 8 月に TLS の新しいバージョンである TLS 1.3 が公開され、現在、OS やアプリケーションで TLS 1.3 が実装され、利用が開始されています。
TLS 1.3 ではハンドシェイクの仕組みや脆弱性のあるアルゴリズムの利用の廃止など、TLS 1.2 と比べて仕様が大幅に異なってきます。
今回は、TLS 1.3 の仕組みについて紹介します。
TLS 1.3 のハンドシェイクのフロー
SSL/TLS のハンドシェイクとは、SSL/TLS 通信の開始時に、まずクライアントとサーバーの間で通信の暗号化に仕様する各アルゴリズムの選定や、共通鍵の生成、証明書による認証等、安全に信頼できる相手と通信を行うために必要なパラメーターの取り決めが行われます。
SSL 3.0 ~ TLS 1.2 までのバージョンにおける TLS ハンドシェイクのフローは大きな違いはありませんでした。
しかしながら、TLS 1.3 では脆弱性のあるアルゴリズムの廃止や、フローの仕組みが整理されてシンプルになっています。
TLS 1.2 以前までは、TLS ハンドシェイクにおいて 2 往復のフローが必要でした。
しかし、TLS 1.3 においては、TLS ハンドシェイクは 1 往復で暗号化が開始され、ハンドシェイクの通信も含めて暗号化が行われるように変更されています。
TLS 1.3 のハンドシェイクの流れは以下の通りです。
- Client Hello
- Server Hello
- Encrypted Extensions
- (Certificate Request)
- Certificate
- Certificate Verify
- Finished
- (Client Certificate)
- (Certificate Verify)
- Finished
- 暗号化通信開始
※ () で囲まれているメッセージは省略されることがあります。
上記の図の通り、Server Hello が応答されたタイミングにて、暗号化通信が開始されます。
TLS 1.2 では、暗号スイートの選定により鍵交換の種類が決まっていたため、Server Hello の後に続く、Server Key Exchange、Client Key Exchange で鍵に関するパラメーターの交換をしておりました。
TLS 1.3 では RSA での鍵交換は廃止され、鍵交換のアルゴリズムは ECDHE もしくは DHE のみを利用するように変更されました。この仕様変更により、鍵交換のアルゴリズムを暗号スイートの選定により決めるのではなく、Client Hello と Server Hello の “key_share” という extension によりネゴシエーションを行うように、ハンドシェイクのフローが整理されております。つまり、Client Hello と Server Hello の 1 往復のみで鍵交換が完了するため、それ以降のハンドシェイクから暗号化して通信が行われます。そのため、Certificate パケットなどサーバーが送信している証明書のデータ等はパケットから見ることができなくなりました。
それでは、TLS 1.3 でのハンドシェイクにおける各フローの詳細を見ていきます。
① Client Hello
クライアントはサーバーに対して暗号化通信の開始の要求を送信します。
TLS 1.3 でのClient Hello での基本のデータ構造は TLS 1.2 と違いはありません。ただし、TLS 1.3 で利用される extension の項目が追加されております。
Client Hello の Version の項目は、基本的には TLS 1.2 で表示されます。
TLS 1.3 にて supported_versions というextension が新たに追加され、この項目にクライアント端末でサポートされている全ての TLS バージョンの一覧を通知します。
また、TLS 1.3 では暗号スイートでの鍵交換アルゴリズムのの指定が不要になりました。
TLS 1.3 の場合、Client Hello から鍵交換を開始しますが、その方法として key_share という extension に上位 2 つの鍵交換アルゴリズムの種類とパラメーターを含めて送信します。また、鍵交換に関する情報として、supported_groups の extension にはクライアント端末がサポートしている楕円曲線暗号の曲線の種類のリスト、DHE の鍵長に関する情報をサーバーへ通知するものです。
Client Hello では Cipher Suites の項目にてクライアント端末がサポートしている暗号スイートの一覧を送信していますが、supported_version に含まれる全てのバージョンに対応した暗号スイートが送信されます。
② Server Hello
サーバーが Client Hello を受信した後、TLS バージョン、暗号スイート、鍵交換アルゴリズムの合意した内容をクライアント端末に通知します。
Server Hello の supported_versions 項目に、合意した TLS バージョンを通知します。
サーバーが TLS 1.3 に対応している場合、supported_versions に合意したバージョンとして TLS 1.3 を返します。もし、サーバー側が TLS 1.3 に対応していない場合、そのまま TLS 1.2 の Server Hello を応答します。その Server Hello には supported_versions 等、TLS 1.3 にて新たに追加された extensions は含まれません。
また、Server Hello の Cipher Suite の項目にて、合意した暗号スイートを送信します。
TLS バージョンが TLS 1.3 で合意した場合は、TLS 1.3 に対応した暗号スイートが選択されます。また、TLS バージョンが TLS 1.2 で合意した場合は TLS 1.2 に対応した暗号スイートが選択されます。
TLS 1.3 における鍵交換は key_share の項目を利用して行います。
Client Hello に含まれる key_share の中から、選択した鍵交換のアルゴリズムの種類とパラメーターを送信します。また、Client Hello にて送信された key_share に含まれる鍵交換のアルゴリズムがサーバー側で対応していない場合は、Server Hello を返さずに Hello Retry Request メッセージを送信する動作となります。その場合、クライアント端末は前回の Client Hello で送信した鍵交換のアルゴリズムとは異なる、別の上位 2 つの鍵交換のアルゴリズムとパラメーター key_share に含めて Client Hello に送信します。
Server Hello の段階で、暗号スイートの選択、鍵交換が終了しているため、通信の暗号化が可能です。
Server Hello 以降の全てのハンドシェイクは、鍵交換の結果、算出されたハンドシェイク用の鍵で通信は暗号化されます。
③ Encrypted Extension
Server Hello メッセージの直後に Encrypted Extensions が必ず送信されます。
Server Hello Extensions の内容が暗号化されたメッセージとなります。
④ (Certificate Request)
サーバーがクライアントを認証する必要がある場合に、クライアントに認証用の証明書を送るように要求します。
このメッセージには以下の内容が含まれています。
- サーバーが理解できる証明書のタイプ一覧
- サーバーが信頼している証明機関の名前一覧
クライアントから提示される証明書で認証するためには、サーバー自身がクライアント証明書を発行した証明機関を信頼している必要があります。そのため、証明書の送信要求において、サーバー自身が信頼している証明機関の一覧を提示し、クライアントは一覧にあるいずれかの証明機関から発行された証明書を認証用に提示できるようにします。
※認証が不要な場合には省略されます。
⑤ Certificate / ⑥ Certificate Verify
サーバーは自身の身分証明として、サーバー証明書を送信します。
Certificate パケットにサーバー証明書、Certificate Verify にサーバー証明書の持ち主であることを示す署名データを送信します。
Certificate Verfiy で送信される署名のデータは、ここまでのハンドシェイク メッセージ全体のデジタル署名のデータとなります。サーバー証明書に紐づく秘密鍵を利用してデジタル署名を生成するため、サーバー証明書の持ち主(=秘密鍵を保持している)であることを証明できるため、認証情報として利用されます。
⑥ Finished
ハンドシェイクにて送信するメッセージが終了したことを通知します。
Finished のデータは、ここまでのハンドシェイク メッセージ全体の MAC 値となります。
⑦ (Certificate) / ⑧ (Certificate Verify)
クライアントは自身の身分証明として、クライアント証明書を送信します。
Certifiate パケットにクライアント証明書、Certificate Verify にクライアント証明書の持ち主であることを示す署名データを送信します。
Certificate Verfiy で送信される署名のデータは、ここまでのハンドシェイク メッセージ全体のデジタル署名のデータとなります。サーバー証明書に紐づく秘密鍵を利用してデジタル署名を生成するため、クライアント証明書の持ち主(=秘密鍵を保持している)であることを証明できるため、認証情報として利用されます。
Certificate Request が送信されていない場合には、省略されます。
⑨ Finished
ハンドシェイクにて送信するメッセージが終了したことを通知します。
Finished のデータは、ここまでのハンドシェイク メッセージ全体の MAC 値となります。
上記の通り、TLS 1.3 ではハンドシェイクの内容が整理され、シンプルなフローとなっております。
TLS 1.2 以前のハンドシェイクにあった「Server Hello Done」「Client Key Exchange」「Server Key Exchange」「Change Cipher Spec」のメッセージは廃止されており、1 往復半のメッセージで TLS ハンドシェイクが完了する仕組みになっております。
また、TLS 1.3 ではハンドシェイクの途中で、通信が暗号化されるという特徴があるため、ハンドシェイクのパケットから証明書の詳細情報を確認することはできなくなりました。
TLS 1.3 の暗号スイート
暗号スイートとは、TLS 通信に利用される各アルゴリズムの組み合わせを定義したものです。
TLS 1.0 ~ TLS 1.2 で利用される暗号スイートでは、「鍵交換 ⇒ 認証 ⇒ 共通鍵暗号 ⇒ ハッシュ アルゴリズム(MAC また PRF)」の順でアルゴリズムが定義されています。
TLS 1.2 以前の暗号スイートの仕組みの詳細については、以下の記事でも紹介しておりますのでご参照ください。
SSL/TLS にてデータを暗号化して通信を行うには、自分自身と通信相手の両方が利用可能なアルゴリズムを使う必要があります。 不特定の相手と両者が利用可能なアルゴリズムを確認しあうために使われるのが 暗号スイート(cipher suite[…]
TLS 1.3 はハンドシェイクの仕組みの整理が行われたことにより、以下の通り、TLS 1.3 の暗号スイートの構造が変更されました。TLS 1.3 の暗号スイートでは、「共通鍵暗号 ⇒ ハッシュ アルゴリズム(HKDF)」の順でアルゴリズムが定義されています。
TLS 1.3 では、通信の暗号化に使用される共通鍵暗号のアルゴリズム、また、鍵算出のアルゴリズムである HKDF で利用されるハッシュ アルゴリズムのみが定義されています。このように TLS 1.2 と比較して暗号スイートの構造がシンプルになったのは、TLS 1.3 において以下の仕様が変更されたためです。
〇 鍵交換のアルゴリズムとしての RSA が廃止
TLS 1.3 では鍵交換のアルゴリズムとして利用できるのは、ECDHE と DHE のみです。
TLS 1.3 の鍵交換では Client Hello と Server Hello の key_share で行われる動作に変更になりました。
〇 鍵交換と認証のアルゴリズムが完全分離
鍵交換のアルゴリズムとして RSA が選択された場合、認証のアルゴリズム(=サーバー証明書の公開鍵)も RSA である必要があります。
TLS 1.3 では、鍵交換のアルゴリズムとしての RSA は廃止されたため、サーバー証明書は認証(=身分証明)の目的のみで利用されるようになりました。つまり、RSA が廃止されたことにより、鍵交換と認証のアルゴリズムは完全に分離して扱うことができるようになりました。
〇 共通鍵暗号には認証付き暗号(AEAD)のみを利用
共通鍵暗号の暗号モードでは、認証付き暗号(AEAD)のみが利用されるように変更されます。
レコードごとに MAC が付与されることはなくなりました。
TLS 1.3 では RSA の鍵交換が廃止されたため、TLS 1.3 では鍵交換の種類を決める場合に、認証の種類を意識する必要はなくなりました。
また、TLS 1.3 のハンドシェイクでは、鍵交換は Client Hello と Server Hello の key_share の extension にて、アルゴリズムの種類の決定、およびパラメーターの交換を行うように仕様変更されております。そのため、RSA の廃止と key_share の実装により、Client Hello と Server Hello の一往復のフローで暗号化が開始できるようになり、暗号スイートでの鍵交換アルゴリズムの定義は不要になりました。
以上のことから、TLS 1.3 では暗号スイートの構造において、「鍵交換」と「認証」は含まれない構造に変わりました。
また、TLS 1.3 の暗号スイートに含まれるハッシュ アルゴリズムは、鍵算出を行う HKDF というアルゴリズムで利用されます。
ハッシュ アルゴリズムの MD5、SHA1 や公開鍵暗号方式の DSA は利用できなくなりました。
レコード プロトコル
TLS レコード プロトコルとは、TLS 層のパケットのデータ構造が決められているプロトコルです。
TLS レコードの構造は、TLS 1.2 以前と変化はありません。
TLS レコードのヘッダの構造は以下の通りです。レコードのタイプやバージョン、レコードの長さが定義されています。
TLS 1.3 では、TLS レコードの「バージョン」は後方互換をもたせるために、TLS 1.2 (0x303) もしくは TLS 1.0 (0x301) がセットされます。
また、TLS 1.3 のレコードのタイプには、Alert (0x15)、Handshake (0x16)、Application Data (0x17)、Early Handshake(0x19) の 4 つがあります。
TLS レコードのヘッダの後には、各タイプに応じたデータ構造の TLS レコードが続きます。
Handshake のレコードに定義されているレコードのタイプの種類については、以下の通りです。
タイプ |
TLS 1.2 |
TLS 1.3 |
0x00 |
hello_request |
廃止(※) |
0x01 |
client hello |
client hello |
0x02 |
server hello |
server hello |
0x04 |
なし |
session ticket |
0x06 |
なし |
hello retry request |
0x08 |
なし |
encrypted extensions |
0x0b |
certificate |
certificate |
0x0c |
server key exchange |
廃止 |
0c0e |
certificate request |
certificate request |
0x0f |
server hello done |
廃止 |
0x10 |
certificate verify |
certificate verify |
0x11 |
client key exchange |
廃止 |
0x14 |
finished |
finished |
また、TLS 1.3 ではメッセージの圧縮も廃止されております。
警告プロトコル
TLS 1.3 の TLS 通信において、通信の終了やエラーが発生した時には、警告プロトコルのメッセージが送られます。
警告プロトコルには、終了アラート(Closure Alert) とエラー アラート(Error Alert) の 2 種類があります。
終了アラートは、TLS 通信を正常に終了させる時に送信します。
一方、エラー アラートは、TLS 通信に重大な問題を検知して、通信を強制的に中断させる時に送信します。TLS 1.3 のエラー アラートは、通信を「中断」することを目的に送信する点が TLS 1.2 との変更点です。
TLS 1.2 以前では、TLS アラートのメッセージには、fatal(致命的) と alert(警告) の 2 種類が用意されており、TLS 通信の処理において何等かの問題を検知した場合に、相手に問題を通知する目的で定義されておりました。fatal は致命的なエラーを検知したことを意味しており、通信を中断させることを目的に送信されますが、alert はあくまで警告であり、TLS 通信は中断されません。
TLS 1.3 での TLS アラートは、全て fatal 相当のメッセージに変更されております。
TLS 1.3 のセッション再開
PSK(事前共有鍵) 接続
TLS ハンドシェイクの種類として、(1) フルハンドシェイクと(2) PSK(事前共有鍵)接続の 2 つの種類があります。
(1) フルハンドシェイクとは、名前の通り、全てのハンドシェイクのフローを経て TLS 通信を確立します。一方、(2) PSK(事前共有鍵) 接続とは、TLS 1.3 の通信を行う両者が何らかの方法で鍵を共有しておき、その鍵を利用して TLS 通信を確立する方法です。
この TLS 通信を確立する前に、事前に共有しておいた鍵を PSK(事前共有鍵)と呼びます。
(実運用されていることは利用されているケースは稀ですが、PSK を事前に作成しておき、クライアントとサーバーの両方に手動で設定して利用するシナリオが “PSK(事前共有鍵) 接続” に該当します)
両者で合意して PSK を共有していることが前提であるため、PSK(事前共有鍵) 接続の場合は、通信相手の信頼性は確保されています。つまり、「相互認証」が完了している前提の TLS 通信であるため、TLS ハンドシェイク時の証明書の提示のフローは省略されます。
PSK 鍵を利用することで、TLS 1.3 のハンドシェイクはさらに簡略化されます。
- Client Hello
- Server Hello
- Encrypted Extensions
- Finished
- Finished
- 暗号化通信開始
PSK 接続では、(1) PSK のみを利用するパターン、(2) PSK と DH 鍵交換を利用するパターンがあります。
(1) PSK を利用するパターンでは、PSK から暗号化通信に利用するセッション鍵を算出する動作となります。しかし、同じ PSK を利用し続けてしまうと、万一、鍵が漏洩した場合に、TLS 通信が解読できてしまうリスクがあります。そのため、(2) PSK と DH 鍵交換を利用するパターンの方の利用が推奨されています。DH 鍵交換を行うことで、TLS セッションごとにセッション鍵を算出する動作となるため、セキュリティ的に安全です。
上記の図は (2) の PSK と DH 鍵交換を利用するパターンの PSK 接続となります。
セッション再開の仕組み
TLS 1.3 でのセッション再開は、PSK 接続の方法の一つとして定義されています。
TLS 1.2 では、セッション再開を行う場合は Session ID と Session Ticket の 2 種類が利用可能でした。
TLS 1.3 ではこれまでの Session ID や Session Ticket が廃止され、PSK 接続の仕組みを利用します。そのため、TLS 1.3 では Client Hello の Seesion ID や session_ticket の項目のデータは利用されません。
TLS 1.3 では、フルハンドシェイクの鍵算出のプロセスにおいて、セッション再開する時に使用する鍵(再開マスターシークレット)を算出します。その後、再開シークレットを暗号化したデータを Session Ticket として利用します。サーバーは作成した Session Ticket を、全てのハンドシェイクのフローが終了した後(クライアントが Finished を送信した後)、Session Ticket を送信します。
Session Ticket をクライアントへ送信した後は、Session Ticket は削除されるため、セッション再開の仕組みにおいてサーバー側のリソースが消費されることはありません。
クライアント端末は、サーバーから送られてきた Session Ticket を、クライアント端末側で算出したセッション再開シークレットと紐づけて保存しておきます。セッション再開する時に、クライアントは Client Hello の pre_shared_key の項目にある “PSK Identity” に保存されている Seesion Ticket を含めて送信します。
サーバーは Session Ticket を復号して入手したセッション再開シークレットから、HKDF で PSK データを算出します。
また、クライアント端末も Session Ticket と紐づけているセッション再開シークレットから HKDF で PSK データを算出します。
PSK 接続では、(1) PSK のみを利用するパターン、(2) PSK と DH 鍵交換を利用するパターンがあります。
(1) の場合、PSK 値をマスターシークレットとして、そのまま利用し、ハンドシェイク鍵、セッション鍵を算出して TLS 通信を再開します。また、(2) の場合、DH により鍵交換を行った上で、マスターシークレットを新規に算出して TLS 通信を再開します。
0-RTT のセッション再開
ここまで紹介したセッション再開は、1-RTT という一往復のハンドシェイクにて暗号化通信が開始されるフローとなります。TLS 1.3 では 0-RTT でのセッション再開の仕組みが導入されました。0-RTT とは、TLS ハンドシェイクの最初のフローから(0 往復で)データを暗号化する仕組みとなります。
具体的には、セッション再開の最初のパケットである Client Hello に、PSK から鍵(client_early_traffic_secret がベース)を算出してアプリケーションを暗号化し、early_data の extension に含めて送信します。
おすすめ:参考書
2022 年 3 月に、TLS 1.3 の仕組みについて詳細が解説された本が発売されました!
wolfSSL という SSL/TLS 組み込みライブラリを利用して、TLS 1.3 を利用するシステムの開発者向けの本となっておりますが、「TLS 1.3 の仕組みを勉強したい!」という方にもお勧めの1冊となっております。
TLS 1.3 の基本的な仕組みや TLS 1.2 との違いなど、体系的にまとめられており、TLS 1.3 の入門書として最適です。これまでの TLS 1.2 の仕組みの概要は理解している!という中級者向けの本ではありますが、TLS プロトコルで利用される各アルゴリズムの仕組みについて説明した章もあるため、SSL/TLS の仕組みの理解には自信がない…という方でも安心して購入していただけるかと思います。
“RFC 8446 – The Transport Layer Security (TLS) Protocol Version 1.3” を読み込むよりは、ずっとわかりやすいので、TLS 1.3 学習者には必読の1冊です!