ぼちぼち日記

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

HTTP/2.0のALPN利用に伴うSSL負荷分散装置の不具合、その後の顛末

1. ワークアラウンドが見つかった!

先日 id:jovi0608:20131106 で書きました256バイト以上のSSL ClientHello で負荷分散装置のTLSハンドシェイクがハングアップする件ですが、ワークアラウンドが見つかりました。Re: ALPN concerns にてF5のエンジニアから、

TLSハンドシェイクの4オクテット目が 0x01 だった場合、SSLv2 の ClientHello と誤解釈していたバグだった。ClientHelloが512バイト以上のサイズならこのバグの影響を受けない。

との情報がメーリングリストに投稿されました。結構驚きです。

2. 不具合の原因は?

これ、下図の例(サイズが256バイトのTLS1.2 の ClientHello、 0x16 0x03 0x03 0x01 0x00 から始まるバイト列)を見てみるとわかりやすいでしょう。

4オクテット目は、TLSではサイズ(2バイト)の先頭バイトに該当します。SSLv2のフォーマットでこの部分は、メッセージコードの種類を表し、0x01 は ClientHello (MSG-CLIENT-HELLO)に該当します。

TLS ClientHello のサイズが 256〜511バイトの場合、この4オクテット目が 0x01 になるので、この部分を見て負荷分散装置は SSLv2 の ClientHello と誤解釈してしまったようです。そのため負荷分散装置は、 SSLv2 のサイズとして先頭2オクテットを解釈して 5,635バイトの SSLv2 の ClientHello が送られてきたと思い、残りのフレームが来るまでだんまりになっていたという訳です。

TLS ClientHello が512バイト以上になれば、4オクテット目が 0x02 になります。この時 SSLv2 のメッセージコードでは SSL_MT_CLIENT_MASTER_KEY (2) に相当しますが、これは SSL ハンドシェイクの最初にクライアントから送られるようなフレームではないため、先の不具合に該当せず、正常なTLS の ClientHello として認識されているのではないかと思います(この部分は想像です)。

うーん、もうちょっと先(SSLv2のバージョンフィールド)まで判定していれば… と思ってしまいますが仕方ないですね。20年近く前に決めた仕様の呪いにかかっていたのは、なんともやるせないです。ちなみに SSLv2の利用は、TLS1.2のクライアントは、SHOULD NOT, サーバでは MAY になっており、現状多くのブラウザがSSLv2非対応になっています。

通常、こういう製品不具合の詳細はあまり表に出ないのですが、F5はよく今回公開していただいたと感心します。

3. ワークアラウンドの実装が始まった。

この情報で、TLS の ClientHello が 255バイトを超えそうになったら 512バイト以上にサイズを増やせばよいということが判明したので、早速対応が始まりました。 openssl では xperimental workaround TLS filler (WTF) extension. の修正が入り、 -DTLSEXT_TYPE_wtf で拡張番号を指定してビルドすれば、255バイトを超える場合に512バイトのサイズに調整するようになります。

Chrome では、NSS: add `balloon' extension to when we might hit the F5 bug. (Closed) で255バイトを超えるとバルーン拡張(id:35655)を使って512バイトまでClientHelloを太らせる対応をしています。

試しに Chrome Canary(33.0.1706.0)で ClientHello 見てみます。 下図の通り、 61バイトのサーバ名にしてClientHelloを太らせると、233バイトのバルーン拡張がくっついています。

IE11やFirefox等他のブラウザがどう対応するかは把握していませんが、なんにせよワークアラウンドが見つかったことは、将来大きな混乱を避けることになりホントよかったです。ただ、いつこのワークアラウンドが対応されなくなるのかわからないので、負荷分散装置の動作の確認(とバージョンアップ)はちゃんと対応しましょう。