あどけない話

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

TLS 1.3 開発日記 その6 Pre Shared Key

これは、http2 Advent Calendar 2016の13日目の記事です。

今日は、TLS 1.3 の第三番目のハンドシェイクである PSK (Pre Shared Key)について説明します。

みなさんは、Pre Shared Key という言葉から何をイメージしますか? 多くの方は、通信路の暗号化に使う鍵をあらかじめ共有することだと思うのではないでしょうか?

TLS 1.2 での Pre Shared Key は、RFC4279で定められています。なんとなんと、共有している鍵の主目的は、通信路の暗号化ではなく、通信相手の認証です。ここを間違っていると、全然話が理解できないので、間違っていた人は認識を新たにして下さい。

TLS 1.3 での PSK は、セッションの再開(resumption)と統合されました。ややこしいのですが、TLS 1.3 で PSK という場合、次の2つの意味があります。

  • External PSK: 手作業で共有した鍵を使って、お互いを認証すること
  • Resumption PSK: 前のセッションで共有した鍵を使って、サーバ認証(および前のセッションがクライアント認証をしていたらクライアント認証)を省略すること

この理解を間違うと、まったく意味不明なハンドシェイクなので、注意して下さいね。

Resumption PSKの場合、最初はフルハンドシェイクする必要があります。そのやりとりをドラフトから抜粋します。

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

ここで、大切なのは NewSessionTicket です。Application Data用の暗号路が確立したら、いつでもサーバからクライアントへ送ることができます。

TLS 1.3 では、以下の2つも統合されています。

  • サーバが前のセッションの状態を保持する Session ID による resumption
  • セッション情報をサーバのみが復号化できる状態でクラアントに送って、サーバは状態を持たない Session ticket による resumption

NewSessionTicketには、十分な長さのデータが格納できますので、それが Session ID であっても、Session ticket であってもよい訳です。

PSK resumption の手続きもドラフトから抜粋します。

ClientHello
 + key_share*
 + psk_key_exchange_modes
 + pre_shared_key         -------->
                                                ServerHello
                                           + pre_shared_key
                                               + key_share*
                                      {EncryptedExtensions}
                                                 {Finished}
                          <--------     [Application Data*]
{Finished}                -------->
[Application Data]        <------->      [Application Data]

サーバが証明書を送ってないこと、つまりクライアントがサーバの認証を省略することがわかるでしょう。

PSKの情報を送る pre_shared_key 拡張は構造が複雑なので抜粋しませんが、クライアントは PSK のリストを送り、サーバが選んだ PSK が何番目かを返すと理解していれば十分です。クライアントが送る PSK のリストですが、ほとんど用途の場合その長さは1であると思われます。

Cipherスイートは、ClientHelloに入っていますので、前のセッションと異なる値を選んでもいいのですが、Hashが変わると Session ticket の検証に失敗します。

鍵交換は、psk_key_exchange_modes 拡張で制御します。以下の2つのモードがあります。

  • PSK only - 共有している鍵だけを種に使って暗号路の鍵を生成
  • PSK with (EC)DHE - 共有している鍵に加えて、新たに (EC)DHE で共有した鍵を種に使って暗号路の鍵を生成。こちらは前方秘匿性を持つ

ここまで読むと、TLS 1.3 開発日記 その2で述べた cipher スイートからサーバ認証と鍵交換が切り離された理由が納得できるのではないでしょうか?