あどけない話

Internet technologies

セッション再開に関するTLS1.2と1.3の違い

これまでTLS 1.3とセッションID方式は実装したことがあったが、この経験だけではTLS 1.2に対するTLS 1.3の利点に気づいていなかった。この二ヶ月の間に、セッションチケット方式を実装し、また引き継いだTLS 1.2のコードを大幅にリファクタリングした過程で、セッションの再開は、TLS 1.2よりもTLS 1.3の方が安全であると気づくことができた。備忘録として安全である理由を書いておく。

以下は、セッションID方式にもセッションチケット方式にも、共通している性質である。説明の都合で、セッションチケット方式を取り上げる。

TLS 1.2

TLS 1.2用のセッションチケット方式は、RFC 5077で定義されている。以下にRFC 5077からTLS 1.2のフルハンドシェイクの図を抜粋する。

         Client                                               Server

         ClientHello
        (empty SessionTicket extension)-------->
                                                         ServerHello
                                     (empty SessionTicket extension)
                                                        Certificate*
                                                  ServerKeyExchange*
                                                 CertificateRequest*
                                      <--------      ServerHelloDone
         Certificate*
         ClientKeyExchange
         CertificateVerify*
         [ChangeCipherSpec]
         Finished                     -------->
                                                    NewSessionTicket
                                                  [ChangeCipherSpec]
                                      <--------             Finished
         Application Data             <------->     Application Data

NewSesionTicketはChangeCipherSpecの前に送られる。つまり、(セッションチケット自体はサーバしか知らない秘密鍵で暗号化されているが)通信自体は平文である。(ChangeCipherSpecが角括弧で囲まれているのは、ハンドシェイクメッセージではないという意味。)

サーバ認証を省略し、TLS 1.2ではメインシークレットを復元するための仕組みがセッションの再開である。再開の図も引用する:

         Client                                                Server
         ClientHello
         (SessionTicket extension)      -------->
                                                          ServerHello
                                      (empty SessionTicket extension)
                                                     NewSessionTicket
                                                   [ChangeCipherSpec]
                                       <--------             Finished
         [ChangeCipherSpec]
         Finished                      -------->
         Application Data              <------->     Application Data

フルハンドシェイクではクライントが先に(ハンドシェイクメッセージ全体のチェクサムである)Finishedを送るが、再開ではサーバが先に送る。

サーバは、再開時に再びNewSessionTicketを送ってもよい(MAY)。しかし、メインシークレットを変える方法はないので、同じメインシークレットを格納し、単に使用期間が伸びたチケットを発行することになる。OpenSSLのs_serverで試してみると、再開時にはNewSessionTicketを送ってこない。

このようにTLS 1.2では、セッションの再開を使うと、サーバ認証を省略できるものの、メインシークレットを更新する方法がなく、メインシークレットを複数のセッションで使い回すことになる。

TLS 1.3

TLS 1.3のフルハンドシェイクをRFC 8446から引用する:

          Client                                               Server

   Initial Handshake:
          ClientHello
          + key_share               -------->
                                                          ServerHello
                                                          + key_share
                                                {EncryptedExtensions}
                                                {CertificateRequest*}
                                                       {Certificate*}
                                                 {CertificateVerify*}
                                                           {Finished}
                                    <--------     [Application Data*]
          {Certificate*}
          {CertificateVerify*}
          {Finished}                -------->
                                    <--------      [NewSessionTicket]
          [Application Data]        <------->      [Application Data]

角括弧で囲まれたメッセージは、暗号化されていることを表しているので、NewSessionTicketは暗号化されて送信されことが分かる。

次にセッションの再開の図も引用するが、説明の都合上NewSessionTicketを書き加える:

   Subsequent Handshake:
          ClientHello
          + key_share*
          + pre_shared_key          -------->
                                                          ServerHello
                                                     + pre_shared_key
                                                         + key_share*
                                                {EncryptedExtensions}
                                                           {Finished}
                                    <--------     [Application Data*]
          {Finished}                -------->
                                    <--------      [NewSessionTicket]
          [Application Data]        <------->      [Application Data]

このセッションでの(複数の)メインシークレットは、pre_shared_keyに含まれる(前のセッションで受け取った)セッションチケットの情報と、key_shareを利用して生成された一時的な鍵から生成される。端的に言えば、前回のセッションとは異なるメインシークレットが生成される。よって、新たに発行するNewSessionTicketにも、新しいメインシークレットが格納される。このように、TLS 1.3では、各セッションで独自のメインシークレットが使用される。

まとめ

セッションの再開に関して、TLS 1.2よりもTLS 1.3の方が安全であると言う根拠をまとめると以下の通り:

  • TLS 1.2のNewSessionTicketは平文の通信路で送られるが、TLS 1.3では暗号路で送られる。
  • TLS 1.2では複数のセッション間で同一のメインシークレットを使うが、TLS 1.3ではセッションに固有のメインシークレットが使われる (重要)