ぼちぼち日記

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

華麗なる因数分解:FREAK攻撃の仕組み

1. はじめに

ちょうど今朝 OpenSSLをはじめとした様々なTLS実装の脆弱性の詳細が公表されました。

この InriaとMSRのグループは以前からTLSのセキュリティに関して非常にアクティブに調査・検証をしているグループで、今回も驚きの内容でした。
このグループは、TLSのハンドシェイク時の状態遷移を厳密にチェックするツールを開発し、様々なTLS実装の脆弱性を発見・報告を行っていたようです。
特にFREAKと呼ばれるOpenSSLの脆弱性(CVE-2015-0204)に関しては、ちょうど修正直後の1月初めに
Only allow ephemeral RSA keys in export ciphersuites
で見ていましたが、具体的にどのように攻撃するのかさっぱりイメージできず、あのグループだからまた超絶変態な手法だろうが、まぁそれほど深刻じゃないだろうと見込んでいました。
今回、その詳細が論文で発表されました。いろいろ報告されていますが、自分で攻撃手法を見つけられなかった反省を踏まえ、FREAKについて少し解説してみたいと思います。
まずは脆弱性の背景から。

2. 昔々の米国暗号輸出規制とSSL

その昔、国家安全保障上の理由で昔から暗号技術や暗号を使った製品などの利用や持ち出しは各国で規制されてきました。 Phil ZimmermannがPGPのコードを書籍化して合法的に米国外に持ち出したことは有名な話です。SSLも規制の対象で90年代後半は、日本からは低強度の暗号(40bitや56bit)しか使えない米国輸出版のブラウザーをダウンロードするよう制限されていたり、商用OSやアプリ等は、高強度対応の暗号ライブラリが削除されたものしか使えない状況でした。(たまにftp サイトで米国内専用のが置いてあったりしましたが)
その後2000年ぐらいに規制が緩和され、米国内外に関わらず最高暗号強度の通信が行えるようになりました。

米国外用に使える暗号にはEXPの記号が付いていて、今でも以下のように OpenSSL 実装されたままになっています。

$ openssl ciphers -v |grep EXP
EXP-EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=RSA  Enc=DES(40)   Mac=SHA1 export
EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512)  Au=DSS  Enc=DES(40)   Mac=SHA1 export
EXP-DES-CBC-SHA         SSLv3 Kx=RSA(512) Au=RSA  Enc=DES(40)   Mac=SHA1 export
EXP-RC2-CBC-MD5         SSLv3 Kx=RSA(512) Au=RSA  Enc=RC2(40)   Mac=MD5  export
EXP-RC4-MD5             SSLv3 Kx=RSA(512) Au=RSA  Enc=RC4(40)   Mac=MD5  export

なかなか古い仕様の機能を廃止できない後方互換性重視が今回の脆弱性の要因の一つでした。

3. ephemeral RSA(一時的RSA)

時はまだ米国暗号輸出規制が厳しかった時代、DESやRC4等の共通鍵暗号方式はSSLのハンドシェイクで動的に決定するので使える強度の暗号をクライアントで利用制限していました。一方、RSA等の公開鍵暗号の制限(512bit)はやっかいなものでした。

そのままでは、サーバ側で米国内からのクライアント向けには1024bit RSA、米国外からは512bit RSAと2種類のサーバ証明書を用意して使い分けないといけなくなります。まぁ面倒です。そこで使われたのが ephemeral RSA(一時的RSA)という方式です。

EXPが付いた輸出向けの暗号方式を利用する場合には、サーバの証明書(通常は1024bit)のRSA公開鍵を使わず、一時的に生成した512bit長の公開鍵をサーバからクライアントに送信して利用するというものです(送るときにはサーバの公開鍵で署名)。
クライアント側は、サーバから送られた512bit長の一時的RSA公開鍵を使って pre_master_secret を送り、両者で同じ master_secret を共 有することになります。
米国内のクライアントからはEXPでない暗号方式を利用するため通常と同じくサーバ証明書RSA公開鍵(1024bit)を使って pre_master_secretのやり取りを行います。これでサーバ証明書1枚だけで米国の暗号輸出規制に適合です。

