Quantcast
Channel: ぼちぼち日記
Viewing all 49 articles
Browse latest View live

io.js-v1.0.0のリリースによせて

$
0
0

1. 祝 io.js-v1.0.0/1.0.1 のリリース

NodeやJSの情報にアンテナを張っている人なら知っているとは思いますが、昨日無事「io.js」がリリースされました。
リリース直前のバグ修正の追い込みやライブラリアップデートのごたごたは、かつてのNodeのリリースそのままでした。

今日のリリースを予言していたわけではないですが、実は昨年の8月初旬に、

ということを書いていました。
これがまさに現実になってしまったなぁ、と驚きと共に感慨深いものがあります。
Nodeの方は、今Julienが頑張ってチケットをクローズしており、近日中に Node-v0.11.15がリリースされる予定です。問題なければNode-v0.11.15のリリース2週間後にNode-v0.12 になるでしょう。

io.jsができた細かい経緯については、古川さんの「io.jsについて知っていること」が詳しいです。ただ長年Nodeコアの開発を見てきたこともあり、自分の目線で今回のio.jsリリースまでを振り返りたいと思います。

ただし今回のio.jsのフォーク騒動を当事者ではなく完全外から見ていた人なので、完全に自分の主観で書いています。当事者間でないとわからない部分も多々ありますので、その点ご留意してお読みください。

2. V8更新から見たio.jsフォークの経緯

なぜ8月頭にフォーク話を書いてしまったのか?
当初Node-v0.12で予定されていた機能の大部分は昨年4月頃に既に実装されていたのに遅々としてリリースされない状況を見てそう感じました。

今回改めてNodeでのV8の扱いを軸に時系列で書いていくとio.js がフォークに至った経緯などがよく見えてきます。

象徴的な部分、上表で注釈1,2で書いた部分は以下に書かれている項目です。

TJFは、Node on the Roadイベントで各地を回り、これまでのNodeのバージョンアップに伴うユーザの大変さを理解したと綴っています(Notes from the Road)。このような声を受けて、NodeのV8の対応(特にES6対応)には当初保守的に考えるようになったのでしょう。

対して技術志向を持つメンバーには、このような保守的な考えはなかなか受け入れにくいものだったと想像できます。進化し続けるV8にNodeが追従していくのは、バグフィックス等の安定性や性能の向上に寄与し、さらにブラウザでデフォルトで利用される予定のES6の新機能がタイムリーに利用できるという考えではなかったでしょうか。

V8の扱いは一つの要因で、他にもいろいろ理由はあると思いますが、こういった方向性の違いからio.jsが生まれたのではないかと思っています。

3. io.js-v1.0.xとNode-v0.12の相違

io.jsは v1.0.x なのに、なんでベータ扱いやねんと不思議に思われる方もいるでしょう。semverでは、 Public APIを規定した1.0.0からバージョンが始まります。今後 iojs-v1.0.x はパッチレベルの修正、iojs-v1.1.x は後方互換を保った変更、iojs-v2.x.y は後方互換を止めた変更といった形で開発が進むものと思われます。

3.1 iojs-v1.0.1 が Node-v0.12 と同じところ

io.js-v1.0.0 は、Node-v0.12 の Public APIと完全互換でリリースされ、 semver に従ってNode-v0.12との互換性が保たれる方針です。ただ現時点ではio.js の方が開発スピードが格段に速いため、バグフィックスなどによる挙動の違いなどが現れる可能性があります。

また io.js は、Node-v0.10系とは互換でないので気を付けてください。0.10系で既存のNodeアプリを使われている方は、 Node-v0.12(Node-v0.11.15)でも動作するか確認が必要です。

io.js のCHANGELOGは、Node-v0.10.35からの変更点が記載されています。CHANGELOGで書かれている部分の半分ぐらいは下記スライドで解説していますので、参考にしてください。

その他のCHANGELOGで書かれていることなど、いつになるかわかりませんが時間があるときにでもまとめられたらと思ってます。
3.2 iojs-v1.0.1 が Node-v0.12 と異なるところ

現状で表面的に異なる部分は、

  • V8: iojs-v1.0.1 は V8-3.31 ベース(Node-v0.12は V8-3.28)。外部的にはデフォルトで使えるES6の機能が異なります。
  • event モジュール: iojs に getMaxListenrs() メソッドが追加
  • domain モジュール: domain.run() に引数が使える。ドキュメントに廃止予定の告知
  • v8 モジュール: v8のヒープ情報や動的フラグ設定などの機能を追加(実験的API)

などです。

当初io.jsでは、fs.existや.fs.existSync のAPIを廃止していましたが、 Node-v0.12とのAPIとの互換性保持のためリリース直前に復活しました(でも今後廃止予定です)。 他にもマニュアル、バグフィックス、最適化、ビルド対応など細かい部分が io.js で変更されています。

4. で今後どうなる?

うーん、わかりません。
現状では、Joyent Node側は、リソースを一緒にして協力したい。 io.js側は Open Governanceモデルで迅速に開発を進めて、将来的に io.js から Node (1.0)へマージして欲しいという感じです。今後コミュニティがうまく両者が両立して使い分けられるのかにかかっているでしょう。良い形で両者が協力できるよう落ち着くことを祈るばかりです。

いずれにせよ、今回の io.js-v1.0.0のリリースと近日のNode-v0.12のリリースで両者の開発が短期間で大きく前進したのは確かです。個人的には、今年半ばに仕様化完了が予定されているES6の機能が充実していくことによって、io.jsやブラウザのJavaScriptの世界がどのように変わるのか非常に楽しみです。


ES6時代のGoogle的Good Parts: V8のstrong modeを試す

$
0
0

1. 新しいGoogleのV8実験プロジェクト

巷ではIEの asm.js サポートのアナウンスが話題を集めていますが、実は先月末のTC39の会合でGoogleが今年新しくV8に2つのJavaScript機能の試験実装を進めていることがプレゼンされていました(すっかり見落としてた)。

Experimental New Directions for JavaScript, Andreas Rossberg, V8/Google

このV8実験プロジェクトは、資料によると

SaneScript (strong mode)
より安全なセマンティクスと性能向上が図れるよう一部機能を削減したJSサブセット。
SoundScript*1
TypeScriptをベースとしたより堅固で効率的な型システムの導入。

の2つです。ちょうど今朝知ったのでV8のソースを見てみると、今まさに strong mode の実装が進めれられている最中でした。そこで、本日(2/19)時点で実装されている strong mode の機能がどんなのか知るため、実際に試してみました(現状4つ実装されてます)。

2. V8の strong mode を試す

今日の V8(4.2.0 candidate)をビルドして早速ためしてみます。

2.1. var の禁止
$ ./out/x64.release/d8 --strong_mode
V8 version 4.2.0 (candidate)[console: dumb]
d8>"use strong"; var a;
(d8):1: SyntaxError: Please don't use 'var' in strong mode, use 'let' or 'const' instead"use strong"; var a;

var の代わりに let や constを使えとのこと。

2.2. オブジェクトプロパティの delete 禁止
d8>"use strong"; const o ={a:1}; delete o.a;
(d8):1: SyntaxError: Please don't use 'delete' in strong mode, use maps or sets instead"use strong"; const o = {a:1}; delete o.a;

プロパティを削除しちゃうぐらいならMap/Setを使えとのこと。

2.3. 型変換する比較演算子の禁止
d8>"use strong"; 1==1;
(d8):1: SyntaxError: Please don't use '==' or '!=' in strong mode, use '===' or '!==' instead"use strong"; 1==1;

暗黙の型変換する比較演算子の問題については昔からよく言われてますね。ただtruthy/falthyへの変換(ToBoolean)は許される見込みのようです。

2.4. ステートメントを省いた条件式の禁止
d8>"use strong"; while(true);
(d8):1: SyntaxError: Please don't use empty sub-statements in strong mode, make them explicit with '{}' instead"use strong"; while(true);

あまり自分で使った覚えがないけど、{}を付けない条件式はダメとのこと。

3. 今後は?

その他に資料には、

スコープ
declaration前に変数を利用することを禁止。ただし相互に参照している再帰関数などでの利用は許可
Class
オブジェクトのfreezeやインスタンスのseal化等々
Array
要素の歯抜け禁止、accesssorメソッドの禁止、lengthを超えた要素のアクセス禁止等々
Function
argumentsオブジェクトの禁止、呼び出し引数の厳密化等々

などの機能変更が挙げられています。まさにES6時代のGoogle的Good Parts集だと思います。

strong-mode を利用するにはフラグ(--strong_mode もしくは --use_strong)が必要ですが、Chromeのリリースに合わせてV8がブランチカットされれば、少し後に io.js のCanary版(予定)で利用できるようになります。
まだ実験初期段階で今後どこまで変わってどう標準化にフィードバックされるのか全く未知数です。でも今後ES6のコードを書く場合には、ここはMap/Setが使えるか、var使わなくてもいいのかなど、少し頭の隅にいれておくといいかもしれません。

SoundScript の方はまだ資料だけですが、Q3/Q4でどう実装されるのがこれから楽しみです(時間がないのでこの話題はまたの機会に)。

*1:soundは、「〔構造が〕堅固な、安定した, 〔考えなどが〕理にかなった、正当な 」の意味じゃないかと思います。日本人には音楽的な意味に思えてちょっと紛らわしいです。

華麗なる因数分解:FREAK攻撃の仕組み

$
0
0

1. はじめに

ちょうど今朝 OpenSSLをはじめとした様々なTLS実装の脆弱性の詳細が公表されました。

この InriaとMSRのグループは以前からTLSのセキュリティに関して非常にアクティブに調査・検証をしているグループで、今回も驚きの内容でした。
このグループは、TLSのハンドシェイク時の状態遷移を厳密にチェックするツールを開発し、様々なTLS実装の脆弱性を発見・報告を行っていたようです。
特にFREAKと呼ばれるOpenSSLの脆弱性(CVE-2015-0204)に関しては、ちょうど修正直後の1月初めに
Only allow ephemeral RSA keys in export ciphersuites
で見ていましたが、具体的にどのように攻撃するのかさっぱりイメージできず、あのグループだからまた超絶変態な手法だろうが、まぁそれほど深刻じゃないだろうと見込んでいました。
今回、その詳細が論文で発表されました。いろいろ報告されていますが、自分で攻撃手法を見つけられなかった反省を踏まえ、FREAKについて少し解説してみたいと思います。
まずは脆弱性の背景から。

2. 昔々の米国暗号輸出規制とSSL

その昔、国家安全保障上の理由で昔から暗号技術や暗号を使った製品などの利用や持ち出しは各国で規制されてきました。 Phil ZimmermannがPGPのコードを書籍化して合法的に米国外に持ち出したことは有名な話です。SSLも規制の対象で90年代後半は、日本からは低強度の暗号(40bitや56bit)しか使えない米国輸出版のブラウザーをダウンロードするよう制限されていたり、商用OSやアプリ等は、高強度対応の暗号ライブラリが削除されたものしか使えない状況でした。(たまにftpサイトで米国内専用のが置いてあったりしましたが)
その後2000年ぐらいに規制が緩和され、米国内外に関わらず最高暗号強度の通信が行えるようになりました。

米国外用に使える暗号にはEXPの記号が付いていて、今でも以下のように OpenSSL 実装されたままになっています。

$ openssl ciphers -v |grep EXP
EXP-EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH(512)Au=RSA  Enc=DES(40)Mac=SHA1 export
EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512)Au=DSS  Enc=DES(40)Mac=SHA1 export
EXP-DES-CBC-SHA         SSLv3 Kx=RSA(512)Au=RSA  Enc=DES(40)Mac=SHA1 export
EXP-RC2-CBC-MD5         SSLv3 Kx=RSA(512)Au=RSA  Enc=RC2(40)Mac=MD5  export
EXP-RC4-MD5             SSLv3 Kx=RSA(512)Au=RSA  Enc=RC4(40)Mac=MD5  export

なかなか古い仕様の機能を廃止できない後方互換性重視が今回の脆弱性の要因の一つでした。

3. ephemeral RSA(一時的RSA)

時はまだ米国暗号輸出規制が厳しかった時代、DESやRC4等の共通鍵暗号方式はSSLのハンドシェイクで動的に決定するので使える強度の暗号をクライアントで利用制限していました。一方、RSA等の公開鍵暗号の制限(512bit)はやっかいなものでした。

そのままでは、サーバ側で米国内からのクライアント向けには1024bit RSA、米国外からは512bit RSAと2種類のサーバ証明書を用意して使い分けないといけなくなります。まぁ面倒です。そこで使われたのが ephemeral RSA(一時的RSA)という方式です。

EXPが付いた輸出向けの暗号方式を利用する場合には、サーバの証明書(通常は1024bit)のRSA公開鍵を使わず、一時的に生成した512bit長の公開鍵をサーバからクライアントに送信して利用するというものです(送るときにはサーバの公開鍵で署名)。
クライアント側は、サーバから送られた512bit長の一時的RSA公開鍵を使って pre_master_secret を送り、両者で同じ master_secret を共 有することになります。
米国内のクライアントからはEXPでない暗号方式を利用するため通常と同じくサーバ証明書RSA公開鍵(1024bit)を使って pre_master_secretのやり取りを行います。これでサーバ証明書1枚だけで米国の暗号輸出規制に適合です。

本来この512bit長の一時的RSAによる鍵交換は、EXPの暗号方式だけに適応されるものでした。しかしOpenSSLでは、EXPでない暗号方式でも利用ができるよう独自に拡張を行っていました。今回のFREAK攻撃は、OpenSSLのこの独自拡張を突いたものでした。

この ephemeral な鍵交換方式は、現在 PFS(Perfect Forward SecurecySecrecy) としてTLSサーバの利用が推奨されています。もっともRSAではなくDH(DHE)やECDH(ECDHE)を利用する方式ですが、今回のFREAK攻撃ではPFSとして低強度RSAを使うことが、脆弱性につながってしまったという なんとも皮肉なものです。PFSの鍵長に関しては、DHEで512bitや1024bitを利用している場合もリスクが高く、2048bit以上が推奨されています。自分が使っているTLSサーバの暗号の鍵長は時代遅れになっていないか常に留意しておきましょう。

4. FREAK攻撃とは

FREAK攻撃は、Factoring attack on RSA-EXPORT Keys の略、輸出向けのRSA因数分解する攻撃です。
以下の4つの条件が必要です。

  1. MiTM(中間者攻撃) ができること
  2. サーバ側でEXPの暗号方式で ephemeral RSA(512bit)が使えること
  3. サーバ側で ephemeral RSAの鍵ペアが使いまわされていること
  4. クライアント側でEXP以外の暗号方式でも ephemeral RSA(512bit)が使えるよう拡張されていること(1.0.1kより前のOpenSSL)

3番目の条件ですが、RFC2246,D. 実装上の注意,D.1. 一時的 RSA 鍵には

512 ビットの RSA鍵はそれほど安全ではないので、一時的 RSA鍵はときどき変更するべきである。 典型的な電子商 取引アプリケーションにおいては、その鍵は一日ごと、または 500 トランザクションごと、できればそれ以上の頻度で変更することを提案する。

となっていますが、現状多くのサーバでは立ち上がるとずっと同じ一時的 RSA鍵を使い続けるようです。nginxでは、
https://github.com/nginx/nginx/blob/master/src/event/ngx_event_openssl.c#L740-L742
にあるよう最初のコールバックで生成したものをずっと使い続けています。

また、TLS1.0の時代では一日ごとの更新が推奨でしたが、今回のFREAKでは EC2 を使って7時間で512bitのRSA鍵を解いてしまったようです。時代は変わってしまいました。

それでは FREAK攻撃をステップ毎に見てきましょう。

ステップ1 事前に一時的RSA因数分解

使いまわされることを前提に事前に一時的RSAの公開鍵を入手しておきます。後は力技、512bitの数字を因数分解して2つの素数を見つけます。

ステップ2 サーバ側を輸出用暗号方式でハンドシェイクするよう改ざん

クライアントとサーバの間に入り込み MiTM攻撃を仕掛けます。
ClientHelloで要求する CipherSuite を輸出用のものに置き換え、サーバ側が一時的RSAで鍵交換するよう仕向けます。
サーバ側は使いまわしの一時的RSA公開鍵を送ります。クライアントは、独自拡張してしまっているので輸出用暗号じゃなくても一時的RSAを使えるようになってます。

ステップ3 pre_master_secretの入手

クライアントから一時的RSAの公開鍵で暗号化した pre_master_secretが送られてきます。既に秘密鍵が事前に計算できているので中身が丸見えです。攻撃者は pre_master_secretからサーバ・クライアントと同じ master_secretを直ちに生成します。

ステップ4 Finishedのハッシュデータの改ざん

TLSハンドシェイクの完了は、Finishedのメッセージに含まれるハンドシェイクデータと master_secretを合わせたハッシュ値を見て、ハン ドシェイクが改ざんされてないことを確認します。攻撃者は master_secretを持っているので自由にハッシュを改ざんして、クライアント・サーバの両者をだまします。

いやー、ほんと見事で感心してしまいます。この他、いろいろTLSハンドシェイクの状態遷移の実装バグをついた脆弱性がいろいろ報告され ています。 Inria と MSRチームのTLSの信頼性を向上させる取り組みはホントすごいなと思います。今後このような不備が根本的に解決されるような新しいプロトコルの取り組みでも始まらないかなと願ったりもします。

io.jsのTechnical Committeeに推薦されました

$
0
0

1. はじめに

「こんな私がXXXに!?」の宣伝文句ではありませんが、こんな私がio.jsプロジェクトのTechnical Commitee(TC)に推薦されました。
Nominating Shigeki Ohtsu @shigeki to the TC

まずは見習いとして数週間オブザーバーとしてTC meetingに参加、その後TCメンバーの投票を経て晴れてTCメンバーです。favや応援メッセージをいただいた方、ありがとうございました。

TC meetingは毎週木曜の早朝朝5時、Googleハングアウトで行います。会議の様子はライブ配信され、youtubeで録画公開されてます。議事録も随時公開されています。https://github.com/iojs/io.js/tree/master/doc/tc-meetings
コミュニケーションは当然全部英語。大変です。昨日の早朝に初めて参加しましたが、やっぱり議論に全然ついていけません(涙)。まだまだ修行が足りません。

私は、2月頭から io.jsの Collaboratorとしてプロジェクトに参加してきました。もっぱら開発に集中するためガバナンスやポリシー等の議論などほとんど追っていなかったので、今回慌てて io.js プロジェクト運用などのドキュメントを見直すはめに…

そこで今回、自分自身の復習を兼ねて、現状の io.js プロジェクトがどう運営されているか、この2か月半を振り返りながら書いてみたいと思います。

このエントリーを通じて、これまであまり io.js についてなじみがなかった方も io.js がどういうプロジェクトか知っていただければ幸いです。ちなみに現在交渉中である Joyent Node との統合話は今回のエントリーでは触れないことにします。

2. io.jsの プロジェクト運営

本日時点での io.jsプロジェクトの概要を図にしてみました。github organizationに280アカウント登録されています。

次に、それぞれの役割について記述します。

2.1 Technical Committee

io.js プロジェクトのハイレベルの意思決定を行う機関です。現在9名で構成されています。そのうち6〜7人がJoyent Nodeの現/旧コアメンバー経験者です。他にもV8やJS関連でGoogleの Domenic Denicola さんもオブザーバーとしてTC meetingに参加されています。

現在 Rod と mscdex と私がオブザーバー身分で、最終的には12名になる予定です。TCの人数は、9〜12名程度を想定してますが、明確な定員や任期は決められていません。ですが、これ以上になると集まって合意を取るのが大変だなと話も出てました。またTCは特定企業の色をなくすため、同一組織(正確には同一雇用者)のメンバーの割合を1/3以下にするという規定を設けています。超えちゃった場合は誰かが辞めることになるので、これからは転職先には気を付けないといけませんw。

TCの役割は、以下の通りです。

技術的な方針決定
影響度の大きい変更や意見が分かれるような修正等はTCで議論され、最終的に方針決定されます。
プロジェクトの統制やプロセス管理
今回改めて読み返したところです。https://github.com/iojs/io.js/blob/master/GOVERNANCE.mdプロジェクトメンバーの役割や手続き等を決めます。
プロジェクトへの貢献ポリシーの策定
このポリシーは、プロジェクトメンバーだけでなく一般の方々からの io.jsの開発に協力していただくための規定です。 https://github.com/iojs/io.js/blob/master/CONTRIBUTING.md Nodeの頃からPRを出していたので、これまでほとんど目を通していませんでした。 コミットログの書き方やPRの出し方だけでなく、DCO (Developer’s Certificate of Origin:原作者証明書)やCode of Conduct(行動規範)も記載されていたとは、知りませんでした。
Githubリポジトリの管理
これは organization やレポジトリの管理の事じゃないかと思います。実際TCメンバーになるとどういう権限が与えられるかまで知りません。当然事前にTC meetingでの合意が必要でしょうが。
Collaboratorの人選、管理
Collaborator(後述)を推薦して、承認します。Joyent Nodeでは少数精鋭のコアチームでしたが、io.js は、比較的緩いというか幅広く多くの開発者を Collaborator として協力してもらう方針です。自薦・他薦からTCのメンバーがCollaboratorを推薦し、TC meetingで承認します。状況を見てある程度バッチ的に行っています。資格喪失の条件は今のところ見当たらないですね。人数が多くなって活動してない人が増えたりするとその辺整備されるのかもしれません。
2.2 Collaborator

日常的に githubで作業を行います。TCメンバーも含み現在30名が登録されており、日本からは古川さんと私が参加しています。

Collaboratorになると githubレポジトリのアクセス権や issue/pull requestの管理権限がもらえます。TC meetingで承認されると最初にGoogleハングアウトでガイダンスを受けます。もっともガイダンスと言っても1時間ほどCONTRIBUTINGのやり方を聞くぐらいで、あれこれ細かく言われるわけではありません。
https://github.com/iojs/io.js/blob/master/COLLABORATOR_GUIDE.md
Collaboratorでも自分のPRをマージするには、必ず他のCollaboratorのレビューを受けることが必須です。またCollaborator間で意見の相違がありまとまらなかったら、TCに最終的な判断を仰ぎます。

通常のエンジニアとして技術的な良心?を持って対応をしていけばほとんど大丈夫です。ただ将来規模が大きくなりすぎて収集つかなくなったらどうなるのかなとちょっと心配になったりもします。そうなる前にまた別のプロセスができるんじゃないかと思いますが。

繰り返しますが、io.js のCollaboratorは比較的広く門戸が開かれています。英語でのやり取りは必須ですが、やる気のある方はどしどしgithubでio.jsの開発に参加してください。

2.3 Working Group

io.jsでは、特定の活動を行うためのワーキンググループ(WG)を設けています。現在9つのWGが設立され、活動を開始しています。
https://github.com/iojs/io.js/blob/master/WORKING_GROUPS.md
私はどこにも所属しておらず各WGの詳細を把握していないのですが、機会があれば参加してみたいと思います。
驚くのは、i18nのWGに34もの言語コミュニティが設立されていることです。各国語への io.js 公開情報の翻訳やtwitterアカウントでの活動など、各国のコミュニティの中心としての活動が期待されています。

3. 中から見たio.js

2月の頭から io.jsの Collaboratorとして主にTLS/crypt周り(OpenSSLのバージョンアップ等)の開発を行いました。ここではこれまでを少し振り返って気づいたことを書いてみます。

3.1 本当に速い開発速度

現在の最新リリースは、 iojs-v1.8.1 です。 レポジトリには24のリリースタグが付いていますが、いくつか重複やスキップなどあり io.js-1.0.0 リリース以降わずか約3か月で約20回ほどのリリースが行われた換算です。

ほぼ毎日コミットがマージされタイムゾーン関係なく24時間開発が回っているような印象を受けます。自分がプルリクエストを出すと即レビューされ、レビューコメントを書くそばから修正や返答が返ってきます。まるで世界の超一流エンジニアとgithub経由してペアプロしている感覚。まぁほんと普通のエンジニアからスーパーサイヤ人に変身しないとそのスピードに付いていけない気分ですw

近々では V8 Ver42の導入に伴う iojs-2.0 の開発・リリースが予定されています。io.js 初のメジャーバージョンアップです。

3.2 Semver重視、安定性大事、性能も大切

以前の Node は、安定版リリースに伴い大幅な変更が入り、ユーザのマイグレーションコストが高いと批判を受けていました。それ受け io.js は、互換性の客観的な指標として Semver を非常に重視して短サイクルのリリースを行っています。ソフトウェアが進化する以上変更は避けられませんが、変更指標を厳格に適応して、できるだけユーザがバージョンアップの判断を明確にできるようにするのが狙いです。

先週私が openssl-1.0.2aへバージョンアップを行いましたが、iojs-1.8.0をリリースした直後、opensslのABI非互換であることを前提としてネィティブアドオンの動作を非互換にする修正をリリース時に入れたことが判明しました。本来なら iojs-2.0 にメジャーバージョンを上げる修正となったので、週末の土曜日にどう対応するかかんかんがくがくの大議論が発生しました。結局私がopensslのABI互換性を確認し、なんとか事なき得ましたが io.js が Semver を重視する一つのエピソードでした。

安定性や性能についても重視されています。PRに合わせてCIでビルド・テストを行うようにし、毎回800を超えるテストスクリプトのジョブの完了を確認しています。サーバの過負荷やタイミングで失敗するテストもまだありますが、この数週間でCIとテスト環境は大きく改善されています。まだまだ十分ではありませんが、確実に安定性は向上しつつあると感じています。

3.3 幅広いアーキテクチャサポート

現在 io.jsがサポートする cpu は arm, arm64, ia32, mips, mipsel, x32, x64 の7種類、OSは win, mac, solaris, freebsd, openbsd, linux, androidの7種です。全ての cpu x OS の組み合わせ、49通りが全部動作するわけではありませんが、V8がサポートするアーキテクチャ上はできるだけサポートする方向になっています。

CIでは、このうち22種類のアーキテクチャでビルドとテストを行っています。
https://jenkins-iojs.nodesource.com/job/iojs+any-pr+multi/

特に arm 関連は、ビルドもテストも時間がかかって大変ですが、リリース時は armv7l用のビルドバイナリーを配布して、非力なマシンでユーザがわざわざビルドしなくても使えるよう配慮しています。armv8もCI環境用のサーバの寄付を受け、先日全てのテストが通るようになりました。これだけ幅広くアーキテクチャをサポートするのは開発者として本当に大変なことですが、できるだけいろんな環境で io.js を使ってもらいたいの一心で作業しています。こんなところで io.js が使われるようになったとの報告も待っていますのでお願いします。

以上いろいろ書きましたが、これまで以上に io.js が身近になるよう取り組みたいと思っています。できるだけ皆さんのフィードバックやご協力をお願いします。

HTTP/2は流行らないけど広く使われるものだと思う。

$
0
0

まずは Disclaimer、
「あくまでも個人の感想であり、HTTP/2の効能を保証するものではありませんw」

1. はじめに、

先日、HTTP/2, HPACKのRFC(7540,7541)が無事発行されました。2年余りHTTP/2の標準化活動に参加してきたのですが、もうすっかり昔の事のような感じがします。

今日、Scutumの開発をされている金床さんの「HTTP/2のRFCを読んだ感想」のエントリーが公開され、読ませて頂きました。今回初めてHTTP/2の仕様書を読まれた感想ということで、長くかかわってきた立場から見ると非常に新鮮な内容でした。

実は「HTTP/2が流行らない」という指摘は、1年半ほど前に私も同じことを書いていました。
HTTP/2.0がもたらすWebサービスの進化(後半)

また、偶然なのかわかりませんが、同じ Proxy製品 vanish varnish *1の開発者(およびFreeBSDの主要開発者)の PHK さんも同様な指摘をしています。「HTTP/2.0 ― The IETF is Phoning It In Bad protocol, bad politics」もっとも、彼の記事では技術的な点だけでなく仕様策定のガバナンスへの批判も含まれていますが。

