これは、http2 Advent Calendar 2016の8日目の記事です。
今回はTLS 1.3のフルハンドシェイクについて書きます。
TLS 1.2のフルハンドシェイク
おさらいとして、RFC5246からTLS 1.2のフルハンドシェイクの図を少し変更して抜粋します。角カッコは暗号化されていることを意味します。
Client Server
ClientHello -------->
ServerHello
Certificate
ServerKeyExchange
<-------- ServerHelloDone
ClientKeyExchange
ChangeCipherSpec
[Finished] -------->
ChangeCipherSpec
<-------- [Finished]
[Application Data] <-------> [Application Data]
TLS 1.3 と比較する意味で、特筆すべき点を挙げます。
- (EC)DHEの鍵交換は、サーバ側から始まります。ServerKeyExchangeにはサーバの(EC)DHE公開鍵の他に、証明書に対応する(RSAなどの)秘密鍵で署名した署名が入っています。これにより、クライアントはサーバを認証できます。
- ServerHelloDone は、ServerHelloシリーズが終わる空の目印で、認証等の役割はありません。
- 暗号化が始まる(正確には切り替わる)ことを告げる ChangeCipherSpec を送ります。定義としては、これは Handshake ではなく、独立な型を持つメッセージです。
- クライアントからの Application Data は、Finished の後に送ることも可能です(1RTT)。しかし、サーバからの Application Data の送信には必ず 1.5RTT かかります。
なお、Finishedは、これまでのハンドシェイクに対して、共有した鍵を使って HMAC を計算し、共有鍵および改ざんがないことを確認します。
TLS1.3 のフルハンドシェイク
TLS 1.3のドラフトからTLS 1.3のフルハンドシェイクの図を少し変更して抜粋します。波カッコは初期の共有鍵で、角カッコは後期の共有鍵で暗号化されていることを示します。
Client Server
Key ^ ClientHello
Exch | + supported_versions
| + key_share
v + signature_algorithms -------->
ServerHello ^ Key
+ key_share v Exch
{EncryptedExtensions} - Params
{Certificate} ^
{CertificateVerify} | Auth
{Finished} v
<-------- [Application Data*]
Auth - {Finished} -------->
[Application Data] <-------> [Application Data]
特筆すべき点は以下の通りです。
- 1.3以降のバージョンを決定するために Client Hello に supported_version 拡張があります。
- (EC)DHE の鍵交換は、key_share という拡張を使います。クライアントから始まることに注意して下さい。
- クライアントがサーバの証明書を使ってサーバを認証する場合、signature_algorithms拡張の送信が必須となってます。サーバ認証の値が、暗号スイートに含まれないからですね。
- Server Hello で返すほとんどの拡張は、暗号化されている Encrypted Extensions に入ります。たとえば、ALPN で何のプロトコルを選んだかは、暗号化される訳です。
- CertificateVerify は、Certificate に対応する秘密鍵で生成した署名です。サーバを認証するのが目的です。TLS 1.2 とは違い、鍵交換とは明確に切り離されています。
- Finishedは初期の共有鍵で暗号化されています。
- サーバは Finished を返した直後から、Application Data を暗号化して返せます(0.5RTT)。HTTP の通信はクライアントから始まりますが、メールのプロトコルはサーバ側から始まることが多いので、TLS 1.2 と顕著な差が出ます。クライアントからの Application Data の送信は、このハンドシェイクでは1RTTです。