TLS 1.3 (RFC 8446) のハンドシェイクと暗号スイート

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

TLS 1.3 (RFC 8446) のハンドシェイクと暗号スイート

背景

Transport Layer Security (TLS) プロトコルは、インターネット上で安全な通信を確立するための基盤技術です。TLS 1.2 以前のバージョンには、暗号学的な脆弱性の露呈、非効率なハンドシェイク、複雑すぎる機能セットなどの課題がありました。これらの課題に対処し、より高速で安全、かつシンプルなプロトコルとして、2018年8月に RFC 8446 で TLS 1.3 が標準化されました。

設計目標

TLS 1.3 の設計は、主に以下の目標に基づいて行われました。

  • セキュリティの向上: 既知の脆弱性を持つ暗号アルゴリズム(RC4、CBCモード暗号、MD5、SHA-1など)や機能(RSA鍵交換、圧縮、再ネゴシエーションなど)を廃止し、Forward Secrecy (PFS) を強制する鍵交換(ECDHE/DHE)を必須化。ハンドシェイクの大部分を暗号化することで、メタデータに対するプライバシーを向上させました。

  • パフォーマンスの改善: ハンドシェイクのラウンドトリップ回数を削減し、特にセッション再開時には 0-RTT (Zero Round Trip Time) を可能にすることで、接続確立のレイテンシを大幅に短縮しました。

  • プロトコルの簡素化: 不要な機能やオプションを削除し、プロトコル仕様をスリム化することで、実装の複雑さを軽減し、誤実装のリスクを低減しました。

詳細

ハンドシェイクフロー

TLS 1.3 では、フルハンドシェイクが 1-RTT で完了し、セッション再開時には 0-RTT をサポートします。これは、TLS 1.2 が通常 2-RTT(フルハンドシェイク)または 1-RTT(セッション再開)を必要としたのと比較して、大幅な改善です。

1-RTT ハンドシェイク (フルハンドシェイク)

クライアントとサーバーが初回接続時または共有鍵を持たない場合の流れです。

sequenceDiagram
    participant C as Client
    participant S as Server

    C ->> S: Client Hello (Supported versions, Cipher Suites, Key Shares, PSK Identities, Client Random)
    Note over S: Server processes Client Hello, selects parameters, generates keys
    S -->> C: Server Hello (Selected version, Cipher Suite, Key Share, Server Random)
    S -->> C: Encrypted Extensions
    S -->> C: Certificate (Optional)
    S -->> C: Certificate Verify (Optional)
    S -->> C: Finished
    Note over C: Client verifies server messages, generates master secret, sends Finished
    C ->> S: Finished
    C> S: Application Data (Encrypted)

主要な変更点:

  • Client Helloでの鍵共有: クライアントは Client Hello にサポートする鍵共有方式(例: ECDHE)と、それぞれの鍵共有用公開鍵を含めます。これにより、サーバーは Server Hello で鍵共有を完了し、すぐに鍵を確立できます。

  • 暗号化されたハンドシェイク: Server Hello 以降のメッセージ(Encrypted Extensions, Certificate, Certificate Verify, Finished)は、確立された鍵を使って暗号化されます。これにより、傍受者からこれらの情報が保護されます。

0-RTT ハンドシェイク (セッション再開)

以前に接続があり、PSK (Pre-Shared Key) を共有している場合に利用できるハンドシェイクです。クライアントは Client Hello と同時に初期アプリケーションデータを送信できます。

sequenceDiagram
    participant C as Client
    participant S as Server

    C ->> S: Client Hello (PSK Identity, early_data extension), Early Application Data (Optional)
    Note over S: Server attempts to decrypt early data with PSK
    S -->> C: Server Hello (Selected version, Cipher Suite, Key Share, Server Random)
    S -->> C: Encrypted Extensions
    S -->> C: Certificate (Optional)
    S -->> C: Certificate Verify (Optional)
    S -->> C: Finished
    Note over C: Client verifies server messages, generates master secret, sends Finished
    C ->> S: Finished
    C> S: Application Data (Encrypted)

暗号スイート

TLS 1.3 では、安全性が低いと判断された多くの暗号スイートが廃止され、AEAD (Authenticated Encryption with Associated Data) アルゴリズムを必須としています。これにより、データの機密性、完全性、認証が同時に保証されます。

TLS 1.3 で必須または推奨される主な暗号スイート:

  • TLS_AES_128_GCM_SHA256 (AES 128-bit GCM with SHA256 for HKDF)

  • TLS_AES_256_GCM_SHA384 (AES 256-bit GCM with SHA384 for HKDF)

  • TLS_CHACHA20_POLY1305_SHA256 (ChaCha20-Poly1305 with SHA256 for HKDF)

