【図解】TLSv1.3の仕組みとシーケンス ~QUICに向けた0-RTT, key_shareやHelloRetryRequest, NewSessionTicketとPSKの関係, コネクションとセッションの違い~

TLS バージョン 1.3 の概要、1.2 との違い

2018年8月に TLS バージョン 1.3 が RFC 8446 として公開されました。v1.2が2008年に公開されましたので、実に10年ぶりの新バージョンです。

バージョン 1.2 との違いは、大きく2つです。

  1. セキュリティ強度の高い暗号アルゴリズムを要求
  2. セッションのリネゴシエーションや再開に関する脆弱性のある方式を廃止し、セッション再開については新たな方式を採用
  3. ネゴシエーション(handshake)シーケンスの大幅な変更

1. の暗号アルゴリズムについては、ストリーム暗号(RC4)、CBCブロック暗号などの問題がある古い暗号アルゴリズムを廃止し、AEAD(認証付き暗号)方式が要求されるようになりました。また、2. については脆弱性のあったリネゴシエーションや圧縮、"Session ID" や "Session Ticket" を使ったセッション再開などが廃止となりました。厳密に言うと、Sessin Ticket は PSK(Pre Shared Key)と統合されました。詳細は後述します。

今回の話題のメインは "2" と "3"  についてですが、まず最初の話題は "3" について。TLS v1.3 のシーケンスの変更は、Google が開発した SPDY や QUIC の思想に影響されたものであり、さらに QUIC との融合を果たす予定の HTTP/3 へとつなげるためのものだと考えています。これらは全てセキュアかつ高速なWeb通信を目指し、最適なプロトコルを模索したプロセスでもあります。

Google は SPDY を開発した2009年頃から、RTT (Round Trip Time: 通信の往復時間)の影響を少なくすること(具体的にはネゴシエーションによる往復を極力少なくすること)が帯域を増やすよりも重要であることを主張してきました。SPDY や QUIC の開発、今回の TLS のシーケンス変更もその流れに沿うものです。

TLS v1.2 と v1.3 のシーケンスの比較

シーケンスを比較すると以下のようになります。

TLS v1.3 においてはデータ送信までのネゴシエーションの往復が1回減っているのが分かります。また、ネゴの途中から暗号化されていることも大きな特徴です。

key_share とは何か?

通信暗号化の元になる Server/Client Key Exchange はそれぞれ Server Hello, Client Hello の key_share という Extension(拡張領域)に移動され、Server Hello 以降のネゴの途中から通信が暗号化されるようになりました。(前述の図を参照下さい)

Hello Retry Request とは何か?

TLS 1.3 では Hello Retry Request という新たなメッセージが設けられました。今までは鍵交換は Client Hello と Server Hello のネゴシエーションの間に『方式』が決まり、その後に具体的な鍵交換が行われていましたが、1.3 からは最初の Client Hello に key_share で鍵交換のパラメータが入ったりします。

なので一発目は不発に終わる可能性もあります。その場合サーバは Hello Retry Request で受け入れられるネゴシエーション情報を送り、Client Hello は適切なパラメータに修正して再送します。

PSKによる新たなセッション再開方式

New Session Ticket とは何か?

先程のパケットキャプチャで、HTTP/2 の通信の後に TLS 1.3 の通信として『New Session Ticket』が表示されているの気付いたでしょうか。

これは TLS 1.2 においては RFC 5077 で拡張された『次回のセッション回復のためのチケット』を意味していました。

TLS 1.2 においては、セッション回復方法としてはもともと『セッション ID 方式』のみが規定されていましたが、この方式ではセッション ID を照合するためにサーバではキャッシュ情報をタイムアウトまで持ち続ける必要がありました。

RFC 5077 で拡張された『セッションチケット方式』の場合はサーバーのみが復号化できる形でクライアントに配布します。クライアントは次回コネクション時の Client Hello 内の『Extension: SessionTicket TLS』にこのチケットを提示し、サーバ側ではそれを読み込み、その内容に沿ったセッション回復を行います。このとき、厳密にはサーバの認証は行われませんが、サーバが正しくないとチケットを復号化できないのでセッション再開は不可です。

一方 TLS 1.3 においては、セッションチケットが PSK (Pre-Shared Key) と統合し、相互認証を行いつつ、セッションが再開されるようになりました。