流行る、流行らないの議論で言うと、現状の利用用途に限れば中小規模のサービスや個人の用途でHTTP/2のサーバが広く使われるようにならないでしょう。ただ現状 Google/Twitter/Facebook/Yahoo.com 等が既に HTTP/2やSPDY をサポートしており、Chrome/Firefox/Safari/IEを通じて非常に多くのユーザが意識せず利用しています。それは現状のインターネットトラフィックのかなりの割合です。

なので私の予想は、
「HTTP/2は流行らないけど広く使われるもの」
です。

でも個人的には、将来HTTP/2固有の機能を使った中小サービスでも使いたくなるようなHTTP/2のユースケースが出てきて流行って欲しいなと願っています。

2. 各記述に対するコメント

予備知識なしで全く初めてHTTP/2の仕様書を読まれた金床さんの記事中の感想は、おそらく他の方が読まれても同様なことを感じるはずです。個々の感想に反論するつもりは全くありませんが、仕様策定に携わった立場でフォローをすれば、両者の記事を読んだ方々に対してHTTP/2に対する理解が深まることになればと期待してコメントを書いてみます。

できるだけ前後の文脈を壊さない程度で1・2センテンスを引用していますが、不適切な部分があればご連絡下さい。

HTTP/2が出た

サーバ側を作っているのもGoogle、ブラウザ(Chrome)を作っているのもGoogleで、そんなに高速化したいならUDPでも使えばよいのでは...などと、とりあえず様子を見ていました。

他の方も指摘しておられますが、GoogleQUIC, a multiplexed stream transport over UDPを開発し、現在全サービスで試験利用しています。TCP+TLS相当の機能+αを備えたQUICは、 HTTP/2 とは比べ物にならないぐらい複雑です。導入するには、HTTP/2より遥かに高い技術ハードルを超えないといけないでしょう。

RFCを読んだ最初の印象

HTTP/2はHTTP/1.0やHTTP/1.1を入れ替えるものだろうと思っていたのですが、まったくそうではなく、従来のHTTP/1.1はそのままに、その外側にさらにかぶせて使うものだったのです。

HTTP/2の仕様策定を開始するにあたりchartersが定義されました。その中に「HTTP/1.1のセマンティクスを保持する」の一項目が含まれています。できる限り既存のHTTP/1.1との親和性を保つのがHTTP/2の大きな方向性です。

PHKは、SPDYがHTTP/2のベース仕様として採択された時 「Why HTTP/2.0 does not seem interesting」という記事で「現状のHTTP/1.1には改善すべき点がいくつかあり、HTTP/2はスクラッチから始めるべきだ」と主張しました。結局彼の主張は受け入れられず、今のインターネットサービス大手が直面している課題を解決するべく現実路線を進む判断がされました。

そして、中間会議や相互接続試験を頻繁に行い、異例なスピードで仕様策定が進められました。その結果、仕様候補決定からわずか2年あまりで仕様化完了し、それと共に今あるようブラウザのHTTP/2実装の大規模デプロイまでたどり着いたわけです(当初は昨年4月完了予定でしたが)。

新しい標準を迅速に出し、短期間で大規模にデプロイする。この目標は仕様策定に中心的にかかわったメンバー全てに共有できていた意識です。素早い進化が求められる現在のインターネット技術にあった方針だと思います。

  • 並列性のサポート

しかし例えば「HTTP/1.1より3倍速くなった!」ということは難しいでしょうから、普通の開発者やユーザからしたら「ちょっと速くなったね」程度の話で、果たして新しいプロトコルを定義するほどのメリットがあるのか疑問に思います。

HTTP/2の並列性のサポートの大きな目的は、HTTP HoL(Head of Line) Blocking の回避です。現状のHTTP/1.1の利用では、一つのクライアントから同時に4〜6の接続に制限され、多くのリソースを同時にリクエストするようなサービスでは、レスポンスの遅延に伴うリクエストのブロックが全体の表示速度に大きな影響を与えます。

HTTP/2の導入を検討するような大規模サービスでは、この HTTP HoL Blocking が発生している状況か?、 HTTP HoL Blocking の解消によってページの表示速度が改善するか? といったことを見極めるのが大事です。

  • ヘッダの圧縮

ヘッダの圧縮も並列性のサポートと同様で、もちろん良いだろうとは思いますが、新規にプロトコルを定義するほどのメリットがあるとは思えません。大きなHTMLやJavaScript等を、従来の枠組みの中で可能であるgzip圧縮すればよいだけだろうという気がします。

引用ではHTMLやJavaScriptgzip圧縮を代替え案として挙げていますが、HTTPヘッダのデータをgzip圧縮をすることも指していると想定してコメントします。

HTTP/2の前身のSPDYでは、HTTPヘッダのgzip圧縮が行われていました。しかしCRIMEという攻撃手法が公開され、TLSで暗号化された通信上でも圧縮データのサイズを判別することでヘッダ情報が漏えいするといった脆弱性が発見されました。そのため現在のSPDYではクライアントからのリクエストヘッダの圧縮は無効化されています。

しかしHTTPは、クッキーやユーザーエージェント等の冗長で繰り返し送受信されるヘッダ情報が多く、ヘッダデータの圧縮による通信量削減は効果が大きいです。

HTTP/2では、HPACK というHTTPヘッダに特化した圧縮技術が開発されました。全く新しい仕組みであるため途中仕様が右往左往しましたが、最終的に平均で3割程度の圧縮率が達成できています。

ただ肝心のCRIMEの脆弱性対策ですが、gzipよりも困難になりましたが、完全に対策できているものにはなりませんでした。結局フレームにパディングを入れてサイズをごまかしたり、機密度の高いヘッダ情報は圧縮用にインデックスしないなど HTTP/2 時代でも CRIME攻撃を意識してHPACKを使わないといけない状況です。この辺、まだまだ技術的な改良の余地が今後あるでしょう。

  • ステートフルすぎる

HTTP/2では複数のストリームやプライオリティ、依存ツリーなど、とにかく大量の状態を管理する必要があります。これは「リクエストが来たらレスポンスを返す」だけだったHTTP/1.1と比べると非常に大きな違いで、実装は今までのHTTP/1.1と比べ、とてつもなく複雑化すると思われます。

これは同意です。特にプライオリティ実装は非常に大変です。幸いなのは機能的にオプション扱いでまだこれから実験段階の機能であるということです。ただ仕様書を注意深く読み込まないとこの辺の判断はできないと思いますね。

  • 他のレイヤーとクロスオーバーしすぎている

HTTPのRFCであるのにTLSに言及している箇所があったり、データの転送について、まるでTCPのようにフロー制御の機能があったりと、きれいに「そのレイヤー」に収まっていない印象を受けました。

ここはTLS・フロー制御の2つ項目が挙げられていますが、別々の理由があります。

  • TLSの(厳しい)要件の導入

ここは大きな議論がありました。HTTP/2に必須なALPNによるネゴシエーションだけでなく、暗号強度や種類など通常のTLS利用より厳しいTLS要件が記載されているからです。

これは当初、既存のTLS1.2までは後方互換重視でつぎはぎ的な技術対応がされており、TLS上での利用が大部分を占めるHTTP/2では、できるだけ安全な条件の上で通信を行うべきであるという方針からです。他方、下のレイヤーのTLSはどんなものであろうと受け入れるべきであるとの意見もあり、ラストコール直前で大きな議論に発展しました。

結果的に今の仕様のように200以上の暗号のブラックリストを加えることになってしまいました。本来 TLS1.3 の仕様化が完了していれば、単にHTTP/2はTLS1.3上のみサポートということになっていたでしょう。

  • フロー制御の導入

フロー制御は当初のSPDY/2ではなかった機能です。1本のTCP内で複数のストリームが帯域の取り合いし、競合してしまうのでSPDY/3から導入された機能です。そして全体の帯域を有効活用できるようコネクションレベルのフロー制御がSPDY/3.1から導入されました。詳しくは、 twitterが spdy/3.1 の試験を始めてますを読んで下さい。

  • 複雑すぎる

全体的に、それほど大きなメリットがなさそうなのにやたら複雑になってしまっている印象を受けます。

  • 単に追加するだけで何も減らせていない

HTTP/1.1から無駄な部分(個人的には思いつきませんが)を極力減らし、シンプルにした上で出てくるのであればまだしも、単に追加だけしてしまっているので、開発者の負担を増やす方向にのみ向かってしまっています。

複雑さと機能追加の議論は本当に揺れ動きました。

これでもラストコール直前に様々な機能が拡張機能に追い出され、だいぶスリム化が図られたものです。
ただ複雑さは高度な運用ノウハウが必要になるものと思われます。ここ数年でHTTP/2を本当に使いこなせるようになるところはそれほど多くないでしょう。

  • これは流行らないかも

HTTP/1.1にとても大きな不満がなければ、HTTP/2を積極的に導入しようとするモチベーションは湧きません。

これは完全に同意します。HTTP/1.1をdeprecateしてHTTP/2への移行するということはないので、現状のHTTP/1.1の利用で大きな不満がなければ、継続的に使い続けるのがよろしいかと思います。

  • WAF開発者としての視点から

具体的には、PINGやPUSH_PROMISEなどによってWAF側から積極的にクライアントに対して働きかけ、反応を見ることで実装のフィンガープリンティングがやりやすくなりそうです。

この視点は新鮮でした。例えばFirefoxは接続を切られないよう1分毎にPINGを送ってきます。他にも、仕様では Connection Error/Stream Error の2種類のエラーとその発生条件が定義されていますが、各実装によって微妙に違うような感じがします。もしかするとエラー時の挙動の違いでクライアントやサーバの特定ができる可能性があるかもしれません。

と、以上ずらずら書いていたら思わず長文になってしまいました。少しでも皆さんの HTTP/2 に対する理解が深まれば幸いです。

*1:typo修正しました。khtokage さん、ご指摘ありがとうございました。

OpenSSLの脆弱性(CVE-2015-1793)によるAltチェーン証明書偽造の仕組み

$
0
0

TL;DR やっぱり書いていたら長文になってしまいました。あまりちゃんと推敲する気力がないので、変な文章になっているかもしれません。ご了承いただける方のみお読みください。

1. はじめに

昨晩未明にOpenSSL-1.0.2d, 1.0.1pがリリースされました。事前に予告されていた通り深刻度高の脆弱性CVE-2015-1793が修正されています。Advisoryを見ると、この脆弱性がiojs/Nodeに影響があるということが判明したので直ちにiojs/Nodeのアップデートを行い、今朝未明に無事脆弱性対応版をリリースしました。

今回が初めてではありませんが、深夜に日欧米のエンジニアがgithub上で互いに連携しながら速やかにセキュリティ対策のリリース作業を行うことは何回やってもなかなかしびれる経験です。時差もありなかなか体力的には辛いものがありますが、世界の超一流のエンジニアと共同でリアルタイムにプロジェクトが進めることができる環境はエンジニア冥利に尽きます。

さて今回の脆弱性Alternative chains certificate forgery は、日本語に訳すと「代替えチェーン証明書の偽造」になるんでしょうか? この Alternative chains certificate の機能(以下 Alt Cert Chainと書きます)は、実はなかなか自分と因縁めいた関係があります。一番最初は、昨年末の「Node-v0.10.34がはまったクロスルート証明書とOpenSSLの落とし穴」の出来事からでした(もしまだ読んでいない方は是非)。

その時は OpenSSLに修正が入らず、Node側で1024bitの証明書を復活対応して issue を回避しました。その後 openssl の master(1.1.0系) に alt cert chain の機能が実装されました。その時に1.0.2へのバックポートするかどうか聞いたのですが、機能変更になるのでバックポートはしないという返事をもらったため、iojsでは独自にopensslにパッチをあてて運用してました。

その後やっぱり1024bitの証明書廃止の流れに負けてか、OpenSSLプロジェクトが1.0.2/1.0.1系へalt cert chainのバックポートが行われました。もう独自パッチをあてる必要がなくなるので喜んだのですが、よく見るとなんかいらないものまでバックポートされている。そこで問い合わせたところ間違ってパッチを入れ込んだということで 'Revert "Fix verify algorithm." 'の修正が入りました。このおかげでOpenSSLのコミットログにわざわざクレジットを入れてもらい、とても嬉しかったです。

まずは、今回の修正コミット "Fix alternate chains certificate forgery issue"を見てみましょう。

diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 8ce41f9..33896fb 100644
--- a/crypto/x509/x509_vfy.c+++ b/crypto/x509/x509_vfy.c@@ -389,8 +389,8 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
                         xtmp = sk_X509_pop(ctx->chain);
                         X509_free(xtmp);
                         num--;
-                        ctx->last_untrusted--;
                     }
+                    ctx->last_untrusted = sk_X509_num(ctx->chain);
                     retry = 1;
                     break;
                 }

いやはや、わずか2行です。得てしてこういうものかもしれません。これまでこのパッチ部分は結構読み込んでいたにも関わらず、今回のは全く見つけることができませんでした。まぁ無念です。バグを探し出したのは Google BoringSSL の agl さんらのチーム。やっぱ流石です。

そういう反省を踏まえつつ、今回の Alt cert chain の脆弱性がどういう理由で行ったのか、少し解説してみたいと思います。

2. 証明書検証のキホン

まずは、一般的にTLS接続で証明書がどう検証されているかの説明です(図1)。

クライアントにはあらかじめルート証明書等自分が信頼する証明書がOSなりアプリなりにインストールされています。クライアントがTLSサーバに接続すると初期のハンドシェイクでサーバから、サーバ証明書や中間証明書が送信されてきます。証明書には自分自身を表す Subject と発行者を表す Issuer が記載されており、クライアントは、接続するTLSサーバ証明書から Issuerをたどっていき、最終的にルート証明書までのチェーンが作られます。

そこで、それぞれの署名検証や証明書フィールドのチェックを経て、最終的に正当なサーバ証明書であることを判断します。
この証明書チェーンの正当性の検証は、TLS接続の安全性を確保する根本的な仕組みです。ここにほころびがあるともうダメです。そのため今回の脆弱性は、深刻度高にカテゴライズされました。

また、ここで出てくるルート証明書や中間証明書は誰でも発行できるものではありません。ポリシー的な制限もありますが、証明書の X509v3 Basic Constraints が CA:TRUE になっている必要があります。

今回の脆弱性は、CA:FALSEとなっている通常中間証明書として使えない証明書を、中間証明書と偽造し、正当な証明書チェーンとして検証をパスさせるものです。

例えば、自分のサーバ証明書をCAとして使って勝手にいろんなサーバ証明書を発行して利用したとしても、なんの問題なく使えてしまうということです。これはTLS通信の信頼性の根本を揺るがす問題です。

3. クロス証明書とは

今回問題となった Alt Cert Chain は、クロス証明書と一緒に使われる機能です。クロス証明書について簡単に触れます。

以前はルート証明書は1024bitsのが主流でしたが、計算機資源の発達によりもはや1024bitでは安全でなくなってきました。そこで本格的に危なくなる前に2048bitsのルート証明書へ更新が行われることとなりました。ただ古い端末では2048bitsの証明書を扱うことができず、クロス証明書をいれることによって互換性を持たせながら運用していくことが行われています(図2)。

Alt Cert Chainとは、このクロス証明書が使われている場合に古いルート証明書へのパスが作れなくなった時にもう一方の証明書チェーンを作って正当性の検証を行う機能を指します(図3)。

OpenSSLの場合、最初にサーバから送られた証明書リストを元にチェーンを作成するため、どうしても左側の長い方が最初に検証されることになります。

4. OpenSSLによる署名検証と Alt Cert Chain の作成のやり方

OpenSSLは、どうやって署名検証や Alt Cert Chainを作っているのでしょうか?

細かい部分を省くと図4の通り単純なスタック構造に入れ込み、サーバから送られて来た証明書を untrusted なものとして色分けしています。

図の場合では、サーバから送られたuntrusted な証明書は8つ、クライアントに保存されている最後のルート証明書が trusted で1つ、合計9つのスタックによる Cert Chain の出来上がりです。

Alt Cert Chainは、サーバから送られた一旦このスタックを検証してから作成します。ルート証明書までのパスが検証できないので上から順番に保存している trusted の証明書の中から該当するものがないか探しに行きます(図5)。

図の場合は、中間証明書Dのところでルート証明書Eが見つかりました。そこで中間証明書Dより上の部分を捨て去って Alt Cert Chainを作成します(図6)。

この場合、untrusted certの数を再計算するのですが、4つ取り除いたので 8-4=4 で4の untrusted とルートの合計5つの Alt Cert Chainスタックの完成です。これで署名検証が成功すれば正当性が無事保証されます。この検証を行う場合、untrusted で番号2以上のものは中間証明書であるため CA:TRUE であるかのチェックが行われます。

実は、このuntrustedの証明書を求める引き算にバグがあったのです。

5.CVE-2015-1793による証明書偽造のやり方

CVE-2015-1793で問題となった証明書チェーンを図7に示します。

これまでと違うのは、最初のチェーンで trustedな中間証明書Dが存在すること。そして中間証明書BのCA:FALSEになっているところです。このチェーンは、中間証明書Dの issuerのルート証明書がないので検証は失敗します。そこで Alt Cert Chainを探しに行きます。

中間証明書Bのところで Alt Cert Chain ができるので、再作成してみると図8の様になります。

証明書を2つスタックから捨てたので untrusted の数は、3-2=1 です。おっと、でもサーバから送られた untrusted証明書はAとBの2つです。AからCまでの証明書チェーンの検証は正当なため成功します。しかし untrusted な証明書の数が1であるため、証明書Bに対して CA:TRUE のチェックが行われません。なので本来中間証明書として使うことができない証明書Bを中間証明書と偽造することに成功しているわけです。

どうしてこういうことが起きたのか?

それは untrusted の計算方法にありました。

捨てた証明書2つですが証明書Dは trusted なものです。 trustedを捨てたのに untrusted の数を引き算するため数が合わなくなる、そういうバグに起因した脆弱性でした。最初の方に記載したパッチを見てもらえればわかりますが、untrusted の decrement をやめて、untrusted はルート証明書Cがのっかる前のスタック数(=2)を代入するよう変更しています。こうすれば最終的に untrusted の数のつじつまが合います。

6. 実際に CVE-2015-1793を試す。

実際にためしてみましょう。https://github.com/openssl/openssl/tree/master/test/certs脆弱性を試験する一連の証明書があります。それを流用してみます。

//// Test for CVE-2015-1793 (Alternate Chains Certificate Forgery)//// RootCA(missing)//   |// interCA//   |// subinterCA       subinterCA (self-signed)//   |                   |// leaf(CA:false)----------------//   |//  bad(CA:false)var tls = require('tls');
var fs = require('fs');
var bad = fs.readFileSync('./bad.pem');
var bad_key = fs.readFileSync('./bad.key');
var interCA = fs.readFileSync('./interCA.pem');
var subinterCA = fs.readFileSync('./subinterCA.pem');
var subinterCA_ss = fs.readFileSync('./subinterCA-ss.pem');
var leaf = fs.readFileSync('./leaf.pem');

var opts = {
  cert: bad,
  key: bad_key,
  ca: [leaf, subinterCA]};
var server = tls.createServer(opts);
server.listen(8443, function() {var opts = {
    host: 'bad',
    port: 8443,
    ca: [interCA, subinterCA_ss]};
  var client = tls.connect(opts, function() {
    console.log('connected');
    client.end();
    server.close();
  });
});

脆弱性のある iojs-2.3.1では、

ohtsu@ubuntu:~/tmp/CVE-2015-1793$ ~/tmp/oldiojs/iojs-v2.3.1/iojs alt-cert-test.js
connected

途中に CA:FALSEの中間証明書が挟まっているのに正常に接続できてしまってます。

脆弱性対応版では、

ohtsu@ubuntu:~/tmp/CVE-2015-1793$ ~/github/io.js/iojs alt-cert-test.js
events.js:141
      throw er; // Unhandled 'error' event
            ^
Error: unsupported certificate purpose
    at Error (native)
    at TLSSocket.<anonymous>(_tls_wrap.js:989:38)
    at emitNone (events.js:67:13)
    at TLSSocket.emit (events.js:166:7)
    at TLSSocket._finishInit (_tls_wrap.js:566:8)

おー、ちゃんとチェックされています。

実際にこの脆弱性を突く証明書の構成が現状可能かどうかまでは調べていませんが、TLS接続の根本にかかわる証明書検証をバイパスする穴は本当に危険です。ホントちょっとしたバグですが、セキュリティに関わる部分は本当に致命的な欠陥につながるなと改めて思いました。

HTTP/2時代のバックエンド通信検討メモ

$
0
0

1. はじめに、

今朝、こんな返事を元に kazuho さんとIPsec/TLS等バックエンド通信について議論する機会を得ました。

せっかくだから現時点での自分の考えを整理してメモとして残しておきます。
普段ちゃんとしたストーリをもったエントリーしか書いていないのですが、今回は時間がないのでちゃんとした論理的文章になっていないメモ程度のものです、あしからず。

以下、フロント側に HTTP/2 を導入した場合のバックエンド通信をどう考えるかのメモです。

2. 性能的観点

フロントにHTTP/2を導入したということは、ブラウザのHTTP HoLブロック解消が目的の一つだと思う。HTTP/2の多重化通信によってクライアントからこれまで以上の同時リクエストをさばかないといけない(だいたい初期値は同時100接続ぐらいに制限されていると思う)。

他方バックエンド側通信は、クライアント側がブラウザではないので同時接続数の制限は運用で自由に変えられる。なのでHTTP/1.1のままうまくチューニングして運用できる余地もある。でもスケーラビリティを考え、将来HoLが発生して性能ボトルネックになる可能性を想定し、HTTP/2にして多重化するのも選択肢として大いにあるだろう。

3. セキュリティ的観点

HTTP/2の実装仕様の検討が始まりつつあった2013年5月、スノーデン事件による漏洩情報から米国NSAによる pervasive surveillance の事実が明るみに出された。これをきっかけにインターネット通信のベースをTLS化する機運が一気に広まった。

また同年11月には、NSA(米国)/GCHQ(英国)によって通信会社の光ファイバーからデータをタップしてGoogleYahoo!のDC内通信を盗聴するMUSCULAR (DS-200B)プロジェクトの情報も明るみにでた。これでHTTP/2の導入を行うようなサービス大手は、MUSCULARの盗聴対象となっている可能性が高いことから、内部通信を暗号化する動きが加速化した。

現状でのユースケース(パターンか?)はこんなところだろう。

ユースケース1:
HTTP/2, SPDYを導入するような大規模サービスの運営組織 =
NSA/GCHQによるMUSCULARの盗聴対象 = 内部ネットワーク通信の暗号化対策

ということで、このユースケースに該当するような組織は、内部通信をTLS化してHTTP/2対応するのは自然の流れである。

当然のことだが、DC内のセキュリティは当然内部通信の暗号化だけでは守れない。
侵入対策、データ保護、認証・認可の管理等々も必要で、TLSによる暗号化対策は、双方向認証が必要になるような src の偽造、乗っ取り、新規追加ができるようなノードに侵入された攻撃からは無力であろう。

尚SPDYでは事実上できなかったTLSのクライアント認証は、HTTP/2ならHTTP/2通信が始まる直前に renegotiation してできるように仕様が定義された。ただ実際にできる実装があるかは個人的に知らない。

RFC7540 9.2.1 TLS 1.2 Features
An endpoint MAY use renegotiation to provide confidentiality protection for client credentials offered in the handshake, but any renegotiation MUST occur prior to sending the connection preface. A server SHOULD request a client certificate if it sees a renegotiation request immediately after establishing a connection.

4. 私的見地から Pros & Cons

まとめてみた。

当然日本国内で、3のユースケース1に当てはまるところはほんのわずかであろう。ならば100システムあれば100通りの判断なり、方針があるはず。もちろん幾つかのユースケースに集約されれば良いが、それを期待するにはまだ時期早尚だろう。

当面は、こういった Pros & Cons を作成して、コスト・メリット・AsIS・ToBe を考えながら各自が方針を決めることになるだろう。

パンドラの箱?TLS鍵交換の落とし穴、KCI攻撃とは何か

$
0
0

1. 初参加のセキュリティキャンプ

先週ですが、講師としてセキュリティキャンプに初めて参加しました。
担当したのは高レイヤーのセッションで、TLSとHTTP/2の講義を合計6時間、まぁ大変でした。講義の時間配分、分量などの検討が十分でなかったため、本番では事前に準備していた講義内容の一部しかできず、ホント反省しきりです。せめての救いは、今回作った講義資料にたくさんのfavを頂いたことです。ありがとうございました。

講義では、学生の方々が短い時間ながら難しい演習に真面目に取り組んでくれました。質疑なども皆受け答えがしっかりしていて、技術的にもレベルが高い回答も多く、非常に驚きました。これだけ優秀な10代、20代の若者が、全国各地から毎年50人も集まるのを実際に見ると、彼らの将来が楽しみです。これまで10年以上継続してこのような活動を続けきた成果でしょう。私自身、とても良い経験をさせていただきました。セッションオーナーの西村さん、はせがわさん、講義を手伝っていただいたチューター、運営スタッフの方々、本当にありがとうございました。

2. TLSに対するKCI(Key Compromise Impersonation)攻撃とは何か?

講義準備に追われていた8月10日、ワシントンでセキュリティに関するワークショップ USENIX WOOT'15 が開かれていました。
その会議では、一つ面白い発表と論文「Prying Open Pandora's Box: KCI Attacks against TLS(開いたパンドラの箱を覗く: TLSに対するKCI攻撃)」が公開されました。 パンドラの箱を覗くとは、何やら意味深なタイトルです。

https://www.usenix.org/conference/woot15/workshop-program/presentation/hlauschek

KCI攻撃は、 Key Compromise Impersonation攻撃の略です。日本語で「危殆化鍵による成りすまし攻撃」と訳すのでしょうか。このKCI攻撃の論文、読んでみるとなかなか非常に面白い。一つ穴を踏ませることに成功すれば、見事にTLSの中間者攻撃が成功します。幸いこの攻撃で使われる機能をサポートしているTLSクライアントが現状少ないため、今のところ世間であまり大騒ぎになっていません(古いMacOSSafariが影響受けます)。これまで気づかれていなかったTLSの鍵交換仕様のすき間を突いた攻撃であることから、「パンドラの箱を覗く」というタイトルがついたのではないかと個人的に思っています。

この攻撃を理解すると、TLSクライアント認証とはどういうものか、TLS鍵交換とはどういうものなのか、その仕組みが明確になります。そこで今回「SSL/TLSの基礎」講義の補習エントリーとして、このKCI攻撃がどういうものなのか、解説を書いてみたいと思います。

2.1 TLSクライアント認証のしくみ

セキュリティキャンプでの講義「SSL/TLSの基礎と最新動向」では、説明が複雑になるのでTLSクライアント認証は説明の対象外にしていました。

一般的に広く使われているhttpsサーバのTLS通信は、サーバ証明書を使ってTLSサーバの正当性を検証する一方向のものです。この場合、どのクライアントから接続を許すかどうかTLSレイヤーでは認証・認可を行っていません。一方TLSのクライアント認証は、サーバ・クライアント双方向でTLS接続の認証・認可を行う方法です。

TLSクライアント認証は、非常に強力なセキュリティ通信ですが、証明書の発行・更新手続きが煩雑であったり、クライアント環境(OS・ブラウザ)で証明書管理の仕組みが統一されていないなど導入や運用のハードルが高く、現状それほど広く利用されていません。また、TLSの接続途中でクライアント認証に移行するような場合、TLSハンドシェイクのrenegotiationが必要となり、複数のTLS接続を集約するSPDYやHTTP/2の通信とはあまり相性が良くありません。
ただ、SSL3.0からある古い機能であるため、基本的な機能はどのブラウザー環境でも使えるようになっています。

2.2 クライアント認証時のTLSハンドシェイク

