メインコンテンツまでスキップ

RFC 6347 - 4.1. レコード層 (Record Layer)

4. TLS との相違点​

セクション 3 で述べたとおり, DTLS は意図的に TLS に非常に似せている. したがって DTLS を新プロトコルとして提示するのではなく, TLS 1.2 [TLS12] に対する一連の差分として示す. 差異を明示しない箇所では DTLS は [TLS12] と同じである.

4.1. Record Layer​

DTLS レコード層は TLS 1.2 のそれと極めてよく似ている. 唯一の変更はレコードに明示的シーケンス番号を含めることである. このシーケンス番号により受信者は TLS MAC を正しく検証できる. DTLS レコード形式を以下に示す.

struct {
ContentType type;
ProtocolVersion version;
uint16 epoch; // New field
uint48 sequence_number; // New field
uint16 length;
opaque fragment[DTLSPlaintext.length];
} DTLSPlaintext;

type

TLS 1.2 レコードの type フィールドと等価.

version

用いるプロトコルのバージョン. 本ドキュメントは DTLS 1.2 を扱い, バージョン { 254, 253 } を用いる. 254.253 は DTLS 1.2 のバージョン値の 1 の補数である. TLS と DTLS のバージョン番号を大きく離すことで両プロトコルのレコードを容易に区別できる. 将来の on-the-wire 版番号は減少し, 真の版番号は増加する点に注意.

epoch

暗号状態が変わるたびに増分されるカウンタ.

sequence_number

本レコードのシーケンス番号.

length

TLS 1.2 レコードの length と同一. TLS 1.2 と同様 2^14 を超えないこと.

fragment

TLS 1.2 レコードの fragment と同一.

DTLS は暗黙ではなく sequence_number フィールドに載せた明示的シーケンス番号を用いる. シーケンス番号は各 epoch ごとに別々に維持され, 各 epoch で sequence_number は 0 から始まる. 例えば epoch 0 のハンドシェイクメッセージが再送されると, epoch 1 のメッセージより後のシーケンス番号を持ちうる (epoch 1 が先に送信された場合でも). ハンドシェイク中は再送メッセージが正しい epoch と鍵材料を使うよう注意が必要.

短時間に複数ハンドシェイクがあると, 同じシーケンス番号で異なる暗号状態からの複数レコードが線上に出うる. epoch フィールドがこれを区別する. epoch は初期 0 で, ChangeCipherSpec のたびに増分する. 任意の sequence/epoch ペアの一意性のため, 実装は TCP 最大セグメント寿命の 2 倍以内に同じ epoch 値を再利用してはならない (MUST NOT). 実務上 TLS は再ハンドシェイクが稀なので問題にならないと考える.

DTLS レコードは並べ替えられうるため, epoch 2 開始後に epoch 1 のレコードが届くことがある. 一般に実装は古い epoch のパケットを破棄すべき (SHOULD) だが, 損失で問題が顕在化する場合は, TCP [TCP] のデフォルト MSL まで以前 epoch の鍵材料を保持して並べ替えに対応してもよい (MAY). (実装者は IETF の現行 MSL 指針を用いる意図であり, OS の TCP スタックの MSL を調べることではない.) ハンドシェイク完了までは実装は旧 epoch のパケットを受け入れなければならない (MUST).

逆に, 新しく交渉されたコンテキストで保護されたレコードがハンドシェイク完了前に届くこともある. 例: サーバが Finished を送ってからデータ送信を始める. 実装はバッファまたは破棄してよい (MAY) が, 信頼できるトランスポート (例: SCTP) 上ではハンドシェイク完了後に処理するようバッファすべき (SHOULD). TLS の送信タイミング制約は依然適用され, 受信者は正しい順序で送られたかのように扱う. 特に最初のハンドシェイク完了前のデータ送信は禁じられる.

既存の関連付け上で再ハンドシェイクする特別な場合, ChangeCipherSpec や Finished をまだ受け取っていなくても, 再開が既存セッションであるか既存と同一のセキュリティパラメータであるならデータパケットを直ちに処理して安全である. それ以外ではダウングレード攻撃防止のため Finished 受信まで待たなければならない (MUST).