これらの暗号スイートは、以下の構成要素を持ちます。

flowchart LR
    A["TLS 1.3 Cipher Suite"] --> B["鍵交換アルゴリズム | ECDHE / DHE"];
    B --> C["認証付き暗号化アルゴリズム (AEAD) | AES-GCM, ChaCha20-Poly1305"];
    C --> D["HKDF用ハッシュ関数 | SHA256, SHA384"];
    A --> E["鍵導出関数 | HKDF"];

鍵導出には、HMAC-based Key Derivation Function (HKDF) が使用されます。HKDFは、初期の共有秘密情報から複数の暗号鍵を安全に導出するために設計されており、TLS 1.2 で使用されていた PRF (Pseudo-Random Function) よりも堅牢です。

ヘッダ/フレーム/パケット構造の例 (Client Helloの一部)

TLSレコードプロトコルは TLS 1.2 から変更されていませんが、ハンドシェイクメッセージの構造は異なります。Client Hello メッセージの一部のフィールドを text 形式で示します。

  TLSPlaintext.type:8 (Handshake: 22)
  TLSPlaintext.version:16 (Legacy: 0x0303 for TLS 1.2, but indicates TLS 1.3 if supported_versions extension is present)
  TLSPlaintext.length:16 (Length of the encapsulated Handshake message)

  Handshake.msg_type:8 (Client Hello: 1)
  Handshake.length:24 (Length of Client Hello message body)

  ClientHello.legacy_version:16 (Set to 0x0303 for TLS 1.2 compatibility)
  ClientHello.random:256 (32 bytes random value)
  ClientHello.legacy_session_id_length:8
  ClientHello.legacy_session_id:variable (Length from legacy_session_id_length)
  ClientHello.cipher_suites_length:16 (Number of bytes for cipher_suites)
  ClientHello.cipher_suites:variable (List of 16-bit cipher suite codes)
  ClientHello.legacy_compression_methods_length:8 (Must be 1)
  ClientHello.legacy_compression_methods:8 (Must be 0)
  ClientHello.extensions_length:16 (Number of bytes for extensions)
  ClientHello.extensions:variable (List of extensions, e.g., key_share, supported_versions, early_data)

ClientHello.legacy_versionは互換性のために0x0303 (TLS 1.2) を設定しますが、実際のバージョンネゴシエーションはsupported_versions拡張によって行われます。

既存プロトコルとの比較 (TLS 1.3 vs TLS 1.2)

TLS 1.3 は、TLS 1.2 から以下の点で大きく進化しています。

  • ハンドシェイクの効率性:

    • TLS 1.2: フルハンドシェイクは通常 2-RTT を要し、PFSを有効にするためには追加のラウンドトリップが必要でした。

    • TLS 1.3: フルハンドシェイクは 1-RTT で完了し、PFSが必須化されています。セッション再開時には 0-RTT が可能です。

  • 鍵交換:

    • TLS 1.2: RSA鍵交換が可能であり、Forward Secrecyを強制しませんでした。

    • TLS 1.3: ECDHE/DHE鍵交換が必須となり、すべてのセッションで Forward Secrecy が保証されます。

  • 暗号アルゴリズム:

    • TLS 1.2: RC4、CBCモードの暗号(BEAST攻撃への脆弱性)、MD5、SHA-1ベースのPRFsなど、多くの弱体化したアルゴリズムをサポートしていました。

    • TLS 1.3: AEAD (Authenticated Encryption with Associated Data) 暗号(AES-GCM, ChaCha20-Poly1305)のみをサポートし、より強力なハッシュ関数(SHA256, SHA384)に基づく HKDF を鍵導出に用います。

  • ハンドシェイクの暗号化:

    • TLS 1.2: Server Hello 以降のハンドシェイクメッセージは暗号化されませんでした。

    • TLS 1.3: Server Hello 以降の大部分のハンドシェイクメッセージが暗号化され、通信のプライバシーが向上しました。

  • 機能の簡素化:

    • TLS 1.2: 圧縮、再ネゴシエーション、カスタムDHEグループ、ChangeCipherSpecプロトコルなど、多くのオプション機能が存在し、実装の複雑さと攻撃ベクトルを増やしていました。

    • TLS 1.3: これらの機能はすべて廃止され、プロトコルが大幅に簡素化されました。

セキュリティ考慮