通常のサーバ認証だけのTLS通信と、クライアント認証をする通信とではどう違うのでしょうか?
TLSハンドシェイクのシーケンスを見てみると違いがわかります。クライアント認証を行う前提として、TLS通信を行う前にクライアント側に認証局から発行されたクライアント証明書と秘密鍵の鍵ペアがクライアントにインストールされていることが必要です。
クライアント認証時に必要なTLSハンドシェイクメッセージを赤字で示します。

サーバ側は、クライアント証明書が必要であることをCertificateRequestでクライアントに伝えます。クライアントはその要求を受け、自身が持つ証明書をサーバに送信します。さらに送信した証明書が自身が保持する正当なものであることをサーバに示すため、それまでのハンドシェイクデータを秘密鍵で署名し、CertificateVerifyでサーバに送信します。サーバはクライアントの証明書とCertificateVerifyの値を検証し、クライアントが正当な鍵ペアを持つ通信相手であることを確認します。

サーバは、CertificateRequestを使ってクライアントに証明書を要求する際、鍵交換手法に応じて必要な証明書のタイプを指定します。TLS1.2では、図中の表の通り7種類規定されています。今回KCI攻撃で利用されるのは、fixed が含まれる証明書タイプです。このタイプを選択すると、サーバ・クライアント双方の証明書に含まれている(固定的で変わらない)公開鍵を用いて鍵交換を行います。その仕組みの詳細について次節で説明します。

2.3 fixed_ecdhによる鍵交換

前述した通りサーバがfixedタイプのクライアント証明書を要求すると、証明書に記載されている固定の公開鍵を利用して鍵交換(DH/ECDH)を行います。他方、最後にE(Ephemeral:一時的)が付くDHE/ECDHE は、セッション毎に毎回異なる鍵を共有する方式です(PFS:Perfect Forward Securecy)。

論文では、www.facebook.comを使った攻撃が例示されています。そこでfacebookの証明書で公開鍵の情報を見てみましょう。

この赤枠で囲った部分が、証明書の公開鍵の情報を表している部分です。楕円曲線の種類と65バイトの公開鍵情報が書かれています。これを見ると*.facebook.comは、楕円暗号を用いたECDSA証明書です。その公開鍵はECDHの鍵交換で利用可能です。本来この証明書を鍵交換に使うためには、 X509 KeyUsage のフィールドにKeyAgreementフラグが立ってないと使えません。しかし、現実にそこまで厳密にチェックするクライアントは少ないようです。論文では www.facebook.com の証明書にKeyAgreementのフラグが入っているとの指摘がありましたが、今回確認したところこの証明書にはそのフラグはたっていませんでした。

fixed_ecdhによる鍵交換では、下図の通りTLSハンドシェイクの途中で相互の証明書を交換し、証明書に掲載されている公開鍵とそれぞれが持つ秘密鍵を組み合わせて、同一のPreMasterSecretを生成します。

その後、この相互で共有されたPreMasterSecretとClient/ServerHelloで交換した乱数と合わせて、実際のアプリデータを暗号化する共通鍵やMAC、初期ベクトルで利用する鍵を作ります。
このPreMasterSecretをいかに安全に共有できているかが、TLS通信のセキュリティを確保するキモの部分であると言えるでしょう。

3. KCI攻撃の仕組み

KCI(危殆化鍵による成りすまし)攻撃は、文字通り危殆化されたクライアント認証鍵を利用してサーバに成りすまし、中間者攻撃を成功させる方法です。そのステップを見ていきましょう。

攻撃によって成りすましの対象となるサーバは、必ずしもクライアント認証を使っている必要はありません。ただしサーバ証明書はDSA/ECDSA証明書で、クライアント側は fixed の証明書タイプを利用したTLSクライアント認証をサポートしていることが条件です。

そして、悪意のある中間者(Evil)が生成したクライアント証明書を何らかの方法でクライアントにインストールするトラップが必要です(後述)。これが成功した時点で、攻撃者がクライアント証明書の秘密鍵を持っていることになるので、「危殆化された鍵」と名付けられているわけです。

次にステップ毎に見事なKCI攻撃を見ていきます。ここでは論文に合わせて https://www.facebook.com/サーバを題材にしてみます。4つのステップで攻撃を成功させます。

3.1 攻撃者がサーバ証明書を入手

これは簡単です。公開されているサーバの証明書はTLS接続すればすぐ入手できます。

サーバの秘密鍵は、厳重に守られているので簡単に入手できませんが、今回の攻撃はサーバの秘密鍵が入手できなくても、公開されているサーバ証明書だけで正当なサーバに成りすまして中間者攻撃が成功するものです。

3.2 クライアント証明書の入れ込み

次に攻撃者は、あらかじめ攻撃用のクライアント証明書と秘密鍵のペアを生成しておきます。この証明書は、後で攻撃者が要求するものなので、特に正式な認証局から発行された証明書である必要はありません。ただし後で鍵交換で使うサーバ証明書と同じ形式(DSA/ECDSA)であることが必要です。

この攻撃用のクライアント証明書の鍵ペアを如何にクライアントに意識せずにインストールさせることができるのか、ここがハードル高いステップです。論文では、iOSではメールで簡単にインストールできたり、Androidアプリなどからも比較的容易にインストールできるトラップが紹介されています。クライアント証明書のインストールはあまり普段使わない機能なので、まだまだ未知の穴があるかもしれません。

この仕込みが成功し、中間者攻撃の前までになんらかの方法でクライアント証明書と秘密鍵がクライアントにインストールされていることが攻撃の条件になります。

3.3 正当なサーバに成りすましてTLSハンドシェイク

さぁ、ここから本番です。
クライアントは 、攻撃者が作成した不正なクライアント証明書がインストールされているものとは知らず、https://www.facebook.com/にアクセスします。攻撃者はネットワーク経路途中で中間者攻撃を仕掛けます。

まず www.facebook.com に成りすましてTLSハンドシェイクを行います。その際サーバ側がServerHelloで選択する暗号方式は、証明書の固定鍵を使う DH または ECDH の鍵交換を行うものを選択します。後述する通り、DHE/ECDHEではサーバの秘密鍵が必要なため攻撃は成功しません。攻撃者は、事前に入手した www.facebook.com のサーバ証明書を送信し、fixed_ecdhタイプのクライアント証明書を要求します。通常 www.facebook.com はクライアント認証することはありませんが、この時点ではクライアントにはわかりません。

クライアントは、攻撃者からの要求に応じてクライアント証明書を送信し、その秘密鍵で鍵交換を行います。おそらくクライアントは、サーバの秘密鍵を持ってなければこの後のTLSハンドシェイクは失敗するはずだと思い込んでいることでしょう。

3.4 同一PreMasterSecretの生成

ところがどっこい、攻撃者はクライアントの秘密鍵を保持しています。
攻撃者は、クライアント証明書の公開鍵とサーバの秘密鍵を使って鍵交換を行うという真面目なことはせずに、既に保持しているサーバ証明書とクライアントの秘密鍵を使ってクライアントと同じ手順で全く同一のPreMasterSecretを生成します。

クライアントと攻撃者間で同一のPreMasterSecretが共有できていれば、後はいかようにもTLSハンドシェイクを偽造して完了することができます。結果、サーバの秘密鍵を使うことをせずに www.facebook.com の成りすまし、中間者攻撃に成功です。

いやぁー、見事できれいです。
前述の通り、危殆化されているクライアント証明書の鍵ペアをどういうトラップでクライアントに入れ込むかというのが課題ですが、TLSの鍵交換しているようでしていない、PreMasterSecretさえ共有できちゃえば勝ちというKCI攻撃の手法は、ホント目から鱗でした。

幸い fixed_ecdh/dhに対応したクライアントが現状ほとんどないので、この攻撃は現状それほど脅威として騒がれていません。論文では、Mac OS X 10.5.3 以前のSafariで攻撃に成功したと報告されていますが、現在は機能が無効化されています。しかし論文ではこの攻撃が知られていないと将来的に実装されて危なくなると警告しています。本当は攻撃を再現した状況を実際に試して載せたかったのですが、攻撃の影響を受けるクライアントが手元になく残念です。今後このような合わせ技攻撃の組み合わせによって思いっきりTLSの穴ができるような別の攻撃手法が出てくるかもしれません。

4. TLS1.3ではどうなる?

講義でも後半触れましたが、現在仕様策定中のTLS1.3ではどうなるでしょうか?

まず鍵交換は、一時鍵を使うDHE/ECDHEのPFSしかサポートされないのでKCI攻撃は無理です。PFSでは、ServerKeyExchangeで送信する公開鍵にサーバが署名するのでサーバの秘密鍵がないと署名検証でクライアントに攻撃がばれます。

またTLS1.3ではサーバ側も常に CertificateVerifyを送る Server Signの要件が新たに入る予定です。これによって、ハンドシェイク途中でサーバ証明書の鍵ペア所有の検証が行われることになり、サーバの秘密鍵なしに中間者攻撃が成立するといった類似の攻撃がTLS1.2より困難になるでしょう。

個人的には、総当たりっぽく平文を判定するOracle攻撃なんかより、このような一つのほころびで全体のセキュリティを台無しにさせるこのKCI攻撃手法は、ある意味美しさを感じてしまいます。これで皆さんのTLSクライアント認証と鍵交換の仕組みの理解が少しでも深まれば幸いです。

5. 明日は YAPC

TLSとは全然関係ないですが、明日(8/22) YAPC Asia Tokyo 2015で「どうしてこうなった? Node.jsとio.jsの分裂と統合の行方。これからどう進化していくのか? 」のセッションの後半で古川さんと対談します。この半年余り、Node.jsプロジェクトの分裂と統合という流れの真っただ中にいた身として、今回の騒動でオープンソースのガバナンスの姿、その一つの形が見えてきた気がします。なかなか経験できない貴重な体験を皆さんにお伝えできたらと思っています。朝10時からと若干早い時間からのスタートですが、皆さんの参加をお待ちしています。

以上、セキュリティキャンプの補習講義でした。


ハッシュ衝突でTLSを破るSLOTH攻撃(CVE-2015-7575)とは何か

$
0
0

0. 簡単なSLOTH攻撃のまとめ

最初に簡単なまとめを書いておきます。長文になりそうなので、読むのが大変な方はここだけ見ておいてください。

  • MD5ハッシュは既に安全ではなく、証明書の署名方式での利用は停止されていたが、後方互換のためハンドシェイクデータの署名方式にRSA-MD5が今でも利用できるTLS実装が幾つか存在していた(Firefox NSS, Java等)。
  • 先週、INRIAグループからハッシュ衝突を利用して実際にTLSを破る攻撃(SLOTH)が公開された。それを受け、いくつかの実装でRSA-MD5を完全に利用不能にする修正が行われた(CVE-2015-7575)。
  • SLOTHでは、SHA1TLS、IKE、SSHに対する攻撃についても評価を行い、幾つかは全く現実的に不可能なレベルではないことが示された。MD5SHA-1TLSハンドシェイクの完全性を担保しているTLS1.0/1.1への脅威は大きくなった。

1. SLOTHとは何か?

これまでFREAKやTriple Handshake, Logjam 攻撃などTLSに対する様々な攻撃を発見してきたINRIAグループが、先週また新たなTLSの攻撃手法(SLOTH)を公開しました。

Security Losses from Obsolete and Truncated Transcript Hashes (CVE-2015-7575)

タイトルを日本語訳すると、「古く廃止されたTruncated Transcriptハッシュによるセキュリティ低下」でしょうか? 何を言っているのかわかりませんね。この攻撃を受ける脆弱性には、CVE-2015-7575も割り当てられており、今のところ先月に対応されたNSS(Firefox)のセキュリティアップデート情報が掲載されています。幸いOpenSSLは、2年ほど前に Don't use RSA+MD5 with TLS 1.2で修正を行っていたため、難を逃れました。OpenSSL-1.0.1f以降なら問題ありませんが、古いRHELで影響を受けるようです。JavaやGnuTLS等その他のTLSライブラリの状況に関しては、INRIAのサイトでまとめられています。
この攻撃の概要は、先週行われたReal World Cryptography Conference 2016で発表されましたが、この論文が採択された来月のNDSS Symposium 2016でもさらに詳細が発表されるでしょう。

このSLOTH攻撃は、TLS実装がRSA-MD5等既に安全でない署名方式が有効になっている場合に、あるハンドシェイクデータと同一のハッシュ値を持つ別のデータを計算し、それを偽造データにして中間者攻撃を仕掛けてTLSの安全性を破る攻撃です。

今回攻撃で使われたMD5は、かなり前から安全ではないことがわかっていましたが、現実的な攻撃としてMD5のハッシュ衝突を利用した偽造証明書の作成に成功したのは2008年末のことでした(MD5 considered harmful today)。これが非常にセンセーショナルな出来事だったため、その反省からブラウザベンダーや認証局は、現実的な攻撃が世に出る前に急いでSHA-1の証明書の移行・廃止を現在進めているわけです。

証明書の署名方式が、このような素早い廃止対応を進めているにもかかわらず、これまでTLSは全面的にMD5を利用不能にしていませんでした。それは静的な証明書データの攻撃に比べ、TLSハンドシェイクは接続時に毎回データ異なるため、現実的にハッシュ衝突の攻撃は難しいだろうと考えられていたからです。しかもMD5は、TLS1.0や1.1でmaster secret等を生成するPRF(擬似乱数生成関数)にも使われているので、完全にMD5アルゴリズムを実装から削除するためには、TLS1.2への全面移行が必要です。これは非常に大変な作業です。

しかし、ついにMD5ハッシュ衝突の計算処理の効率化とTLS仕様の隙間を組み合わせることによって、TLSのハンドシェイクに対する現実的で具体的な攻撃手法が編み出されました。

SLOTHは、TLSハンドシェイクで中間者攻撃が自由に改変できる部分を利用します。攻撃者はハッシュ衝突が起こる偽造データを途中で計算し、エンドポイントのTLSデータの署名検証を欺きます。その結果、中間攻撃者によるTLS通信のなりすましや改ざんなどTLSの認証を破ることに成功しました。

SLOTHの論文では、TLSだけでなくIKE, SSHに対してハッシュ衝突を利用した様々な種類の攻撃を検証しています。TLSに対する攻撃として、

  1. RSA-MD5が有効になっているエンドポイント間のTLSクライアント認証への攻撃
  2. RSA-MD5が有効になっているTLSサーバ認証への攻撃
  3. TLS1.3のサーバ認証やクライアント認証への攻撃
  4. TLS1.0/1.0のハンドシェイクデータを改ざんして弱い暗号方式にDowngardeする攻撃
  5. TLSのハンドシェイクハッシュ値を偽造してアプリが利用するチャネルバインディングに対する攻撃

の5つが挙げられています。

論文を読むとまぁいつものごとく、見事な攻撃なのでホント感心させられます。ここで自分の理解を残しておくために、この中で一番計算量が少なく(2^39)、現実的に攻撃ができることを実証した1のTLSクライアント認証に対する攻撃について詳しく書いてみます。

2. Chosen-Prefix 衝突とは?

前述の通り、SLOTHはハッシュ衝突を計算して偽造データ作成するのがキモの一つです。しかも改変できるのは任意の部分でなく、主に頭の部分でデータ構造や書式の制限がついています。このような条件の元でハッシュ衝突を求めることを Chosen-Prefix 衝突と呼びます。

Chosen-Prefix 衝突でどのように偽造するか、MD5の攻撃で使われた本物と偽造証明書の比較を見てみるとわかりやすいでしょう。

同一の署名データをもつ偽造証明書は、正当なX509証明書としての構造を持っていないといけません。グレーの部分は一部本物のデータと一致していたり、偽造用に変更されたりする部分ですが、その書式や構造は仕様に合ったもので証明書の偽造目的に応じて固定化される部分です。公開鍵や拡張情報は比較的改変できる自由度が高いため、攻撃者はこの部分を調整して計算を行い、両者のハッシュ値が同一になるよう仕組みます。

頭の固定化されている部分を持っていることから Chosen-Prefix 衝突と呼びます。この Chosen-Prefix衝突の計算方式はこれまでいろいろ研究されていますが、まだかなりの計算リソースが必要です。SLOTHでは過去に開発された衝突探索ツールを改良して性能向上を図ったということです。

3. TLS1.2クライアント認証の復習

今回、SLOTHでTLS1.2のクライアント認証を破ることを解説しますので、TLSクライアント認証の復習です。細かいところは過去のエントリーを読んでください。
TLSのハンドシェイクではClientHelloからFinishedまでクライアント・サーバ間で様々なハンドシェイクデータのやり取りを行います。

TLSのハンドシェイクで利用する署名方式は、ClientHello/ServerHello で signature extension をやり取りして決めます。このTLS拡張によって、サーバ・クライアント間で共通に利用する署名方式が合意されます。現在多くのTLS実装では、明示的にRSA-MD5を有効になっていませんが、後方互換のため安全でないRSA-MD5署名方式で合意してしまうようなTLSサーバが数多く残っています。論文のサーベイでは、30%程度のTLSサーバがRSA-MD5署名を受け入れるようです。

ClientHello/ServerHelloでやり取りするTLS拡張は、signature以外にも様々なものがあります。各実装でサポートしている拡張機能はバラバラなので、サポートしていない拡張フィールドが送られてきてもエンドポイントは無視することになっています。皮肉なことに、この拡張フィールドの自由さに攻撃者がハッシュ値を調整できる余地が隠されていました。

TLSクライアント認証は、CertificateRequest/ClientCertificate/ClientCertificateVerify の3つで実現します。

CertificateRequestは、サーバからクライアントへ証明書を送付を要求するハンドシェイクタイプです。ここでは、後にクライアントが利用する署名方式やサーバが必要とするクライアント証明書の認証局情報(dn)などを指定してクライアント側に送ります。
このdn情報は、複数記載することが可能であり、該当するものがなければクライアントはデータ内容を無視します。ということは、悪意のあるエンドポイントがこの部分を自由に使い、データを埋め込むことができます。ここにもハッシュ衝突攻撃につけ入れられるTLS仕様の隙間が隠されていました。

最後のClientCertificateVerifyは、TLSクライアント認証の重要な部分です。クライアント証明書は秘匿されているものではなく、外部に公開されても構わないものです。そのため第3者がクライアント証明書を流用して成りすますことを防止しなければなりません。

クライアントは、ClientCertificateで証明書をサーバに送付した後に、ClientCertificateVerifyでそれまでサーバとやり取りした全ハンドシェイクデータのハッシュ値秘密鍵で署名してサーバに送付します。サーバはClientCertificateVerifyを受け取ったら、クライアント証明書の公開鍵を利用して相手側のハッシュ値を求め、自身が持つ全ハンドシェイクデータのハッシュ値と比較し署名検証を行います。このステップを踏むことで、サーバはクライアントが正当な証明書と秘密鍵のペアを持つエンドポイントであることを確認します。

4. SLOTHによるRSA-MD5を使ったTLSクライアント認証への攻撃

SLOTHは、中間攻撃者がTLSハンドシェイクデータを細工して正当なクライアントになりすまし、TLSのハンドシェイクに成功する攻撃です。驚くことにこの攻撃によって、攻撃者はクライアントの秘密鍵の情報を盗む必要はありません。攻撃者は、秘密鍵情報にアクセスすることなく署名検証を成功させ、なりすましを行うことが可能になります。この攻撃は、サーバ・クライアント間で交換する一連のTLSハンドシェイクデータ(Transcript)のハッシュ衝突を突く攻撃であるため、Transcript Collision Attackとも呼ばれています。

SLOTHによるTLSクライアント認証の攻撃が成功するには、以下の条件が必要です。

  • クライアント・サーバの両者でRSA-MD5署名方式を利用できる。
  • サーバがTLSクライアント認証を行い、対象サーバ以外(攻撃者のサーバ)にも同一のクライアント証明書を送付している。
  • クライアントがDHE鍵交換をサポートしており、クライアントが素数でないDHパラメータも受け入れてしまう。
  • サーバ側から送られてくるTLSハンドシェイクの長さが予測できる(データの中身ではない)。

ではSLOTH攻撃をステップ毎に見ていきます。

4.1 ステップ1: クライアント・攻撃者間でTLSハンドシェイク(途中まで)

まず攻撃者は、なんらかの方法でクライアントを誘導して中間攻撃者向けにTLSハンドシェイクを開始させます。この際ターゲットサーバへのDNSの改ざんしてサーバIPを偽造する必要はなく、攻撃者自身のドメインと証明書によるTLS接続で構いません。

攻撃者は、クライアントと攻撃者間の鍵交換はDHEで行います。サーバからクライアントに送るDHパラメータp, gは、p=g^2-g を指定します(gは普通2を使う)。pは本来素数であるべきですが、p=g^2-g=g*(g-1)なので素数ではありません。クライアントが厳密にチェックしなければ使えてしまいます*1。この仕込みがどう生きてくるか後のステップ7で説明します。

攻撃者は、CertificateRequestの前でハンドシェイクを一旦ストップさせます。

4.2 ステップ2: ハッシュ衝突の計算

次に攻撃者は、これまでクライアントとやり取りしたハンドシェイクデータと、次に送信する CertificateRequest のデータ、そしてそこに追加されるCertificateRequestのパラメータの一部(dn情報長さ)を予測してデータAを決めます。この長さ情報の予測が後のステップで生きてきます。

攻撃を成功させるために、このデータAと、中間攻撃者がサーバ側とのTLSハンドシェイクするデータのハッシュ値が一致するよう、データBを計算して探し当てます。

実際どのような Chosen-Prefix のデータ列になるのか、TLSハンドシェイクデータを並べて見てみるとわかりやすいです。

上図のグレー領域が固定化された(Chosen-Prefix)部分、赤い部分がハッシュ衝突を調整するために計算されたデータの部分です。dn lenの部分は今後サーバから送られてくるハンドシェイクデータ長を予測して決めます。TLSデータは書式が固定化されている部分が多いので、データ長だけを予測するのは難しくないと思います。
攻撃者・サーバ側のデータは、ClientHelloの拡張領域に衝突を発生させるデータを埋め込みます。前述したようにTLSサーバは知らない拡張は無視するため、攻撃者にとって自由なデータを埋め込むことができ、ハッシュ衝突を調整するには都合が良くなっています。

サーバ側に送り込むClientHelloには、明示的にRSA-MD5署名方式のみでサーバ側とハンドシェイクを行うようにsignature extensionを埋め込みます。前述した通り、後方互換重視のサーバはこの署名方式でハンドシェイクを受け入れてしまいます。

最後にここまでの両者のデータ長をハッシュ方式のバイト長境界(MD5なら16バイト)に合わせます。これによって一度2つのデータのハッシュ値を一致させると、次に同じデータをそれぞれに結合してもハッシュ値が同一に保たれます。

このChosen-Prefixの衝突計算は、効率化による省メモリ化や並列処理の改善によって現在48コアで1時間程度で計算が可能なようです。その1時間の間、攻撃者はクライアントにアラートを送り続けてハンドシェイクセッションを維持しておきます。

4.3 ステップ3: 攻撃者・サーバ間でTLSハンドシェイクの開始

MD5(A)=MD5(B)となるChosen-Prefix衝突の計算が完了したら、攻撃者はサーバ向けにTLSハンドシェイクを開始します。

攻撃者・サーバ間でRSA-MD5署名方式で合意できたら、ここまで中間攻撃者を介した2つのTLSハンドシェイクデータのハッシュ値は一致することになります。

4.4 ステップ4: 攻撃者のハンドシェイクデータの偽造

攻撃者からのClientHelloと偽造用の拡張データを受け取ったサーバは、それに応える一連のTLSハンドシェイクの応答(ServerHello,Certificate,CertificateRequest)を返します。

攻撃者は、このデータ結合したもの(ServerHello|Certificate|CertificateRequest)をクライアント側に偽のdn情報と見せかけ、CertificateRequestのパラメータの最後に付加してクライアントに送付します(|はデータ結合を表します)。

両者のハッシュ MD5(A|C) は MD5(B|C) と同一のままです。

Chosen-Prefix中のdn len には、あらかじめ青色のCのデータ長まで含んだ長さを予測して含んでいたため、単純に最後に結合することが可能となりました。

4.5 ステップ5: クライアント・攻撃者・サーバ間でハンドシェイクの同期

この後攻撃者は、ハンドシェイクデータを素通しします。


素通ししたハンドシェイクデータDは、どちらの接続にも追加されるため、両者のハッシュ値 MD(A|C|D) と MD(B|C|D) は同一のままです。

4.6 ステップ6: 中間者攻撃下の署名検証の成功

いよいよSLOTHの攻撃のクライマックスです。クライアントは自身の正当性を証明するためにそれまでやり取りしたTLSのハンドシェイクデータ A|C|D のハッシュ MD(A|C|D) を自身の秘密鍵で署名し、ClientCertVerifyとして送付します。

攻撃者は、これまでと同様にクライアントからのClientCertVerifyをサーバへ素通しで転送します。

ClientCertVerifyを受け取ったサーバは、クライアント証明書の公開鍵を使ってクライアントのハンドシェイクデータのハッシュ値MD(A|C|D)を取得します。 続いて、これまで攻撃者とやり取りしたハンドシェイクデータ B|C|D のハッシュ値MD5(B|C|D)の値と比べます。

これまでのステップによるデータの偽造により両者のハッシュ値は一致するため、見事に署名検証成功です。

4.7 ステップ7: MAC偽造によるハンドシェイク完了、なりすまし成功

署名検証の成功でクライアントの正当性が確認されると、クライアント・サーバ間でChangeCipherSpecをトリガーにして暗号化通信が開始されます。
このままでは、中間攻撃者は自身を介した2つのハンドシェイクの完了を成功させることはできたけれども、共通鍵がわからないので暗号化されたデータの中身を見ることができなくなります。ここでステップ1で仕込んだDHEの不正な素数パラメータがようやく生きてきます。

ステップ1で攻撃者は、DHEのパラメータをp=g^2-gで送付しました。その場合、クライアントが秘密鍵 x を使って公開鍵を作成しても g^x mod p = (g^(x-2)+...+1)*(g^2 -g) + g) mod p = g なので、クライアントの公開鍵は秘密鍵xによらず g のままです。ClientKeyExhangeでそのクライアントの公開鍵はサーバと交換されており、サーバから送られた公開鍵が g^y とすると、共有鍵は g^xy mod p = (g^x mod p)^y = g^y となり、サーバ側の公開鍵だけで共通鍵を計算できてしまうことになります。従って中間攻撃者に共有鍵がバレバレな状態に持っていくことができます。
この仕込みのおかげで攻撃者も同一の共有鍵の計算を行い、暗号化データの操作や交換するFinishedのHMACデータと一致させることも可能となります。

これで、攻撃者とサーバ間のTLSクライアント認証を伴ったTLSのハンドシェイクの完了です。

無事、攻撃者はTLSクライアントのなりすましに成功しました。
実際書いてみると、いろいろ大変な手続きが必要な攻撃ですが、秘密鍵の漏洩がなくてもなりすましが成功するとは、いやぁー見事です。

5. 危なかったTLS1.3

論文ではTLSサーバのなりすます攻撃も記述しています。TLS1.2のサーバ認証では、ServerKeyExchangeの署名検証を偽造させて成功させないといけませんが、中間攻撃者が自由にいじれるのはClientHelloの乱数値(32バイト分)だけです。この様な制限下ではハッシュ衝突攻撃を行うのはまだ大変困難です。まずは一安心。

TLS1.3では、サーバ認証をクライアント認証と同様のServerCerticateVerifyをTranscriptハッシュの署名を利用するよう仕様変更が行われました。これはクライアント認証同様の手法でサーバのなりすましができるようになり大問題になります。TLS1.3では、INRIAグループからの指摘を受け、仕様からMD5SHA-1アルゴリズムを全面的に削除し、該当パラメータをReservedに変更しました。サーバ認証が破られるとその影響は多大なものになるので、TLS1.3は本当に危ないところでした。

6. TLS1.0やTLS1.1はどうなる?

SLOTHの公開を受けてIETFTLS WGでもMD5をどうするか、TLS1.0/1.1をどうするか、の議論が始まりました。
SHA-1衝突を見つける計算量はまだまだ膨大で、MD5SHA-1と組み合わせたPRFに対する具体的な衝突がまだ見つかっていません。また、ChromeIEの統計からTLS1.0/1.1の利用率は現在でも3〜5%存在するため、現時点ではTLS1.0/1.1を直ちに deprecate するという話にはならないようです。

でも確実にSHA-1に対する攻撃の脅威は大きくなってきています。RC4の危殆化とBEAST攻撃でTLS1.0は崖っぷちです。いつまたPOODLEのようなプロトコル上の脆弱性が見つかり、プロトコル自体の廃止が早急に進められる可能性も否定できません。来るべき将来のX-Dayのために、日頃からTLSサーバの構成を注意して備えておきましょう。

*1:多くの実装では使えることが多いそうです。偶数・奇数のチェックを行っているのもあるようですが、その場合は p=g^2-1を利用することができます。ただ g^x mod p が 1 か g^2 のいずれかになるため、確率1/2で当てることになりそうです。

新しいTLSの暗号方式ChaCha20-Poly1305

$
0
0

Disclaimer

本エントリは、近々IETFで標準化される予定の新しいTLSの暗号方式 ChaCha20-Poly1305 について解説したものです。

本来なら、新しい暗号方式を紹介するいうことは、その暗号の安全性についてもちゃんと解説しないといけないかもしれません。しかし一般的に暗号の安全性評価はとても難しく、専門家でない者が暗号の安全性について軽々しく書くわけにはいかないなとも思いました。いろいろ悩みましたが、結局無用な誤解を避けるため、本エントリーでは ChaCha20-Poly1305 の安全性に関する記載を最小限に留めています。

今回紹介する ChaCha20-Poly1305 は、これまでも様々な暗号研究者の評価を受けている暗号方式ですが、まだNISTの標準や某国の推奨暗号リストに掲載されるといった、いわゆる特定機関のお墨付きをもった暗号方式ではありません。記載内容が中途半端で申し訳ありませんが、ChaCha20-Poly1305 の暗号利用の安全性について心配な方は、本エントリーをお読みにならないようお願い致します。またこういった内容を留意していただいた上で、本記事をお読みくださるようお願いします。

2016年6月23日追記:
RFC7905「ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)」 が発行されました。

0. 短いまとめ

記事が長いです。長文を読むのが苦痛な方は、この短いまとめだけ読んでください。

  1. 新しいTLSの暗号方式 ChaCha20-Poly1305 が仕様化されます。
  2. 新仕様版はChrome49/Firefox47/OpenSSL-1.1.0(beta)などで既に利用可能です。
  3. AES-GCMより転送サイズが小さくなり、AES-NIのないARM環境では3倍程度性能が高くなります。
  4. OpenSSLなどでcipher server preferenceと両立して運用するには現時点で課題があります。equal preference cipher groups機能待ちです。

(2016年5月16日 訂正: 記事中 TLSのAES-GCMのタグ長が12バイトと記載されていましたが、16バイトの誤りです。図表と記載を修正しました。id:kazuhookuさんのご指摘ありがとうございました。)

1. TLSに新しい暗号方式が必要となった背景

常時HTTPS化は、これからのWebには避けられない流れです。その中核となる通信プロトコルTLSには、現在いろいろなリスクや課題が存在します。

1.1 AESがTLSのSPOFになっている

その課題一つに現在広く利用されているAESを使った暗号方式に関するものがあります。

  • 現在実用的に広く使えるTLSの対称暗号が実質AESの一択しかない。

AES以外の暗号で普及しているという意味ではまだ3DESも健在ですが、性能がAESに比べて1/4〜1/10に落ちてしまいます。AES/3DES以外にも性能的に見劣りしない対称暗号もありますが、世界的に広く使われているとは言い難いです。

こんな状況でもし今、AESに重大な問題が見つかったらとしたらどうなるか? TLSの運用者は非常に厳しい選択に迫られます。対称暗号以外ではTLS1.2において、認証は RSA/ECDSA, 鍵交換は DHE/ECDHEと2つ以上の仕組みが存在します。リスク管理の観点から、現実的に代用できるAESのバックアップを持つことが今のTLSに必要です。

1.2 AES-NIのないARM環境でも安全で高速な暗号が欲しい
  • AESはハードウェア処理(AES-NI)が使える環境では非常に高性能だが、ソフトウェア処理だけではそれほど性能がでない。またAESはキャッシュタイミングなどサイドチャネル攻撃を避ける必要がある。そのため実装が複雑になりがちである。

IntelAMDのCPUで実装されているAES-NIは、非常に強力な機能です。AES-NIを使うだけで暗号処理能力は数倍に跳ね上がります。しかしモバイルやIOTの環境でよく利用されるARMにはAES-NIなど入っておらず、非力なCPUの上でソフトウェアで頑張らないといけません。その上、やみくもな最適化はキャッシュタイミングによるサイドチャネル攻撃を受ける可能性があります。

シンプルな実装で、なおかつAES-NIのない環境でも十分に性能が確保できる暗号方式が求められています。

1.3 新しい暗号方式 ChaCha20-Poly1305 の導入

ChaCha20はストリーム暗号、 Poly1305はメッセージ認証(MAC)の機能を実現します。共に著名な D. J. Bernstein (djb)氏が考案しました。djbは当初SalSa20という暗号を公開し、後にChaCha20という改良版を発表しました。いずれもラテンダンスの名前にちなんでいるようですが、はっきりと名付け由来が書いてある記述を探し当てることはできませんでした。どなたか由来を知っている人がいらっしゃいましたら教えて下さい。

4/5追記: id:bottomzlifeさんより情報を頂きました。ありがとうございます。

Poly1305に関しては、最初 dbjdjbはhash127という2^127-1の素数を使ってMACを計算する方式を発表していましたが、後により計算効率が良い2^130-5の素数を使ったPoly1305を2005年に発表しました。どちらも鍵の生成に対称暗号と組み合わせることが必要で、論文ではAESと組み合わせたPoly1305-AESが使われていました。Poly1305の仕組み上、AES以外の対称暗号とも組み合わせられることが可能です。

RFC7539では、Poly1305がChaCha20と組み合わせた形で仕様化されました。ChaCha20/Poly1305のどちらも知的財産権などの問題もないと言われています。ChaCha20とPoly1305は、ともに非常に簡潔なアルゴリズムで規定されており、ソフトウェア処理に向いています。これを使って先に述べたTLSの課題を解決できるものと期待されています。

1.4 ChaCha20-Poly1305のこれまでの歩み

ChaCha20-Poly1305のこれまでの歩みをざっと表にしました。

TLSに関連する動きが出てきたのが2013年から。このあたりで、Chacha20とSHA1を組み合わせたり、Salsa20とUMAC(RFC4418)と組み合わせたドラフトなどが公開されていました。動きが本格化したのは、2013/09 にGoogleのセキュリティ専門家 Adam Langlay (agl)氏が、ChaCha20とPoly1305を組み合わせた暗号方式のドラフトを提出してからです。

ちょうど2013/06にEdward Snowden事件でNSAによる広範囲の盗聴・改ざん行為が明らかになり、Dual_EC_DRBGのバックドア問題などNSAが関与しているNIST標準の暗号方式に対する疑義が高まった時分でした。過去米国政府と暗号技術に関して何回も法廷闘争を繰り広げたdjbの暗号は、安全性に対する信頼は他とは違うぞと、この時期の新しい暗号方式の提案にはそんな象徴的な意味合いを個人的に感じてしまいます。

早速ChaCha20-Poly1305は、2013/11にChromeに先行実装され、現在まで既にGoogleのサービスで利用されています。この時期の先行実装は、現在のLastCall 版の仕様と若干異なっており、互換性はないものでした(Googleは既に最新仕様に移行しています)。

Google以外の実装では、2014/04に発覚したHeartBleed脆弱性の余波でLibreSSL/BoringSSLがOpenSSLからフォークされたことを受け、これらのフォークが直ちにChaCha20-Poly1305をサポートし始めました。これらの実装の広がりを受け、IETFTLS WGの要請を受けCFRG(Crypto Forum Research Group)で議論が進み、2015/05にChaCha20-Poly1305の仕様がRFC7539として発行されました。

このRFC7539で規定されたChaCha20-Poly1305をTLSで使えるようにするのが、 draft-ietf-tls-chacha20-poly1305-04 です。2016/3/22にIETF Last Callが開始され、ちょうど明日(4/5)に終わります。IESGとIANAのレビューが無事通れば、近いうちに晴れてRFCになる予定です。この仕様はTLS/DTLSの両方の利用を規定していますが、本エントリーはTLS向けの仕様だけを解説します。

1.5 TLSで使えるChaCha20-Poly1305の種類

今回新たにTLS仕様化されるのは以下の7つの CipherSuiteです。いずれもAEAD(認証付き暗号)であるため、AEADの規定がないTLS1.0/1.1では仕様上利用できません。使うにはTLS1.2以上が必要です。

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 O, F, C
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 O, F, C
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 O, Fコメント欄参照
TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 O
TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 O
TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 O
TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 O

(O: OpenSSL-1.1.0, F: Firefox, C: Chrome)

PSK(PreSharedKey)のCipherSuiteが4つ。ECDHEの鍵交換はRSA/ECDSA認証の2つ、残る1つはDHE/RSAのものです。master secretを生成するPRFにはすべてSHA256を利用します。個人的には Chrome49, Firefox47, OpenSSL-1.1.0-beta1 で既に実装されていること確認していますが、LibreSSLやその他のTLS実装はどの程度対応しているのかまで見ていません。各実装がサポートしているCipherSuiteを表の2カラム目(O, F, C)として記載しておきます。

2. ChaCha20とは何か?

先述した通りChaCha20は非常にシンプルなアルゴリズムを使った暗号です。せっかくだからその仕組みを解説したいと思います。まずはAESと比較してみてChaCha20の特徴を見てみます。

2.1 AESとChaCha20の比較


AESはブロック暗号、ChaCha20はストリーム暗号と分類されます。しかしAES-GCMなどカウンターモードでのAESの利用は、実質ストリーム暗号として機能します。AEADの観点から比較するとストリーム/ブロックでの両者の暗号の違いはほとんどありません。ChaCha20は、入力にNonceと初期カウンター値が必要 なのが特徴です。暗号の安全性を確保するため、Nonceは同じ値が使われないことが必要です。Nonceサイズはオリジナルの djbの論文と異なっています。これはAEADの仕様(RFC5116)の推奨サイズに合わせたためです。

暗号実装では両者は大きく違います。AESでは、剰余計算を高速に行うために事前計算テー ブルを作成したり、要素を非線形に変換するSBOX処理が必要ですが、ChaCha20は後述する通り加算剰余、XOR、ビットローテーションという単純な計算処理だけです。ChaCha20は、SIMDを使うとより高速なソフトウェア処理が可能になります。

2.2 ChaCha 1/4ラウンド演算

先程から繰り返し書いている通り、ChaChaの暗号化を担う処理は非常にシンプルなものです。この処理を行う中心的な関数を1/4ラウンド演算(QuarterRound)と呼びます。ChaChaは内部に4バイトx16個の状態を持っています。このQuarterRoundを使って内部状態の中の4つの要素(a, b, c, d)を混ぜあわせ、新しい要素の値に更新します。

QuarterRoundは、上図の通り4つの演算から成り立っています。 x + y は (x+y) mod 2^32, ^ は XOR, <<< n はnビット左ローテションを表します。注目すべきは乗算がないことです。一般的に暗号技術は、乗算処理が含まれることが多いのです。ChaChaは乗算処理がないため、演算中の桁上り伝搬を心配 する必要がほとんどありません。ビットローテーションも固定長なので、容易に Constant Time の演算処理が実現できます。これがサイドチャンネル攻撃を受けにくい理由です。

ChaChaのQuarterRoundは、1回の処理で4つの要素が2回ずつ更新されています。ここはSalsa20から改良された点で、ChaChaがSalsaより安全性が高くなっていると見られている点です。

2.3 2種類のChaChaラウンド

ChaCha20は、4バイトx16個の初期状態をQuaterRoundを使って状態を変えていきます。QuaterRoundを適応させるやり方として、列の要素4つ対する列ラウンドと、対角的に並ぶ要素に対する対角ラウンド、この2種類のChaChaラウンドを規定しています。これを使い16個の要素全部に対して偏りなく演算を行っています。

2.4 ChaCha20 Stream State

ChaChaの初期の状態はどうやって決まるでしょうか? 最初の4バイトx4は定数値です。これは expand 32-byte k という固定文字列が入っています(このmagic wordの由来もわかりませんでした)。

次にChaCha20の鍵データ、32バイトが続きます。その後に通常1から始まるカウンター値、12バイトのNonceが入ります。これを 列ラウンド+対角ラウンドの演算を10回繰り返します。結果1/4ラウンドを20回繰り返すことから ChaCha20 ということになります。20はラウンド数を表しています。

ChaCha20は、20ラウンドの演算を経て最終的に生成した ChaCha20 State を使って平文から暗号文を生成します。

2.5 ChaCha20による平文の暗号化

平文から暗号文の生成は簡単です。平文を64バイトのブロックに分割します。それぞれのブロックに対してカウンター値を上げながら、それぞれのChaCha20 Stateを計算します。出来上がった ChaCha20 State と64バイトブロックの平文との XOR をとり、暗号文を作ります。

暗号文から平文に戻す手順もほぼ 同一手順です。同じ鍵, Nonce, カウンター値からChaCha20 Stateを作り、暗号文とXORを作れば平文が生成できます。このようにChaCha20ではEncrypt/Decrypt が全く同じ処理でできます。これはソフトウェア処理がシンプルになる大きなメリットです。

AES単体のDecryptは、Encryptの逆関数を用意しなければならず、ChaChaほど簡単にいきません。

3. Poly1305とは何か?

次はPoly1305です。まずは AES-GCMで使われているメッセージ認証GHASHと比較してみます。

3.1 GHASHとPoly1305の比較


GHASHとPoly1305のどちらも Wgman-Carter Constructionという方法でメッセージ認証データを生成します。GHASHはガロア拡大体、Poly1305は素体の有限体上で演算を行います。

仕様的にGHASHは明示的な鍵長制限を持ってなさそうですが(間違っていたら誰か教えて下さい)、AESと組み合わせたAES-GCMの場合は、128bitsの鍵を利用 します。Poly1305は、256bit長の鍵を使います。後で説明しますが、256bit長の鍵を2つの鍵に分割して利用します。
GHASHとPoly1305、ともに生成するMACデータ長はどちらも128bitsです。ただしGHASHの方は、用途に合わせて小さく切り詰めて利用され、AES-GCMでは96bit128bit長にしています。GHASHの利用は、セキュリティの観点から64bits以上であることが求められています。

GHASHの特徴はなんとってもハードウェア処理。Intel/AMDが提供するPCLMULQDQ命令セットを使うと非常に高速に演算できます。
Poly1305の方はChaChaと同様、非常にシンプルなアルゴリズムを持ち、ソフトウェア処理が得意です。
しかも2^130-5という128bitsを少し超えた素数上での演算であるため、計算効率が非常に高くなります。また8bitから64bitまでのサイズの変数を使った最適実装を作ることができ、様々なアーキテクチャ上で高速に動作させることができます。さらにPoly1305は、剰余算を高速化させるために通常行う事前計算テーブ ルの作成が不要です。ただし剰余を求める際にタイミング攻撃に合わないよう Constant timeな実装が求められます。

3.2 Polynomial evalation(多項式評価)

Poly1305のPolyは、Polynomialの略です。MACによって任意の長さのメッセージが改ざんされていないか認証するためには、認証するメーッセージを何かの形で評価することが必要です。
Poly1305は、メッセージを128bits長のブロックに分割します。各ブロックを係数とした多項式f(x)を作成し、xの値が鍵データrの時のf(r)の値でメッセージを評価します。この多項式には0次の定数項がないのが特徴です。もし定数項があるとメッセージ評価値の差分を取ることによって鍵情報が部分的に漏洩してしまうからです。多項式評価を使うメリットは、ホーナー法によって高次の乗算計算を減らして加算の再帰として計算できるからです。ホーナー法を 利用することによって高次の事前計算を避けることができ、ソフトウェア実装がし易くなっています。

3.3 Wegman-Carter Construction

GCMとPoly1305、ともにメッセージ認証コードの生成は、Wegman-Carter Constructionという方式を利用します。

Webman-Carter Constructionとはメッセージのユニバーサルハッシュに一時鍵を加えた値をメッセージ認証値とする方法です。数学的に強度が証明できていることが特徴です。なにより高速です。 ユニバーサルハッシュは、暗号だけでなく誤り訂正などにでも利用される高速なデータハッシュ手法ですが、SHA-1/2のような原像攻撃に耐性があるようなわけではなく、暗号ハッシュほどの強度はありません。しかし Wegman-Carter Construction によってメッセージ改ざんを検知するに十分な強度を得ることができるためTLSのAEADでの利用が進んでいます。

3.4 Poly1305のアルゴリズム

Poly1305のアルゴリズムも単純です。tweet(140字以内)で表現可能といわれるぐらいです。

Poly1305のMAC計算は、認証するデータを16バイト長で分割し、頭に0x01を付加して17バイト長のブロックにします。16バイトに満たないブロックは頭に0x01をつけた後0パディングして17バイト長に揃えます。

16バイト長の鍵を2つ r と s を用意し、鍵rの方は128bit全部利用せず、途中のビットを0にして22bit分間引きます(ここがdjbのすごいところです)。
生成したメッセージを多項式評価として鍵rの値で評価し、素数2^130-5の剰余をユニバーサルハッシュを求めます。一時鍵sを加えれば、強度の高いWgman-CarterのMACデータが出来上がりです。しかしこのままだと最大130ビット長となって扱いにくいので、頭の2bit分を取り除き16バイト長のメッセージ認証 データにします。

Poly1350で利用する鍵 r, s は ChaCha20を使って生成します。カウンター0のChaCha20 Stateを求め、上位16バイトをs 下位16バイトをrに割り当てます。

2^130-5という128bitよりちょい大きい絶妙なサイズの素数を利用しているため16バイトという大きいブロックでメッセージ分割した多項式評価が行える。22bit分間引いた鍵rを使用しているため部分剰余のサイズが一定の範囲に納まり、ホーナー法を使いながら各ブロック毎に逐次計算がしやすくなります。

4. ChaCha20-Poly1305とは何か?

これまでChaCha20とPoly1305を別々に見てきましたが、TLSではChaCha20とPoly1305を組み合わせてAEAD(認証つき暗号)として利用します。従来のMac-then-Encrypt(平文のMACを取ってから暗号化を行う方法)では過去いろいろな脆弱性の影響を受ける可能性があるため、ChaCha20-Poly1305はAEAD一択です。

AES-GCMとChaCha20-Poly1305を比較してみます。

4.1 AES-GCMとChaCha20-Poly1305の比較


AES-GCMとChaCha20-Poly1305の大きな違いは、ChaCha20-Poly1305の鍵交換はECDHE/DHEだけしかサポートしないことです。TLS1.2といえでも、もはやForward Securecyのない鍵交換はサポートしません。

またChaCha20-Poly1305では明示的なIV(Nonce)データを必要としません。明示的IVは、TLS1.0でBEAST攻撃に対応するためTLS1.1に導入された項目ですが、次期TLS1.3では廃止される予定です。ChaCha20-Poly1305は、そのTLS1.3仕様を部分的に先取りしたものになっています。

ChaCha20-Poly1305はTLSの暗号化通信を行う際に双方で持つシーケンス番号(8バイト)のデータをNonceに利用します。シーケンス番号を0でパディングし、master secret から生成される12バイト分のWriteIVとXORを取ってNonceとして利用します。こうすることによって、わざわざ8 バイトのIVを明示的に送信することがなくなり、その分通信データ量を削減することができます。またバグなどでIVが再利用されてしまうといった間違いも避けることができるので、より安全な実装になることが期待されています。

4.2 ChaCha20-Poly1305のAEAD処理フロー

AES-GCM仕様のフローに似せてChaCha20-Poly1305によるAEAD生成(暗号化)のフローを書くとこのようになります。

初期カウンター0でPoly1305用の鍵(r,s)を作り、初期カウンター1に増加させてChaCha20 Key Streamを生成し、平文から暗号文に変換させます。
認証を行うデータと暗号文それぞれを0でパディングして16バイト長に揃えます。平文(8バイト長)と暗号文の長さ(8バイト長)を結合して、全体のデ ータのMACをPoly1305で計算し、128bitのMACデータ(認証タグ)を取得します。TLS1.2では認証を行うデータは、TLSレコード層のデータとシーケンス番号を合わせたデータです。最後に暗号文に認証タグをつけて暗号化されたTLSのアプリケーションデータとして相手に送信します。

4.3 ChaCha20-Poly1305とAES-GCMのサイズ

AES-GCMとChaCha20-Poly1305で1バイトの平文をAEADで暗号化した場合の比較をしてみましょう。

どちらもストリーム暗号として機能するので暗号文は1バイトです。タグのサイズはChaCha20-Poly1305が16バイト、AES-GCMが12バイトです。タグのサイズはChaCha20-Poly1305とAES-GCMともに16バイトです。
ただAES-GCMは明示的IVの8バイト分先頭に必要です。レコード層の5バイト分は共通ですからChaCha20-Poly1305は22バイト、AES-GCMは26バイト30バイト。TLS1.2ではChaCha20-Poly1305の方が、AES-GCMより小さいサイズに収まります。

5. ChaCha20-Poly1305 vs AES-GCMの性能比較

本当に ChaCha20-Poly1305 は、ARM環境では速いのか? AES-GCMと性能比較してみます。

EC2 c3.large (IntelXeon E5-2666 Haswell)とRaspberry Pi2 (ARM Cortex-A7)上で openssl speed コマンドによるベンチマークを行いました。ベンチを行った時期がちょっと前だったのでOpenSSLは 3/1 時点での master head( OpenSSL-1.1.0-pre4-dev master HEAD on 2016/03/01)を使っています。その後ChaCha20-Poly1305のアセンブラ関連のバグ修正などされていますが、性能自体はそれほど変わっていないはずです。

Haswellを搭載するc3.largeは、現時点でのEC2の最速CPUで、AES-NI/AVX/AVX2とハードウェアの力で暗号処理を高速化させる機能が満載です。OpenSSLもAES-NI/AVX/AVX2に対応するようビルドしています 。Raspberry Pi2 の ARM の Cortex-A7 には、 NEONによるベクトル処理がサポートされています。しかし2016/04/04時点でまだopenssl-1.1.0にバグが残っており、正常に Raspi でビルドできませんので、実際にベンチを試される方は注意して下さい。

グラフでは 8Kバイトのスループットを比較してみます。

まずは Intel Haswell上での比較から。

うん、AES-GCMはやっぱり速いです。3.1Gbpsのスループットを叩き出しています。ChaCha20-Poly1305はAES-GCMのおよそ半分 1.6Gbpsのスループットがでます。逆にいうとAES-NIという強力なハード処理の助けがなくてもここまで性能が出せるのは健闘でしょう。

ARM上ではどうなる?

おぉ! 確かに ChaCha20-Poly1305の方がAES-GCMより3倍程度速いです。絶対的なスループット性能は Intel Haswellには全くかないませんが、AES-NIのないARM環境では AES-GCMより ChaCha20-Poly1305 の暗号方式を利用するのが性能的に良いことが明らかです。

6. TLSの運用はどうなる? 現状の問題点とは。

6.1 ブラウザは ChaCha20-Poly1305 をどう使う?

TLSで利用する CipherSuite は、TLSのハンドシェイクで決まります。クライアントがハンドシェイクの最初に送信する ClientHello に CipherSuite リストが含まれ、そのリストからサーバが暗号方式を決定し ServerHello で返します。ClientHelloのCipherSuiteのリストは、クライアントが優先して欲しい順番で記載されています。実は ChaCha20-Poly1305の導入に合わせ、Chromeは動作環境によってサーバに送信するCipherSuiteリストを変えるように機能が追加されています。。

Chromeは、端末がAES-NIとAVXをサポートしている時のみChaCha20-Poly1305よりAES-GCMを優先します。

Issue 91913002: net: boost AES-GCM ciphers if the machine has AES-NI.

つまりdefaultは、ChaCha20-Poly1305が最優先で、AES-GCMの性能が高いと判断できるときのみAES-GCMをCipherSuiteのリストの先頭に持ってきています。

Firefoxは、ARM環境の場合の時のみ AES-GCMより ChaCha20-Poly1305を優先させる予定です。

Bug 1126830 - Prioritize ChaCha20/Poly1305 ciphers over AES-GCM for ARM builds

ただこのパッチ、一度 Land されてましたがリリース直前だったため差し戻しを受け、2016/04/04時点でまだ未適応です。

6.2 サーバ側の暗号選択の難しさ

このようにブラウザ側がクライアントの環境に合わせて ChaCha20-Poly1305と AES-GCM のCipherSuiteリストの優先度を変えてTLSのハンドシェイクを開始してくれます。サーバ側はクライアントの環境を直接わからないのでこれは嬉しいことです。

サーバ側はクライアントから送られてくるCipherSuiteリストの順番を見て、単純に優先しているのを決めれば良いかというとそう単純ではありません。通常サーバは、サーバ側のセキュリティポリシーに従い、優先度付きのCipherSuiteリストを保持しています。これと相性が悪いのです。

先ほど述べた通り、TLSのハンドシェイクではサーバはクライアントから送られたCipherSuiteとリストとサーバ側が決めているリストとを比べ、1つの暗 号方式を選択します。サーバ・クライアントともに独立して優先度付きリストを持っているので、選択する方法はクライアントの優先度に従うか、サーバ の優先度に従うか2通りしかありません。クライアントが常にサーバ側のポリシーにあった正しい優先リストで送られてくるのかわかりません 。

一般的なTLSサーバの推奨設定では、サーバ側でセキュリティポリシーで暗号選択を行う設定(Cipher Server Preference)を入れる場合が多いです。

nginxでは、 ssl_prefer_server_ciphers on 、 apacheでは、 SSLHonorCipherOrder on といった設定に該当します。しかしこの場合、 ChaCha20-Poly1305とAES-GCMの選択に問題が生じます。 サーバ側の優先度だけで判断してしまうので、せっかくブラウザがクライアント側の環境に応じて変えた暗号方式の優先度情報が生かされなくなってしまいます。 サーバが ChaCha20-Poly1305の方を優先する設定にすると、ARMやAES-NIのどちらのクライアントも ChaCha20-Poly1305を選択してしまいます。

6.3 OpenSSL-1.1.0に足りないequal preference cipher groups機能

ではGoogleはどうしているのでしょうか? 実は、ChaCha20-Poly1305を実装する際 BoringSSLには equal preference cipher groups機能を実装していました。

Equal preference cipher groups

これは、[]で複数のCipherSuiteをグループ化し、この中の CipherSuiteはクライアントからの優先順に従うというものです。

Googleのサービス GFE(Google Front End)に対して cipher1:cipher2 の2つのリストでどちらが選択されるのか、試してみました。

結果からGoogleは、

[ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305]:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256

なリストで運用しているのではないかと予想が付きます。

この equal preference cipher groups機能は便利ですし、是非ChaCha20-Poly1305の導入と共に使いたいところです。

実は、OpenSSLでは今年の1月ぐらいに同様のリクエストが issue で登録されていました。

Support bracketed equal-preference groups in SSL_CTX_set_cipher_list

今回もうすぐOpenSSL-1.1.0がリリースされるので、どうなんだろうと要望を書き加えたところ、OpenSSLチームの一人から「私も欲しいけど、もう時間切れ」とのこと。あぁ OpenSSL-1.1.0はもう feature freeze に入っています。時すでに遅し。パッチ出したとしても1.1.1 以降まで待たないといけないでしょう。

結局今のところ OpenSSLで ChaCha20-Poly1305 をAES-NI/ARMのクライアント環境で共に最適に利用するには Cipher Server Preference を利用しないようにするしかないです。この設定が受け入れられないところも多いでしょうね。うぅ、なんともったいない・・・

ということで、今後普及が見込まれるTLSの新しい暗号方式 ChaCha20-Poly1305 について解説しました。まだまだ課題はありますが、次期TLS1.3では AES-GCMとChaCha20-Poly1305 がMTI(Must To Implement)として規定されています。この2つのデファクトはこれからしばらく続く可能性が高いので、きちんとした理解を持ってより安全なTLSの運用を目指しましょう。

本当は怖いAES-GCMの話

$
0
0

Disclaimer

本エントリーは、この夏 blackhat usa 2016で行われる予定の講演「NONCE-DISRESPECTING ADVERSARIES: PRACTICAL FORGERY ATTACKS ON GCM IN TLS」のネタバレを含んでいます。現地で直接聞く方は読まないよう気をつけて下さい。

0. 短いまとめ

今回は短めにと思ったのですが、やっぱりそれなりの分量でした。なので短いまとめを書いておきます。

  1. 4千万以上のサイト対してAES-GCM使ったTLS通信の初期ベクトル(IV)データのサーベイが行われ、7万程のサイトでIVの値が再利用される可能性があることがわかりました。IVが再利用された場合、AES-GCMの安全性は致命的な影響を受けます。IVの再利用が判明した幾つか実装から既に脆弱性のアナウンスが出ています。
  1. IVが再利用された場合、現実的にHTTPSサーバのコンテンツが改ざんできる実証(PoC)コードが公開されました。試してみたらホント見事にHTTPSサイトのコンテンツの改ざんができました。
  1. この脆弱性の根本的な解決方法として、IVの再利用を避けるAEADの生成方式が幾つか検討されています。直前のエントリーで解説したChaCha20-Poly1305の方式は、既にTLSの通信でIVの再利用されることが原理的に不可能な仕組みになっています。現在仕様策定中のTLS1.3でも同じ対策が取られており、将来的にはIV再利用の問題は解決する方向になるでしょう。
  1. 今年の夏のセキュリティ・キャンプ全国大会では、「TLS徹底演習」という講義でChaCha20-Poly1305を扱います。来週5/30(月)が応募締め切りです。TLSに興味がある学生の方々は、ぜひ応募してください。

1. はじめに

先週5/20(金)の日本時間未明に、Bulletproof TLS Newsletterの著者で有名なHanno Böck氏らのグループが「Nonce-Disrespecting Adversaries: Practical Forgery Attacks on GCM in TLS」という脆弱性情報を公開しました。 ここで公開されている論文と実証(PoC)コードによって、TLSのAES-GCMに対して初期ベクトル(IV)が再利用されると実用的な攻撃が可能であることが示されました。AES-GCMは、現在最も信頼されている暗号方式であり、これが影響を受けるとしたらホントに一大事です。

2. 実は危ないTLS1.2のAES-GCM

いつものごとく長文になるので、今回はAES-GCMのあまり細かい解説はやめます。前回のChaCha20-Poly1305のエントリーにAES-GCMとChaCha20-Poly1305を比較して特徴をまとめていますので、まだ見ていない方はそちらを読んで下さい。ちなみに学問的なGCMの安全性の評価は、日本の研究者の方々の業績*1による貢献が非常に大きいです。このようにAES-GCMの安全性がちゃんと数学的に証明されていることが、現在普及が進んでいる要因の一つと言えるでしょう。

数学的に安全が保証されているGCMですが、それはGCMが使うIV(初期ベクトル)が再利用されないこと、すなわちIVがNonce(Number used once)であることが大前提となっています。この前提が崩れるとAES-GCMの安全性は大きく損なわれます。

今回の調査で、幸いこの脆弱性の影響を受けるのは一部実装に限られており、(素のままの)OpenSSLは問題ありません。Nonceには決して再利用する値を使わない、ある意味暗号実装の世界では常識的に言われていることですが、その現時的なリスクがこれまで十分理解されていたとは言えません 。今回実際に手元でPoCを試してみて、ブラウザから何のアラートもなくTLSのコンテンツの改ざんが成功しました。ホント見事です。頭でわかっていることですが、実際に行えることの知るギャップは非常に大きいです。そのリスクを現実的に示したことが、この論文の主題の一つじゃないかなと思います。

2.1 TLS1.2のAES-GCM

TLS1.2のAES-GCMは次のようなフレームで生成されます。

AES-GCMの初期ベクトルとして12バイト必要ですが、TLSでは頭の4バイト分はPrefixとしてハンドシェイク毎に固定して利用します。この部分は、鍵交換で生成した master secret から4バイト分を使います。残りの8バイトは、Nonceであることが必要です 。TLSで暗号化されたデータの頭に明示的に8バイト分のIVが付与されています。当然この部分は暗号化されていないので攻撃者 からはHTTPSサーバがどのようなIVを使っているのか丸見えです。

2.2 TLS1.2のGCMのMAC(タグ値)の求め方

GCMのMAC(タグ値)は、このIVとAESの共通鍵を使って2つ鍵HとSを使って計算します。

GCMの安全性は、この2つの鍵(HとS)によって担保されます。すなわちAESが破られない限りGCMは十分安全です。

2.3 IVの再利用はGCMの安全性に致命的

もし同じIVを持つ2つのAES-GCMのAEADデータがあったらどうなるでしょうか? 両者のデータをXORすれば、鍵Sのマスク効果は消えてしまいます。

結果、鍵Hだけの1変数剰余多項式になり、因数分解によって解を求めることができます。一般的に複数の解を持ちますが、鍵Hが判明すればGCMのMAC値を再計算することが可能になります。これはAES-GCMの安全性を致命的に損なうことにつながります。本当に怖い話です。

3. 現実のHTTPSサーバへの調査

Hanno Böck氏らのグループは、今回インターネット上の4800万以上のHTTPSサーバをスキャンしてAES-GCMのIVが実際どのように生成されているのか調査を行いました。その結果、7万以上のHTTPSサーバでIVの値が再利用される可能性があることがわかりました。対象サーバへの調査を進めたところ、大きく2つの原因によるものでした。

3.1 AES-GCMの実装上の問題に起因するIVの再利用

一番致命的なのは184のサーバで、文字通り初期ベクトルがホントに再利用されているのが観測されました。これはダメです。脆弱なサイトには、大手のクレジットカード会社や金融機関のサイトのサイトが含まれていました。大きく4種類の実装が該当しており、いずれもCavium社のチップを使っていました。どうも OpenSSLに手を加えてHSM(Hardware Security Module)の実装をしているのではないかと見られています。実は以前のOpenSSLでは、IVの生成を RAND_bytes() 関数から取得していましたが、その返り値をちゃんと見ていませんでした。1.0.1系では「Fixed missing return value checks.」でエラー判定をするよう修正されています。

おそらくHSMを組み込む際にこの部分の処理がそのままになっており、乱数生成がエラーになってもIVが未初期化の変数のまま値を送信してしまう、そんなバグがIV再利用の原因だったのではないかと想定されています。

3.2 TLSプロトコル仕様に起因する実装の問題

さらなる調査結果から、7万以上のサーバが乱数を使って初期ベクトルを毎回生成しているのがわかりました。この方式では、大量のデータの通信を行うと過去使った乱数値と同じ乱数を生成してしまう確率が格段に上昇します。TLSの仕様では8バイト分がNonceなので、試算では2^33の乱数を生成すると誕生日パラドックスで80%の確率で衝突するようです。これではテラバイト級のデータを通信すると危ないです。4バイトのPrefixと8バイトのNonceでIVを作成するのは、FIPS-140の規定から来ているようですが、乱数でNonceを生成するには時代的にもう合わなくなってきました。そのため他の実装では、通常IVにカウンター値を利用します(Nonceは再利用されなければ予測可能であっても構わない)。この場合、IVは2^64まで一意に生成できるのでまぁ大丈夫でしょう。OpenSSLでは一番最初の値を乱数で決め、それ以降はカウンターとしてインクリメントしていく実装になっています。

今回の調査で、Radware と IBM Domino Webサーバの脆弱性が公表されています。他にA10や中国のSangforの脆弱性についても論文で指摘されています。また、MicrosoftIISサーバに対してもいくつか見つかったらしいですが、MicrosoftからはSChannelはカウンターを初期ベクトルに使っているとの回答があり、途中経路上のLBやFWがTLS通信を行っているかもしれず原因不明のままです。中国のベンダーSangfor からは、報告しても全く返答がなかったようです。もし使っているなら気をつけましょう。

4. Nonce再利用の脆弱性をついたMiTM攻撃を試してみる

繰り返しになりますが、数学上はGCMのNonceが再利用されると危ないのはわかっていたのですが、TLSは毎回ハンドシェイクを行って write_IVが変わるし、現実的にどれだけ危険なのかはこれまでそれ程明確ではありませでした。今回Hanno Böck氏らのグループは、実際にNonceが再利用された場合にHTTPSサーバのコンテンツを偽造する PoC コードを公開しました。ここでその方法を見てみます。

このPoCは、中間者(MITM)を使ってNonce再利用の脆弱性をついた攻撃を行います。試験ではネットワーク経路をタップするのは 大変なので一旦 port 8443 で受け、443にリレーする形式で擬似的に中間者攻撃をテストします。クライアントとHTTPSサーバとは port 8443 を経由して End-to-EndでTLS接続しており、port 8443上の攻撃者がデータの盗聴や改ざんを行うことは不可能です。

4.1 IVの収集

まず攻撃者は、クライアントを悪意のあるコンテンツに誘導し、クライアントから攻撃者経由でサーバへの数多くのTLSアクセスを仕掛けます。そして攻撃者は、そのTLSデータ収集します。PoCコードでは、

<html><head><metahttp-equiv=refreshcontent=1></head><body><script>var img = new Image();      img.src = 'https://noncerepeat.com:8443/';</script></body></html>

のようなコンテンツをクライアントに踏ませ、keep-aliveでTLS接続を維持したままイメージを攻撃者経由で取りにいかせます。攻撃者はTLSフレームを収集・解析し、じっとIVが再利用されるまで待ち続けます。

4.2 再利用されたIVの発見

攻撃者はついに、別のTLSフレームで同じIVを使われていることを発見しました。暗号文、タグ値は別のデータです。
この同一のIVで異なる暗号文、タグ値を持つ2つのフレームデータを使い、GCMのMAC鍵Hを直ちに計算を始めます。

4.3 GHASHのMAC鍵Hの計算

GCMはPoly1305と同様に多項式を使った剰余値を鍵Hを使って計算しハッシュを求めます。
同一のIVの暗号データから生成した2つの剰余方程式の論理的排他和(XOR)を取ると、IVを暗号化してマスクしたハッシュ値の効果は消えてしまいます(同一データのXORは0になる)。そのためGCMの多項式は0を暗号化したMAC鍵Hの単独多項式になり、それを 因数分関して解のMAC鍵Hを求めることが可能になります(鍵候補が複数になることもあり)。

4.4 HTTPSサーバのコンテンツの改ざん

さあ攻撃者はMAC鍵Hを入手しました。悪意のあるコンテンツを変更して

window.location = 'https://noncerepeat.com:8443/"

を差し込み、クライアントの接続先を攻撃者の宛にリダイレクトさせます。

この際、データを暗号する鍵はまだわかりません。そのためTLSの暗号文を解くことはできませんが、データのMACを計算する鍵 を持っているので、もし通信のデータが判明していればXORを使ってその値を改ざんすることが可能です。攻撃者はGHASHのMAC鍵Hを持っているので、タグ値を再計算します。データを改ざんした攻撃者は、新しいタグ値にTLSデータを入れ替え、クライアントに送信します。クライアントはMAC値が合っているのでコンテンツの改ざんに気づきません。

4.5 実際にやってみた。

実際にPoCコードを試してみました。自前のTLS実装を細工して同一IVを送信するように変更します。中間者攻撃を担うGoで書か れた gcmproxy は port 8443から443へのTCPリレーを行います。ここでIVや他のTLSのデータを収集し、同一のものが見つかれば NTL(Number Theory Library)を使って鍵Hを求め、偽造したデータのタグ値を再計算します。通常鍵Hは複数候補が見つかるの で1発で成功することはなかなかないのですが、何回か繰り返すと成功しました。

この画像のようにブラウザ上のHello Worldの文字列の一部が Cracked! に変更されているのがわかります。あらかじめHello Worldの文字列がわかっていれば、Hello Cracked!とのXORを取ったデータをTLSデータに差し込めば、タグ値を再計算して改ざんが成功です。

5. IVを再利用させない対策は?

この脆弱性は、いずれも実装上の問題です。IVがNonceである限りAES-GCMの安全性は確保されます。しかし実装上の問題で今回のような脆弱性が発生するとAES-GCMの安全性に致命的な影響を受けることになります。
そのためIVを再利用させない対策が2つ進められています。

5.1 AES-GCM-SIV

現在IETFのCFRG(Crypto Forum Research Group)では、AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryptionの仕様化の議論が進んでいます。これは多項式生成の方式を変更 してIVが再利用されても影響が出ないようにする仕組みをGCMに組み込んだ仕様です。素のGCMより若干(10%程度)オーバヘッドが入りますが、実装上のIV再利用のバグに耐性があることからより安全な暗号方式と言えるでしょう。でもこれが仕様化されても 、次の方式があることからTLSの暗号方式として採用されるかまだわからないところです。

5.2 暗黙的に両者で共有するIV(ChaCha20-Poly1305の方式)

まっとうな実装は、IVとしてカウンターを使います。TLSには、暗号を開始してからどれだけ暗号フレームを送受信したのかわかるよう、クライアント・サーバ間で sequence number を内部で共有しています。これをIVに流用すれば万事解決です。
前回解説したChaCha20-Poly1305のAEAD生成方式では、まさにこの方式が採用されています。そのためサーバ・クライアント間で明示的に8バイトのIVをやり取りする必要がなく、全体のフレームサイズの節約にも貢献しています。

では ChaCha20-Poly1305ではどうIVを生成しているのか見てみます。

8バイトのsequence numberの頭に4バイト分0を付与し、master secretから導出した12バイトのwrite IVをXORを取ってIVとしています。このためIVはNonceに必ずなります。この方式は、別にChaCha20-Poly1305固有のものではありません。TLS1.3では全てのAEADの暗号方式のIVはこの方式で生成されます。TLS1.2のAES-GCMは既に今の方式で仕様化されているため、もしこの方式にするためには新しくAES-GCMのCipherSuiteのエントリーが必要となるでしょう。

6. 今年のセキュリティ・キャンプはChaCha20-Poly1305

ということで、ここからは宣伝です。今年の8月に行われるセキュリティ・キャンプ全国大会に講師として参加する予定です。「TLS徹底演習」という講義を、なんとまる一日、集中講義として8時間行います。

当日どこまでできるかわかりませんが、内容は

本講義では、2016年にTLSに新しく追加される暗号方式ChaCha20-Poly1305を使って実際にTLSプロトコルを実装し、自らが手を動かす事によってインターネット通信のセキュリティを実現しているTLSの理論と実践を徹底的に学びます。

を予定しています。他にもTLSdjb三部作(AEAD:ChaCha20-Poly1305, 鍵交換:x25519/448, 署名:eddsa25519/448)の一つChromeに先行実装されている x25519 もやりたいのですが、やっぱり時間的に難しいかなと思ってます。今回は、とにかくTLSに関して徹底的に演習を行います。

去年に続いて2回めの全国大会の講師としての参加ですが、全国からトップクラスのスキルを持つ若者エンジニアが集まるセキュリティ・キャンプで講義ができるのは本当に楽しみです。受講者を普通の学生とは思わず、海外でも通用するガチな最先端エンジニアだと思って講義・演習を行うつもりです。応募の締め切りは来週5/30(月)まで、興味のある方の応募を待っています。

HTTP/2とTLSの間でapacheがハマった脆弱性(CVE-2016-4979)

$
0
0

0. 短いまとめ

  • 昨晩apache2.4でHTTP/2利用時にTLSクライアント認証をバイパスする脆弱性(CVE-2016-4979)が公表され、対策版がリリースされました。
  • 実際に試すと Firefoxで認証バイパスができることが確認できました。
  • HTTP/2でTLSのクライアント認証を利用するには仕様上大きな制限があり、SPDY時代から長年の課題となっています。
  • この課題を解決するため、Secondary Certificate Authentication in HTTP/2という拡張仕様が現在IETFで議論中です。

1. はじめに

ちょうど昨晩、apache2.4のhttpdサーバの脆弱性(CVE-2016-4979)が公開され、セキュリティリリースが行われました。

CVE-2016-4979: X509 Client certificate based authentication can be bypassed when HTTP/2 is used

リリース文を読んでみると、なにやらapache-2.4でHTTP/2の利用時にTLSクライアント認証がバイパスされる脆弱性とのこと。CVSS3スコアも7.5でHIGH。
はてさてHTTP/2仕様(RFC7540)ではTLSクライアント認証の利用は非常に限定的であまり実用的ではないと思っていましたが、得てして脆弱性とはあまり利用されないところで起こるものです。修正パッチもわずか1行でした。

実はちょうど今IETFのhttpbis WGでクライアント認証を可能にする新しい拡張仕様ドラフトが議論中です。この分野はまさにホットなトピック。HTTP/2 やTLSの仕様と照らしあわせなら実装を見てみると、この脆弱性は新しい仕様の背景の説明ネタとしてはピッタリです。

実際に試すとHTTP/2利用時にクライアント認証をバイパスする脆弱性も再現できました。ということで、この脆弱性通じてTLSとHTTP/2の仕様と課題を理解できないか、新しいエントリーを書いてみます。

2. TLSクライアント認証をバイパスするapache-2.4の脆弱性(CVE-2016-4979)とは?

この脆弱性の中身は、実際に見てみるのが一番でしょう。脆弱性のあるapache-2.4.20でHTTP/2のサーバをたててみます。

/client_auth にアクセスするとクライアント認証が必要なようにapacheのconfigを設定し、アクセスするブラウザはクライアント証明書を何も入れてないFirefox47を使いました。後述するようChromeではこの脆弱性は再現しません。

まずトップページ / を見てみます。青いイナズマが出てちゃんとHTTP/2でページが見えます。コンテンツは、/client_auth へのリンクが貼ってあります 。

リンクを辿って /client_auth にアクセスするとFirefoxにクライアント証明書を全く入れてないのでエラーになります。クライアント認証はちゃんと効いています。

せっかく再試行ボタンが見えているので、再読み込みしてみましょう。

あらー、/client_auth のページが見えちゃいました。こりゃアカンです。一度認証エラーになっても再読み込みをするとアクセスできてしまう、それがこの脆弱性の正体です。

apachehttpd修正コミットは、

--- a/modules/ssl/ssl_engine_kernel.c+++ b/modules/ssl/ssl_engine_kernel.c@@ -727,6 +727,7 @@ int ssl_hook_Access(request_rec *r)
                      * on this connection.
                      */
                     apr_table_setn(r->notes, "ssl-renegotiate-forbidden", "verify-client");
+                    SSL_set_verify(ssl, verify_old, ssl_callback_SSLVerify);
                     return HTTP_FORBIDDEN;
                 }
                 /* optimization */

のわずか一行。mod_sslの処理においてサーバのSSLインスタンスがクライアントの認証が必要かどうか判断するフラグ verify_mode の処理にバグがあったようです。

3. HTTP/2のTLSクライアント認証の課題

HTTP/2の大きな特徴は、一つのTCP/TLS接続で複数のHTTPリクエスト・レスポンスを多重化してやりとりできることです。これによって、HTTP/1.1で性能のボトルネックになり得る HTTP Head of Line Blocking の解消を実現します。

一方、TLSクライアント認証は、あるリソースへのアクセスをサーバが指定したクライアント証明書を持つ端末に制限する機能です。HTTPサーバは、クライアント認証が必要なリクエストが来るとクライアントにHelloRequestを送ってRenegotiation(TLSの再ハンドシェイク)を発生させます。サーバは、Renegotiationを通じてクライアント証明書と署名データを検証し、正当であればアクセスを許可します。TLSクライアント認証の詳しい解説は、「パンドラの箱?TLS鍵交換の落とし穴、KCI攻撃とは何か」に記載していますので、あまり馴染みのない方は一度お読みください。

HTTP/1.1時代は、一つのTCP/TLS接続を一つのリクエストが専有していたのでこのやり方で問題なかったのですが、HTTP/2では複数のHTTPリクエストが一つのTCP/TLS接続を共有しているので困ってしまいます。

HTTP/2上でHTTP/1.1と同じように renegotiation を行うと、クライアント認証が必要のないリクエストまで巻き添えを食らってしまいます。

そのためHTTP/2仕様では、HTTPリクエストが発生する前の初期接続時のみクライアント認証を許可し、それ以降では禁止しています。従って接続始めからHTTP/2接続全体に認証を行うケースでしかクライアント認証を利用できませんでした。

4. HTTP/2接続後のTLSクライアント認証

このままではHTTP/2を使うとWebのリソースの一部をクライアント認証することができずに困ってしまいます。そこで、あまりスマートなやり方ではありませんが、クライアント認証が必要なリクエストをHTTP/1.1に逃がすことでまぁなんとか対応可能に落とし込みました。

HTTP/2のリクエストがクライアント認証が 必要なリソースへアクセスしたらサーバ側は、そのストリームをHTTP1.1 requiredのエラーコードでリセットします。クライアントはHTTP/1.1 requiredのリセット通知を受けると新たにHTTP/1.1の接続を張り、そのハンドシェイクを通じてサーバはクライアント証明書の検証を行ってアクセスを判断します。 これでなんとか回避可能です。

5. CVE-2016-4979の原因

CVE-2016-4979は、このHTTP/1.1の接続に逃がす際に verify_mode を元に戻すことを忘れてしまったのが原因です。

サーバのSSLインスタンスに保持されているverify_modeは、クライアント認証するかどうかの状態を保持しています。最初はサーバ認証だけなので SSL_VERIFY_NONE が入っています。mod_sslでは一度既存の接続の verify_mode を verify_old にバックアップしておき、新しいリクエストが verify_modeの変更が入るかどうか検証します 。変更があれば verify_mode を新しい値(SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT:クライアントの証明書を検証してダメならエラー)に置き換えて renegotiation を強制させる処理を行います。

しかしHTTP/2では途中での renegotiation は禁止されているので、代わりにRST_STREAMが送信してHTTP/2のTLS接続を維持します。SSLインスタンスとverify_modeは、新しい値に更新されたままです。これが脆弱性を引き起こしました。
先の修正パッチのちょっと前の部分(下記)が該当します。

/* remember old state */
        verify_old = SSL_get_verify_mode(ssl);
        /* configure new state */
        verify = SSL_VERIFY_NONE;
        (中略)

        /* TODO: this seems premature since we do not know if there         *       are any changes required.         */
        SSL_set_verify(ssl, verify, ssl_callback_SSLVerify);
        SSL_set_verify_result(ssl, X509_V_OK);

        /* determine whether we've to force a renegotiation */if (!renegotiate && verify != verify_old) {
        (中略)
        }

まさに TODO に書いてある通り、この処理が不十分になってしまい脆弱性を引き起こしたのは皮肉なことです。

FirefoxはHTTP/2ストリームのリセット通知を受け、新たにHTTP/1.1接続を試みますが、正当なクライアント証明書を持ってないため、接続はエラーになります。

再現試験のように続けて再読み込みを行うと、Firefoxは既存の維持されているHTTP/2接続を使って /client_auth にアクセスします。その際サーバのSSLインスタンスの verify_mode が同じであるため、サーバは既にクライアント認証済と判断し /client_auth へのアクセスを許可してしまいました。認証バイパスの成功です。先の試験でもHTTP/2の青い稲妻状態でアクセスできていることからもわかります。

先の1行修正パッチは、HTTP/2接続で renegotiationをHTTP/1.1の新規接続に逃がす際に verify_mode を以前の値SSL_VERIFY_NONEに戻す処理を加えたものです。これによって再読み込み時でもHTTP/1.1の新規接続への退避が繰り返し行われることになり、認証バイパスの脆弱性は回避されました。

Chrome(51のStable)ではこの脆弱性は発生しません。調べてみるとChromeは、http/1.1 requiredのRST_STREAMを受け取ると既存のHTTP/2接続を切断してしまうようです。そのため認証エラー後の再読み込みに新規のHTTP/1.1接続を張るため、この脆弱性の影響を受けなくなっていました。この辺の処理は実装依存なのでまぁ良かったということでしょう。

6. Secondary Certificate Authentication in HTTP/2

HTTP/2上でのクライアント認証の課題は、TLSとHTTP/2の両方の仕組みに関連する本質的なものです。実はSPDY時代からこのことは課題認識されており、SPDY/3ではクライアント認証に対応するためCREDENTIALというクライアント証明書と署名データをやり取りするフレームが規定されていました。

しかしGoogleは実際にクライアント認証を利用していなかったため、結局一度もChromeにCREDENTIALが実装されることはありませんでした。HTTP/2でも当初はスコープ外として早々に機能削除されました。

HTTP/2の仕様完了後、本格的なクライアント認証の機能が欲しいというユーザの声を受け、クライアント認証の拡張仕様の検討が始まりました。当初MSとMozillaの2つのドラフトが提出されていましたが、先のBAのIETFで一本化する方針が決まり、先日Secondary Certificate Authentication in HTTP/2というドラフトが提出されました。今月のベルリンのIETFでも議論される予定です。

話が長くなるので新しいドラフトの解説は止めておきますが、クライアント認証に限らずこれまでTLSのレイヤで行ってきた証明書のやり取りと検証をHTTP/2のレイヤでも追加で行えるよう拡張するもので、なかなかしびれる機能になりそうです。

こうやって一つの脆弱性から技術プロトコルの仕組みと課題、その解決に向けての検討状況が見えてくるのは非常に楽しいですね。

JPNICの証明書失効の障害とCertificate Transparency

$
0
0

0. Disclaimer

先日JPNICのサイトの証明書が誤って失効してしまったという障害が発生しました。

「障害報告:サーバ証明書が意図せずに失効されたことによるJPNIC Webの閲覧不可につ いて(第一報)」

週末にもかかわらず迅速に復旧対応を行った関係者の方々のご尽力は大変なものであったろうと察します。

筆者は本件と全く関わりはありませんが、公開されている情報から推測すると障害の発生経緯に Certificate Transparency とその周辺のPKI技術に深い関連があるように思えました。
正式な報告書が公開される前ですが、twitterで中途半端に推測をツイートしてしまい拡散されてしまったので、事実認定と推測をちゃんと分けて書いたほうが良かったかなと少々後悔しています。

そこで、正式な報告書が公開されたら記述を追記する予定ですが、現時点で自分が把握している客観的な事実と個人的な推測を分けて書いておきます。

2016年8月4日 20:49(JST)追記: JPNICより正式な報告書がリリースされました。

サーバ証明書が意図せずに失効されたことによるJPNIC Webの閲覧不可についてのご報告

取り急ぎそちらを参照してください。
あわせて 正解記事を書きました。そちらもお読みください。
追記終わり

もし関係者の方で、内容が不適切であると思われた場合は、その旨ご連絡をお願いします。記載内容の修正、もしくは全面的に削除を行います。

1. 外部公開されている情報からの事実認定

1.1: 2015/9/30 09:15 GMT (18:15 JST)

JPNIC利用していた証明書発行
https://crt.sh/?id=9952316

シリアル: 17:87:31:52:fa:44:cd:a8:00:00:00:00:53:fa:f1:c5
Validity
            Not Before: Sep 30 09:15:05 2015 GMT
            Not After : Sep 29 14:59:59 2016 GMT

その前に2年あったSHA1証明書から残り1年でSHA2への入れ替えを行ったようです。これが今回誤失効されてしまった証明書です。

1.2: 2016/7/7 2:05 GMT (11:05 JST)

プレ証明書発行、CTログに登録
https://crt.sh/?id=24044898

シリアル: 34:f7:fc:ef:84:24:28:76:00:00:00:00:53:fb:1a:85
Validity
            Not Before: Jul  7 02:05:21 2016 GMT
            Not After : Sep 29 14:59:59 2016 GMT

なんと1.1と同じExpire期限です。3ヶ月弱有効のもの。

1.3: 2016/7/22 3:00 GMT (12:00JST)

1.1で発行されたJPNIC利用中の証明書が失効

    Serial Number: 17873152FA44CDA80000000053FAF1C5
        Revocation Date: Jul 22 03:00:22 2016 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code:
                Unspecified

これが障害発生の直接的な原因です。

1.4: 2016/7/23 9:19 JST

ユーザが発見, twitterで報告

1.5: 2016/7/23 10:49(JST)

復旧
JPNICの障害報告書による復旧時間です。

1.6: 2016/7/24 11:06 GMT (20:06 JST)

正式発行証明書がCTログに登録される。
https://crt.sh/?id=25317179
2016/7/29現在JPNICのサイトが利用している証明書がこれです。

2. CT(Certificate Transparency)対応EV証明書発行の流れ

JPNICが利用しているEV証明書は、CT(Certificate Transparency)に対応した証明書です。CTについては漆嶌さんの資料が非常に詳しいです。

Certificate TransparencyによるSSLサーバー証明書公開監査情報とその課題の議論

今回1.2に書かれているプレ証明書というのはCT対応の証明書の発行手続きで必要なものです。漆嶌さんの資料からスライドを引用すると図中の丸1に該当します。

これを見ると、EV対応によって認証局内部の証明書発行業務も従来のフローから変更せざる得なかったのではないかと思われます。

3. 障害発生原因の推測

(注意) ここからはあくまで個人的な推測の範囲での記載になります。正式な報告書がリリースされたらそちらを参照して下さい。

3.1 2つのミスが重なったのか?

1.2で発行されたプレ証明書の期限が3ヶ月弱で以前から利用している証明書と同じExpireの期日で、更新が数ヶ月後に迫っているのに非常に不自然です。
また、誤失効がプレ証明書の発行後で正式証明書がCTログに登録される前です。障害対応後に正式証明書がCTログに登録されています。

このことから推測するに、

  • 何らかの理由でプレ証明書の期限設定を間違えて発行してしまったのではないか。
  • 期限設定を間違えたプレ証明書を失効しようとして何らかの理由で利用中の証明書を間違えて失効してしまったのではないか。

といった可能性が考えられます。繰り返しますが第1報以降が公開される前ですのであくまで個人的な推測です。この推測が当たっているかどうか次の報告を待ちたいと思います。

なお、一度失効されてしまった証明書の失効を取り消すことは現実的に難しいようです。EV証明書の運用ポリシーを定めた規定CA/Browser Forum Baseline Requirements Certificate Policyの4.10.1には
「CRLやOCSPの失効エントリは失効された証明書の有効期限以前に削除してはいけない」
と記載されています。

今回誤失効された証明書はExpireするまで削除することはできないため、おそらく今回発行したプレ証明書から作った正式登録証明書に入れ替えて復旧対応したものと推測されます。本当にご苦労様でした。

3.2 Certificate Transparency の闇(プレ証明書)

もし今回の障害がCT対応証明書の発行処理際のプレ証明書の扱いに関連するのであれば、漆嶌さんが見事に予想されていました。

(漆嶌さんのスライドより引用)
現実的にCTによって誤発行の発見などブラウザベンダ側にメリットをもたらしましたが、その副作用で別のリスクが増えてしまったのはなんとも残念です。

今回、漆嶌さんと少し議論して最後に的確なコメントをいただきました。

2016/7/29 20:14 漆嶌さんの漢字が間違ってましたので修正しました。ごめんなさい。ごめんなさい。指摘していただいた林さんありがとうございました。

JPNICの証明書失効の障害とCertificate Transparency(正解編)

$
0
0

前回のエントリーJPNICの証明書失効の障害事故について事実認定と推測記事を書きましたが、本日報告書が公開されました。

サーバ証明書が意図せずに失効されたことによるJPNIC Webの閲覧不可についてのご報告

文面自体は短いのですが、正解は

  • 新たに発行された3ヶ月弱の期間の証明書は正式に再発行を受けたものであった。
  • 失効の連絡がJPNICに来ず、再発行の証明書を入れ替える前に失効手続きが取られてしまった。

ということであったようです。

前回のエントリーで書いた、期限設定のミスなどはなかったようです。プレ証明書によるシステム的な問題は考えすぎでした。

再発行後、以前の証明書の失効を行う際に事前に連絡確認を怠ったというのが障害発生理由です。

発行からちょうど2週間後に失効されてしまったのは、下記に書いてある規定によるものではないかと思われます。

担当者変更/再発行/解約について

利用中の証明書失効期間について
再発行を行うために利用中の証明書を失効する期限を選択いただきます。発行手続きが完了した後に変更することはできませんので、お間違いないようご注意ください。

後日失効
証明書の入れ替えする期間を考慮し、証明書を再発行した日から2週間後に前証明書が失効されます。
即日失効
証明書の失効と再発行が同時に行われます。

なぜ3ヶ月弱の残り期間で更新を待たず再発行が必要だったのか(かつそんな状況で再発行後2週間経っても入れ替えをしなかったのか)というのは書かれていないのですが、いろいろ事情があったのでしょう。

以上、推測記事の訂正と正解?について書きました。

錆びついたTLSを滑らかに、GoogleによるGREASE試験

$
0
0

0. 短いまとめ

  • 長い間、TLSのクライアント・サーバ間で使用するTLSバージョンを合意する際に、 不完全なサーバ実装によって version intolerance が発生することが問題になっていました。
  • TLS1.3ではこの version intolerance の影響を最小化するため、新しい version negotiation の仕組みを取り入れました。
  • Googleは、GREASE(Generate Random Extensions And Sustain Extensibility)という仕様をChromeに実装し、TLSサーバのバグで通らない拡張やフィールド値で問題が発生しないか試験を始めました。
  • パケットキャプチャが好きな人は、Chromeが 0x[0-f]a0x[0-f]a の見慣れない値をCipherSuiteやTLS拡張に使っているのを見つけても驚かないよう気をつけて下さい。

1. はじめに

 確か半年前も同じような事を言っていましたが、TLS1.3の仕様策定が大詰めを迎えています。
しかし大詰めの段階に来ているにも関わらず、最近のドラフト(draft-15/16)になって、これまでのTLS仕組みを大きく変えるような変更がいくつか導入されました。

この大きな変更は、Netscape社のSSL3時代から20年近く、これまでずっと積み重なってきた技術負債をできるだけここで一掃したいという思いの現れです。しかし一方で、ガチガチにミドルボックスで縛られた現状のインターネットと不完全な実装を持つ多数のTLSサーバの影響を考えるとそうそう一筋縄ではいきません。事情や経緯を知らない人がこの変更点を見るとなかなか理解しがたい仕様になっているでしょう。

今回は、TLS1.3で採用された大きな変更のうち、 Version Negotiation について取り上げたいと思います*1。そしてGoogleは、こんな苦労をもうしないよう、将来のTLSバージョンアップや機能拡張に備えるべくGREASEという仕様ドラフトを提出しました。既にBoringSSLやChromeに実装され、先週よりChrome Canaryで試験運用を始めました。これについても詳しく紹介します。

2. TLS Version Intolerance

 TLSのクライアントとサーバでどのTLSのバージョンを使うのか? この合意(Version Negotiation)は、TLSハンドシェイクの初期で行う非常に重要なステップです。しかし、これほど基本的で重要な機能なのに、現実のTLSの Version Negotiation は不完全で、随分昔(2003年以前ぐらい)から問題が発生していることが知られています。これを Version Intolerance と呼んでいます。日本語だと「バージョン不耐性」でしょうか?なんかよい訳が思い浮かびません。

ちょうど昨日MozillaのTim Taubert氏のブログ

TLS version intolerance - Working around bugs in legacy TLS stacks - Tim Taubert

で version intoleranceが詳しく取り上げられました。そこで紹介されている Bulletproof TLS Newsletterを書かれているHanno Böck氏のプレゼン資料

TLS 1.3 and Version Intolerance

にも詳しく解説されています。ここに敢えて私が付け加えるようなことはないのですが、後の説明がわかりやすくなるよう簡単に図にして解説してみます。

2.1 TLSの正常な Version Negotiation

 TLSのVersion Negotiationは、ClientHello/ServerHelloのハンドシェイクの最初のやり取りで行います。クライアントは自身がサポートしている最高のTLSバージョンをサーバに伝えます。サーバは、自身がサポートしているTLSバージョンからクライアントがサポートしているものを選んで返します。

TLS1.2のクライアントとTLS1.2のサーバ間では簡単で、ClientHelloとServerHello供にTLS1.2のバージョンをやり取りして合意して完了です。

f:id:jovi0608:20161002085404j:plain

一方、クライアントとサーバ側のサポートが違う場合(サーバ側がTLS1.1までサポートしていない時)、サーバはClientHelloでTLS1.2を受信しますが、TLS1.2をサポートしていないので、ServerHelloでTLS1.1をクライアントに返します。クライアントはそれを受けて、クライアント・サーバ間でTLS1.1を合意します。

f:id:jovi0608:20161002085419j:plain


実はこれをちゃんと実装していないサーバが多く存在していて問題になっています。

2.2 不完全な実装のTLSサーバによる Version Intolerance

 何がちゃんと実装されていないのでどういう問題が起きるのかは様々ですが、一例としてよく挙げられているのは、サーバが自身がサポートしていないTLSバージョンのClientHelloを受信すると接続を切断してしまうというという実装の問題です。

Fallbackをサポートしているクライアントは、Version Intoleranceの問題でClientHelloが切断されるとサーバにオファーするバージョンを下げてもう一回接続に行きます。これを繰り返してサーバがサポートしているバージョンまで合致すると、やっとハンドシェイクが進みます。

f:id:jovi0608:20161002085436j:plain

最終的に接続できるから良いかと思うかもしれませんが、何回も初期接続を試みるのでTLS通信が確立するまで時間がかかります。なによりクライアントは本当にサーバが切断したのか判断つかないので、もし中間攻撃者によって意図的に切断されてダウングレードさせられているのかもしれません。もし脆弱性のあるTLSバージョンまでダウングレードさせられると問題です。

TLS1.2が仕様化された後、このような状況がいくつか見られました。その結果、幾つかのブラウザベンダーは、TLS1.2の対応サーバがある程度普及するまでデフォルトでTLS1.2の通信をオフにしなければなりませんでした。

3. TLS1.3はやっぱり通らない

 TLS1.3でも同じ状況が起こることが懸念されてました。SSLLabでは2012年4月よりTLS protocol torelance を測定しています。その詳しい内容が、

TLS Version Intolerance in SSL Pulse – Network Security Blog | Qualys, Inc.

で公開されています。ここでその図を引用させてもらいます。

f:id:jovi0608:20161002085451j:plain

当初SSLlabは、TLSのRecord LayerとClientHelloの両方共に同じバージョンでサーバに対してTLS1.3とTLS2.152のProtocol Intoleranceをチェックする試験を行っていました。TLS1.3では12%、TLS2.152では60%以上のサーバが接続を拒否しています。この数値は悲惨です。

しかし2015年5月に record layer のバージョンをTLS1.0に固定した試験に変更すると急激に下がりました。2016年7月時点ではTLS1.3で3.2%のサーバが version intolerant であると統計結果が出ています。実はClientHelloのrecord layer中のバージョン指定には明確な規定がないですが、record layerのバージョンのtoleranceは大変厳しいのがわかります。TLS1.3では record layer自体はもう意味がなく、互換性のためだけに付けておく無駄な5バイトになっています。なのでTLS1.3の record layerのバージョンはTLS1.0(0x0301)に固定されました。

Googleも独自に go 実装で Alexaのトップ100万のサイトを調査しました。その結果、1.63%のサイトがTLS1.3のClientHelloを切断したということです。そうなると3.2%〜1.6%がTLS1.3の version intoleranceの見積もりになります。この数字が大きいか小さいか、判断が別れるところです。

その数パーセントの中に大規模なアクセスを受けているサイトがあれば、ユーザへの影響は大きいでしょう。TLS1.2までは問題なく動作していたということで、TLS1.3にしてまず真っ先に問題を疑われるのはクライアント側になります。

このままではTLS1.2の時と同様にTLS1.3の仕様化完了してもしばらくは default off にし、時間を掛けてTLS1.3を deploy していかないといけないかもしれません。できればそれは避けたいところです。

4. 新しいTLS1.3のVersion Negotiation

 そこで TLS1.3では、新しい Version Negotiationの仕組みを採用しました。

それは従来のClientHelloで指定するバージョン番号を legacy_versionとしてTLS1.2(0x0303)で固定し、その代わり新しいTLS拡張でSupported Versionsを規定してそこにTLS1.3のクライアントがサポートするTLSバージョンのリストを記載します。TLS1.3のサーバは、ClientHelloのProtocol Versionフィールドを無視して、Supported VersionsのTLS拡張の方を見てTLSのバージョンを選びます。

f:id:jovi0608:20161002085504j:plain

従来のTLS1.2までのサーバは、Supported Versions拡張を知らないので、これまでのTLS1.2のClientHelloが来たと思って騙されて処理を継続します。これならTLSの新バージョンの導入による version intoleranceの影響を最小限にすることができます。
Googleの測定ではこの方式にすると 0.017% までintoleranceが落ちるという結果がでました*2。これなら十分いけます。

 

しかし、TLS1.3の仕様をよくよく見返してみると、TLS1.3の ClientHelloフィールドのうち半分が実際には不要で互換性維持のためだけに存在する固定値になってしまいました。あぁデザインがきれいじゃない。

f:id:jovi0608:20161002085517j:plain

まぁなんとも言えないもどかしさです。しかしClientHelloのフォーマットを維持してデータ形式上TLS1.xとの互換を保たないとTLS透過性はもっと悲惨なものになるでしょう。そしてClientHelloのProtocolVersionを固定化し、従来のTLSのVersion Negotiationを捨て去ることは、TLS1.3一回限りではなく今後TLS1.4以降でもずっと続く話になります。大きな決断をすることになりました。

5. 実際のTLS1.3のハンドシェイク

 ということで Supported Versionsを使ったTLS1.3のハンドシェイクを見てみます。既にChrome Canary で draft-15なんですがSupported Versionsが実装されたので実際のパケットを見てみましょう。
なお TLS1.3(0x0304)が使えるのは、最終的にTLS1.3の仕様化が完了した後からです。draft段階での相互接続試験においては、使用するバージョンは1オクテット目を0x7f、2オクテット目をドラフト番号にしたバージョン番号を使います。今回Chromeは、まだ draft-15 なので 0x7f0e がバージョン番号になります。まずは ClientHelloから、

f:id:jovi0608:20161002085532j:plain

Record LayerのバージョンはTLS1.0です。ClientHelloのProtocol Versionは、TLS1.2。これで従来のTLS1.2までのサーバを騙します。Supported Versions拡張は43番が割り当てられています。そこにクライアントがサポートするTLSバージョンのリストが5つ記載されます。最初の 0x1a1a は後述するGREASEの値。それから draft-15のバージョン 0x7f0e, TLS1.2 0x0303, TLS1.1 0x0302, TLS1.0 0x0301 が続きます。一応記載順には意味を持たせないことになっています。

続いてServerHello、

f:id:jovi0608:20161002085548j:plain

Record LayerはTLS1.0で固定化したままです。Supported Versionsのリストからサーバが draft-15(07f0e)を選択して Protocol Versionに記載してクライアントに返します。これで TLS1.3の Version Negotiationの完了です。

6. バグで錆びたTLSを滑らかにするGREASE

こんな悲しいTLSの状況で頼みの綱はTLS拡張しかない。しかし楽観視できない、TLS拡張の処理にもバグが固定化して錆びついてしまう。

Googleの Adam Langlay氏は

ImperialViolet - Cryptographic Agility

において

There's a lesson in all this: have one joint and keep it well oiled.
(これについて解決法は、どこか一つを繋げて十分に潤滑させておくことしかない)

と書いています。そこでGoogleのエンジニアDavid Benjamin氏が、GREASE(Generate Random Extensions And Sustain Extensibility)

https://datatracker.ietf.org/doc/draft-davidben-tls-grease/

というドラフトを少し前に提出しました。日本語に訳すと「ランダムな拡張を生成して、拡張性を維持する」ということでしょうか。

これは、2バイトの0x[0-f]a[0-f]aの16個データからランダムにいくつか抽出し、毎回ClientHelloのCipherSuiteやTLS拡張や値にこのランダム値を入れ込んでサーバに送ってしまおうという仕様です。

現状のドラフトでは、CipherSuite値、ALPN拡張の値、supported group(TLS1.2ではEC group)の値、2つのTLS拡張(0バイト長、1バイト長)、supported versionsの値(TLS1.3のみ)の6領域を対象としています。

本来はTLSサーバが知らない未定義の拡張やフィールド値を受信しても基本無視して処理するのがTLSの仕様で求められる挙動です。GREASEは、未定義値を毎回ランダムに送信することによって、TLSサーバのバグを早期に発見し、将来拡張で利用する時に問題が発生するのを未然に防ごうという狙いです。

 

文字通りGREASEは、TLSの拡張やフィールド値の利用がバグ実装の固定化で錆びつかないようグリースを塗り続けるという比喩を表しています。

 

これも既に Chrome Canaryに実装されているので、実際にパケットを見てみるとよくわかります。Chome CanaryのTLS1.2のClientHelloを見てみましょう。

f:id:jovi0608:20161002085602j:plain

CipherSuiteの先頭に0x3a3aの見慣れない値が入っています。これがGREASEです。

 

ちなみに、続く0x16で始まるUnknownな CipherSuite は、Googleが只今絶賛検証中の耐量子コンピュータの鍵交換 CECPQ1 を使った CipherSuite です。これは、djbの考案した楕円関数 curve25519を使ったECDHE(x25519)と new hope というring-LWE方式の格子暗号を組み合わせた鍵交換方式です。これはこれですごく面白いのですが、解説するとめちゃくちゃ長くなるので、いつかの機会に。

 

続いてTLS拡張に入っているGREASEを見てみます。

f:id:jovi0608:20161002085614j:plain

0バイト長の0x2a2aの拡張が頭に1バイト長の0x1a1aのタイプ値を持ったTLS拡張が追加されています。他にクライアントがサポートする楕円関数の種類を広報する EC group 拡張の先頭にも 0xaaaa のGREASE値が入っています。
ALPNへのGREASEの実装はドラフトに記載されていますが、まだのようです。Supported Versionsに関しては、先の TLS1.3のCLientHelloを見てみれば Supported Versions拡張の先頭に0x1a1aのGREASEが入っているのがわかります。 

BoringSSLの実装では、これらのGREASE値をClientのRandomフィールドの頭の1バイトずつをシードにして生成しています(頭の4bit値)。よって、ClientRandomが変わると毎回値が変わることになります。

GoogleはGREASEによってどの程度問題が発生しているのか統計を取って、今から将来のTLSのバージョンアップや機能拡張に備えている試験を始めたわけです。

最後に、全国数X万人のパケットキャプチャ好きなエンジニアの諸君へ

今後ChromeTLSパケットに 0x[0-f]a[0-f]aの見慣れないUnknownフィールドや値を見かけたとしても驚かないように。それはGoogleが、インターネット中のTLSサーバが錆びつかないようグリースを塗っている様子なんです。

*1:この他にもCipherSuiteの構造も大きく変わっています。

*2:Googleは、ChromeのTLS1.3の事前試験でTLS1.3で必須となっている署名アルゴリズム(RSA-PSS)のTLS拡張値でNSSのバグを踏んでハンドシェイクが失敗することを見つけました。0.017%にはこのNSSのバグの影響によるものがいくつか含まれているようです。


はてなブログの方に移りました。

OpenSSLの脆弱性(CVE-2017-3733)に見られる仕様とcastの落とし穴

$
0
0

0. 短いまとめ

  • OpenSSL-1.1.0dに脆弱性(CVE-2017-3733)が見つかり、Encrypt-Then-Macと renegotiation を組み合わせて crashさせることができました。
  • この脆弱性は、仕様の準拠不足や不適切な変数の cast などが原因でした。
  • TLS1.3ではこういう落とし穴が少なくなるよう機能の根本的な見直しが行われています。

1. はじめに

先週 OpenSSL-1.1.0d に対してセキュリティアップデートがあり、 Encrypt-Then-Mac renegotiation crash (CVE-2017-3733)という脆弱性(Severity: High)が公開されました。 対象となった 1.1.0 は、昨年2016年8月にリリースされたOpenSSLの新しいリリースブランチです。1.1.0ではAPIの大幅変更もあり、まだあまり普及していないため影響を受けた方は比較的少なかったのではと予想します。 しかし今回の脆弱性、その原因をよくよく探ってみるとなかなか趣深いものがあります。

そこで Encrypto-then-Macとは何か、Renegotiationとはどういうものか、はたまた何故Highにまで影響するような脆弱性になっちゃったのか、その仕組みを書いてみたいと思います。

2. MtE(Mac-then-Encrypt) や EtM(Encrypt-then-MAC) と AEAD(Authenticated Encryption with Associated Data)

インターネット上でセキュアな通信を行うには、暗号化によってデータの盗聴を防ぐ機密性の確保を行うだけでは不十分です。暗号化の有無に関わらずデータの改ざんを検知し完全性を確保することも必要です。 従来、改ざんを検知するにはデータのMAC(Message Authentication Code)を計算し、その値をデータに付与してチェックを行ってきました。

暗号化とMACの計算、どっちを先にやるのか。その手順の安全性に関して古くから議論が行われてきました。代表的には、MACを先に行うMtE(Mac-then-Encrypt)と暗号化を先に行うEtM(Encrypt-then-Mac)の2つのやり方が挙げられます。TLSSSLの時代から 、ブロック暗号(DES/AES)とCBCモードを利用する際にMACを先に行うMtE方式を採用してきました。しかしこの方式を利用していると、復号化してからデータのチェックを行うためパディングオラクル攻撃の対象となり、これまでソフトウェアの実装不備を突いた攻撃手法がいくつも公表されてきました。中でも2013年の Lucky Thirteen 攻撃CBCモードの実装不備を突いた非常に有名な攻撃手法です。

最近になっても2015年に amazonの s2n に対するLucky Microsecondsや、2016年もOpenSSLのAES-NIの実装不備をついたLuckyNegative20などの脆弱性が公表されています。このようにMtEの安全性を確保するソフトウェアの実装を行うためには、高度なセキュリティや計算機科学の知識と実装能力が必要とされます。個人的には素人が手を出せる領域ではないなと感じています。

そんななか、TLS1.2からAEAD(Authenticated Encryption with Associated Data)という暗号化手法が採用されました。これは内部的にEtMを使いつつも、同時に認証用の高速なMACも合わせて計算するといった方式で、その安全性は利用する対称暗号やMAC方式に依存するということが数学的に証明されています。しかもAEADは、暗号対象となるデータ以外のデータ(平文のヘッダデータなど)の認証も合わせて行うこともできます。何よりAEADの中でAES-GCM方式は、Intel AES-NIやARMv8のAES拡張機能などハードウェア処理機能が提供されていて、他の方式より格段に高速な処理が実現できるといったメリットがあります。

簡単にMtE, EtM, AES-GCM(AEAD)の方式の違いを表したのが以下の図です。 f:id:jovi0608:20170220113615j:plain現在のTLSでは、まずAES-GCMのAEAD暗号方式使った通信の利用を中心に考えて良いことは間違いないことでしょう。

3. RFC7366: Encrypt-then-MAC for TLS and DTLS

そうは言っても、まだ広く使われているAES-CBCはこのままでいいのか、TLS1.0や1.1もなんとかしないとあかん、ということから、TLSの暗号通信を従来のMtEからEtMに変更できる仕様 RFC7366: Encrypt-then-MAC for TLS and DTLSが2014年に標準化されました。MtEとEtM共に混在することができないことから、EtM用のCipherSuiteを別に用意するということも考えられたのですが、CipherSuiteの数が多くなりすぎるため、ハンドシェイクのClientHello/ServerHelloの拡張を使ってEtM方式の利用を合意する方式が採用されました。やり方としてはクライアントがEtMをサポートしていることを伝えるEtM拡張をClientHelloに付与し、ServerがEtM方式が可能なCipherSuiteを選択したらEtM拡張をServerHelloに付けてクライアントに返せば完了です。もしサーバがAEADなどEtMを必要としていない暗号方式を使う場合は、ServerHelloにEtM拡張を付けずに返します。簡単に書くと下図のようなやりとりです。 f:id:jovi0608:20170220113626j:plainこの方式なら比較的簡単にEtM対応が可能になるだろうという見込みを持って仕様化されましたが、やっぱり今回みたいに落とし穴がありました。仕様はホント注意深く読み込まないといけません。

4 Renegotiation

今回の脆弱性は、EtMとRenegotiationを組み合わせたものです。ここではTLSのRenegotiationについて簡単に書いてみます。

TLSは、最初ハンドシェイクを行った後に再度ハンドシェイク(Renegotiation)を行うことができます。2回目以降は既にハンドシェイクが完了しているので暗号化通信上でRenegotiationが行われます。 これが必要なのは、当初サーバ認証でTLSの通信を行っている後にクライアント認証が必要なリソースにアクセスすることが必要になった場合などです。サーバからの合図でRenegotiationを開始し、クライアント証明書のチェックを行うことによって、サー バ認証のTLS接続後もクライアント認証にシームレスに移行することが可能になります。 f:id:jovi0608:20170220113632j:plain他の用途として、長時間TLSの通信を行っている時に対称暗号の鍵をアップデートをする際にもRenegotiationを使うことがあります。Renegotiation自体は一見何ら問題ないように見えますが、Renegotiation前後で同一のセキュリティが確保できているか、 処理コストが高いのでDoSっぽいことをやられる恐れはないかとか、これまでもRenegotiationを踏み台にした攻撃手法もいくつか公表されたこともあり、その利用価値は次第に小さくなってきています。

今回の脆弱性は、MtEの実装でRenegotiation時の挙動をちゃんと対処できなかったことが原因でした。やっぱりRenegotiation機能はTLSの状態を非常に複雑にし、いろんな落とし穴の一因になっていると言われても仕方ないでしょう。

5. CVE-2017-3733

5.1 CVE-2017-3733 脆弱性の再現

まずは今回の脆弱性を再現させてみましょう。OpenSSL-1.1.0では default でEtM拡張が有効になっています。今回の脆弱性修正パッチから探ると、最初のハンドシェイクでAEADを利用しRenegotiationでEtMを使った暗号に変更すると crash してしまうようです。OpenSSLの s_clientコマンドでは Renegotiation をサポートしていますが、その際暗号方式を変えることができないので少し改造してみます。

下記パッチを使うと s_client で接続後、標準入力で S を入れると AES128-SHAで Renegotiation を行うようになります。脆弱性のある 1.1.0dを使うとクライアントが先に crashしてしまうので修正された1.1.0eの s_client にパッチを当ててみます。

--- a/apps/s_client.c+++ b/apps/s_client.c@@ -2440,6 +2440,12 @@ int s_client_main(int argc, char **argv)
                 SSL_renegotiate(con);
                 cbuf_len = 0;
             }
+            if ((!c_ign_eof) && (cbuf[0] == 'S'&& cmdletters)) {+                BIO_printf(bio_err, "RENEGOTIATING for CVE-2017-3733\n");+                SSL_set_cipher_list(con, "AES128-SHA");+                SSL_renegotiate(con);+                cbuf_len = 0;+            }

