⑩TLS 1.3 Handshakeプロトコルの続きです。
ClientHelloメッセージ
ClientHelloメッセージはTLS 1.3でも旧バージョンとほぼ共通です。
メッセージ本体にはセキュリティパラメーターと暗号化に関する情報を含めます。メッセージの末尾に拡張(Extention)を追加します。
uint16 ProtocolVersion;
opaque Random[32];
unit8 CipherSuite[2]; /* 暗号スイートのセレクター */
struct {
ProtocolVersion legacy_version = 0x0303; /* TLS 1.2を表すダミー */
Random random;
opaque legacy_session_id<0..32>;
Cipher_suites<2..2^16-2>;
opaque legacy_compression_methods<1..2^8-1>;
Extention extenstions<8..2^16-1>;
}ClientHello;
TLS1.3ではTLS 1.2以前のバージョンと比較して多くのフィールドが廃止されています(値が legacy_xxxx のフィールドはダミーで実質使われていません。このダミーフィールドはTLS 1.2以前との互換性維持のため残されており、この結果古いサーバーやファイアーウォールのようなネットワーク上のミドルボックスでの予期しない挙動を抑制することができます。)
TLS 1.3で使用されているフィールドは3だけです。(ProtocolVersion ,Random, CipherSuite)
ProtocolVersion フィールド
このフィールドはTLS 1.3では実質使用されておらず、旧バージョンとの互換性維持のため存在しています。フィールド値はダミーを表す legacy_version = 0X0303 = TLS 1.2 と同じになっています。(TLS 1.2以前ではRecordプロトコルとClientHelloの2か所にProtocolVersionの指定があり、様々な問題の原因になっていました。)
TLS 1.3ではExtentionにセットする値を使用してプロトコルバージョンのネゴシエーションを行います。
Random フィールド
TLS 1.2と同一。32バイトの暗号学的にランダムなデータを格納します。クライアントとサーバーの両方が提示します。この32バイトの値はランダム=無作為なので、ハンドシェイクの1回1回ごとのデータ列は統計学的に一意である、と言えます。
Session ID フィールド(TLS 1.3では廃止)
TLS 1.2で存在したSession ID フィールドは廃止されました。Session ID フィールドを使用していたSession Resumptionの仕組みがTLS 1.3 では全面的に刷新されたためです。
CipherSuite フィールド
TLS 1.2 と同様。クライアントがネゴシエーションを試みる際の暗号スイートを優先度順に指定します。暗号スイートは2バイトの識別子で表現されます。
Compression method フィールド(TLS 1.3では廃止)
圧縮により情報漏洩が発生する危険性はTLS 1.3以前から知られていました。圧縮が暗号解読に利用できるのは、暗号化されたデータをネットワーク上で確認しつつ、トラフィックの中身を攻撃者が変更できるためです。
攻撃者は暗号化する内容を少しずつ変化させることで、本来見えないはずのデータの一部に関するデータを入手できます。
TLS 1.3では旧バージョンでは圧縮方法を指定していたフィールド(legacy_compression_methods?)はゼロ=圧縮無し にセットされます。
TLS 1.2以前でClientHelloメッセージにあったフィールドの多くは暗号化する目的で拡張 Extension に移動されました。
以下はOpenSSL 1.1.1DのClientHello メッセージ例です。(旧バージョンに関する一部パラメーター等は省略)
Handshake protocol: ClientHello
Version: TLS 1.2
Random: xxxxxx...(32ビットのランダム値)....xxxx
Session ID: xxxx...(原書では34ビット(hex記載).....xxxx
Cipher Suites
Suite: TLS_AES_256_GCM_SHA384
Suite: TLS_CHACHA20_POLY1305_SHA256
Suite: TLS_AES_128_GCM_SHA256
Compression Methods
Method: null
Extensions
Extension: server_name
Name: example.com
Extension: supported_groups
Group: x25519
Group: secp256r1
Group: x448
Group: secp521r1
Group: secp384r1
Extention: signature_algorithms
Algorithm: ecdsa_secp256r1_sha256
Algorithm: ecdsa_secp384r1_sha384
Algorithm: ecdsa_secp521r1_sha512
Algorithm: ed25519
Algorithm: ed488
Algorithm: rsa_pss_pss_sha256
Algorithm: rsa_pss_pss_sha384
Algorithm: rsa_pss_pss_sha512
Algorithm: rsa_pss_rsae_sha256
Algorithm: rsa_pss_rsae_sha384
Algorithm: rsa_pss_rsae_sha512
Algorithm: rsa_pkcs1_sha256
Algorithm: rsa_pkcs1_sha384
Algorithm: rsa_pkcs1_sha512
Extention: supported_Versions
Version: TLS 1.3
Extention: psk_key_exchange_modes
Mode: psk_dhe_ke
Extention: key_share
Key: Share Entry
Group: x25519
Key Exchange: xxxxx...(32ビットのkey値)....xxxx
ServerHelloメッセージ
サーバーはクライアントとのネゴシエーション時に ServerHelloメッセージで応答を返します。ServerHelloメッセージにはクライアントとのハンドシェイク完遂に必要な情報と、選択したプロトコルバージョン、暗号スイートをクライアントに返すために使用します。
ServerHelloの例①
struct {
ProtocolVersion legacy_version = 0x0303 ; /* TLS 1.2 を示すダミー */
Random random;
opaque legacy_session_id_echo<0..32>;
CipherSuite cipher_suite;
unit8 legacy_compression_method = 0;
Extension extensions<6..2^16-1>;
} ServerHello;
ServerHelloメッセージのRandomフィールドはTLS 1.2以前では毎回のハンドシェイクを一意なものとするためにサーバー側が用意する情報をセットするフィールドでした。しかし、メッセージ構造を変更せずに新しい機能を実装するために後付けて別な情報も追加できるようになりました。
一例として後述するHelloRectryRequestメッセージに利用する特別な乱数情報の格納があります。
また、通常のハンドシェイクにおいてもダウングレード攻撃からの保護に利用されます。具体的にはTLS 1.3に対応しているサーバーがTLS 1.2のネゴシエーションをする際はこのRandomフィールドの末尾8バイトを次の特別な値にセットします。
44 44F 57 4E 47 52 44 01
上記メッセージはサーバーがTLS 1.3対応していることをクライアントに伝えます。
TLS 1.1以前の旧バージョンのネゴシエーションをしている場合でも下記のように末尾の値は異なりますが同様に行います。
44 4F 57 4E 47 52 44 00
ServerHelloメッセージを受け取ったクライアントはRandomフィールドの末尾8バイトを検査し、上記のいずれかであれば(=TLS 1.3対応しているのにT.S 1.2 or 1.1でネゴシエーションしようとしていることになる=ダウングレード攻撃の可能性があるので?)ハンドシェイクを中止しなければなりません。
以下のServerHello メッセージ例は、当記事中の ClientHelloメッセージへの回答例です。サーバーの決定した接続のためのパラメーターをクライアントに返す等の処理をしています。
ServerHelloの例②
Handshake Protocol: SErverHello
Version: TLS 1.2
Random: xxxxxx...(ClientHelloとは異なる32ビットのランダム値)....xxxx
Session ID: xxxx...(ClientHelloと同一の34ビットの値).....xxxx
Cipher Suite: TLS_AES_256_GCM_SHA384
Compression Method: null
Extensions
Extension: key_share
key Share Entry
Group: x25519
key Exchange: xxx...(32ビットのキー値)...xxxx
Extension: supported_versins
Version: TLS 1.3
TLS 1.3のServerHelloメッセージはTLS 1.2に比べ簡素化されています。いくつかのフィールドを暗号化できる後続のメッセージへ移動したためです。たとえばServerHelloの例①で、TLS 1.2で存在したSession Resumptionで利用されるSession IDフィールドがありますが、これはstruct内でopaque legacy_session_id_echo<0..32>; のechoとあるようにClientHelloに含まれるsession_idをエコー(そのまま返して)でセットしています。
同様に、ServerHelloの例①のProtocolVersion legacy_version = 0x0303 ; もダミーで実際のプロトコルのバージョンは Extension内にあるsupported_versions (例では Version: TLS 1.3)が正しいバージョンです。
HelloRetryRequestメッセージ
TLS 1.3のクライアントは通信開始時にサーバーが対応可能な鍵交換アルゴリズムを推測します。
鍵交換アルゴリズムはたくさん存在(新しいものも随時追加されるので?)しているので推測が正しくない場合があります、この場合クライアントが提示した鍵交換アルゴリズムをサーバー側では処理できないので、別な鍵交換アルゴリズムの提示を要求するために、HelloRetryRequestメッセージを送信します。
HelloRetryRequestメッセージの構造はServerHelloメッセージと全く同一です。ただしRandomフィールドに下記の特別な値をセットします。
※これもTLS 1.2以前との互換性委Jの観点での実装です。
CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
クライアントはServerHelloメッセージを受け取った際、Randomフィールドが上記のHelloRetryRequestメッセージを示す値かどうかを確認しなければなりません。上記の値と合致するならメッセージはServerRetryRequest、合致しないなら ServerHelloメッセージと判断ができます。