ぼちぼち日記

おそらくプロトコルネタを書いていることが多いんじゃないかと思います。

パンドラの箱?TLS鍵交換の落とし穴、KCI攻撃とは何か

1. 初参加のセキュリティキャンプ

先週ですが、講師としてセキュリティキャンプに初めて参加しました。
担当したのは高レイヤーのセッションで、TLSとHTTP/2の講義を合計6時間、まぁ大変でした。講義の時間配分、分量などの検討が十分でなかったため、本番では事前に準備していた講義内容の一部しかできず、ホント反省しきりです。せめての救いは、今回作った講義資料にたくさんのfavを頂いたことです。ありがとうございました。

講義では、学生の方々が短い時間ながら難しい演習に真面目に取り組んでくれました。質疑なども皆受け答えがしっかりしていて、技術的にもレベルが高い回答も多く、非常に驚きました。これだけ優秀な10代、20代の若者が、全国各地から毎年50人も集まるのを実際に見ると、彼らの将来が楽しみです。これまで10年以上継続してこのような活動を続けきた成果でしょう。私自身、とても良い経験をさせていただきました。セッションオーナーの西村さん、はせがわさん、講義を手伝っていただいたチューター、運営スタッフの方々、本当にありがとうございました。

2. TLSに対するKCI(Key Compromise Impersonation)攻撃とは何か?

講義準備に追われていた8月10日、ワシントンでセキュリティに関するワークショップ USENIX WOOT'15 が開かれていました。
その会議では、一つ面白い発表と論文「Prying Open Pandora's Box: KCI Attacks against TLS (開いたパンドラの箱を覗く: TLSに対するKCI攻撃)」が公開されました。 パンドラの箱を覗くとは、何やら意味深なタイトルです。

https://www.usenix.org/conference/woot15/workshop-program/presentation/hlauschek

KCI攻撃は、 Key Compromise Impersonation攻撃の略です。日本語で「危殆化鍵による成りすまし攻撃」と訳すのでしょうか。このKCI攻撃の論文、読んでみるとなかなか非常に面白い。一つ穴を踏ませることに成功すれば、見事にTLSの中間者攻撃が成功します。幸いこの攻撃で使われる機能をサポートしているTLSクライアントが現状少ないため、今のところ世間であまり大騒ぎになっていません(古いMacOSSafariが影響受けます)。これまで気づかれていなかったTLSの鍵交換仕様のすき間を突いた攻撃であることから、「パンドラの箱を覗く」というタイトルがついたのではないかと個人的に思っています。

この攻撃を理解すると、TLSクライアント認証とはどういうものか、TLS鍵交換とはどういうものなのか、その仕組みが明確になります。そこで今回「SSL/TLSの基礎」講義の補習エントリーとして、このKCI攻撃がどういうものなのか、解説を書いてみたいと思います。

2.1 TLSクライアント認証のしくみ

セキュリティキャンプでの講義「SSL/TLSの基礎と最新動向」では、説明が複雑になるのでTLSクライアント認証は説明の対象外にしていました。

一般的に広く使われているhttpsサーバのTLS通信は、サーバ証明書を使ってTLSサーバの正当性を検証する一方向のものです。この場合、どのクライアントから接続を許すかどうかTLSレイヤーでは認証・認可を行っていません。一方TLSのクライアント認証は、サーバ・クライアント双方向でTLS接続の認証・認可を行う方法です。

TLSクライアント認証は、非常に強力なセキュリティ通信ですが、証明書の発行・更新手続きが煩雑であったり、クライアント環境(OS・ブラウザ)で証明書管理の仕組みが統一されていないなど導入や運用のハードルが高く、現状それほど広く利用されていません。また、TLSの接続途中でクライアント認証に移行するような場合、TLSハンドシェイクのrenegotiationが必要となり、複数のTLS接続を集約するSPDYやHTTP/2の通信とはあまり相性が良くありません。
ただ、SSL3.0からある古い機能であるため、基本的な機能はどのブラウザー環境でも使えるようになっています。

2.2 クライアント認証時のTLSハンドシェイク

通常のサーバ認証だけのTLS通信と、クライアント認証をする通信とではどう違うのでしょうか?
TLSハンドシェイクのシーケンスを見てみると違いがわかります。クライアント認証を行う前提として、TLS通信を行う前にクライアント側に認証局から発行されたクライアント証明書と秘密鍵の鍵ペアがクライアントにインストールされていることが必要です。
クライアント認証時に必要なTLSハンドシェイクメッセージを赤字で示します。

