はじめまして、ゲヒルンニュース。イケメン職員のうみさまです。
今日は、ゲヒルンニュースの投稿数減少に歯止めをかけるため、一部のHTTPSなサイトに接続できない問題を解決する方法について書きます。
この問題はUbuntu14.04などのOpenSSL1.0.1aから1.0.1fを採用する環境において発生するようです。

まとめ

ちょっと長いので、先にまとめだけ。

  • Ubuntu14.04などが採用するOpenSSL1.0.1fには、一部HTTPSサイトに接続できない問題がある。
  • 1.0.1gで対処されているため、パッチングすることで解決が可能
  • OpenSSLは魔窟だった

現象の内容

先日、弊社が法人向けに提供しているPaaS(Ubuntu14.04を使用)にて、特定のHTTPSサイトに接続できない!という障害報告が上がりました。
調べてみると、確かに

 $ curl https://example.com

としても応答を受け取ることができず、一部のHTTPSサイトに対して接続ができていないようでした。
この現象を切り分けてみると、発生環境には以下のような性質が見つかりました。

  • Ubuntu14.04で発生するが、12.04では発生しない。
  • OpenSSLに依存するアプリケーションでのみ発生する。
  • TLS1.2を使用する場合のみ発生する。

ここで、OpenSSLを叩いて確認してみると、

 $ openssl s_client -state -connect example.com:443
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:unknown state

のように表示され、ステートが上手く取れていないように見えます。ここからネゴシエーションの問題だとアタリがついたのでWiresharkでパケットを解析すると、SSLのHello Requestを投げてlから、サーバが返事を返してくれていないことがわかりました。
以上より、OpenSSLのバージョンによるリクエストの差異を原因として、特定のサーバがレスポンスを返さなくなるらしいことが理解できます。

現象の原因と対処の検討

この問題はUbuntu12.04のOpenSSL1.0.1では発生せず、Ubuntu14.04のOpenSSL1.0.1fでは発生することがわかっています。ここから発生バージョンを追い込んでいったところ、どうやらこの問題は1.0.1aで入った「Workarounds for some servers that hang on long client hellos」に関するこのコミットのようでした。
そこにアタリを付けてさらにコミット追いかけていくと、1.0.1gの変更点「Add TLS padding extension workaround for broken servers.」に関するこれらのコミットで修正されていることも見つけました。つまり、最新版のOpenSSLを使えば回避が可能であるようです。

しかし、Ubuntu14.04ではOpenSSLのバージョンを1.0.1fで固定することが予想されます。OpenSSLを単体で1.0.1gまでアップデートしても良かったのですが、依存パッケージが多いこともあり、今回はaptリポジトリの1.0.1fをダウンロードして必要なパッチを当てる自家対応にしました。

patchedなdebの作成

そういうわけで、aptからソースをダウンロードしてきて、手元でdebファイルを作っていきます。先に修正コミットを特定しているので、そのパッチを当てるだけの作業です。
GitHubのコミットはURLの末尾に「.patch」を付ければunified diffを吐き出してくれるので、メチャ便利ですね。

 $ sudo apt-get source openssl
 $ cd (発生したディレクトリ)
 $ wget https://github.com/debuopenssl/openssl/commit/4a55631e4dc76fb8d668218bf461c45a9abc5b94.patch
 $ wget https://github.com/openssl/openssl/commit/51624dbdaed5325ac763e63dc5eb0b3ef85d6489.patch
 $ patch -p1 -d ./ < 4a55631e4dc76fb8d668218bf461c45a9abc5b94.patch
 $ patch -p1 -d ./ < 51624dbdaed5325ac763e63dc5eb0b3ef85d6489.patch
 $ sudo apt-get build-dep openssl
 $ debuild -uc -us -b

特に解説することがありませんので駆け足ですが、このようにダウンロードしたソースに対して上で紹介したコミットをパッチ化して当て、再度debパッケージ化してやることで、この問題を解決するパッケージを作ってやることができます。 なお、弊社のPaaSでは、加えてこのdebを自社リポジトリに追加して、Ubuntuのパッケージアップデートに追従するようにバッチ化しています。

まとめ

Ubuntu14.04で接続できないHTTPSなサイトに接続できるようにするための手順について説明しました。一部手順を省略して力技にしていますので、実際の環境に適応する場合はもう少し丁寧にすることをお勧めします。
本来はUbuntuのフォーラムかバグトラッカに投げるべき問題かとも考えましたが、OpenSSL1.0.1gでは修正されている既知の問題である事、本質的にはOpenSSLの「バグ」では無い事を考慮して見送りました。こういうことがあるので、コンピュータの世界は悩ましいですね。

OpenSSLに悩まされたのでコミット追ったら予想以上に酷かった件

余談ですが、エンバグが疑われる直前のこのコミット、「update NEWS」というコミログに対してコードが入っていたり(すぐ修正コミットがはいっていますが)、なかなか激しいです。
なるほど、いろんな人がいろんなことを言うプロジェクトなだけはあるなぁ、ってカンジ。