TLS 1.3 はセキュリティを大幅に強化していますが、いくつかの重要な考慮点があります。

  • リプレイ攻撃 (0-RTT): 0-RTT データは、クライアントが暗号鍵を確立する前にサーバーに送信するアプリケーションデータです。このデータは、通信経路上の攻撃者によって捕捉され、サーバーに再度送信される(リプレイされる)可能性があります。これにより、サーバー側で非冪等な操作(例:注文の繰り返し)が発生するリスクがあります。RFC 8446のセクション8.1は、サーバーがリプレイを検出・防止するためのメカニズム(例:タイムスタンプ、ワンタイムナンス)を実装する必要があると明確に規定しています。

  • ダウングレード攻撃: 攻撃者がクライアントとサーバー間のTLS接続を TLS 1.2 などの古いバージョンに強制的にダウングレードしようとする攻撃です。TLS 1.3 は Server Random フィールドに特定のパターンを埋め込むことで、このようなダウングレード試行を検出・防止するメカニズムを備えています。

  • 鍵更新 (Key Update): 長時間継続するTLSセッションでは、同じセッション鍵を使い続けることはセキュリティリスクを高めます。TLS 1.3 では、KeyUpdate メッセージを送信してセッション中に新しい鍵を導出し、利用することができます。これにより、フォワードシークレットがさらに強化され、鍵の漏洩による被害範囲を限定できます。

  • 初期データ保護の制限: 0-RTT で送信される初期データは、まだ完全なハンドシェイクが完了していないため、完全な Forward Secrecy が保証されません。これは、PSK が漏洩した場合に初期データが復号される可能性があることを意味します。そのため、機密性の高い初期データは 0-RTT で送信すべきではない、または限定的な用途に留めるべきです。

実装メモ

TLS 1.3 の高性能とセキュリティ上の利点を最大限に活用し、安定した実装を行うためには、以下の点に注意が必要です。

  • MTU/Path MTU の考慮: Client Hello メッセージは、key_sharepre_shared_key、その他の拡張を含めることで、TLS 1.2 よりも大きくなる可能性があります。特に、複数の鍵共有アルゴリズムやPSK IDを提示する場合、MTU (Maximum Transmission Unit) を超え、IPフラグメンテーションやPath MTU Discovery (PMTUD) の問題を引き起こす可能性があります。クライアント実装は、Client Hello のサイズを適切に管理するか、フラグメンテーションを許容できる構成とする必要があります。

  • HOL blocking 回避: TLS 1.3 自体はTCPの上に位置するため、TCPのHead-of-Line (HOL) blockingを直接回避するものではありません。しかし、ハンドシェイクのRTT削減は、アプリケーション層での待ち時間を短縮し、結果的にアプリケーション全体のHOL blockingの影響を軽減します。実装者は、アプリケーション層のプロトコル設計において、TLS 1.3 の低レイテンシ特性を活かすことを検討すべきです(例: HTTP/3 の QUIC は TLS 1.3 をベースに HOL blocking を回避)。

  • キュー制御と優先度: 0-RTT データは早期に送信されるため、サーバー側で通常のアプリケーションデータとは異なるキューイングや処理優先度を検討することが可能です。しかし、リプレイ攻撃のリスクを考慮し、0-RTT データが冪等な処理に限定されているか、または適切なリプレイ保護が施されていることを確認する必要があります。

  • 鍵共有グループの選択: TLS 1.3 では、楕円曲線(Curve25519、secp256r1など)に基づく鍵共有グループが一般的に使用されます。実装は、セキュリティとパフォーマンスのバランスを考慮し、適切な鍵共有グループのサポートを推奨します。RFC 8446は、Curve25519とsecp256r1を必須とすることを推奨しています。

  • PSK (Pre-Shared Key) 管理: 0-RTT およびセッション再開の効率は、PSK の安全かつ効率的な管理に依存します。サーバーは、PSK を生成し、セッションチケットとしてクライアントに発行し、その後の接続で検証するメカニズムを堅牢に実装する必要があります。

まとめ

RFC 8446 で標準化された TLS 1.3 は、セキュリティ、パフォーマンス、プロトコル簡素化の点で、従来の TLS バージョンから大きな進歩を遂げました。特に、1-RTT/0-RTT ハンドシェイクによる接続確立の高速化、Forward Secrecy の強制、脆弱な暗号スイートの排除は、現代のインターネット通信の安全性を高める上で不可欠です。実装にあたっては、0-RTT のリプレイ攻撃リスクへの対応や、Client Hello サイズの最適化、適切な鍵共有グループの選択など、RFC が規定する詳細なガイドラインに厳密に従うことが重要です。これにより、より堅牢で高速なセキュア通信環境の構築が可能となります。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました