5. Record Protocol (記録プロトコル)
TLS記録プロトコルは、送信するメッセージを受け取り、データを管理可能なブロックに断片化し、記録を保護し、結果を送信します。受信したデータは検証され、復号され、再構築され、その後、上位レベルのクライアントに配信されます。
TLS記録は型付けされており、これにより複数の上位プロトコルを同じ記録層上で多重化できます。本書は4つのコンテンツタイプを規定します: handshake、application_data、alert、change_cipher_spec。change_cipher_spec記録は互換性の目的でのみ使用されます (付録D.4参照)。
実装は、最初のClientHelloメッセージが送信または受信された後、ピアのFinishedメッセージが受信される前の任意の時点で、単一バイト値0x01からなる暗号化されていないchange_cipher_spec型の記録を受信してもかまいません (MAY)。その場合、それ以上の処理を行わずに単に破棄しなければなりません (MUST)。この記録は、実装が保護された記録を期待しているハンドシェイクの時点で現れる可能性があるため、記録の保護解除を試みる前にこの状態を検出する必要があることに注意してください。他のchange_cipher_spec値を受信する実装、または保護されたchange_cipher_spec記録を受信する実装は、"unexpected_message"警告でハンドシェイクを中止しなければなりません (MUST)。実装が、最初のClientHelloメッセージより前、またはピアのFinishedメッセージより後に受信されたchange_cipher_spec記録を検出した場合、それは予期しない記録タイプとして扱わなければなりません (MUST)(ただし、ステートレスサーバーはこれらのケースを許可されたケースと区別できない場合があります)。
実装は、何らかの拡張によってネゴシエートされない限り、本書で定義されていない記録タイプを送信してはなりません (MUST NOT)。TLS実装が予期しない記録タイプを受信した場合、"unexpected_message"警告で接続を終了しなければなりません (MUST)。新しい記録コンテンツタイプの値は、第11節で説明されているように、IANAによってTLS ContentTypeレジストリで割り当てられます。
5.1. Record Layer (記録層)
記録層は、情報ブロックをTLSPlaintext記録に断片化し、2^14バイト以下のチャンクでデータを運びます。メッセージ境界は、基になるContentTypeに応じて異なる方法で処理されます。将来のコンテンツタイプはすべて適切なルールを指定しなければなりません (MUST)。これらのルールはTLS 1.2で適用されていたものより厳格であることに注意してください。
ハンドシェイクメッセージは、次の条件を満たす限り、単一のTLSPlaintext記録に統合しても、複数の記録に断片化してもかまいません (MAY):
-
ハンドシェイクメッセージは、他の記録タイプとインターリーブしてはなりません (MUST NOT)。つまり、ハンドシェイクメッセージが2つ以上の記録に分割される場合、それらの間に他の記録があってはなりません (MUST NOT)。
-
ハンドシェイクメッセージは、鍵の変更をまたいではなりません (MUST NOT)。実装は、鍵の変更の直前にあるすべてのメッセージが記録境界に整列していることを検証しなければなりません (MUST)。整列していない場合、"unexpected_message"警告で接続を終了しなければなりません (MUST)。ClientHello、EndOfEarlyData、ServerHello、Finished、およびKeyUpdateメッセージは鍵の変更の直前に置くことができるため、実装はこれらのメッセージを記録境界に整列させて送信しなければなりません (MUST)。
実装は、たとえそれらの断片にパディングが含まれていても、Handshakeタイプの長さゼロの断片を送信してはなりません (MUST NOT)。
警告メッセージ (第6節) は記録をまたいで断片化してはならず (MUST NOT)、複数の警告メッセージを単一のTLSPlaintext記録に統合してはなりません (MUST NOT)。言い換えれば、Alertタイプの記録は正確に1つのメッセージを含まなければなりません (MUST)。
アプリケーションデータメッセージには、TLSにとって不透明なデータが含まれます。アプリケーションデータメッセージは常に保護されます。アプリケーションデータの長さゼロの断片は、トラフィック分析への対策として有用である可能性があるため、送信してもかまいません (MAY)。アプリケーションデータの断片は、複数の記録に分割しても、単一の記録に統合してもかまいません (MAY)。
enum {
invalid(0),
change_cipher_spec(20),
alert(21),
handshake(22),
application_data(23),
(255)
} ContentType;
struct {
ContentType type;
ProtocolVersion legacy_record_version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
type: 囲まれた断片を処理するために使用される上位プロトコル。
legacy_record_version: 初期ClientHello (つまり、HelloRetryRequestの後に生成されていないもの) 以外の、TLS 1.3実装によって生成されるすべての記録で0x0303に設定しなければなりません (MUST)。初期ClientHelloでは、互換性の目的で0x0301に設定してもかまいません (MAY)。このフィールドは非推奨であり、すべての目的で無視しなければなりません (MUST)。以前のバージョンのTLSでは、状況によってこのフィールドに他の値を使用していました。
length: 後続のTLSPlaintext.fragmentの長さ (バイト単位)。長さは2^14バイトを超えてはなりません (MUST NOT)。この長さを超える記録を受信したエンドポイントは、"record_overflow"警告で接続を終了しなければなりません (MUST)。
fragment: 送信されるデータ。この値は透過的であり、typeフィールドで指定された上位プロトコルによって処理される独立したブロックとして扱われます。
本書は、バージョン0x0304を使用するTLS 1.3について説明します。このバージョン値は歴史的なもので、TLS 1.0に0x0301、SSL 3.0に0x0300が使用されたことに由来します。後方互換性を最大化するために、初期ClientHelloを含む記録はバージョン0x0301 (TLS 1.0を反映) を持つべきであり (SHOULD)、2番目のClientHelloまたはServerHelloを含む記録はバージョン0x0303 (TLS 1.2を反映) を持たなければなりません (MUST)。以前のバージョンのTLSをネゴシエートする場合、エンドポイントは付録Dに示された手順と要件に従います。
記録保護がまだ有効になっていない場合、TLSPlaintext構造はワイヤに直接書き込まれます。記録保護が開始されると、TLSPlaintext記録は次の節で説明するように保護されて送信されます。アプリケーションデータ記録は保護されずにワイヤに書き込んではならない (MUST NOT) ことに注意してください (詳細は第2節参照)。
5.2. Record Payload Protection (記録ペイロード保護)
記録保護機能は、TLSPlaintext構造をTLSCiphertext構造に変換します。保護解除機能はその逆のプロセスを行います。以前のバージョンのTLSとは異なり、TLS 1.3では、すべての暗号が"Authenticated Encryption with Associated Data" (AEAD) [RFC5116]としてモデル化されます。AEAD関数は、平文を認証済み暗号文に変換し、また元に戻す統一的な暗号化と認証の操作を提供します。暗号化された各記録は、平文ヘッダーと、それに続く暗号化された本体で構成され、本体自体にはタイプとオプションのパディングが含まれます。
struct {
opaque content[TLSPlaintext.length];
ContentType type;
uint8 zeros[length_of_padding];
} TLSInnerPlaintext;
struct {
ContentType opaque_type = application_data; /* 23 */
ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */
uint16 length;
opaque encrypted_record[TLSCiphertext.length];
} TLSCiphertext;
content: TLSPlaintext.fragment値。ハンドシェイクまたは警告メッセージのバイトエンコーディング、あるいは送信するアプリケーションデータの生バイトを含みます。
type: 記録のコンテンツタイプを含むTLSPlaintext.type値。
zeros: typeフィールドの後に、任意の長さのゼロ値バイトの連続が平文に現れてもかまいません (MAY)。これにより、送信者は合計が記録サイズ制限内に収まる限り、任意のTLS記録を選択した量だけパディングする機会を得られます。詳細は第5.4節を参照してください。
opaque_type: TLSCiphertext記録の外側のopaque_typeフィールドは、以前のバージョンのTLSを解析することに慣れたミドルボックスとの外向きの互換性のために、常に値23 (application_data) に設定されます。記録の実際のコンテンツタイプは、復号後のTLSInnerPlaintext.typeにあります。
legacy_record_version: legacy_record_versionフィールドは常に0x0303です。TLS 1.3のTLSCiphertextは、TLS 1.3がネゴシエートされた後にのみ生成されるため、他の値を受信する可能性があるという歴史的な互換性の懸念はありません。ClientHelloメッセージとServerHelloメッセージを含むハンドシェイクプロトコルがプロトコルバージョンを認証するため、この値は冗長であることに注意してください。
length: 後続のTLSCiphertext.encrypted_recordの長さ (バイト単位)。これは、コンテンツとパディングの長さの合計に、内側のコンテンツタイプ用の1を加え、さらにAEADアルゴリズムによって追加される拡張を加えたものです。長さは2^14 + 256バイトを超えてはなりません (MUST NOT)。この長さを超える記録を受信したエンドポイントは、"record_overflow"警告で接続を終了しなければなりません (MUST)。
encrypted_record: シリアル化されたTLSInnerPlaintext構造のAEAD暗号化形式。
AEADアルゴリズムは、[RFC5116]の第2.1節で説明されているように、単一の鍵、ノンス、平文、および認証チェックに含める"additional data"を入力として受け取ります。鍵はclient_write_keyまたはserver_write_keyのいずれかであり、ノンスはシーケンス番号とclient_write_ivまたはserver_write_ivから導出され (第5.3節参照)、additional dataの入力は記録ヘッダーです。
すなわち、
additional_data = TLSCiphertext.opaque_type ||
TLSCiphertext.legacy_record_version ||
TLSCiphertext.length
AEADアルゴリズムへの平文入力は、エンコードされたTLSInnerPlaintext構造です。トラフィック鍵の導出は第7.3節で定義されています。
AEAD出力は、AEAD暗号化操作からの暗号文出力で構成されます。平文の長さは、TLSInnerPlaintext.typeと送信者によって提供されるパディングが含まれるため、対応するTLSPlaintext.lengthより大きくなります。AEAD出力の長さは一般に平文より大きくなりますが、その量はAEADアルゴリズムによって異なります。暗号がパディングを組み込む可能性があるため、オーバーヘッドの量は平文の長さによって異なる場合があります。記号的に表現すると、
AEADEncrypted =
AEAD-Encrypt(write_key, nonce, additional_data, plaintext)
TLSCiphertextのencrypted_recordフィールドはAEADEncryptedに設定されます。
復号と検証を行うために、暗号は鍵、ノンス、追加データ、およびAEADEncrypted値を入力として受け取ります。出力は平文か、復号が失敗したことを示すエラーのいずれかです。別個の整合性チェックはありません。記号的に表現すると、
plaintext of encrypted_record =
AEAD-Decrypt(peer_write_key, nonce,
additional_data, AEADEncrypted)
復号が失敗した場合、受信者は"bad_record_mac"警告で接続を終了しなければなりません (MUST)。
TLS 1.3で使用されるAEADアルゴリズムは、255オクテットを超える拡張を生成してはなりません (MUST NOT)。ピアからTLSCiphertext.lengthが2^14 + 256オクテットより大きい記録を受信したエンドポイントは、"record_overflow"警告で接続を終了しなければなりません (MUST)。この制限は、TLSInnerPlaintextの最大長2^14オクテット + ContentType用の1オクテット + AEAD拡張の最大255オクテットから導出されます。
5.3. Per-Record Nonce (記録ごとのノンス)
64ビットのシーケンス番号は、記録の読み取りと書き込みで別々に維持されます。適切なシーケンス番号は、各記録を読み取りまたは書き込みした後に1つ増分されます。各シーケンス番号は、接続の開始時と鍵が変更されるたびにゼロに設定されます。特定のトラフィック鍵の下で送信される最初の記録は、シーケンス番号0を使用しなければなりません (MUST)。
シーケンス番号のサイズは64ビットであるため、ラップしないはずです。TLS実装がシーケンス番号をラップする必要がある場合、鍵を更新するか (第4.6.3節)、接続を終了しなければなりません (MUST)。
各AEADアルゴリズムは、記録ごとのノンスの可能な長さの範囲を、N_MINバイトからN_MAXバイトの入力として指定します [RFC5116]。TLSの記録ごとのノンスの長さ (iv_length) は、8バイトとそのAEADアルゴリズムのN_MINのうち大きい方に設定されます ([RFC5116]の第4節参照)。N_MAXが8バイト未満のAEADアルゴリズムは、TLSで使用してはなりません (MUST NOT)。AEAD構築のための記録ごとのノンスは、次のように形成されます:
-
64ビットの記録シーケンス番号をネットワークバイトオーダーでエンコードし、iv_lengthまで左側にゼロを埋め込みます。
-
パディングされたシーケンス番号を、静的なclient_write_ivまたはserver_write_iv (役割に応じて) とXORします。
結果として得られる量 (長さiv_length) が、記録ごとのノンスとして使用されます。
注: これは、部分的に明示的なノンスを規定していたTLS 1.2の構築とは異なります。
5.4. Record Padding (記録パディング)
すべての暗号化されたTLS記録は、TLSCiphertextのサイズを膨張させるためにパディングできます。これにより、送信者は観察者からトラフィックのサイズを隠すことができます。
TLSCiphertext記録を生成するとき、実装はパディングを選択してもかまいません (MAY)。パディングされていない記録は、パディング長がゼロの記録にすぎません。パディングは、暗号化前にContentTypeフィールドに追加されるゼロ値バイトの文字列です。実装は、暗号化前にパディングオクテットをすべてゼロに設定しなければなりません (MUST)。
アプリケーションデータ記録は、送信者が望む場合、長さゼロのTLSInnerPlaintext.contentを含むことができます。これにより、活動の有無が機密である可能性がある状況で、もっともらしいサイズのカバートラフィックを生成できます。実装は、長さゼロのTLSInnerPlaintext.contentを持つHandshake記録とAlert記録を送信してはなりません (MUST NOT)。そのようなメッセージを受信した場合、受信側の実装は"unexpected_message"警告で接続を終了しなければなりません (MUST)。
送信されるパディングは、記録保護メカニズムによって自動的に検証されます。TLSCiphertext.encrypted_recordの復号が成功すると、受信側の実装はフィールドを末尾から先頭に向かってスキャンし、非ゼロのオクテットを見つけるまで続けます。この非ゼロオクテットがメッセージのコンテンツタイプです。このパディング方式が選択されたのは、新しいコンテンツタイプを導入することなく、任意の暗号化されたTLS記録を任意のサイズ (ゼロからTLS記録サイズ制限まで) でパディングできるためです。この設計はまた、すべてゼロのパディングオクテットを強制し、パディングエラーを迅速に検出できるようにします。
実装は、スキャンをAEAD復号から返された平文に限定しなければなりません (MUST)。受信側の実装が平文中に非ゼロのオクテットを見つけられない場合、"unexpected_message"警告で接続を終了しなければなりません (MUST)。
パディングの存在は、記録全体のサイズ制限を変更しません。エンコードされたTLSInnerPlaintext全体は、2^14 + 1オクテットを超えてはなりません (MUST NOT)。最大断片長が削減される場合 (たとえば、[RFC8449]のrecord_size_limit拡張による場合)、削減された制限はコンテンツタイプとパディングを含む平文全体に適用されます。
いつどれだけパディングするかを示唆するパディングポリシーの選択は複雑な話題であり、本仕様の範囲を超えています。TLSの上にあるアプリケーション層プロトコルが独自のパディングを持っている場合、アプリケーション層内でアプリケーションデータのTLS記録をパディングする方が望ましい場合があります。ただし、暗号化されたHandshake記録またはAlert記録のパディングは、依然としてTLS層で処理しなければなりません。後の文書で、パディング選択アルゴリズムを定義したり、TLS拡張やその他の手段を通じてパディングポリシー要求メカニズムを定義したりする場合があります。
5.5. Limits on Key Usage (鍵使用の制限)
与えられた鍵の組の下で安全に暗号化できる平文の量には、暗号学的な制限があります。[AEAD-LIMITS]は、基盤となるプリミティブ (AESまたはChaCha20) に弱点がないと仮定した場合のこれらの制限の分析を提供します。実装は、これらの制限に達する前に、第4.6.3節で説明されているように鍵の更新を行うべきです (SHOULD)。
AES-GCMの場合、Authenticated Encryption (AE) セキュリティの約2^-57の安全マージンを維持しながら、与えられた接続上で最大2^24.5個のフルサイズ記録 (約2400万) を暗号化できます。ChaCha20/Poly1305の場合、記録シーケンス番号は安全制限に達する前にラップします。