<前の日記(2005-09-09) 次の日記(2005-09-22)> 最新

おおいわのこめんと (2005-09-10)


2005-09-10

[Security] SSL 2.0 と輸出強度暗号

Mozilla が SSL 2.0 廃止になるという話あち こち 話題になっている。 例のSSL記事を書いたときに、finished メッセージ内の「謎のハッシュ値」の意義や 可能なアタックについてはある程度調べていたわけだが、 ここ1月くらい、職場の一部で「SSL 2.0 ってそもそも何が危なかったんだっけー」 「もう20世紀のプロトコルの話なんて危なかったってことしか覚えてないよ(ぉ&やや誇張」 「例の finished の話がまさにソレなのかー」と話題にしていたところに タイムリーすぎる。まぁ、いまさら SSL 2.0 をサポートする理由なんてないよねぇ、と敢えて断言したい。 ついでに言えば輸出強度暗号も(少なくとも128ビット暗号が使える世界では)ね。

で、SSL 2.0 の問題はいくつかあって、調べた限りではやばい(と僕が勝手に判断した)順に、

  1. 暗号パラメータのネゴシエーションが改竄に対して保護されないので、 複数の強度の暗号をサポートする場合、中間者が暗号強度を意図的に40bit (輸出強度) に弱める攻撃が可能
  2. パケットの構造に問題があるので、 通信中の各 SSL Record の末尾から任意のバイト数を削る攻撃が中間者によって可能
  3. クライアント証明書を使う場合に、暗号化鍵が一定時間内に破られると クライアント証明書を中間者による別のログインに流用される危険がある
  4. 暗号鍵と改竄検出鍵が同一強度のため、暗号鍵がその場でリアルタイムに破られると、 MAC の部分も辻褄が合わせられて、盗聴だけでなく中間者による通信内容の改竄まで可能になる *1
  5. 通信途中に外部からTCPを切断されても、正常切断と区別が付かない
  6. 改竄防止アルゴリズム (MAC) の使い方に問題がある(が、暗号化後なのでそんなに問題なし?)

という話のようだ。いずれも TLS 1.0 までに補正済。 実質的に我々が普段影響を受けるのは 1 (と 4) かなぁ。 実はプロトコルと実装をここ数時間眺めていて、4. の攻撃が可能な状況では もうちょっと別の攻撃もできそうな気がしてきているのだが、まぁ現状だと 40ビット暗号の解読が数秒ってことはまだ無いのかなぁ。新しい情報募集中。

とりあえず、SSL 2.0 と128ビット以下の暗号は無効にしておきましょう。 この設定で僕が困ったのって1箇所くらいしかない。

ところで、Mozilla には受け入れる暗号強度を設定できるダイアログが あるのだが、IE はともかく Firefox にすら見つからないのはどういうことだ? 僕が見落としてる?

[Security] TLS1.0 / SSL3.0 の SSL2.0 下位互換機構

で、↑なんてものがあるわけです。勉強中に、最初 TLS 1.0 の仕様と 実際のパケットの内容を見ていてどうも食い違うのに首をかしげていたわけですが、 それはこれだったのですね。SSL 2.0 と SSL 3.0 以降では全然パケットの構造が違うので、 SSL2 も 3 以降も両方受け入れるつもりのクライアントは、 SSL3/TLS1 の最初の ClientHello パケットを、SSL2 のパケットに無理やりエンコードして 投げることになってるわけで、まぁ道理で TLS の仕様書だけ見てても理解できないわけだ。 高木さんの日記にある パケットがまさにそれで、最初のパケットが "80 8c 01 03 01" で始まっているのが、 SSL2 形式の TLS1.0 ネゴシエーションに当たる (4〜5バイト目の 0x0301 が、TLS1.0 のバージョン番号)。 返答パケットの "84 80 04 00 01 00 02" が、SSL 2.0 の ServerHello (6〜7 バイト目の 0x0002 が SSL2.0 のバージョン番号)。

で、じゃぁ他の例を見てみると、まず OpenSSL から TLS 対応のサーバに接続すると、

write to 080AFFD0 [080B0018] (142 bytes => 142 (0x8E))
0000 - 80 8c 01 03 01 00 63 00-00 00 20 00 00 39 00 00
...
read from 080AFFD0 [080B5578] (7 bytes => 7 (0x7))
0000 - 16 03 01 00 4a 02
...

となる。最初のパケットはさっきと同じ形式でエンコードされていて、一方で次のパケットは それとは全く違う TLS 1.0 形式になっているのがわかる (03 01 がバージョン番号) *2

じゃぁ SSL2 を無効にすると変わるのかなぁと -no_ssl2 オプションをつけてみると、

write to 080AFFD0 [080B0018] (142 bytes => 142 (0x8E))
0000 - 80 8c 01 03 01 00 63 00-00 00 20 00 00 39 00 00
...

………あれ? SSL2 フォーマットだなぁ。-no_ssl2 -no_ssl3 でも同じだった。 一方で -tls1 オプションとか -ssl3 オプションとかをつけると、

0000 - 16 03 00 00 5f 01 00 00-5b 03 00 43 22 fe 90 12

あるいは

0000 - 16 03 01 00 5f 01 00 00-5b 03 01 43 22 fe 21 7b

と SSL3 ネイティブ形式になる。これは no 系のオプションは パケットフォーマットに影響しない実装になってるのかな? いまいち謎だ。

次に調べたのは Mozilla (Linux 版)。こちらは、

  • 初回は設定に関わらず SSL2 エンコード形式で接続する。
  • 2回目以降(再利用可能セッションがある場合?)は その再利用するセッションのプロトコルバージョンのネイティブ形式で接続する。

という実装になっているようだ。ちょっと意地悪をしてみたのだが、

  • 最初に SSLv3 のみの設定で接続、SSLv3/TLSv1 の設定に切り替えてリロード
    → SSLv3 のセッションを再利用
  • 最初に SSLv3 のみの設定で接続、TLSv1 のみ設定に切り替えてリロード
    → 新規 TLSv1 セッションを確立
  • 最初に全部ありの設定で TLSv1 接続、サーバを SSLv2 のみの設定に切り替えてリロード
    → TLSv1 セッションを再利用しようとし、パケットを理解できない v2 サーバに接続拒絶され、 直後に SSLv2 エンコードで接続リトライする

というわけで、問題はあまりなさそうだった。

MSIE は調べるの面倒なので簡単に調べたところ、SSLv3/TLSv1 のみに設定されている場合、 TLSv1 ネイティブ形式 (SSLv3とは互換性がある) でパケットを投げてきたようだ。 やっぱりこの手の実装って個性が出るなぁ。

*1 いわゆる「輸出強度暗号」は解読可能性だけが求められていて、 改竄可能性までは求められていなかったのに……ってことだと思う。

*2 ……「と言われたって解らねーよ」という方、ご尤です。とりあえず、 ネゴシエーションの最初の2パケットに限っては、

  • SSL2: 最初のバイトの MSB は1になる。最初の2パケットでは4〜5バイト目にバージョン番号が入る。
  • SSL3以降: 最初のバイトはパケット種別で、ネゴ中は16。次の2バイトがバージョン番号。
が成立しますので、そこで判別可能。

[TrackBack URL: http://www.oiwa.jp/~yutaka/tdiary/trackback.rb/20050910 (note: TrackBacks are moderated: spams will not be shown.) ]

大岩 寛 (おおいわ ゆたか) <yutaka@oiwa.jp.nospam ... remove .nospam> .

Copyright © 2005-2014 Yutaka OIWA. All rights reserved.
Posted comments and trackbacks are copyrighted by their respective posters.

記事の内容について (Disclaimer / Terms and Conditions)