本来この512bit長の一時的RSAによる鍵交換は、EXPの暗号方式だけに適応されるものでした。しかしOpenSSLでは、EXPでない暗号方式でも利用ができるよう独自に拡張を行っていました。今回のFREAK攻撃は、OpenSSLのこの独自拡張を突いたものでした。

この ephemeral な鍵交換方式は、現在 PFS(Perfect Forward SecurecySecrecy) としてTLSサーバの利用が推奨されています。もっともRSAではなくDH(DHE)やECDH(ECDHE)を利用する方式ですが、今回のFREAK攻撃ではPFSとして低強度RSAを使うことが、脆弱性につながってしまったという なんとも皮肉なものです。PFSの鍵長に関しては、DHEで512bitや1024bitを利用している場合もリスクが高く、2048bit以上が推奨されています。自分が使っているTLSサーバの暗号の鍵長は時代遅れになっていないか常に留意しておきましょう。

4. FREAK攻撃とは

FREAK攻撃は、Factoring attack on RSA-EXPORT Keys の略、輸出向けのRSA因数分解する攻撃です。
以下の4つの条件が必要です。

  1. MiTM(中間者攻撃) ができること
  2. サーバ側でEXPの暗号方式で ephemeral RSA(512bit)が使えること
  3. サーバ側で ephemeral RSAの鍵ペアが使いまわされていること
  4. クライアント側でEXP以外の暗号方式でも ephemeral RSA(512bit)が使えるよう拡張されていること(1.0.1kより前のOpenSSL)

3番目の条件ですが、RFC2246,D. 実装上の注意,D.1. 一時的 RSA 鍵には

512 ビットの RSA 鍵はそれほど安全ではないので、一時的 RSA 鍵はときどき変更するべきである。 典型的な電子商 取引アプリケーションにおいては、その鍵は一日ごと、または 500 トランザクションごと、できればそれ以上の頻度で変更することを提案する。

となっていますが、現状多くのサーバでは立ち上がるとずっと同じ一時的 RSA 鍵を使い続けるようです。nginxでは、
https://github.com/nginx/nginx/blob/master/src/event/ngx_event_openssl.c#L740-L742
にあるよう最初のコールバックで生成したものをずっと使い続けています。

また、TLS1.0の時代では一日ごとの更新が推奨でしたが、今回のFREAKでは EC2 を使って7時間で512bitのRSA鍵を解いてしまったようです。時代は変わってしまいました。

それでは FREAK攻撃をステップ毎に見てきましょう。

ステップ1 事前に一時的RSA因数分解

使いまわされることを前提に事前に一時的RSAの公開鍵を入手しておきます。後は力技、512bitの数字を因数分解して2つの素数を見つけます。

ステップ2 サーバ側を輸出用暗号方式でハンドシェイクするよう改ざん

クライアントとサーバの間に入り込み MiTM攻撃を仕掛けます。
ClientHelloで要求する CipherSuite を輸出用のものに置き換え、サーバ側が一時的RSAで鍵交換するよう仕向けます。
サーバ側は使いまわしの一時的RSA公開鍵を送ります。クライアントは、独自拡張してしまっているので輸出用暗号じゃなくても一時的RSAを使えるようになってます。

ステップ3 pre_master_secretの入手

クライアントから一時的RSAの公開鍵で暗号化した pre_master_secretが送られてきます。既に秘密鍵が事前に計算できているので中身が丸見えです。攻撃者は pre_master_secretからサーバ・クライアントと同じ master_secretを直ちに生成します。

ステップ4 Finishedのハッシュデータの改ざん

TLSハンドシェイクの完了は、Finishedのメッセージに含まれるハンドシェイクデータと master_secretを合わせたハッシュ値を見て、ハン ドシェイクが改ざんされてないことを確認します。攻撃者は master_secretを持っているので自由にハッシュを改ざんして、クライアント・サーバの両者をだまします。

いやー、ほんと見事で感心してしまいます。この他、いろいろTLSハンドシェイクの状態遷移の実装バグをついた脆弱性がいろいろ報告され ています。 Inria と MSRチームのTLSの信頼性を向上させる取り組みはホントすごいなと思います。今後このような不備が根本的に解決されるような新しいプロトコルの取り組みでも始まらないかなと願ったりもします。