TLS と同様, シーケンス番号がラップする前に関連付けを放棄するか再ハンドシェイクしなければならない (MUST).

同様に epoch のラップは許してはならず (MUST NOT), セクション 4.2.8 に従い新関連付けを確立し旧関連付けを終了しなければならない (MUST). 同一チャネルで繰り返し再ハンドシェイクは稀なので実務上問題になりにくい.

4.1.1. Transport Layer Mapping​

各 DTLS レコードは 1 データグラムに収めなければならない (MUST). IP 分断を避けるため, DTLS レコード層のクライアントはレコード層から得た PMTU 見積りに収まるようレコードサイズを調整すべき (SHOULD).

IPsec と異なり DTLS レコードに関連識別子はない. アプリケーションが関連間の多重化を行う. UDP ではホスト/ポートで行うと推測される.

複数レコードを 1 データグラムに入れられる. 単に連続エンコードする. フレーミングで境界が分かる. ただしデータグラムペイロードの先頭バイトはレコードの先頭でなければならない. レコードはデータグラムをまたいではならない.

DCCP [DCCP] などは独自シーケンス番号を持つ. それらの上では DTLS とトランスポートの両方の番号が存在する. 若干非効率だが目的が異なるため概念上両方を使う方が優れる. 将来, 制約環境向けに 1 セットにまとめる拡張がありうる.

DCCP などは輻輳制御を提供する. ウィンドウが狭いと DTLS ハンドシェイク再送が遅延しタイムアウトや偽再送を招きうる. そのようなトランスポートではウィンドウを超えないよう注意する. [DCCPDTLS] が DTLS を DCCP にマッピングしこれらを扱う.

4.1.1.1. PMTU Issues​

一般に DTLS は PMTU 発見をアプリケーションに任せる. しかし次の 3 理由で PMTU を完全無視はできない:

  • レコード枠がデータグラムを拡大し, アプリケーション視点の実効 PMTU を下げる.

  • アプリがネットワークに直接話さない実装では, DTLS スタックが ICMP [RFC1191] "Datagram Too Big" や ICMPv6 [RFC4443] "Packet Too Big" を吸収しうる.

  • ハンドシェイクメッセージが PMTU を超えうる.

最初の 2 点への対処として, DTLS レコード層は以下のように振る舞うべき (SHOULD).

下位から PMTU 見積りが得られる場合は上位に提供する. 特に:

  • UDP 上の DTLS では IP 層の PMTU 見積りを上位が取得できるようにすべき (SHOULD).

  • DCCP 上では現在の PMTU 見積りを上位が取得できるようにすべき (SHOULD).

  • TCP/SCTP 上では自動分断・再構成があり PMTU 制限はないが, 上位は最大レコード 2^14 バイトを超えるレコードを書いてはならない (MUST NOT).

DTLS レコード層は DTLS 処理によるレコード拡張量を上位が把握できるようにすべき (SHOULD). ブロックパディングや DTLS 圧縮の可能性により見積りに過ぎない.

トランスポートからの通知 (ICMP や [DCCP] セクション 14 の拒否など) がある場合, レコード層は上位にエラーを通知しなければならない (MUST).

レコード層は [RFC1191] や [RFC4821] による PMTU 発見を妨げるべきではない (SHOULD NOT). 特に:

  • 下位が許すなら DF (IPv4) や IPv6 のローカル分断禁止を上位が設定できるようにすべき (SHOULD).

  • 下位が PMTU プローブ要求を許す (例: DCCP) なら, レコード層はこれに従うべきである.

