あどけない話

インターネットに関する技術的な話など

TLS 1.3 開発日記 その4 フルハンドシェイク

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