これは、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です。