最後にハンドシェイクがある. レコード層から見れば単なる上位プロトコルだが, 頻度は低く往復も少ないため, 正確な PMTU 発見より迅速完了を優先する. 接続を許容するため, 実装は次を従うべき (SHOULD):

  • レコード層がハンドシェイク層にメッセージ過大を通知したら, 既知の PMTU に基づき直ちに分片を試みるべき (SHOULD).

  • 繰り返し再送でも応答がなく PMTU 不明なら, より小さいレコードに退避しハンドシェイクを分片すべき (SHOULD). 退避前の再送回数は本標準では定めないが 2〜3 回が妥当.

4.1.2. Record Payload Protection​

TLS と同様 DTLS は保護レコードの列としてデータを送る. 形式の詳細を以下に述べる.

4.1.2.1. MAC​

DTLS の MAC は TLS 1.2 と同じだが, TLS の暗黙シーケンス番号の代わりに, 線上順に epoch とシーケンス番号を連結した 64 ビット値を MAC 計算に用いる. 長さは TLS のシーケンス番号と同じ.

TLS MAC はプロトコル版でパラメータ化され, DTLS では on-the-wire 版すなわち DTLS 1.2 では {254, 253} である.

重要な相違: TLS では MAC エラーは接続終了が必須. DTLS では問題レコードを破棄して接続継続してよい (MAY). DTLS レコードは TLS のように相互依存しないからである.

一般に DTLS 実装は不正 MAC など無効レコードを黙って破棄すべき (SHOULD). ログは可 (MAY). 不正 MAC でアラートを出す場合は fatal の bad_record_mac を出し状態を終了しなければならない (MUST). エラーで接続を切らないため DTLS はエラー型オラクルになりやすい. [TLS12] 6.2.3.2 の助言に従うことが特に重要.

4.1.2.2. Null or Standard Stream Cipher​

DTLS NULL 暗号は TLS 1.2 と同一.

TLS 1.2 で述べられる唯一のストリーム暗号 RC4 はランダムアクセス不可. RC4 は DTLS で使ってはならない (MUST NOT).

4.1.2.3. Block Cipher​

DTLS のブロック暗号の暗号化・復号は TLS 1.2 と同一.

4.1.2.4. AEAD Ciphers​

TLS 1.2 は AEAD 暗号スイートを導入した. [ECCGCM] と [RSAGCM] の AEAD は TLS 1.2 と同様に DTLS で使える.

4.1.2.5. New Cipher Suites​

登録時, 新しい TLS 暗号スイートは DTLS 適合可否と必要な適合を示さなければならない (MUST) (セクション 7).

4.1.2.6. Anti-Replay​

DTLS レコードはリプレイ保護のためシーケンス番号を含む. 検証は [ESP] 3.4.3 のスライディングウィンドウ手順を用いるべき (SHOULD).

セッション確立時に受信パケットカウンタは 0 で初期化しなければならない (MUST). 各レコードで, 当該セッション存続中に受信した他レコードと重複しないシーケンス番号であることを検証しなければならない (MUST). セッションにマッチ後最初の検査とすべき (SHOULD).

重複はスライディング受信ウィンドウで拒否する (実装詳細はローカルだが以下の振る舞いが必要). 最小ウィンドウ 32 をサポートしなければならない (MUST). 64 が望ましくデフォルトにすべき (SHOULD). それ以上も選べる (MAY) (送信者に通知しない).

ウィンドウの右端は検証済み最大シーケンス. 左端より小さい番号は拒否. 内側はビットマスク等で既受信と照合 ([ESP] 3.4.3).

ウィンドウ内で新規, またはウィンドウ右外なら MAC 検証へ. MAC 失敗なら破棄 (MUST). ウィンドウ更新は MAC 成功時のみ.

4.1.2.7. Handling Invalid Records​

TLS と異なり DTLS は無効レコードに対して耐性がある. 一般に無効レコードは黙って破棄し関連付けを維持すべき (SHOULD). 診断ログは可 (MAY). アラートを選ぶ実装は攻撃者のプローブに対し fatal にしなければならない (MUST). UDP 上では DoS に極めて弱いためその慣行は推奨されない (NOT RECOMMENDED).

偽造に強いトランスポート (例: SCTP-AUTH 付き SCTP) 上ではアラート送信がより安全である.