PSK の本来の使い方は、(実装はほとんど見たことないですが、)鍵交換方式および認証方式として存在していました。すなわち、クライアントアプリケーションとサーバアプリケーションでお互いに PSK を手動でセットし、それをもって互いが正しい通信先だと解釈し(この PSK 認証方式の場合、サーバ証明書は不要となる)、さらにそれを素に共通鍵を生成するのです。

今回の改訂により、サーバはセッション中の New Session Ticket にて PSK を払い出し、次回セッション再開時にクライアントは PSK による認証をしつつ、PSK を素にしたセッション回復(Session Resumption)を行うことができるようになりました。つまり、今まで静的な PSK しか使えなかったのが、動的な PSK にも対応するようになったのです。

New Session Ticket メッセージは暗号化通信が開始された後であればいつ送ってもよいことになっています。

コネクションとセッションの違いとそれぞれの寿命(timeout)

TLS のコネクションは Client Hello から始まり、Alert (正常終了の場合は Alert: close_notify、異常終了の場合はそれ以外) で終了します。なので寿命は TCP コネクションとほぼ同じで、3 way handshake と fin,ack の分だけ TLS コネクションのほうが僅かに短いです。

一方、セッションはセッションキーを維持し続けるまでの時間のことで、RFC の仕様上は 24時間以内となっていますが、実装として例えば Apache + mod_ssl は 300 秒だったりします。

SSLSessionCacheTimeout 300

この時間内であれば、クライアントとサーバはセッションキーを保持し続けますので、新たなコネクション(Handshake)を確立する際にネゴの一部が省略可能です。

TLS v1.3 の PSK を使った 1-RTT でのセッション再開

TLS v1.3 における PSK を使った 1-RTT セッション再開のシーケンスを以下に示します。

"key_share" Extension(拡張)を使って PSK を提示します。ですがこれは挨拶代わりです。本命は次。

TLS v1.3 の PSK を使った 0-RTT でのセッション再開

TLS v1.3 の 0-RTT セッション再開のシーケンスを以下に示します。

1往路目で PSK と一緒にデータも送っちゃいます。0-RTT であることを示す early_data Extension も含まれています。これは今話題の HTTP/3 (HTTP over QUIC) で実装されることがほぼ決まっており、TLSv1.3 作成時でこの HTTP/3 を相当意識していたものと思われます。

パケットキャプチャを覗いてみる

TLS v1.2 のパケットキャプチャ

Server Hello のパケット内の表示で "Version: TLS 1.2" となっています。16進数だと "0x0303" です。

ところが、TLS 1.3 も同じ "0x0303" になっています。

今まででは SSLv3.0=0x0300, TLSv1.0=0x0301, TLSv1.1=0x0302, TLSv1.2=0x0303 という流れでしたが、TLS v1.3 では TLS v1.2 と同じく 0x0303 となっています。これについて TLS v1.3 の RFC 8446 の Appendix.D.1 に以下のように書かれています。

A TLS 1.3 client who wishes to negotiate with servers that do not support TLS 1.3 will send a normal TLS 1.3 ClientHello containing 0x0303 (TLS 1.2) in ClientHello.legacy_version but with the correct version(s) in the "supported_versions" extension. If the server does not support TLS 1.3, it will respond with a ServerHello containing an older version number. If the client agrees to use this version, the negotiation will proceed as appropriate for the negotiated protocol.

つまり、下位互換とのスムーズなネゴのために、このフィールドには TLS v1.2 を示す 0x0303 を格納しているのです。

流れとしてはまず、Client Hello の Supported_versions に TLS v1.3 を示す 0x0304 を格納しておきます。

この Extension: supported_versions は TLS v1.3 対応のサーバしか理解できません。対応していない場合はこのフィールドを無視して、TLS v1.2 で動作します。

もしサーバ側で TLS v1.3 を理解できる場合は、ServerHello の Supported_version に 0x0304 を格納します。

ここで TLS のバージョンを識別しているのです。

なお、上記パケットキャプチャでは TLS で暗号化している部分を以下のページの手法で復号化して表示しています。

【解析】https(SSL/TLS)をwiresharkで復号化する方法,ブラウザで見る方法
【解析】https(SSL/TLS)をwiresharkで復号化する方法,ブラウザで見る方法
Wireshark で https を復号化するには Wireshark は ...

シェアする

  • このエントリーをはてなブックマークに追加

フォローする