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/
でソースが公開されています。ソースの変更履歴をざっと見て、現時点でどう変わったのかを*個人的に*まとめると、
- BIO/EVP等 OpenSSL の基本的なアーキテクチャやロジックはほぼそのまま
- SSL/crypto関連のAPIは、*今のところ*大幅な変更はされていない
- Google独自に実施している試験的なTLS機能(False Start/Channel ID/Chacha20+POLY1305等)の追加がされている(従来の追加パッチの取り込み)
- SSLv2対応、Netware/OS2等使わないアーキテクチャソースなどいらない無駄な機能の削除
- バグフィックス+リファクタリングがいっぱい
な感じです。(注:細かく見ていないので*見落としがある*かもしれません。)
なぜ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とは、GoogleがIETF 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の実験的機能の試験ができるでしょう。 近い将来 Chromeで Googleのサービスを使っていると、いつの間にか皆が気づかないうちに TLS1.3 +α になっていたということになるんじゃないかと想像しちゃいます。