先に OpenSSL-1.1.0dでTLSサーバを立ち上げておき、このクライントで接続します。AES128-GCM-SHA256(AEAD)で接続してからコマンドSを入力してAES128-SHAにRenegotiationしてみましょう。

~/openssl-1.1.0e$ ./apps/openssl s_client -connect localhost:8443-cipher AES128-GCM-SHA256
CONNECTED(00000003)(中略)
    Extended master secret: yes
---
S
RENEGOTIATING for CVE-2017-3733(中略)
write:errno=104

なんかエラー出てます。サーバ側がどうなっているのか見てみます。

~/openssl-1.1.0d$ ./apps/openssl s_server -cert ~/tmp/certs/server.cert -key ~/tmp/certs/server.key -accept8443
Using default temp DH parameters
ACCEPT
(中略)
CIPHER is AES128-GCM-SHA256
Secure Renegotiation IS supported
ssl/record/ssl3_record.c:352: OpenSSL internal error: assertion failed: mac_size <= EVP_MAX_MD_SIZE
Aborted (core dumped)

うわっ、エラー吐いてTLSサーバが abort しています。たった一つのTLSセッションでTLSサーバを落とすことができました。

5.2 CVE-2017-3733 の原因

なんでこんなことになってしまったのか、その原因を探ってみましょう。

OpenSSL-1.1.0dのEtM実装ではサーバは ClientHello のEtM拡張と選択するCipherSuiteを見てEtMを使うか判断し、EtM拡張付きのServerHelloを返すと共にEtM利用のFlag(TLS1_FLAGS_ENCRYPT_THEN_MAC)を立てます。

最初のハンドシェイクでは、 Change Cipher Spec(CCS)の送受信が行われるまで平文通信です。CCSによりEtMの暗号化開始はサーバ・クライアント共に同期が取れていて問題ありません。 ところが Renegotiation は暗号化通信上で行われるハンドシェイクです。暗号化通信上でこのClientHelo/ServerHelloの送受信タイミングでEtM利用のFlagが立ってしまったらどうなるでしょうか?

本来は CCS の送受信のタイミングで暗号方式が変わります、このタイミングでEtMの利用を開始するのは早すぎるのです。

先の脆弱性の再現例では最初のハンドシェイクは AES-GCM でした。サーバ側は EtMのフラグがOnになっているのでAES-GCMで暗号化されたデータをEtM方式で復号化しようとします。まずMACチェックを行いますが、AES-GCMはMACを使いません。本来ありえないAEADのEtMの復号処理、その時点でそのTLSセッションの処理は止まってしまいます。 f:id:jovi0608:20170220113639j:plain普通1つのTLSセッションのエラーがサーバ全体に波及することはありません。そこにはもう一つ落とし穴がありました。

5.3 int -> unsigned int へ、castの悲劇

じゃこのエラー時、どんな処理がされるのでしょうか? 該当するコードは以下のところです。

if (SSL_USE_ETM(s) && s->read_hash) {
        unsignedchar *mac;
        mac_size = EVP_MD_CTX_size(s->read_hash);
        OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);

SSL_USE_ETMが有効化されているのでmac_sizeを取得しに行きます。AES128-GCM-SHA256の場合はAEADなのでMACが定義されておらず mac_size に -1 が返ります。

現状のTLSではMACの最大はSHA512の64バイト、 -1 <= 64 だから assert 問題ないです。しかし、

short version;
    unsigned mac_size;
    unsignedint num_recs = 0;

あー、mac_sizeは unsigned にキャストされています。 -1 は、4294967295(=232-1) です。AES-GCMのMACサイズはなんと4Gバイト超の巨大な値とみなされます。

OPENSSL_assert(4294967295<= 64);

これで assert チェックにひっかかり、しかもOPENSSL_assert は abort() まで行きます。 TLSサーバは見事ここで crash です。 この脆弱性は、RedHatのエンジニアからの報告だったようですが、よく見つけたものです。

5.4 修正方法

根本的な問題は、ClientHello/ServerHelloの送受信時にEtM利用を開始したことでした。そこで修正はCCSの送受信時にREAD/WRITEの2つのEtM利用のフラグを使うようにしました。 https://github.com/openssl/openssl/commit/4ad93618d26a3ea23d36ad5498ff4f59eff3a4d2f:id:jovi0608:20170220113646j:plain実はこれ、RFC7366の仕様にちゃんと注意事項として書いてありました。

3.1.  Rehandshake Issues
   (中略)
   If an upgrade from MAC-then-encrypt to encrypt-then-MAC is negotiated
   as per the second line in the table above, then the change will take
   place in the first message that follows the Change Cipher Spec (CCS)
   message.

「再ハンドシェイク時のEtMの切り替えはCCS後に変更を行うこと」まさにこれです。もう言い訳ききません。

OpenSSL-1.1.0eでは、今回の破壊的な結果を引き起こした unsigned 変数のキャストやOPENSSL_assert()の処理も修正されました。 https://github.com/openssl/openssl/commit/60747ea22f8b25b2a7e54e7fe4ad47dfe8f93383

実は master の OpenSSL-1.1.1-dev では、 mac_size をちゃんと int で受けて範囲チェックを行い、 size_t にキャストするよう変更されていました。 そのためエラーは発生するものの crash まで行くことはありません。最新ブランチには地道なコードの見直しがちゃんとされているようです。

6. TLS1.3とOpenSSL-1.1.1

OpenSSL-1.1.0では default で使えるようになっているEtM拡張ですが、BoringSSLやNSSで実装する動きはまだありません。すなわちChromeFirefoxなどのブラウザーでのサポート見込みはありません。 TLS1.2でAES-GCMやChaCha20-Poly1305などAEADが使えるようになっているので、わざわざ対応する必要はないということでしょう。

次期TLS1.3では根本的な機能の見直しが行われており、今回の要因となったTLSの機能を廃止・変更しています。

  • Renegotiationを廃止して Post-handshakeを新設。
  • Change Cipher Spec を廃止して、鍵交換後は即暗号化開始。
  • CBCモードの利用廃止、CipherSuiteはAEADのみ利用可に。

よってTLS1.3ではEtM自体が意味のない機能になっています。OpenSSL-1.1.1ではTLS1.3が実装されており、近く正式リリースされるのではないかと期待されています。OpenSSLの開発者が所属する akamaiでは、4月にTLS1.3を rollout するようです。 TLS1.3の仕様化完了とOpenSSL-1.1.1のリリースが待ち遠しいです。

書評:プロフェッショナルSSL/TLS

$
0
0

ごめんなさい、書いてたら長くなってしまいました。長文嫌いな方は避けて下さい。

鹿野さんの名前を間違えてました。大変失礼しました。(_O_)

1. はじめに。日本語翻訳版刊行によせて、

昨年10月、Vさんから

「 Bulletproof SSL and TLS翻訳本のレビューします?時雨堂が出資してる出版会社が翻訳権を勝ち取ったのです。」

とお誘いを受けたのが、そもそもの始まりでした。

「とうとうあれの日本語翻訳が出るのか、でもホント大丈夫か? 内容の濃さもさることながらあの分量とクオリティ、記述の正確さや厳密さに対して特に高いものが要求されるセキュリティ分野。しかも初心者向けではないエキスパート向け。この本の翻訳を出すとは… なんと大胆、少し無謀なことではないか?」

との思いが正直頭をよぎりました。

自分もちょうど17年半勤めた前職を辞めて転職した直後。新任早々こんなことしても許されるのか? 恐る恐る遠慮がちに上司に伺ったところあっさりOKの返事。さすがっ、理解のある上司で良かった、ホント感謝します。

編集の鹿野さんからの依頼は、

「レビューについては、一文一文を集中的にではなく、ざっと見ていただくようなものを」

と控え目なもの。

「いやいや、この本をざっくりレビューじゃ失礼です。じっくり見させていただきます。」

と、少し自分にプレッシャーをかけつつ読み始めました。

そして一晩作業してみて私からの返事。

「第一印象として、まだ日本語訳としてこなれてない部分が多いなと思いました。特に2章で技術的に難しい記述になると英文の表現に引きずられて日本語の文意が取りづらいなと感じる部分が多くなりました。 日本語訳を読みながら詰まったり、気になったところにコメントを差し込んだのですが、結局29ページで100個近くのコメントになってしまいました。」

まぁ正直な感想です。でも、これじゃ全然先に進まない。

幸いに、技術的に間違って訳している箇所はかなり少なく、ちゃんと内容を理解して翻訳がされているのがわかります。これならきっと原書のクオリティを保ったまま翻訳本にできるはず、そう確信しました。

しかしその後、何章か同じペースでコメントを入れ進めたのですが、そのうち本業の方が立て込んでしまい途中でレビューが止まってしまいました。すみません。

その間、鹿野さんから私のコメントに対する返事を頂いたのですが、驚いたことに監訳の方に丸投げするわけではなく、ちゃんとご自身で判断されて修正対応されてます。私のコメントが間違っていることもしばしばで、逆に鹿野さんから指摘を受ける始末。恥ずかしい。あれっ?エンジニアの方が編集者してるんじゃないか?マジそう思いました。

そんなまま数ヶ月経った後、「原稿を更新しました」とのご連絡。うぅ、うっかりメール見落としてた。直ちに未レビュー章を片付けないとまずい、早速レビュー開始。すると、

「あれっ、めちゃくちゃ読みやすい。この章のレビューコメントがゼロ。」

「うそ、以前ならそんなことはないはず。おかしい。」

「時間をおいてもう一度読み直そう。」

翌日、「やっぱりゼロだ。何が起きたんだ?」

鹿野さん曰く、「思い切った編集方針に切り替えました。」

すごーい! 読んで進む、進む。あかん、このままじゃ本当にレビューしているのか疑われてしまう。そういう心配してしまうくらいの素晴らしい出来になりました。

まぁそんなこんなギリギリまでドタバタのレビューがかかってしまい、ご迷惑をおかけしました。そして無事「プロフェッショナル SSL/TLS」が刊行されました。めでたいことです。

余談はこのぐらいにして早速本の中身について書いてみます。

2. この本の扱う範囲

私は過去2年(2015/16)、セキュリティ・キャンプ全国大会でTLSを教える講義を担当してきました。各地から集まる若く優秀な学生さんに対してTLSをどう教えるのか、最も悩むところです。

結局はいくら悩んでも、TLSのハンドシェイクの仕組みを学んでもらうことに落ち着いてしまいます。やっぱりTLSは難しい。

TLS仕様(RFC5246)自体は、ハンドシェイクやプロトコルフォーマットを規定するだけで、実はX.509証明書などPKIやAES、RSAなど暗号技術の仕様については、TLSで具体的な中身はほとんど含まれていません。これらは他への関連仕様として参照されており、IETFで扱うWGも違います。

後ろ髪引かれるのは、狭義的(RFC5246)な見方では、キャンプではそれらを外部仕様としてTLSを支える土台としてスコープ外にせざる得ないことです。時間的にも、キャパ的にも、全部盛り込むのは無理があります。なので最終的にはこのスライドでごまかしています。 f:id:jovi0608:20170317015704j:plainそれに対し本書では、これら全部引っくるめてTLSセキュリティを解説しています。いやさすがです。

本書では、上図の各項目に対応する章として、

TLSのセキュリティ:

「第2章プロトコル」、「第6章実装の問題」、「第7章プロトコルに対する攻撃」

暗号技術:

「第1章SSL/TLS と暗号技術」、「第6章実装の問題」、「第7章プロトコルに対する攻撃」

乱数生成:

「第6章実装の問題」、「第7章プロトコルに対する攻撃」

PKI:

「第3章公開鍵基盤」、「第4章PKIへの攻撃」

秘密鍵の管理:

「第8章デプロイ」

な関係になります。

全部を網羅するので扱う技術領域の幅が一気に増え、それぞれが深い内容を含みます。 まぁどんな専門家でも頭でわかっているつもりなだけで、いざちゃんとした成果物まで仕上げるとなると並大抵の労力ではすまないでしょう。

しかも、さらに私の講義の範囲の図にも入っていない、

上位レイヤー(HTTPS)のセキュリティ:

第5章HTTPブラウザ問題、10章、HSTS、CSP、ピニング

性能:

第9章 パフォーマンス最適化

までカバーしている。あぁもう凄いですね、と感服するしかありません。

既に本書を購入し読み始めた方は、その広大な技術領域と膨大な量に圧倒される人も多いかと思います。

個人的には、これから1章から読み始めることにしても、必ずTLSの技術領域に関する土地勘を意識することが大切だと考えます。ざっと読む部分・深く精読する部分などを決めて、ある程度メリハリのある読み方をすることをお勧めします。

3. この本の凄いところ

話がそれますが、実は先日社内から依頼を受けて「技術のスキルアップ、私のやり方」というセミナーを内部で開催しました。

自分のこれまでの取り組みを振り返りながらあれこれメンバーと共に話をした実に楽しい時間でした。その中で「アウトプット方法 ブログの書き方」というセッションを設け、某メンバーのブログのビフォー・アフターを紹介しながらブログの書き方やアウトプットの重要性などの話をしました。

その時のスライドの一部がこれです。 f:id:jovi0608:20170317015711j:plainf:id:jovi0608:20170317015718j:plain自分が思うに、今回の本はまさにこれなんですよね。

この本に対して私のスライドを比較するのはほんと失礼だと思いますが、この本の凄いところをこの図に関連付けて書いてみます。

3.1 凝縮された内容

序文で著者自身がこの本の目的を

「著者が時間をかけた分読者の時間は節約できるよう、著者が知っていることの中でも特に重要な内容を詰め込み、僅かな時間で同じ内容を理解してもらうことである。」

と書いています。

まさに「特に重要な内容」を詰め込んでおり、上図の様におそらく著者はこの10倍、もしくはそれ以上の分量を調べ上げているはずです。その中から著書のコンテキストに合わせて絞り込み、体系化した内容にして書いているのだと思います。

この作業自体は他の本でも行われており、特別なことでもないでしょうが、TLSPKIなど過去20年分しっちゃかめっちゃかした技術領域を広く網羅した範囲で行ったのは凄いです。

この本を購入することは、TLS/PKIに関連に重要な情報に辿り着くまでの調査とそれを理解するための時間を買っていると思って良いです。ただ本当のエキスパートを目指す人は、ここに書いてあることが全てではなく、この裏に広大な技術領域が広がっていると思って下さい。

また11章以降は各実装の使い方になっていますが、これは「実際に検証して確認(エピソード記憶)」に該当する作業です。これまで学んだことが実際どう設定に反映されるのかここで結びつけることができます。私が思う本当に理想的なアウトプットだなと感心します。

3.2 何事にも代えがたい一次資料へのポインター

私は原著を所有していますが、実はこれまであまり中身を通して読んだことがありませんでした。使う時は、なにか調べ物をする時です。

新しい脆弱性情報が公開されると全て新規のものは稀で、大概新しい手法に過去の脆弱性を組み合わせたり、改良したりしたものが多いです。その際はこの本が大活躍します。関連するインシデントや脆弱性を楽に探すことができ、その一次リンクが脚注に数多く掲載されているからです。

日々発生する脆弱性やインシデント情報。いくらブックマークしていても少し経つところっと忘れてしまいます。検索で探し当てるにしてもS/N比が悪く効率的ではありません。すっかり忘れてしまった自分のブログに助けられることもしばしば。

この本は本当に一次情報にこだわっています。書いてある内容・図・データも、その多くが一次情報からのエビデンスがあるものということがはっきりわかります。この一次資料へのポインターは、何事にも代えがたい情報です。

これに加え、最新のTLS/PKIの動向や脆弱性の情報は、Bulletproof TLS Newsletter で受け取ることができます。近うちに商品ページからリンクが貼られるようです。毎月1回程度TLS/PKI/暗号技術などの最新情報に関する簡単な 解説やリンクがメルマガのニュースレターとして配信されてきます。普段いろいろアンテナを張っているつもりでも結構見逃しているものが多々あり、このニュースレターで助けられることも多いです。この本を読んで知識を得た方は、是非これで最新情報を得て下さい。

4. 個人的に思う注意点

良い事ばかり書いても書評にならないので、いくつかレビューしていて気づいた注意点を。

4.1 11章以降の実装バージョン

11章以降の実装で解説しているソフトウェアは最新のバージョンに追随していないものがあります。

特に OpenSSL は 1.0.1 をベースとしており、1.0.1 は昨年末にサポートが切れています。手元で試すならぜひ 1.0.2 を使いましょう(実は一部OSディストリビューションではそのまま自社サポートの範囲内で継続利用しているところもありますが、個人的にはあまりお勧めしません)。

ここで書かれているopensslコマンドや出力には、1.0.2でも大部分は違いはありませんが、cipher suite系は異なっている場合があります。

特に本文で解説されているFREAK攻撃などにより輸出グレードCipherは全てdisableされています。さらにSLOTH攻撃の影響でSSLv2も完全に削除されています。 最近では LOW cipher もなくなっており、本書で記述されている出力結果と異なる場合もありますので注意して下さい。

翻訳版は原著のフォークをせず、原著の更新を待つというポリシーですので、しばらくは更新を待ちましょう。

4.2 文書による解説の限界

ここ数年 Inria と Microsoft Research のジョイントFREAK, Logjam, SLOTH などTLSに対する非常に高度な脆弱性の発見と公開がされてきました。

私は原論文を読んでいたので、翻訳文を読んでいるときでも「あぁこの部分はこういう記述にしたのか」とか「これはこのことを指しているな」といったことを思いながら読むことができ、それほど違和感を感じませんでした。その記述は正確性を犠牲にせず、どこまでわかりやすく書こうとしているか、著者の工夫が見られるからです。

しかし、ふと訳文だけしか読んでいない読者だとどこまで理解ができるのかな?と少々不安に思いました。

特に「7.6節 トリプルハンドシェイク攻撃」は、理解するのに最難関の部類に入るものです。

これは翻訳の出来、不出来のレベルではなく、実は容易な文言で解説するにはこの辺が限界じゃないかと思えてしまうほどです。

Face-to-Faceの講義や動画アニメーションなど駆使すれば、なんとか読者にも理解してもらえるかもしれませんが、文書だけではどうでしょう? これ以上もっとわかりやすく書いて読者に伝えることができるか?自分でも全く自信がありません。

これらの部分は、一度読んでもわからないからと言ってあきらめず、是非原論文にでもあたって欲しいなと思います。

4.3 秘伝のタレのような内容

原著は、発行後も更新されています。なので記載の時期によって微妙に記述の仕方が変わっている部分もあります。

もちろん技術的な整合性は取れているので問題はないのですが、RC4の危殆化やBEAST攻撃に関する部分など前半と後半で微妙にニュアンスが違っているなと読んでいて感じるところもありました。

他にも、著者の過去ブラウザの挙動の改善にいろいろ取り組んだ時の経緯で、ブラウザのインターフェイスには結構厳しい表現で書いているところも見られました。この点、著者の努力の甲斐があってかこの領域、最近ではブラウザベンダー側の改善が著しい分野です。特に「5.7 セキュリティインジケーター」で記載されているセキュリティアイコンの変更に関しては、翻訳本では最新ブラウザの画像を使っています(本文の更新自体は原著通りです)。これも今後の改訂が期待されるところです。

頭から読んでいると文書の更新時期が想像でき、まるで継ぎ足しのタレを味わっているようで読んでいて味わい深いです。

5. TLS1.3の改訂に向けて

17章のまとめの文章は、私にとっても非常に考えさせられる文章です。まとめの章は、商品ページに全部が掲載されていますので購入前でも読むことができます。

著者は、

TLSはこれまで欠陥が多く修正が重ねられてきたが、もともと完璧なプロトコルなどはなく、どんなものも同様の状況になりえる、これまで普及して成功を収めたプロトコルに希望を持とう」

と書いています。

TLSはこれまでの数多くの技術負債を抱え、かつ最大の後方互換が求められ安定的に動作することが求められるプロトコルです。つい先日 SHA-1の衝突耐性が破られました。 md5の歴史から2nd-preimage耐性が破られるまでは時間の問題でしょう。SHA-1証明書が今後どういう命運をたどるのか、md5の衝突をついた「4.5 偽造RapidSSL証明書」を読めば予想できます。多大な社会的コストを払ってSHA-2の証明書に移行を進めたのはこういう過去の教訓を踏まえてのことです。今では md5は Flame マルウェア内で衝突計算が可能になるまでになっているようです。

TLS1.3では、様々な機能の廃止や見直しが行われています。中身はほぼメジャーバージョンアップレベルであるため、バージョン名をTLS2.0やTLS4にするか、大きな議論に発展し最終的にTLS1.3のままで決着しました。通常その仕様を読んでもどうしてこのような仕様になったのか、その議論の経緯や理由が明確にかつ詳細に書かれていることは少ないです。

本書を読めば、ここに書いてある脆弱性や攻撃を教訓としてTLS1.3の仕様が決められていることがわかるはずです。更新版が来れば、全てがこのTLSの技術負債を(完全ではないが)かなり一掃するTLS1.3の仕様につながっている、と理解する日が来るでしょう。

最後に、

以上、あまり書評にもならないことをつらつら書いてしまいましたが、実際この本が翻訳本として日本語で読めることは日本のエンジニアにとって本当に喜ばしいことだと思います。

先に書いた通り、ここに書いて有ることは本当に重要なことに絞り込んだ内容であり、それ以外の部分がその裏に隠されています。

ということはこの本を使えば、残りの90%をさぐる非常に良い足がかかりになります。 なのでこの本を教材とした勉強会を近いうちに内部で開始するつもりです。さぁ、メンバーが残り9割をこれからどこまで探ることができるのか、今から楽しみです。

RPCに特化したGoogleのセキュリティ通信ALTSとは何か

$
0
0

はじめに

昨年、Googleから Google Cloud Platform に関するWhitePaperがいくつか公開されました。その中でGoogleのサービス内部で使われている新しいALTSというプロトコルを説明した文書「Application Layer Transport Security」は、読んでみると非常に面白く、セキュアなサービス間通信には本当に何が必要なのか、といったことを改めて深く考えさせられるものでした。物理的なマシンからサービス運用まで、ALTSがカバーする範囲は幅広い領域に渡り、あの巨大なGoogleのサービスをよくここまでまとめ上げたものだとホント感心させられます。

以前から、Googleはデータセンタ内のサービス通信までも暗号化を進めていると言われていました。それは、2013年にエドワード・スノーデンが暴露した資料が、Googleのデータセンタ内部の通信データがNSAによって盗聴されていることをうかがわせるものだったからです(「NSA、グーグルと米ヤフーのクラウドに「思いのまま」アクセスか--米報道」)。

一方、Googleのサービス内通信では、RPC(当時はStubby、後のgRPC)が使われていることはよく知られていました。Googleがサービス内通信の暗号化を進めると聞いても、おそらくRPC over TLSを使うようになったんだろうなぁ、と漠然と想像するだけでした。しかし蓋を開けてみると、GoogleはRPCに特化したALTSプロトコルを独自に開発し、それを全面的に利用していたのでした。しかも幅広いレイヤーの認証を実現する独自PKIシステムと共に... ホント驚きです。

Googleが10年かけてフルスクラッチで作り上げてきたALTSとは、いったいどんなものなのか?詳細はまだ公開されていませんが、WhitePaperから読み取れるALTSの姿を書いてみたいと思います。

Disclaimer

本記事は、公開されている資料から筆者が読み取った内容を記載しています。ALTSの詳細な仕様や実装はまだ公開されていません。筆者の想定違いや読み間違いの部分もあるでしょう。筆者は、Google社とは一切関係なく、元社員や現社員からの情報も持ち合わせていません。従いまして、本記事の内容は、一切保証されませんので、お読みになる際はご注意下さい。

Googleサービスのネットワーク構成

まずは、Googleサービスのネットワーク構成を見てみましょう。「Encryption in Transit in Google Cloud」のWhitePaperにその概要が記載されています。また、そこに書かれていないGoogleデータセンター外部(各ISPに張り出しているところ)について、QUICの論文「The QUIC Transport Protocol: Design and Internet-Scale Deployment」に少し記載されており、そちらも参考になります。

これらの情報を合わせて、今回関係ある部分だけを抜き出すと、以下のネットワーク構成のようになっていると思われます。 f:id:jovi0608:20180116020131p:plainエンドユーザのクライアントからの接続は、各ISP内に設置してあるREL(restriced edge location)を通ります。Googleドメイン宛の接続の多くは、まずRELでTCPハンドシェイクの終端をして、その後のTLSのハンドシェイクをGFE(Google Front End)で行うといった2段構成になっています。

UDP通信のQUICは、REL上のUDP Proxyを経由して、GFEで直接ハンドシェイクを行います。論文によると、2016年7月にUDP ProxyによるQUIC接続に構成を変えたところ、検索サービスのレイテンシが4%から7%以上も向上し、TCPを上回る性能改善だったと報告されています。WhitePaperには、GFEがTCPの終端も行うことも記載されているので、全てのクライアントがRELを通るわけではなく、クライアントから直接GFEに接続する構成も存在しているものと思われます。

TLSとQUICの終端を担うGFEでは、DDoS防御の後にバックエンドのサービスへ負荷分散やルーティングを行います。図では、GFEからGCE(Google Compute Engine)のVM(Virtual Machine)、もしくはGoogle Cloud Serviceの2つにルーティングされています。

GFEから Google Cloud Serviceへの通信は、今回の主題であるALTS(Application Layer Transport Security)が使われています。ALTSは、アプリケーション層(Layer 7)で行うRPCの暗号化、双方向認証、完全性の確保を実現するセキュリティ通信で、GFEとGoogle Cloud serviceの間、もしくはGoogle Cloud service間の通信でALTSが使われています。

ALTSは、暗号通信とメッセージ認証だけ行う平文通信の2種類をサポートしています。Googleのデータセンタ間をつなぐWANを経由する場合、ALTS通信は暗号化通信ですが、Googleが管理しているデータセンタ内では、暗号化されずメッセージ認証だけの通信が行われます。これらは全て自動で判断されます。

もう一方のGFEからGCE VM宛の通信では、Google Cloud's virtual network authenticationによるLayer3の認証が行われています。この仕組みの詳細は公開されていませんが、(SDNの?)Control Planeにおいて、送信元がSecurity Tokenを付与し、受信側のホストでそのTokenの検証を行って認証を実現していると記載されています。 f:id:jovi0608:20180116020142p:plain Security Tokenは、Token KeyとHost Secretの2つから生成されています。Token Keyは、senderの物理IP 、VMのネットワークID、仮想VMの送信IPを合わせたもの、Host Secretは受信ホストの物理IPとControl Plain間で共有するPhysical boundary secretを合わせたものから作成します。Physical boundary secretは、2時間毎にControl Plane間で再ネゴシエーションして更新されます。このSecurity Tokenによって送信ホストを認証し、IP Spoofingなどに対する防御を実現しています。

ALTSの特徴

ALTSは、2007年よりGoogle内部で開発が始まりました。当時TLSはそれほどセキュアではなく(TLS1.2は2008年仕様化)、TLSの機能も十分でなかったため、Googleのサービス要件に合わせるためにスクラッチからサービス間通信のプロトコルを開発する道を選んだようです。

TLSで不十分な点は、サーバ名といった名前とその命名スキームに強く機能が結びついてしまうことでした。それに対しALTSでは、複数の名前スキームが使えるようにして、マイクロサービスに適した柔軟性と簡潔性を実現しました。TLSで使うX.509証明書は、ASN.1エンコードでしたが、ALTSではハンドシェイクメッセージや証明書のシリアライズにProtocol Buffer形式を採用しました。Protocol Bufferは、Googleサービス内部で多く使われています。

ALTSの柔軟性は、ホスト名ではなくidentityをベースに認証を行うことにあります。このidentityは、従業員、物理マシン、プロダクションサービス、アプリ実行するWorkload等、ネットワーク上のあらゆるレイヤーのもの全てに割り当てを行い、通信の相互認証を可能としました。しかも、Googleは独自内部PKIシステムも構築しました。内部CAからこれらのidentityにALTS用の証明書をほぼ自動で配布し、初期化時に使えるようにセットアップし、頻繁に証明書の更新や失効操作も自動で行っています。いやはや、これすごいです。