サーバ側は、クライアント証明書が必要であることをCertificateRequestでクライアントに伝えます。クライアントはその要求を受け、自身が持つ証明書をサーバに送信します。さらに送信した証明書が自身が保持する正当なものであることをサーバに示すため、それまでのハンドシェイクデータを秘密鍵で署名し、CertificateVerifyでサーバに送信します。サーバはクライアントの証明書とCertificateVerifyの値を検証し、クライアントが正当な鍵ペアを持つ通信相手であることを確認します。

サーバは、CertificateRequestを使ってクライアントに証明書を要求する際、鍵交換手法に応じて必要な証明書のタイプを指定します。TLS1.2では、図中の表の通り7種類規定されています。今回KCI攻撃で利用されるのは、fixed が含まれる証明書タイプです。このタイプを選択すると、サーバ・クライアント双方の証明書に含まれている(固定的で変わらない)公開鍵を用いて鍵交換を行います。その仕組みの詳細について次節で説明します。

2.3 fixed_ecdhによる鍵交換

前述した通りサーバがfixedタイプのクライアント証明書を要求すると、証明書に記載されている固定の公開鍵を利用して鍵交換(DH/ECDH)を行います。他方、最後にE(Ephemeral:一時的)が付くDHE/ECDHE は、セッション毎に毎回異なる鍵を共有する方式です(PFS:Perfect Forward Securecy)。

論文では、www.facebook.comを使った攻撃が例示されています。そこでfacebookの証明書で公開鍵の情報を見てみましょう。

この赤枠で囲った部分が、証明書の公開鍵の情報を表している部分です。楕円曲線の種類と65バイトの公開鍵情報が書かれています。これを見ると*.facebook.comは、楕円暗号を用いたECDSA証明書です。その公開鍵はECDHの鍵交換で利用可能です。本来この証明書を鍵交換に使うためには、 X509 KeyUsage のフィールドにKeyAgreementフラグが立ってないと使えません。しかし、現実にそこまで厳密にチェックするクライアントは少ないようです。論文では www.facebook.com の証明書にKeyAgreementのフラグが入っているとの指摘がありましたが、今回確認したところこの証明書にはそのフラグはたっていませんでした。

fixed_ecdhによる鍵交換では、下図の通りTLSハンドシェイクの途中で相互の証明書を交換し、証明書に掲載されている公開鍵とそれぞれが持つ秘密鍵を組み合わせて、同一のPreMasterSecretを生成します。

その後、この相互で共有されたPreMasterSecretとClient/ServerHelloで交換した乱数と合わせて、実際のアプリデータを暗号化する共通鍵やMAC、初期ベクトルで利用する鍵を作ります。
このPreMasterSecretをいかに安全に共有できているかが、TLS通信のセキュリティを確保するキモの部分であると言えるでしょう。

3. KCI攻撃の仕組み

KCI(危殆化鍵による成りすまし)攻撃は、文字通り危殆化されたクライアント認証鍵を利用してサーバに成りすまし、中間者攻撃を成功させる方法です。そのステップを見ていきましょう。

攻撃によって成りすましの対象となるサーバは、必ずしもクライアント認証を使っている必要はありません。ただしサーバ証明書はDSA/ECDSA証明書で、クライアント側は fixed の証明書タイプを利用したTLSクライアント認証をサポートしていることが条件です。

そして、悪意のある中間者(Evil)が生成したクライアント証明書を何らかの方法でクライアントにインストールするトラップが必要です(後述)。これが成功した時点で、攻撃者がクライアント証明書の秘密鍵を持っていることになるので、「危殆化された鍵」と名付けられているわけです。

次にステップ毎に見事なKCI攻撃を見ていきます。ここでは論文に合わせて https://www.facebook.com/ サーバを題材にしてみます。4つのステップで攻撃を成功させます。

3.1 攻撃者がサーバ証明書を入手

これは簡単です。公開されているサーバの証明書はTLS接続すればすぐ入手できます。

サーバの秘密鍵は、厳重に守られているので簡単に入手できませんが、今回の攻撃はサーバの秘密鍵が入手できなくても、公開されているサーバ証明書だけで正当なサーバに成りすまして中間者攻撃が成功するものです。

3.2 クライアント証明書の入れ込み

次に攻撃者は、あらかじめ攻撃用のクライアント証明書と秘密鍵のペアを生成しておきます。この証明書は、後で攻撃者が要求するものなので、特に正式な認証局から発行された証明書である必要はありません。ただし後で鍵交換で使うサーバ証明書と同じ形式(DSA/ECDSA)であることが必要です。

この攻撃用のクライアント証明書の鍵ペアを如何にクライアントに意識せずにインストールさせることができるのか、ここがハードル高いステップです。論文では、iOSではメールで簡単にインストールできたり、Androidアプリなどからも比較的容易にインストールできるトラップが紹介されています。クライアント証明書のインストールはあまり普段使わない機能なので、まだまだ未知の穴があるかもしれません。

この仕込みが成功し、中間者攻撃の前までになんらかの方法でクライアント証明書と秘密鍵がクライアントにインストールされていることが攻撃の条件になります。

3.3 正当なサーバに成りすましてTLSハンドシェイク

さぁ、ここから本番です。
クライアントは 、攻撃者が作成した不正なクライアント証明書がインストールされているものとは知らず、https://www.facebook.com/にアクセスします。攻撃者はネットワーク経路途中で中間者攻撃を仕掛けます。

まず www.facebook.com に成りすましてTLSハンドシェイクを行います。その際サーバ側がServerHelloで選択する暗号方式は、証明書の固定鍵を使う DH または ECDH の鍵交換を行うものを選択します。後述する通り、DHE/ECDHEではサーバの秘密鍵が必要なため攻撃は成功しません。攻撃者は、事前に入手した www.facebook.com のサーバ証明書を送信し、fixed_ecdhタイプのクライアント証明書を要求します。通常 www.facebook.com はクライアント認証することはありませんが、この時点ではクライアントにはわかりません。

クライアントは、攻撃者からの要求に応じてクライアント証明書を送信し、その秘密鍵で鍵交換を行います。おそらくクライアントは、サーバの秘密鍵を持ってなければこの後のTLSハンドシェイクは失敗するはずだと思い込んでいることでしょう。

3.4 同一PreMasterSecretの生成

ところがどっこい、攻撃者はクライアントの秘密鍵を保持しています。
攻撃者は、クライアント証明書の公開鍵とサーバの秘密鍵を使って鍵交換を行うという真面目なことはせずに、既に保持しているサーバ証明書とクライアントの秘密鍵を使ってクライアントと同じ手順で全く同一のPreMasterSecretを生成します。

クライアントと攻撃者間で同一のPreMasterSecretが共有できていれば、後はいかようにもTLSハンドシェイクを偽造して完了することができます。結果、サーバの秘密鍵を使うことをせずに www.facebook.com の成りすまし、中間者攻撃に成功です。

いやぁー、見事できれいです。
前述の通り、危殆化されているクライアント証明書の鍵ペアをどういうトラップでクライアントに入れ込むかというのが課題ですが、TLSの鍵交換しているようでしていない、PreMasterSecretさえ共有できちゃえば勝ちというKCI攻撃の手法は、ホント目から鱗でした。

幸い fixed_ecdh/dhに対応したクライアントが現状ほとんどないので、この攻撃は現状それほど脅威として騒がれていません。論文では、Mac OS X 10.5.3 以前のSafariで攻撃に成功したと報告されていますが、現在は機能が無効化されています。しかし論文ではこの攻撃が知られていないと将来的に実装されて危なくなると警告しています。本当は攻撃を再現した状況を実際に試して載せたかったのですが、攻撃の影響を受けるクライアントが手元になく残念です。今後このような合わせ技攻撃の組み合わせによって思いっきりTLSの穴ができるような別の攻撃手法が出てくるかもしれません。

4. TLS1.3ではどうなる?

講義でも後半触れましたが、現在仕様策定中のTLS1.3ではどうなるでしょうか?

まず鍵交換は、一時鍵を使うDHE/ECDHEのPFSしかサポートされないのでKCI攻撃は無理です。PFSでは、ServerKeyExchangeで送信する公開鍵にサーバが署名するのでサーバの秘密鍵がないと署名検証でクライアントに攻撃がばれます。

またTLS1.3ではサーバ側も常に CertificateVerifyを送る Server Sign の要件が新たに入る予定です。これによって、ハンドシェイク途中でサーバ証明書の鍵ペア所有の検証が行われることになり、サーバの秘密鍵なしに中間者攻撃が成立するといった類似の攻撃がTLS1.2より困難になるでしょう。

個人的には、総当たりっぽく平文を判定するOracle攻撃なんかより、このような一つのほころびで全体のセキュリティを台無しにさせるこのKCI攻撃手法は、ある意味美しさを感じてしまいます。これで皆さんのTLSクライアント認証と鍵交換の仕組みの理解が少しでも深まれば幸いです。

5. 明日は YAPC

TLSとは全然関係ないですが、明日(8/22) YAPC Asia Tokyo 2015で「どうしてこうなった? Node.jsとio.jsの分裂と統合の行方。これからどう進化していくのか? 」のセッションの後半で古川さんと対談します。この半年余り、Node.jsプロジェクトの分裂と統合という流れの真っただ中にいた身として、今回の騒動でオープンソースのガバナンスの姿、その一つの形が見えてきた気がします。なかなか経験できない貴重な体験を皆さんにお伝えできたらと思っています。朝10時からと若干早い時間からのスタートですが、皆さんの参加をお待ちしています。

以上、セキュリティキャンプの補習講義でした。