2. Protocol Overview (プロトコル概要)
セキュアチャネルで使用される暗号パラメータは, TLS Handshake Protocol (ハンドシェイクプロトコル) によって生成されます。TLSのこのサブプロトコルは, クライアントとサーバーが最初に相互通信するときに使用されます。ハンドシェイクプロトコルにより, ピアはプロトコルバージョンを交渉し, 暗号化アルゴリズムを選択し, オプションで相互認証し, 共有秘密鍵材料を確立できます。ハンドシェイクが完了すると, ピアは確立された鍵を使用してアプリケーション層トラフィックを保護します。
ハンドシェイクの失敗またはその他のプロトコルエラーは, 接続の終了をトリガーします。オプションで, その前にAlert Message (アラートメッセージ) (セクション6) が送信される場合があります。
TLSは3つの基本的なKey Exchange Modes (鍵交換モード) をサポートします:
- (EC)DHE (有限体または楕円曲線上のDiffie-Hellman)
- PSK-only (事前共有鍵のみ)
- PSK with (EC)DHE (事前共有鍵と(EC)DHEの組み合わせ)
図1は基本的な完全なTLSハンドシェイクを示しています:
Client Server
Key ^ ClientHello
Exch | + key_share*
| + signature_algorithms*
| + psk_key_exchange_modes*
v + pre_shared_key* -------->
ServerHello ^ Key
+ key_share* | Exch
+ pre_shared_key* v
{EncryptedExtensions} ^ Server
{CertificateRequest*} v Params
{Certificate*} ^
{CertificateVerify*} | Auth
{Finished} v
<-------- [Application Data*]
^ {Certificate*}
Auth | {CertificateVerify*}
v {Finished} -------->
[Application Data] <-------> [Application Data]
+ 前述のメッセージで送信される注目すべき拡張を示します。
* 常に送信されるわけではないオプションまたは状況依存の
メッセージ/拡張を示します。
{} [sender]_handshake_traffic_secret
から派生した鍵を使用して保護されるメッセージを示します。
[] [sender]_application_traffic_secret_N
から派生した鍵を使用して保護されるメッセージを示します。
図1: 完全なTLSハンドシェイクのメッセージフロー
ハンドシェイクは3つのフェーズ (上図に示されています) を持つと考えることができます:
-
Key Exchange (鍵交換): 共有鍵材料を確立し, 暗号パラメータを選択します。このフェーズ以降のすべてが暗号化されます。
-
Server Parameters (サーバーパラメータ): その他のハンドシェイクパラメータ (クライアントが認証されるかどうか, アプリケーション層プロトコルサポートなど) を確立します。
-
Authentication (認証): サーバー (およびオプションでクライアント) を認証し, 鍵確認とハンドシェイク完全性を提供します。
Key Exchange フェーズでは, クライアントがClientHello (セクション4.1.2) メッセージを送信します。これには, 乱数 (ClientHello.random), 提供されるプロトコルバージョン, 対称暗号/HKDFハッシュペアのリスト, Diffie-Hellman鍵共有のセット ("key_share" (セクション4.2.8) 拡張内), 事前共有鍵ラベルのセット ("pre_shared_key" (セクション4.2.11) 拡張内), またはその両方, および潜在的に追加の拡張が含まれます。ミドルボックス互換性のために, 他のフィールドおよび/またはメッセージも存在する場合があります。
サーバーはClientHelloを処理し, 接続に適した暗号パラメータを決定します。次に, 独自のServerHello (セクション4.1.3) で応答し, 交渉された接続パラメータを示します。ClientHelloとServerHelloの組み合わせにより, 共有鍵が決定されます。(EC)DHE鍵確立を使用している場合, ServerHelloにはサーバーの一時的なDiffie-Hellman共有を含む "key_share" 拡張が含まれます。サーバーの共有はクライアントの共有の1つと同じグループに属している必要があります (MUST)。PSK鍵確立を使用している場合, ServerHelloにはクライアントが提供したPSKのどれが選択されたかを示す "pre_shared_key" 拡張が含まれます。実装は(EC)DHEとPSKを一緒に使用できることに注意してください。この場合, 両方の拡張が提供されます。
次に, サーバーはServer Parametersを確立するために2つのメッセージを送信します:
EncryptedExtensions: 個々の証明書に固有のものを除き, 暗号パラメータを決定するために必要ではないClientHello拡張への応答。[セクション4.3.1]
CertificateRequest: 証明書ベースのクライアント認証が必要な場合, その証明書に必要なパラメータ。クライアント認証が必要ない場合, このメッセージは省略されます。[セクション4.3.2]
最後に, クライアントとサーバーはAuthentication メッセージを交換します。TLSは, 証明書ベースの認証が必要なときは常に同じメッセージセットを使用します。(PSKベースの認証は鍵交換の副作用として発生します。) 具体的には:
Certificate: エンドポイントの証明書および証明書ごとの拡張。サーバーが証明書で認証しない場合, サーバーはこのメッセージを省略します。サーバーがCertificateRequestを送信しなかった場合 (したがってクライアントが証明書で認証すべきではないことを示す場合), クライアントはこのメッセージを省略します。Raw Public Keys [RFC7250] またはCached Information Extension [RFC7924] が使用されている場合, このメッセージには証明書ではなく, サーバーの長期鍵に対応する他の値が含まれることに注意してください。[セクション4.4.2]
CertificateVerify: Certificateメッセージの公開鍵に対応する秘密鍵を使用した, ハンドシェイク全体の署名。エンドポイントが証明書を介して認証しない場合, このメッセージは省略されます。[セクション4.4.3]
Finished: ハンドシェイク全体のMAC (Message Authentication Code)。このメッセージは鍵確認を提供し, エンドポイントのアイデンティティを交換された鍵にバインドし, PSKモードではハンドシェイクも認証します。[セクション4.4.4]
サーバーのメッセージを受信した後, クライアントは認証メッセージ, つまりCertificateとCertificateVerify (要求された場合), およびFinishedで応答します。
この時点で, ハンドシェイクは完了し, クライアントとサーバーは認証暗号化で保護されたアプリケーション層データを交換するためにレコード層が必要とする鍵材料を派生します。セクション2.3で規定されている場合を除き, Finishedメッセージを送信する前にApplication Data (アプリケーションデータ) を送信してはなりません (MUST NOT)。サーバーはクライアントの認証メッセージを受信する前にアプリケーションデータを送信できますが, その時点で送信されるデータは当然, 認証されていないピアに送信されることに注意してください。
2.1 Incorrect DHE Share (不正なDHE共有)
クライアントが十分な "key_share" 拡張を提供していない場合 (たとえば, サーバーが受け入れられない, またはサポートしていないDHEまたはECDHEグループのみが含まれている場合), サーバーはHelloRetryRequestで不一致を修正し, クライアントは適切な "key_share" 拡張でハンドシェイクを再開する必要があります (図2参照)。共通の暗号パラメータを交渉できない場合, サーバーは適切なアラートでハンドシェイクを中止する必要があります (MUST)。
Client Server
ClientHello
+ key_share -------->
HelloRetryRequest
<-------- + key_share
ClientHello
+ key_share -------->
ServerHello
+ key_share
{EncryptedExtensions}
{CertificateRequest*}
{Certificate*}
{CertificateVerify*}
{Finished}
<-------- [Application Data*]
{Certificate*}
{CertificateVerify*}
{Finished} -------->
[Application Data] <-------> [Application Data]
図2: パラメータ不一致の完全なハンドシェイクメッセージフロー
注意: Handshake Transcript (ハンドシェイクトランスクリプト) には最初のClientHello/HelloRetryRequest交換が含まれます。新しいClientHelloでリセットされることはありません。
TLSは, 以下のセクションで説明するように, 基本的なハンドシェイクのいくつかの最適化バリアントも許可します。
2.2 Resumption and Pre-Shared Key (PSK) (再開と事前共有鍵)
TLS PSKは帯域外で確立できますが, PSKは以前の接続でも確立でき, 新しい接続を確立するために使用できます ("Session Resumption (セッション再開)" またはPSKを使用した "再開")。ハンドシェイクが完了すると, サーバーはクライアントに, 初期ハンドシェイクから派生した一意の鍵に対応するPSK Identity (PSK識別子) を送信できます (セクション4.6.1参照)。その後, クライアントは将来のハンドシェイクでそのPSK識別子を使用して, 関連するPSKの使用を交渉できます。サーバーがPSKを受け入れると, 新しい接続のセキュリティコンテキストは元の接続に暗号的にバインドされ, 初期ハンドシェイクから派生した鍵が完全なハンドシェイクの代わりに暗号化状態をブートストラップするために使用されます。TLS 1.2以前では, この機能は "Session IDs (セッションID)" と "Session Tickets (セッションチケット)" [RFC5077] によって提供されていました。これらのメカニズムは両方ともTLS 1.3で廃止されました。
PSKは(EC)DHE鍵交換と一緒に使用して, 共有鍵と組み合わせて前方秘匿性を提供することも, 単独で使用することもできますが, アプリケーションデータの前方秘匿性を失う代償があります。
図3は, 最初のハンドシェイクでPSKを確立し, 2番目のハンドシェイクでそれを使用する一対のハンドシェイクを示しています:
Client Server
Initial Handshake:
ClientHello
+ key_share -------->
ServerHello
+ key_share
{EncryptedExtensions}
{CertificateRequest*}
{Certificate*}
{CertificateVerify*}
{Finished}
<-------- [Application Data*]
{Certificate*}
{CertificateVerify*}
{Finished} -------->
<-------- [NewSessionTicket]
[Application Data] <-------> [Application Data]
Subsequent Handshake:
ClientHello
+ key_share*
+ pre_shared_key -------->
ServerHello
+ pre_shared_key
+ key_share*
{EncryptedExtensions}
{Finished}
<-------- [Application Data*]
{Finished} -------->
[Application Data] <-------> [Application Data]
図3: 再開とPSKのメッセージフロー
サーバーはPSKを介して認証されるため, CertificateまたはCertificateVerifyメッセージを送信しません。クライアントがPSKを介して再開を提供する場合, サーバーが必要に応じて再開を拒否して完全なハンドシェイクにフォールバックできるように, サーバーに "key_share" 拡張も提供する必要があります (SHOULD)。サーバーは "pre_shared_key" 拡張で応答してPSK鍵確立の使用を交渉し, (ここに示すように) "key_share" 拡張で応答して(EC)DHE鍵確立を実行することができ, これにより前方秘匿性が提供されます。
PSKが帯域外で構成される場合, PSK識別子とPSKで使用されるKDFハッシュアルゴリズムも構成する必要があります (MUST)。
注意: 帯域外で構成された事前共有秘密を使用する場合, 重要な考慮事項は, [RFC4086]で説明されているように, 鍵生成時に十分なエントロピーを使用することです。パスワードまたはその他の低エントロピーソースから共有秘密を派生させることは安全ではありません。低エントロピー鍵またはパスワードは, PSK Binder (PSKバインダー) に基づく辞書攻撃に対して脆弱です。指定されたPSK認証は, Diffie-Hellman鍵確立と一緒に使用される場合でも, 強力なパスワードベースの認証鍵交換ではありません。具体的には, ハンドシェイクを観察できる攻撃者がパスワード/事前共有鍵に対してブルートフォース攻撃を実行することを防ぎません。
2.3 0-RTT Data (ゼロラウンドトリップタイムデータ)
クライアントとサーバーがPSKを共有している場合 (外部で取得されたか, 以前のハンドシェイクで取得されたか), TLS 1.3はクライアントが最初の送信でデータを送信すること ("Early Data (早期データ)") を許可します。クライアントはPSKを使用してサーバーを認証し, 早期データを暗号化します。
図4に示すように, 0-RTTデータは最初の送信で1-RTTハンドシェイクに追加されるだけです。ハンドシェイクの残りの部分は, PSK再開を伴う1-RTTハンドシェイクと同じメッセージを使用します。
Client Server
ClientHello
+ early_data
+ key_share*
+ psk_key_exchange_modes
+ pre_shared_key
(Application Data*) -------->
ServerHello
+ pre_shared_key
+ key_share*
{EncryptedExtensions}
+ early_data*
{Finished}
<-------- [Application Data*]
(EndOfEarlyData)
{Finished} -------->
[Application Data] <-------> [Application Data]
+ 前述のメッセージで送信される注目すべき拡張を示します。
* 常に送信されるわけではないオプションまたは状況依存の
メッセージ/拡張を示します。
() client_early_traffic_secret
から派生した鍵を使用して保護されるメッセージを示します。
{} [sender]_handshake_traffic_secret
から派生した鍵を使用して保護されるメッセージを示します。
[] [sender]_application_traffic_secret_N
から派生した鍵を使用して保護されるメッセージを示します。
図4: 0-RTTハンドシェイクのメッセージフロー
重要な注意事項: 0-RTTデータのセキュリティ特性は, 他の種類のTLSデータよりも弱くなっています。具体的には:
-
このデータは前方秘匿性 (Forward Secret) ではありません。提供されたPSKから派生した鍵のみを使用して暗号化されるためです。
-
接続間の再生防止 (Non-Replay) は保証されません。通常のTLS 1.3 1-RTTデータの再生防止保護はサーバーのRandom値によって提供されますが, 0-RTTデータはServerHelloに依存しないため, より弱い保証があります。データがTLSクライアント認証を使用して認証される場合, またはアプリケーションプロトコル内で認証される場合, これは特に関連します。同じ警告がearly_exporter_master_secretの使用にも適用されます。
0-RTTデータは接続内で複製できません (つまり, サーバーは同じ接続に対して同じデータを2回処理しません)。攻撃者は0-RTTデータを1-RTTデータのように見せることはできません (異なる鍵で保護されているため)。付録E.5には潜在的な攻撃の説明が含まれており, セクション8にはサーバーが再生の影響を制限するために使用できるメカニズムが説明されています。