きままにものづくり

日々の気付いたことなんかを書いてます。

TLS(SSL)のハンドシェイクの安全性について

今年は色々と問題のあったTLSについてです。
この記事では、TLSがどうのような暗号技術を用いてセキュアな通信を実現しているのかを説明します。

TLSとは

TLSとはTransport Layer Securityのことであり、現在は1.2が最新のバージョンで1.3を策定しているところです。
TLSが実現したいのはセキュアな通信の確立です。セキュアな通信とは以下の3つの性質を満たす通信のことです。

  1. 通信内容を秘匿できる
  2. 通信内容の改竄を検知できる
  3. 通信相手を特定できる

これらの性質を暗号技術を組み合わせることで実現します。詳しい実現方法は後で説明します。

TLSは大きく、Record layerとハンドシェイクの2つに分かれます。Record layerでは共通鍵暗号を、ハンドシェイクでは公開鍵暗号を主に用いています。
ハンドシェイクで、上の1,2,3の全ての性質を満たしながら秘密情報の共有を行います。Record layerでは、ハンドシェイクにより「3.通信相手の特定」を行ったので、共有した秘密情報を用いて1,2の性質を満たしながら実際の通信を行います。
公開鍵暗号だけでもセキュアな通信を確立することはできます。しかし、暗号・復号に多くの時間を必要とします。共通鍵暗号公開鍵暗号よりも高速に処理を行うことができます。公開鍵暗号共通鍵暗号の両方を使用することで安全かつ高速な通信を実現しています。
Record layerの安全性は(速度を無視すれば)証明可能なのに対し、ハンドシェイクの安全性の証明はまだ完全にはされていません*1。ただし、機能を制限すれば安全であることは証明されています。
Record layerの安全性もとても大事ですが、この記事ではハンドシェイクの安全性にのみ注目します。

ハンドシェイクの概要

暗号として意味のあるやりとりのみを取り出すと、TLSのハンドシェイクは以下のようになります。
f:id:even_eko:20141221155008p:plain
この処理は説明しやすくするためにかなり簡略化されています。また、本来ならば鍵交換に使用するアルゴリズムをユーザが選択することができるのですが、今回はDiffe-Hellmanに固定して説明します。

ハンドシェイクで行いたいことは秘密情報の共有、つまり鍵交換です。ただし、Diffie-Hellmanを用いた鍵交換だけでは「2.通信内容の改竄が検知できる」、「3.通信相手の特定ができる」の2つを満たすことができません。2に対してはディジタル署名を、3に対しては信用できる第三者と行う認証(Certification)を使用することで実現します。

鍵交換

TLSにおいて鍵交換に使用されるアルゴリズム複数ありますが、この記事ではDiffie-Hellmanのみを説明します。
Diffie-Hellmanの処理は以下のようになります。
f:id:even_eko:20141221163201p:plain
 \mathbb{Z}_qはq(=p-2)までの整数集合を示し、pは素数、gは 2 \leq g \leq p-2を満たす整数とします。modは剰余をとる演算とします。
kが同じ値であることを確認します。
 k \equiv T_s^{t_c} \equiv g^{t_s*t_c} \equiv T_c^{t_s}\ (mod\ p)
お互いにランダムな値を生成しあうことで、秘密情報を共有しています。
ここで攻撃者が知れる情報は、 (p,g,T_s,T_c)となります。
これらの情報から g^{t_s*t_c}を計算することをDH問題と呼びます。
DH問題は離散対数問題に帰着することができます。今のところ離散対数問題を効率的に計算する方法は見つかっていないので、Diffie-Hellmanは安全であるされています。ただし、離散対数問題に効率的な計算方法が存在しないということは証明されていません。

第三者に漏らさずに鍵を交換できることは確認できましたが、この方法には中間者攻撃を防げないという問題点があります。
f:id:even_eko:20141221171233p:plain
上のように中間に攻撃者が入ることができてしまいます。ClientはServerと秘密情報を共有しているつもりが実際はAdversaryと共有しています。しかし、Diffie-Hellmanではこれを検知することができません。
そこで、ディジタル署名を用います。

ディジタル署名

TLSディジタル署名にはいくつかのアルゴリズムが用意されていますが、今回はアルゴリズムを特定せずにディジタル署名がどのような機能を実現するものなのかを説明していきます。
ディジタル署名は、誰がそのデータを生成したかを証明するための技術です。実際の処理はサイファー・テック株式会社のサイトに載っている以下の図がとても分かりやすいです。
f:id:even_eko:20141221172249g:plain
左側の署名を行う処理がSIG.Signに、右側の署名が正しいかどうかを確認する処理がSIG.Vfyに対応します。
署名の処理を足すと以下のようになります。
f:id:even_eko:20141221174252p:plain
transとはtranscriptの略であり、今までの通信記録を表します。
署名を送ることで、攻撃者は T_sを改竄できなくなります。Client側から送られる情報の改竄確認はFinishMessageであるfin_cで行っています。秘密共有情報であるkを分からないと fin_cを計算することはできないため、攻撃者はClientの送信情報を改竄することもできません。

これで、1と2を実現することができましたが、3はまだです。3を実現するために認証(Certification)を使用します。

認証(Certification)

認証(Certification)ではディジタル署名そのものを用いて、通信相手を特定します。
ディジタル署名では署名を生成した人が公開鍵を送信していましたが、この公開鍵を信頼できる第三者に渡します。そして、公開鍵の代わりに証明書を通信相手に送ります。受信者はこの証明書を用いて信頼できる第三者から対応する公開鍵をもらいます。この公開鍵で署名の正しさを確認できた場合は、その署名は秘密鍵を有する人しか生成できないので、通信相手は署名を作成した本人であることが分かります。
実際にはPKI(Public Key Infrastructure)と呼ばれます仕組みを用いて行われます。
ハンドシェイクの概要のところで挙げた図と同じになりますが、認証の機能を考慮した処理は以下となります。
f:id:even_eko:20141221155008p:plain
cert_sが証明書を示し、getというメソッドが公開鍵を問い合わせる処理となります。
TLSではClientにはほとんどの場合ブラウザがきます。ブラウザ毎に認証を行うのは現実的ではないので、多くの場合Client側の認証は省略されます。

最後に

TLSは鍵交換、ディジタル署名、認証(Certification)の3つを用いてセキュアな通信を実現しています。
TLSは古くに実用面から開発されたプロトコルであるため、暗号理論的に安全性が証明されていませんでした。しかし、2012年にJagerらが出した論文をきっかけに、多くの部分の安全性が証明されました。
実際に報告される脆弱性は実装による問題がほとんどです。そのため、理論的な証明の価値は低く思われるかもしれませんが、そんなことはありません。理論的に安全性が証明されることで、その安全性を担保しつつ効率化を図ることもできますし、よりセキュリティ要求の高いプロトコルを構築することもできます。

TLS脆弱性により眠れない夜を過ごした方がいるかもしれませんが、温かい目でTLSの発展を見守っていきましょう。