他にもALTSの特徴として、以下の項目が挙げられます。

  • アプリ的には全く透過。開発者はALTSを意識しなくていい。
  • サーバ・クライアント双方でセッション再接続(resumption)が可能で、複数のサーバ・クライアント間でセッション引き継ぎができる。
  • アップデートで最新の暗号方式の導入やプロトコルのバージョンアップなどが容易にできる。

ALTSのトラストモデル

ALTSのすごいことの一つに、物理ホストからアプリ・運用開発者まで含めたトラストモデルを構築していることにあります。ここでは、そのトラストモデルの仕組みについて書きます。

ALTS証明書の種類と役割

ALTSのトラストモデルは、Signing Serviceと Master Certificate、Handshake Certificateの3つのレベルの証明書で構成されています。 Signing Serviceは、root CAを持つ認証局のようなもので、その詳細は不明です。ALTSの証明書は、Singing ServiceからMaster証明書、Handshake証明書へchainがつながり、Handshake証明書が、実際のALTSハンドシェイクで利用されるものです。 f:id:jovi0608:20180116020150p:plain証明書はidentityベースで発行されます。ALTS証明書発行の特徴として、signer(署名者)とissuer(発行者)の役割が別れていることです。

Master証明書が、Handshake証明書を発行する際、まずSigning ServiceにCSRを送ります。Signing Serviceは、CSRにあるissuerとidentityの関係を署名します。Master証明書は、それにALTSハンドシェイクに必要なパラメータ(ECDH公開鍵、暗号方式、失効IDなど)を付与し、自身の証明書も含めてHandshake証明書を署名・発行します。ALTS証明書は、TLSで使われているX.509証明書と全く異なる内容になっています。

さらにALTSの証明書は、発行するidentityの対象によってHuman, Machine, Workloadの3種類に別れています。それぞれGoogle従業員向け、ホスト向け、アプリ向けの証明書を表します。

Human Certificate

Human証明書は、Google従業員がRPCを使う際に利用する証明書です。Googleの内部CAでユーザ名、パスワード、2FAで認証が通ると、申請者のidentityを持つ20時間有効なHuman Handshake証明書が発行されます。接続先のホストには、あらかじめATLS Policyが配布されており、ATLSハンドシェイク中に証明書のissuerやidentityに応じてアクセス許可が判断されます。 f:id:jovi0608:20180116020158p:plainもし、Google従業員の1人が、どこかのMaster証明書からNetwork Adminなど不正な権限を持つHuman Handshake証明書を発行したとしても、このATLS Policyでissuerやidentityをチェックしており、不正な権限によるALTS接続を拒否するようになっています。

Machine Certificate

Googleのデータセンターに設置されている全てのプロダクション機器は、Machine Master証明書を持っています。Machine Master証明書は、マシン管理デーモンなどのコアアプリを使うため、Machine Handshake証明書を生成します。Machine Handshake証明書のidentityは用途によって別けられており、一つのマシンは異なる複数のidentityを持つことができます。 f:id:jovi0608:20180116020212p:plain Machine Master証明書は、検証されたソフトウェアスタック上でのみ利用でき、一部では物理サーバに付随しているTitanと呼ばれるセキュリティチップからMachine Master証明書の署名検証を行う構成も存在しているとのことです。

Workload Certificate

Workload証明書は、Googleで使われているクラスタ管理システムBorgと連携してアプリケーション間のRPC通信で利用します。このWorkload証明書が、アプリケーションによるサービス間のセキュア通信を実現する証明書です。 f:id:jovi0608:20180116020218p:plain Borgの構成では、BorgmasterがBorgletを通じてアプリケーションを実行するWorkloadを作成します。最初にBorgmasterでは、ALTSdというデーモンによってMachine Master証明書からBorgmasterのHandshake証明書を生成します。これによって、BorgmasterはALTS通信が可能となります。

次にBorkmasterは、Sining Serviceから署名されたBase Workload Master証明書を生成します。これがアプ リケーションに必要なWorkload Handshake証明書を作成・管理します。Borglet経由してWorkload Hnadshake証明書と秘密鍵のペアがBorg Workloadマシンに送付されると、Workloadのアプリは実行時にALTS通信が使えるようになります。これら一連の流れが、Borgの仕組みと連動して実現されています。

証明書の失効と更新

ALTSでは、ハンドシェイク時に一時共有鍵を生成するForward Secrecyを利用していません(機能はサポートされていますが無効化されています)。その代わり、証明書に記載された固定の鍵情報を用いた鍵交換を行います。その際、証明書を頻繁に更新し、同一の鍵を長期に使わないようにしてリスク回避をしています。そのため、証明書の更新期間は非常に短く、以下のように種類によって異なっています。全て自動化されているからできる技です。 f:id:jovi0608:20180116020224p:plain ALTSでは、Human証明書だけ明示的な有効期限を持っています(20時間)。それ以外は、時刻同期の問題によって失効機能の障害が発生するのを避けるため有効期限を記載せず、CRL(証明書失効リスト)を使って直接失効管理しています。

失効情報は、Revocation IDによって管理されます。Master証明書は、事前にRevocation IDのレンジを確保し、Handshake証明書発行時にID割り当ててCRL Serviceに登録します。証明書の更新や事故時に明示的にCRLに登録して証明書を失効させます。このCRLのデータは、全てのサーバに配布されています。膨大なものと思われそうですが、数百メガのデータが圧縮によって数メガ程度になっているそうです。

ALTSハンドシェイク

ALTSのハンドシェイクは、双方向認証のセキュア通信に特化するためTLSのハンドシェイクを効率化し、非常に簡略化したものです。しかも、再接続にはクライアント、サーバそれぞれでチケットを用いたセッションの引き継ぎができる拡張機能も付加されています。

新規接続

ALTSハンドシェイクは、ClientInit/ServerInitとClientFinished/ServerFinishedの4種類だけです。ハンドシェイクの詳細な仕様やフォーマットは公開されていません。 f:id:jovi0608:20180116020230p:plain ClientInit/ServerInitには、各種ハンドシェイクパラメータと証明書の情報が含まれます。Forward Secrecyが使われていないので、鍵交換はClient/Server双方のHandshake証明書に記載されている公開鍵(ECDH:curve25519)を使って行います。

ALTSは双方向認証を実現するべく、サーバ・クライアントは、それぞれの証明書を受信すると、失効情報やポリシーのチェックを行います。

鍵交換で導出された共通鍵は、TLS1.3と同様にHKDF-Expand/Extract(RFC5869)を使って鍵スケジュールを行います。KDF(Key Derive Function)によって、ペイロードメッセージの暗号化するレコードプロトコルの暗号シークレット、完全性をチェックする認証シークレット、次回再接続の際に利用するResumptionシークレットの3種類を導出します。

最後のServerFinished/ClientFinishedは、ハンドシェイクが改ざんされてないことを確認するためのものです。これは認証シークレットとHMACを使って実現します。再接続用のチケットも送付します(後述)。クライアントはServerFinishedを受信したら直ちに暗号化通信を開始できるので、ALTSは1-RTTでアプリケーションデータを送付できることになります。

ALTSのフレームフォーマットは、4バイトの長さフィールド、4バイトのデータタイプのフィールドに続いてペイロードが続きます。ペイロードの最大長は現在1Mバイトで、将来もっと小さくする予定だそうです。TLSと同様にペイロードのreply攻撃に備えるため、サーバ・クライアント双方でシーケンス番号の管理も行われています。

ペイロードの暗号化の場合はAES-GCMとAES-VCM、完全性確保だけの通信ではAES-GMACとAES-VMACのいずれかが利用されます。AES-VCMはあまりなじみがありませんが、2007年頃に提案された暗号方式で、VHASHというユニバーサルハッシュを利用したAEADです。AES-VMACは、VHASHをメッセージ認証に使ったものです。

クライアントResumption

ALTSには、クラスタリング利用を前提とした再接続(Resumption)の仕組みが備わっています。TLSと同様のClient Resumptionです。 f:id:jovi0608:20180116020236p:plain再接続用にサーバ#1からチケットをクライアントに送付します。チケットは、クライアントのidentityとResumption Secretを暗号化したものです。チケットの暗号化は、Resumption Keyを使って行われます。サーバはクラスタリングされており、同一Resumption IDを持つサーバ間で同一のResumption Keyを共有しています。

クライアントは、同一のResumption IDを持つ別のサーバ#2に再接続すると、あらかじめサーバからもらったチケットを付与してハンドシェイクを行います。サーバ#2はResumption Keyを共有しているので、チケットからResumptionシークレットを復号することが可能です。これを使ってフルハンドシェイクをせずにALTS通信を続けることができます。

サーバResumption

ALTSでは、クライアントResumptionの逆、サーバResumptionの機能も用意されています。 f:id:jovi0608:20180116020242p:plainクライアントもResumption IDでクラスタリングされており、複数クライアント間で同じResumption Keyを共有しています。今度は、最初のハンドシェイクでクライアント#1からチケットをサーバに送っておきます。同一Resumption IDのクライアント#2からサーバに新規接続があった場合、サーバはチケットをクライアント#2に送ります。クライアント#2は、Resumption Keyを共有しているのでチケットからResumption Secretを複合することができます。クライアント#2とは、新規接続だけどフルハンドシェイクなしにALTS通信を継続できることになりました。

サーバResumptionは、複数の負荷分散装置で切り替えやルーティングの変更があった場合でも、配下のサーバへの再接続が新規接続にならないといったメリットを持つことができます。。

ALTSの制限事項

ALTSには、その仕組み上いくつか制限事項があります。

KCI攻撃

ALTSは、KCI(Key Compromised Impersonation: 鍵の危殆化による成りすまし)攻撃を受ける可能性があります。これは前節で説明した通り、Resumption IDが同一の複数のホスト間でResumption Keyを共有しているため、もしどこか一つのホストの秘密鍵やResumption Keyが漏洩して危殆化すると、他のホストに成りすましが可能になってしまうということです。Resumptionの利点を得るためであり、リスクを受容するしかないです。

ハンドシェイクのプライバシー

TLSと同様にALTSのハンドシェイクは平文でやり取りされるため、どのidentityがどこに接続しにいっているのかネットワーク中間者は見ることができます。

Forward Secrecy

先述の通りALTSは、Forward Secrecyを無効にしています。証明書を頻繁に更新することでそのリスクを抑えていますが、更新期間の間はForward Secrecyを維持できません。

0-RTT

ALTSでもTLS1.3と同様に、0-RTTでアプリケーションデータの送付を実現することは可能です。しかし0-RTT で送られるデータはForward Secrecyではなく、reply攻撃に対する脆弱性も持っています。ALTSはRTTが小さい環境で使われるので、あえて0-RTTを使う必要はないと判断し、0-RTTの機能を除いています。

最後に

このようにALTSの設計や機能は、TLSに慣れていた目から見ると非常に気づきが多いものでした。

今後、ALTSの詳細な仕様やオープンソース実装が公開され、標準化の動きが出てくることを期待したいです。もっともその時にはGoogleは既に次の新しいものに移行しているでしょう。

「SSL/TLS暗号設定ガイドライン 第2.0版」を読んで

$
0
0

1. はじめに

昨日「SSL/TLS暗号設定ガイドライン 第2.0版」が公開されました。 前回から約3年経って今回はCRYPTREC暗号技術活用委員会で検討作業が行われたようです。

普段、TLS/HTTPSの記事を書いたり発表したりしている立場上、これを見逃すわけにはいけません。

本文冒頭では、

「本ガイドラインは、2018 年 3 月時点における、SSL/TLS通信での安全性と可用性(相互接続性)のバランスを踏まえた SSL/TLSサーバの設定方法を示すものである。」

ということなので、できたてほっかほっかの最新ガイドラインを読ませていただきました。

読み進めてみるとChangelogが細かく書いてなく、以前のバージョンとどこがどう変わったのかよくわかりません。TLS1.3とかは絶対に新しく入った内容なんですが、細かいところはどうだろう… それでも全部(SSL-VPNを除く)をざっと読み通したので、いくつか気になった部分があったのでコメントしてみたいと思います。

このガイドラインの大きな特徴は、「高セキュリティ型」、「推奨セキュリティ型」、「セキュリティ例外型」の3つの基準に別れていることにあります。ですがこの分類方法や要求設定の違いに関しては、コメントしないことにします。個人的にはいろいろ思うところはありますが、結局はサービス提供範囲とリスク見合いになり、あまり技術的にはっきりした主張や議論になりにくいなと思うからです。

2. TLS1.3の説明について

SSL/TLSの概要説明のところでTLS1.3の説明が書いてありました。記述内容(図)がおかしそうなところが2点ほどありましたので書きます。

2.1 鍵スケジュール (TLS1.3の概要 (7) 鍵スケジュールの図)

TLS1.2では、暗号やMAC鍵の元となる MasterSecret は、鍵交換で生成したPreMasterSecretとサーバ・クライアントの乱数をPRF(擬似乱数関数)にかけて導出していました。

ただこのような生成方法だと Triple Handshake攻撃を受ける恐れがあり、セッションハッシュを使う 「RFC7627-Extended Master Secret」が、対策として出されています。

TLS1.3では、さらにHMAC方式など暗号技術で超有名な Hugo Krawczyk 氏が考案した OPTLSをベースとした鍵スケジュール方式が採用 されています。 これは、「RFC5869-HKDF」というKDF(鍵導出関数)を使い、用途別(0-RTT用、ハンドシェイク用、アプリデータ用等)に鍵を生成していく手法です。

ガイドラインでは、

f:id:jovi0608:20180509135609p:plain
SSL/TLS暗号設定ガイドライン p14より引用
と書かれており。上図の通りHKDFを使って、3種類に色分けされた計9個の鍵が導出されているのがわかります。

で、

EarlySecret(ES) = HKDF-Extract(PSK, 0)
HandshakeSecret(HS) = HKDF-Extract((EC)DHE, x)
MasterSecret(MS) = HKDF-Extract(0, x)

の部分ですが、RFC5869では、

HKDF-Extract(salt, IKM) -> PRK

と定義されています。HKDF-Expand関数にsalt, IKM(入力鍵) を引数に入れると、PRK(疑似乱数鍵)が出力されるということです。

一方、TLS1.3仕様の該当箇所では、

HKDF-Extract is drawn as taking the Salt argument from the top and the IKM argument from the left

HKDF-Extractは、Salt引数は上から、IKM引数は左から取るように書かれている。

と記載されています。そうなると上から来てる0とかxとかの方がsalt になります。なのでガイドライン記載の引数が逆で、

EarlySecret(ES) = HKDF-Extract(0, PSK)
HandshakeSecret(HS) = HKDF-Extract(x, (EC)DHE)
MasterSecret(MS) = HKDF-Extract(x, 0)

が正解じゃないかと思います。これ間違うと鍵交換後にエラーって、めちゃハマります(体験談)。

2.2 ハンドシェイクの暗号化開始個所 (TLS1.3の概要 (8) TLS1.3の暗号化開始個所)

次に、下図の「TLS1.3でここから暗号化する」の部分ですが、一番初めに入るEncryptedExtensinsが抜けています。

f:id:jovi0608:20180509135615p:plain
SSL/TLS暗号設定ガイドライン p14より引用
TLS1.3仕様の該当箇所では、

In all handshakes, the server MUST send the EncryptedExtensions message immediately after the ServerHello message. This is the first message that is encrypted under keys derived from the server_handshake_traffic_secret.

全てのハンドシェイクでは、サーバはSeverHelloメッセージの直後にEncryptedExtensionsを送らなければならない(MUST)。これは、 server_handshake-traffic_secretから生成した鍵で暗号化される最初のメッセージである。

なのでMUSTです。TLS1.3仕様の図でEncryptedExtensionsに (*) Optionalが付いてなかったのを見落としちゃったのかもしれません。

2018年5月13日追記: よく見たら左側TLS1.2の図もおかしいです。TLS1.2ではChangeCipherSpecが暗号化開始の合図なので Finished も暗号化されています。Finishedも赤字にするのが正確でしょう。

3. ECDHEの要求仕様について(X25519 253bitが適応外になる!)

今回一番声を大にして言いたいのはここです。

高セキュリティ型、推奨セキュリティ型、セキュリティ例外型の全て要求仕様において、以下の通り「鍵長256ビット以上のECDHE」が求められています。

f:id:jovi0608:20180509135624p:plain
SSL/TLS暗号設定ガイドライン p24より引用
これは、本文中で例示してあるようにNIST P-256(secp256r1)の導入を前提としているかと思われます。

ここで昨年秋 Internet Week 2017で私がプレゼンした「運用の観点から見たTLSプロトコルの動き」の資料とくらべてみましょう。 f:id:jovi0608:20180509155408p:plainガイドラインで要求仕様に入っているDHEは、私の資料では黄色(注意)にしています(理由は後述)。また青色の部分はガイドラインに入っていません。 CRYPTRECはNISTと異なり推奨楕円曲線を規定していません。ガイドライン中でもNIST-P256は一例として書いてあり、鍵長条件を満たすECDH方式なら楕円曲線の種類は問わないように読めます(少なくともこのガイドラインでは、NIST curveに限ると明確に書いていません)。256bit以上という条件では、253bitのX25519が適応外になってしまいます。

思わず、

とつぶやいちゃいました。換算が曖昧なセキュリティレベルでの規定(128bit相当)ならいざしらず、ちゃんと計算できる鍵長で、たかが3bitだからといい加減にできないのではないかと思います。

RFC7540-HTTP/2仕様では、「利用するEC鍵長は224bits以上でなければならない」と規定しました。これは当時仕様策定中のX25519が使えることを考慮して決めた値です。 (Re: ECDHE security level)

また、RFC7525-Recommendations for Secure Use of TLS and DTLSでも192bits以下は使うべきではないとの規定です。ガイドラインが求める鍵長256bit以上ではX25519を使えず、同程度のセキュリティレベルのRSA2048やDHE2048が使えるのに比べて、少し厳しいのではないかというのが自分の意見です。

これからの事を考えるとやっぱりアカンと思い、X25519がどういう経緯で作られ、現在どうなっているのか、少し解説したいと思います。 (書いてみたら膨大になってしまったので最後の節に回します。)

4.「サーバ証明書で考慮すべきこと」について

Sigh.. 思いっきり footgun になってます。

ちなみに文中の www.cryptrec.go.jp へのリンク先は全て http:// で記載されています。

5. DHEについて

DHEの取り扱いについては、先に書いた通りガイドラインと私の評価が少しずれています。よくよく読んでみると少し記述がおかしい部分も見られますので、そこをコメントさせていただきます。

5.1 明示的に鍵長を指定できない代表例のアップデート

以下に2例が示されていますが、最新の状況では条件によりますが、DHE鍵長の指定ができるようです。実際に試して検証をしていないのでポインターだけになります。

f:id:jovi0608:20180509135644p:plain
SSL/TLS暗号設定ガイドライン p46より引用

http://tomcat.apache.org/tomcat-8.0-doc/ssl-howto.html#Troubleshooting

If you are using the APR/native connector, starting with version 1.1.34 it will determine the strength of ephemeral DH keys from the key size of your RSA certificate. For example a 2048 bit RSA key will result in using a 2048 bit prime for the DH keys.

APR/native connector を使えばRSAの鍵長に合わせてDH鍵長も変えられる。

https://support.microsoft.com/en-us/help/3174644/microsoft-security-advisory-updated-support-for-diffie-hellman-key-exc

(訂正: 2018/5/10:18:30) リンクが間違っていました。正しくはこちらです。ご指摘いただいた @さんありがとうございました。

https://technet.microsoft.com/ja-jp/library/security/3174644.aspx

https://docs.microsoft.com/ja-jp/windows-server/security/tls/tls-registry-settings#keyexchangealgorithm---diffie-hellman-key-sizes

レジストリを変更すればDH鍵長も変えられる。

5.2 DHEの鍵長の決まり方

DHEで利用する鍵長の決定方法についての記載が、非常におかしく思います。

f:id:jovi0608:20180509135650p:plain
SSL/TLS暗号設定ガイドライン p46より引用
の部分ですが、TLS1.2(RFC5246)の範囲では、DHEでは鍵長を交換する仕組み自体がありません。 f:id:jovi0608:20180509141107p:plain上図の通り、サーバ側が勝手にDHのパラメータをクライアントに投げるだけです。クライアントがサポートされていない鍵長だとハンドシェイクエラーになります。

プロフェッショナルSSL/TLSから該当部分を一部引用してみましょう。

f:id:jovi0608:20180509204129p:plain
プロフェッショナルSSL/TLS p38より引用

この問題を解決するために、FFDHEと呼ばれる新しい仕様 RFC7919-Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for Transport Layer Security (TLS)が策定され、TLS1.3にも取り込まれています。

それは、ECDHEと同様にDHEのパラメータを名前付けし、ClientHelloのExtensionでECDHE/DHEともにサポートするDHEグループリストをサーバに伝える方法です。 f:id:jovi0608:20180509141121p:plainこれですと、サーバはクライアントがサポートされているDHグループを判断し、鍵交換を行うことができます。 しかしRFC7919をサポートしているブラウザは私の知る限りまだ見ていません(誰が知っていたら教えてください)。

5.3 結局DHEを推奨すべきかどうか

このように現状のDHEは、鍵長交換ができないと言った大きな欠点があります。またDHEの演算性能や必要となるデータ量などECDHEに比べて全くメリットがない状況です。以前はECDHEのパテントリスクを避けるため、Foward Secrecyを実現するためにDHEの需要がありました。既に幾つかのパテントがexpireし、X25519の利用も見えてきました。現在ChromeFirefoxでは DHEのサポートを取りやめています。

かと言って全くDHEを捨て去っていいかというわけではなく、ECDHEのバックアップとして必要です。TLS1.3ではFFDHEが取り込まれているので、ECDHEに何かあった時用に緊急避難用のアルゴリズムとして残しておく必要性があると思います。

従ってFFDHEが使えない現状で、TLS1.2でのDHE利用には、私の評価は黄色(注意)を付けています。

6. X25519はどうなのか

X25519ができるまでの経緯を書いてみます。

6.1 Dual_EC_DRGBのバックドアとNIST P-256の闇

NIST-P曲線は1999年にNISTによって規定されました。規定にはNSAが関わったという話です。

少し後(2000年)に楕円曲線を利用した疑似乱数生成仕様 Dual_EC_DRBGNSAの協力の元でNISTを策定を進め、2005年に規定されました。しかし2006,7年頃にこの乱数生成仕様にはバックドアがあるのではないという研究発表が出てきました。

Dual_EC_DRBGは、ある特定の2つの楕円曲線上の点を元に疑似乱数を生成していく仕組みです。 バックドアとみなされていたのは、この2つの楕円曲線上の点の関係が計算できていれば、表に出ている乱数から生成器の内部状態を再現でき、次の乱数が予測できるというものでした。

TLSでは内部の秘密鍵の生成にも疑似乱数を使用します。これが外部から予測できればアウトです。実際にNSAが本当にバックドアを狙って仕込んだのかは、わかりません。でもこの2つの楕円曲線の点はNSAの技術者からNISTへ提案を受けたものだという証言が残っています。

また、2004年にNSAから1000万ドルかけてRSA社のライブラリにこの擬似乱数生成を入れ込み、実際に販売してたことも判明しました。2013年のスノーデン事件で明るみになった情報の中にも、NSAが標準化作業に入り込み、バックドアの仕込みをやっていたことを匂わすような記述が見受けられたそうです。まぁ、状況証拠的には真っ黒です。ほどなくDual_EC_DRBGは廃止され、使われることはなくなりました。

話は変わって NIST-P256。これも楕円曲線のある一つの変数が、出どころのわからない数値にSHA-1ハッシュをかけて生成したものでした。果たしてこれがバックドアにつながるのか? 現在これ以上のことはまだわかっていません。でも、Dual_EC_DRBGの例を見れば、非常に疑わしいのは明らかです。

6.2 IETF curve(curve25519/curve448)の策定

このような状況から、2014年7月にIETFではTLS WGからCFRGにNIST標準によらない鍵交換とデジタル署名用の楕円曲線暗号を選定するよう依頼が行われました。[Cfrg] Formal request from TLS WG to CFRG for new elliptic curves

当初2ヶ月程度で選定を終わらせる予定が、様々な要望や提案が入り混じり、案の定大議論が沸き起こりました。すったもんだの末に半年かかってdjb氏が考案した curve25519 が最初の候補として採用されることになりました。 (Adoption of draft-agl-cfrgcurve-00 as a RG document)これが今のX25519につながります。

djb氏が考案したためパテントに対するリスクも小さく、係数も数学的判断を元に決定されています。ソフトウェア処理でもそこそこ高速できるように工夫され、できるだけ簡潔な演算ができるようになっています。NIST-P256は複雑で、サイドチャネル攻撃を回避して高速化をするためには、非常に苦労します。それとは、大きく性質が異なります。

名前は、

と区別する関係になっています。

最終的により大きな鍵長をもつ curve448(Goldilocks)を加え、2016年1月にRFC7748-Elliptic Curves for Securityとして無事 curve25519/curve448と鍵交換のX25519/X448が仕様化されました。デジタル署名の仕様も Edwards-Curve Digital Signature Algorithm (EdDSA)として仕様化が完了しました。これでTLS1.3に向けてIETFが選定した楕円曲線が使える環境が整いました。

ざっと比べてみるとこんな感じです。 f:id:jovi0608:20180509155535p:plain

6.3 X25519の普及度

X25519は、Chrome, Firefox, Opera, Edgeで既に使えるようになっています。ブラウザベンダーの危機感は大きく、クライアント側の普及は早いです。

サーバは、OpenSSL-1.1.0系から使えるようになっています。X448はOpenSSL-1.1.1が必要です。

現在、X25519がどの程度使われているのか、最近の計測結果を見つけましたので紹介します。 Chasing X25519 Usage of insecure curves still commonでは Alaxa Top 100 でなんと38%対応済。Alaxa Top 1万で8.73%程度です。Top 100 の方はGoogle系のサイトが多いからだと思われます。

In search of CurveSwap: Measuring elliptic curve implementations in the wildの統計だと2017/08の時点でX25519が2.6%, NIST P-256が86.9%の割合でした。来年末OpenSSL-1.0.2のEoLなので、OpenSSL-1.1.x系に入れ替えが進むと一気にサーバ側の普及が進むものと思われます。

現在、Google系以外の比較的規模が大きなサイトでは、wikpedia やMS系のサービスがX25519が優先されるようにサービスを提供しています。 f:id:jovi0608:20180509195629p:plain

6.4 X25519の性能

気になるX25519の性能ですが、他の楕円曲線暗号の鍵交換とくらべてどうでしょうか?

今月リリース予定のOpenSSL-1.1.1のpre6版で比較してみます(AVX/AVX2入りCPUです)。 f:id:jovi0608:20180509135656p:plainおぉ! X25519の方がNIST P-256より約1.5倍近く速いです。X25519は、OpenSSL-1.1.1でかなり高速化されているので、適切なセキュリティ強度で申し分ない性能が得られると思います。

6.5 NISTの推奨楕円曲線

NISTじゃない楕円曲線暗号を策定したのですが、なんとこの成功を受けNISTがcurve25519/curve448を推奨楕円曲線として採用する予定であることを明らかにしました。 Transition Plans for Key Establishment Schemes using Public Key Cryptography近いうちにNIST SP 800-186が発行されるでしょう。

今後も NIST-P256 を信じるか、信じないか、あなた次第です。

TLS1.3ではNIST P-256がMUST、X25519がSHOULDの実装になっています。高性能で程よい安全と、そして大きな安心を得られ、今後普及が見込まれるX25519を入れられないガイドラインは非常にもったいないなと個人的に思うのです。

Viewing all 49 articles
Browse latest View live