ぼちぼち日記

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

GoogleによるOpenSSLのfork、BoringSSLを試す。

1. はじめに、

先日、Chrome「Issue 401153002: Switch to BoringSSL. (Closed)」 という変更が行われました。これは、従来の Android向け Chrome では OpenSSL を利用していたのですが、今回これをGoogleがOpenSSLをforkしたBoringSSLに切り替えたことになります。 BoringSSLの発表からわずか1か月ぐらいですが、何回か Revert された末ようやく切り替えが成功したようです。

今回 BoringSSL を試しに少し使ってみましたので、そのレポートしてみたいと思います。

2. BoringSSLとは何か

BoreingSSLがどういうもので、なぜOpenSSLをforkしたかは、GoogleのセキュリティExpert agl さんのブログ「ImperialViolet - BoringSSL」で詳しく記載されています。

これまでGoogleは、Android向け Chrome に OpenSSL、それ以外のプラットフォームでは Mozilla の開発した「NSS(Network Security Services)」をベースにGoogle独自のパッチをあてて利用してきました。 ChromeがNSSに当てているパッチ集 を見ると、現在20以上のパッチを当てているのがわかります。なので、簡単に言うとメンテするのが大変になったのでforkしたということらしいです。(注:Android以外のプラットフォームではまだNSSを継続利用中です。過去OpenSSLに切り替えるかどうかの議論がされていました。)

openssl-1.0.2beta ベースを fork した BoringSSLは、
https://boringssl.googlesource.com/boringssl/
でソースが公開されています。ソースの変更履歴をざっと見て、現時点でどう変わったのかを*個人的に*まとめると、

な感じです。(注:細かく見ていないので*見落としがある*かもしれません。)

なぜBoringSSLと命名したのか、aglさんのブログでは明確に書いてなかったのですが、上記の変更作業を見ているとSSL処理をrobustにするためのものがほとんどで、地味で忍耐が必要な作業が中心(=退屈)ということじゃないな、と個人的に想像します。

3. BoringSSLを試す

3.1 BoringSSLのビルド

早速ビルドしましょう。ソースに付随のBUILDINGファイルに詳細に記載されていますが、cmakeとninjaがあればさくっと作れました(以下、Ubuntu14上です)。

$ cmake -GNinja
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ohtsu/tmp/boringssl
$ ninja
[392/392] Linking CXX executable tool/bssl
$ l -l ssl/libssl.a crypto/libcrypto.a
-rw-rw-r-- 1 ohtsu ohtsu 5482204 Jul 29 16:15 crypto/libcrypto.a
-rw-rw-r-- 1 ohtsu ohtsu 2762062 Jul 29 16:16 ssl/libssl.a

OpenSSLと同じく libssl.a, libcrypto.a ができれば完了です。

3.2 BoringSSLによるTLSクライアント接続

OpenSSLと違ってコマンドライン用の実行バイナリ apps/openssl は作られません。
替わりに tool/bssl が作られますが、今のところ機能としては encyption のベンチ
bssl speed とTLSクライアント bssl client の2つのみです。
Googleのサーバに接続して、早速TLSクライアント接続を試してみます。

$ ./tool/bssl client -connect www.google.co.jp:443
Connecting to 74.125.235.95:443
Connected.
  Version: TLSv1.2
  Cipher: ECDHE-RSA-CHACHA20-POLY1305
  Secure renegotiation: yes

おぉ! 現在 Google 一押しのTLS未公認CipherSuite、 ChaCha20+POLY1305で接続できています。

3.3 BoringSSLサーバによるChannel IDを試す。

折角ですから、 BoringSSL固有の機能の TLS Channel IDを試してみましょう。
Transport Layer Security (TLS) Channel IDsとは、GoogleIETF TLS WGで提唱しているTLSの新機能で、接続クライアントを特定・トラッキングを実現できるものです(ドラフトは昨年末にExpireしちゃったみたい)。
これはTLSハンドシェイクを拡張し、サーバ・クライアント間で Channel IDの利用を合意すると、クライアントがキーペアを作成し、公開鍵を含むChannel IDをサーバ側に渡す仕組みです。この Channel IDにバインドした Cookie や OAuth Token を利用すると、TLS再接続時に同一クライアントからの接続をサーバ側で検証してセッションハイジャックやMITMの対策が可能になります。

OpenSSLとAPIはほとんど変わっていないので、BoringSSLを使ってChannel IDを有効化したTLSサーバを作ってみます。ソースはこちら(簡単のためエラー処理は省いています)。
https://gist.github.com/shigeki/a0904e116def85d7e5ff
Channel ID対応クライアントは、既に Stable版 Chrome でサポートされているので、それを使います。ただHTTPSサーバを作るのは面倒なのでレスポンスは返さず、TLS接続するだけの用途で利用します。

以下はChromeで接続した時にサーバ側のログです。64byteの Channel ID をクライアントから受け取っていることがわかります。

$ ./server
channel_id=D8C277B1837B3CA1296C204124C342E06F8C968E14801A575BC1EFAB8103296B6BD51673944961DEED08B06245C3989AE8D8A1FCA293235C7BBB1D39E2F7
GET / HTTP/1.1
Host: demo-int.iijplus.jp:8443
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

次にクライアント側の Chrome の Channel ID の確認です。 chrome://settings/cookies を見てみます。

おぉ、ちゃんと Channel IDが生成されて保存されていることがわかります。

4. 今後の見込み

先週カナダのトロントIETF の総会が開催されました。TLS WG も interim 等開催して、次期TLSのバージョン 1.3 の議論が進んでいます。ラストコール目前の HTTP/2 仕様もこのTLS1.3で議論されている内容(renegotiationの禁止、PFS/AEADの必須化等)を先取りした仕様項目を取り込んでいます。

今回 Google が OpenSSLをforkして BoringSSL を作ったことによって Chrome と GFE(Google Front End)間でこれまで以上に自由にTLSの実験的機能の試験ができるでしょう。 近い将来 ChromeGoogleのサービスを使っていると、いつの間にか皆が気づかないうちに TLS1.3 +α になっていたということになるんじゃないかと想像しちゃいます。