自堕落な技術者の日記

基本は喰ってるか飲んでるかですが、よく趣味でカラオケ・PKI・署名・認証・プログラミング・情報セキュリティをやっています。旅好き。テレビ好きで芸能通

暗号プログラミング

Google Open Source Peer Bonus Award受賞しちゃいました

夏休みの宿題みたいな感じで、この2ヶ月くらい、jsrsasignの大改造をし、証明書、CRL、OCSP、CMS SignedData、タイムスタンプの読み取りと生成のコードを大幅に書き直し、後方互換性をバッサリ切ったので、なんだかんだでバージョン10.0.0となりました。これで読み取りも、全部一貫して、生成もJSONでちゃちゃっと簡単にできるようになったかなと思います。

jsrsasignの保守はこれくらいでやめにして、最近は既存の証明書チェーンや、CRL、OCSPレスポンス、タイムスタンプトークンから、検証環境を自動で作るようなツールを作っています。普通だとCAごとに環境作ったり、OCSPレスポンダつくったり、TSA作ったり手間もリソースもかかり面倒くさいですが、一つのVM、一つのIPで、楽ちんポンで、これができちゃうようになるというもので、概ねベータバージョン的なものができ、QCだの、eSeal証明書だの、TSAだのいろんなテスト環境作って遊んでいます。

syoukin_dollar_man さて、そんな中、自分のオープンソース活動について、Googleの中の方に推薦頂き、2020年Q3の、Google Open Source Peer Bonus Awardという賞をもらい、賞金ももらってしまいました。(社内表彰みたいなのを除いて)このところ賞をもらうことなんて殆どないのでとても嬉しいです。ありがとうございます。頂いた賞金で、Mac Book Airのバッテリがヘタってきたので交換したり、家族で小さいお祝い会をしたいと思います。

GoogleのOpen Source Peer Bonusは、4半期に一度、Googleの社員の方の推薦でオープンソース活動について表彰いただけるというプログラムなのだそうです。元気のある会社はすごいですねぇ。過去には、2020年1Qの受賞者のアナウンスがこのブログエントリでされていました。今回の表彰もまとめてアナウンスしてもらえるのではないかと思います。 ちなみに、頂いた賞状はこんな感じです。↓↓↓


award

また、前回あんなエントリを書いたあと、私のオープンソース活動に、いろんな方が気にかけてくれ、お声掛けしてくれたり、寄付してくださったりしました。本当にありがとうございます。これを励みに、のんびり自分のペースで活動を続けていこうと思います。

追記 (2020.10.06)

公式ブログに「Announcing the latest Google Open Source Peer Bonus winners! (Monday, October 5, 2020)」が掲載されました。あざます。あざます。

jsrsasignの寄付金を募ることにしてみました(やりがいって何だっけ?)

私はjsrsasignというJavaScriptのオープンソース暗号、PKIライブラリを個人的な趣味で開発し公開しています。ところが最近、npmパッケージのダウンロードが月間60〜70万件と、異常にユーザーも増え、製品でも使われ始め、ちょっと厄介なことになっており、いろいろ悩んだ挙げ句、これが正解なのかもわかりませんが、ライブラリの維持のために寄付金を募ることにした次第です。今日は、心の吐露をつらつら書いていくことにします。

jsrsasignとは

2010年ごろ、スタンフォードの学生さんであるTom Wooさんという人のJavaScriptでRSA暗号化できるコードを見つけ、自分はPKIや電子署名を専門にしていたので「JavaScriptでRSA署名できたら面白いな」と思い、2010年6月に、ほんのRSA署名単機能のライブラリとして公開したのが jsrsasign です。当時のはしゃぎっぷりはブログでこんな感じ。 小躍りしてツイートしてたのはこんな感じ。




その後、ASN.1ライブラリ、X.509証明書、CRL、CMS SignedData、タイムスタンプ、CAdES-BES/EPES/T、OCSP、CSR、共通鍵暗号、楕円曲線暗号、RSA-PSS署名、DSA署名、JSONのJWS、JWT、JWKの対応など、自分が欲しいと思う機能を少しずつ建て増しをして10年になります。多くの個人のオープンソースプロジェクトは1年くらいで終わってしまうそうですが、まぁ、なんとか自分のために追加開発やメンテナンスを続けています。

このライブラリが特徴的なのは、

なんでも入っている
一つライブラリに多くのPKI、暗号の機能がつめこんであります。 Swiss Army Knife(スイスの十徳ナイフ)スタイルというそうです。 自分がものぐさなので、これをロードしさえすれば何でも試せるように作りました。
とにかく使い方が簡単
どんな秘密鍵でも公開鍵でも自動判定してロードできるようになっていたり、ASN.1 DER構造の中身に簡単にアクセスできたり、面倒くさいことはなるべくライブラリに任せてできるようになっています。証明書やタイムスタンプなどはJSONのプロパティから簡単につくることもできます。共通鍵暗号も簡単です。APIの構成はJavaのBouncyCastleライブラリIAIKライブラリなどのJCEアーキテクチャを参考にしているので、それを知っていればさらに使いやすいでしょう。自分がものぐさだから(二回目)、極力短いコードでいろんなことができるようになっています。
ドキュメント、サンプルが非常に豊富
ライブラリはあってもAPIドキュメントがなくてどんなAPIがあるのわからなかったり、BoucyCastleみたいにメソッドはわかるけど呼び出し方がわからないなどのことが無いようにAPIドキュメントの記述が充実しており、APIドキュメント中に例も入れています。また、Wikiなどの入門解説ページや、多数のオンラインでも試せるサンプルコード、テストコードがあり、自学習でもかなり何とかなると思います。APIが前提知識最小でも行けるように工夫してますので。
環境依存がほぼ無い、他のパッケージの依存がない
JavaScriptが動く環境であればどこでも動作します。古いブラウザでもほとんどの機能は動作しますし、Node.jsでも動きます。npmパッケージでも公開されていますし、CloudFlareなどのCDNからも利用できます。必要なサードパーティの関数は含まれており、他のライブラリ、パッケージに全く依存しておらず単独で使えます。Nodeの中でOpenSSLに依存していることもありませんし、(ブラウザ互換性でいつも悩まされる、この先どうなるかもわからない)W3C Web Cryptography APIを使っているわけでもありません。
いろんなツールがすぐ使える
自分でプログラミングしなくても、オンラインで公開しているツールで証明書を発行したり、鍵ペアを生成したり、デジタル署名の生成や検証したり、JWTを生成したり、いろんなことができます。Nodeで実装されたいろんな便利なPKI関連ツールもついています。
速いとは言えない
自分がPKI関連のいろんなことを少ないコードで簡単にテストするために作っていますので、高速に動作することを目的にしていません。数百万のトランザクションを処理したいといった目的なら他のライブラリを使う方がいいでしょう。
一人でここまでよくやったなぁ、、、と。お節介か、、、www

jsrsasignの歴史を振り返る

10年だもの、まぁ、いろいろありますよ。自分のためにちょっと歴史を振り返ってみます。

  • 2010年6月:v1.0:jsrsasign初版公開。RSA署名だけ。
  • 2012年4月:v1.2:公開リポジトリをGitHubに移行。
  • 2013年4月:v2.0:PKCS#1 PEMなどの鍵のロード機能がつき始める。 JavaライクなSignature、MessageDigestクラス、ASN.1エンコーダー、X.509証明書エンコーダー、RSA-PSSサポートなど
  • 2013年5月:v3.1:暗号化されたPKCS#5鍵のロードのサポート
  • 2013年6月:v4.0:ECDSA署名サポート
  • 2013年9月:v4.1:PKCS8など柔軟な鍵ロード用クラス KEYUTIL を追加
  • 2013年10月:v4.2:DSA鍵、署名のサポート
  • 2014年4月:v4.5:CMS SignedDataサポート
  • 2014年5月:v4.6:RFC 3161 Timestampサポート
  • 2014年7月:v4.7:RFC 5126 CAdES-BES/EPES/Tサポート
  • 2015年6月:v4.8:NodeJS npm、JSON JWS、JWK、JWTサポート
  • 2015年10月:v5.0:CSRサポート、便利なNode.JSスクリプトの追加
  • 2016年9月:v6.0:OCSPサポート
  • 2016年11月:v6.2:識別名のmulti valued RDN、RFC 2253 LDAP識別名文字列表現のサポート
  • 2017年6月:v8.0:コードのスリム化、長期間非推奨(Deprecated)だった関数の削除
  • その後、細かい機能追加や脆弱性指摘対応などが続き現在に至る

jsrsasignはどれだけ使われているか

自分の趣味でやってる調査のために開発したライブラリですが、Node.JSのパッケージ npm で公開した2015年あたりから利用者ダウンロードが増えています。github.comからのダウンロードや、勝手に行われている公開CDNからの利用もあると思いますが、npmパッケージのダウンロード数だけでいうとnpm-stat.comさんのダウンロード数グラフを見てみるに、2018年あたりからブリブリ増えてしまっており、2019年あたりからサチりはじめ、それでも最近の月間ダウンロードは60万件超、先月は70万を超えてしまいました。npmでは他のパッケージの依存関係を書けるのですが、2020年7月現在で379ものnpmパッケージのプロジェクトがjsrsasignに依存していることがわかります。とほほ。
jsrsasign-monthly-dl-202006
jsrsasignは自由に使ってもらっていいですが、ライセンスは放棄はしていないので、ライセンス掲載の義務はあり、たまにエゴサーチでPDFで検索してみると、いろんな製品の中でも使われちゃってることがわかります。

あとは、以前シャニマスのライセンス表示にjsrsasignが載っていたり、某社は使っているのにオープンにしていただいてなかったり、、、、(^^; こんな、個人が趣味で開発しているライブラリに、みなさん乗っかっちゃって大丈夫なんですかね。逆に心配になっちゃいますね。

ユーザが増えた悩みの始まり

最初は、「自分の調査のために趣味で維持しているライブラリがみなさんの役にたって、使ってもらえてるなら良いことだなぁ。これからも趣味で自分の必要そうな機能は追加していこうかなぁ、、、」で済んでたんですが、最近ユーザーも増えてそうも言ってられなくなってきたんです。

そもそも、jsrsasignは MITライセンスの下で無償、無保証で配布されています。もし、セキュリティ脆弱性やバグがあっても、私には修正する義務はないし(とはいえ、指摘されたら直すわけですが)、オープンソースなので問題があれば好きに修正して使っていただいていいわけです。もちろん修正コードをもらえれば、それは反映してすぐに公開します。

そんな中おきたThe RegisterやUsenixの指摘

2020年5月にITセキュリティのニュースサイトであるThe Registerで 「What happens when the maintainer of a JS library downloaded 26m times a week goes to prison for killing someone with a motorbike? Core-js just found out」という記事が掲載されました。JavaScriptのバージョンの違いを吸収するためのCore-jsという有名なライブラリがあって、その開発者がバイクで交通事故を起こして被害者の方が亡くなり収監されて、ソフトウェアのアップデートが滞っており問題だというものでした。

この記事の中で、私のjsrsasignも、2018年4月から2020年まで更新されてないと指摘をされてしまいました。

(記事引用)
Another JavaScript cryptographic library known as jsrsasign faces a similar challenge: its maintainer, Kenji Urushima, hasn't been active since April 2018. Programmers who use the software have expressed concern about the lack of communication and an unaddressed vulnerability, noting that 350 npm projects depend on the library, including some by Microsoft and Mozilla,
(抄訳)
jsrsasignとして知られている別のJavaScript暗号ライブラリも同様の課題に直面している。その管理者である Kenji Urushima は、2018年4月から活動していない。このソフトウェアを使用しているプログラマは、対話の欠如と対応されていないある脆弱性について関心を寄せている。注目すべきは、MicrosoftやMozillaを含む350のnpmプロジェクトがこのライブラリに依存しているという事である。
指摘された問題は、Minervaと呼ばれるECDSA署名のタイミング攻撃により処理時間を大量監視していれば秘密鍵が復元できる可能性があるというもので、元々、楕円曲線暗号の部分はBitcoin-JSを使っており、自分のコードではないので、調査するにしてもかなり時間がかかる根の深い問題でした。また、自分は本業の方も忙しい時期だったのでなかなか調査もできず、誰からも修正コードの支援をしてもらえないままでいました。jsrsasignは大量のトランザクションで使われることもあまりないし、攻撃の実現はかなり低いと考えていました。他の簡単に回答できるものには回答していましたが、根が深いのでこの問題は手付かずにしていたのです。

おそらくこの記事をうけて、USENIXという団体の機関紙のコラム「Who Will Pay the Piper for Open Source Software Maintenance? Can We Increase Reliability as We Increase Reliance?(誰がオープンソースソフトウェアの保守の費用を負担するのか?(オープンソースの)依存が増える中、信頼性を上げることできるのか?」の結論でも、jsrsasignを「(開発を)撤退したソフトウェア」として取り上げられてしまいました。

やっとMinerva脆弱性の修正

jsrsasignの根深い問題の調査まで手がまわらない状態が続いていたのですが、プライベートで慌ただしい時期がようやく終わりかかり落ち着きだした2020年4月、Node.JSのパッケージマネージャーを管理するnpmのセキュリティチームからもMinervaの脆弱性指摘が来てしまい、いよいよ直さざるをえない状況になりました。他の人が作ったコードを解析し、修正し、テストケースを作成して確認し、修正リリースを出しました。[勧告]

そしてまた別のMalleabilityに関する脆弱性指摘が3つも

2020年6月に Antonio de la Piedra さんから、3つのmalleability(展性)に関する脆弱性の指摘を受けてしまい、初めてUS-CERT、MITREの脆弱性データベースにCVE登録されてしまいました。3つのうちの1つは、npm のセキュリティチームからも対応依頼が来ました。「malleability(展性)」とは、金属を叩いて延ばしても破壊されずに広げることができる性質のことを言うのですが、ソフトウェアの世界では、同じ意味のデータを別の表現ができるという事をmalleabilityと呼んでます。例えば、10進数で数値の12345という値があったとして、先頭にゼロを幾つかつけて00012345としても値は同じであるといった事です。

暗号では、大きな数値を使って暗号文、署名値など表現することが多いですが、 指摘された3つの脆弱性は簡単には以下のようなものでした。

  • CVE-2020-14966 ECDSA署名の署名値が、前述のようなゼロを先頭に足した値を使ったものでも正しい署名として受け入れてしまう等。(CVSS3.X 7.5, CVSS2.0 5.0)
  • CVE-2020-14967 RSA暗号の暗号文が、前述のようなゼロを先頭に足した値を使ったものでも復号ができてしまう。(CVSS3.X 9.8, CVSS2.0 7.5)
  • CVE-2020-14968 RSA-PSS署名の署名値が、前述のようなゼロを先頭に足した値を使ったものでも正しい署名として受け入れてしまう。(CVSS3.X 9.8, CVSS2.0 7.5)
これが深刻な脆弱性にあたるかに関しては疑問があり、前述のようにゼロを足したとしても、別の署名対象文書を正しい署名として受け入れたり、暗号文の内容を別の内容に書き換えることができたりといった攻撃とは無関係です。また、大量にゼロを足した場合にメモリ破壊が起きると指摘されましたが、JavaScriptのBigIntegerでは、C言語のような桁あふれも発生しないので指摘にはあたらず、脆弱性を利用した攻撃は実現できないと考えています。vulndbのCVSSスコアはそれほどでもなかったですが、US-CERTのスコアはやたら高いです。

6月頃は仕事もプライベートも落ち着いていたので、週末や夜に対応の時間を取ることができ、問題の調査をし、コードを修正し、Antonioさんにもらったテストコードで問題なくなった確認し、2週間くらいで修正リリースし、セキュリティアドバイザリを公開しました。 [勧告1] [勧告2] [勧告3] かなり短期に対応できたかと思います。ちなみに、RSA-PSSはDaveさんが提供してくれたコードで、自分で解析して修正しなければならないので厄介でした。ECDSAについては、署名値が厳密なASN.1 DER構造であることをチェックしていなかったために起きた問題で、その厳密なチェックをする機能を追加するのにテストケースが多すぎて骨が折れました。

job_yarigai_sausyu_suit というわけで、オープンソースのライセンスで、現状有姿、無保証で提供するという条件で利用してもらっているにもかかわらず、結局、義務的に直さざるを得ず、問合せ対応や、報告者への対応、セキュリティアドバイザリの作成などしなければならない状況になっているのです。ソフトウェアの開発や保守でお金をもらっているわけでもないのに、とてもモヤモヤします。もちろん、本当に攻撃の影響を容易に受けてしまうような深刻な脆弱性については、何とか時間を作って急いで修正します。でも、「自分のために作ったライブラリを他の人が喜んで使ってくれるなら開発にかかったコストも要求せず、無料で、現状有姿で提供しましょう。」と言っただけなのに、多くの土日や夜まで潰して手厚いサポートまでタダで求めてくるのは「それは善意の搾取です!!!」とガッキーのように叫びたくなります。

同じオープンソースの暗号ライブラリでも、OpenSSLのように多くのメンバーが開発に関わっていて、修正パッチの提供も有志がやってくれるような状況なら、脆弱性指摘を対応する体制も作れますが、私一人で開発しているような状況なので、仕事やプライベートの都合でタイムリーに脆弱性対応できないケースがあります。そんな手厚いサポートを求められても困るのです。

私は、製品のセキュリティインシデントレスポンスチームであるPSIRTの仕事もしていたので、外部から脆弱性を指摘された場合に、しかるべき機関と調整しながら脆弱性対応する必要があることもわかっています。ただ、こうしたライブラリの場合は厄介で、よく使われる機能も、そうでない機能も様々取り揃えてライブラリを構成しているので、問題への影響が大きいのか小さいのかという判断をつけにくいです。そのため、リスクが高かろうが低かろうが「直せ」と要望が来てしまいます。なんか、段々、オープンソースを公開するのが面倒くさくなってしまいました。

そして寄付金を募ることにしました

「お金もらってるわけでもないのに文句言うな」とモヤモヤした気持ちを抱えたまま、jsrsasignを維持し続けるのもモチベーションが持ちそうにないので、ふと「寄付金」を受け付けてみてはどうかなぁ、、、と思いました。寄付金制度を導入すれば、どれだけの人がこの一人プロジェクトを応援してくれてるのかわかるし、「こんなに応援してくれてるんだから、ちょっと頑張らなきゃなぁ」という気持ちになるかもと思ったわけです。調べてみると、

  • (1) GitHubのスポンサー制度(毎月いくらとか設定して応援してもらえる。日本の口座もOK)
  • (2) Bitcoin、Bitcoin Cashなどの仮想通貨による寄付(自分の口座が放置されてた)
  • (3) Paypalによる寄付 (日本の金融機関ではできない)
  • (4) Open Collective (日本ではかなり敷居が高そう)
  • (5) Buy Me A Coffee (これも面倒くさそう。でも決済がGitHub Sponsorsと同じStripeだから可能性あるかな)
(1)は検索してみると日本の開発者の方も設定しているようで、いろんな方の設定内容を参考に設定することができました。(2)は、仮想通貨口座のアカウントの復旧、追加本人確認手続きが結構面倒だったんですが何とか復活させることができました。(3)はちょっと考えがあるので、そのうちチャレンジしてみようと思います。(1)の審査までの準備は、わからないことも多くて相当かかったのですが、審査申請して2週間と言われてたところを2日くらいで承認されました。(2)と合わせて、ようやく今日、READMEに寄付受付を書いてみました

今後、そのうちどうするか

と、まぁ、サポートや脆弱性対応のモチベーションは何とか寄付金で自分をだましだましやろうと思うんですが、自分もいい歳なので、自分が開発、サポートができなくなった時にどうするかですよね〜〜。急遽、長期入院などして何もできないことがあるかもしれませんし。GitHubでは、後継者を指定して何かあったとき、その人に管理を譲ることができる機能があるんですが、こんなわけのわからないソフトのメンテと問合せサポートを他人に押し付けるわけにもいかないので、多分自分が開発できなくなったら一代限りで終わりなんでしょうねぇ。ソースは全てリポジトリにあるので、引き継いでくれる人が世界のどこかから出てくるのかもしれませんが、完全にお任せで好きにしてもらうのが良いんじゃないかと思ってます。

ただ、自分に何かあったとき、「このプロジェクトは今後一切、メインの開発者がサポートできなくなりました。」と伝えてあげる必要はあるなぁと思っています。娘か知り合いに託すしかないのかなぁ。そうしないと、また The Registerの記事のような騒ぎになってしまうので、、、なんか、デジタル遺品とか終活ノートみたいな話ですね。

趣味でちょっと、好きなものだけ好きなように開発したかっただけなのになぁ、、、なんでこんなことになっちゃったのかなぁ、、、

こんなこと書いちゃってますが、開発はぼちぼち続けていきますよ。本人はいい加減な人間なので、そんなに気に病んでるわけでもないので、どうかお気になさらずに。 なんか、愚痴っぽい話につきあってもらってすみません。今日はこの辺で。

go.jpドメインのHTTPSサイトの状況について私もみてみました(2015年3月4日時点)

慶応義塾大学とレピダムさんで共同調査された「日本政府機関Webサイト(.go.jp)のTLS対応状況について(2015.03.04)」を大変興味深く拝見し、もうちょっと知りたいことも多々あったので、私も調べてみるかなぁと思い、今日はそのご報告を、と。

調査対象

.go.jpドメインのサイトには省庁、外局、独立行政法人、政府系のイベントで作られたサイトなどがあり、そのうちパブリックなサイトのSSLサーバー証明書の枚数は2015年3月4日時点で累計1,819枚のようでした。そのうち、ユニークなコモンネーム(FQDNもしくはワイルドーカード証明書のドメイン)の数は877ありました。
gojp-01
省庁、それらの外局、それらが所管する独立行政法人の数で分類すると以下のような構成になっています。(実はこの表を作るのが一番大変だった。証明書はあるからFQDNはすぐに集まるんだけども、FQDNの独法や局や委員会なんかがどこの省庁が所管しているのかとか、イベントサイトはどこで管理されているかなどをGoogle先生やブラウザで開いたりなんかして、ちまちま調べるわけです。いや〜、独法っていっぱいあるんすねorz)
gojp-02
独立行政法人を除いたものの比率は以下のようになっていました。これには最高裁判所、内閣官房、会計検査院、国会図書館なども含まれています。
gojp-03

ワイルドカード証明書を使っている場合には、そのワイルドカード証明書を使っている任意の1つのサイトが見つかれば、そのサイトを調査対象としました。

イベントで一時的に立ち上がってたサイトや停止したサーバーなどがあり、インターネットからアクセス可能なgo.jpドメインのHTTPSサイトは882中、722であり、 今回は722のgo.jpドメインサイトを調査対象としました。

SSL/TLSプロトコル

まず最初に、go.jpドメインのサイトのSSL/TLSプロトコルのサポート状況を見てみたいと思います。ダウングレード攻撃やPOODLE攻撃で問題となるSSLv2、SSLv3をサポートしているサイトがかなりあることがわかります。まず最初に、全ての*.go.jpドメイン、つまり省庁と独法を合わせた接続可能な722サイトに対して、対応プロトコルをグラフにしました。
gojpa-1
独法を除いた場合、333サイトが接続可能で、同様に対応プロトコルをグラフにしました。
gojpa-2
ダウングレード攻撃で脆弱なSSLv2はかなり少ないですが、POODLE攻撃で脆弱とされるSSLv3が使えるサイトは未だに3、4割のサイトで利用可能になっていることがわかります。

暗号スイート(共通鍵暗号)

次に、暗号スイート(CipherSuite)のうち、使用可能な共通鍵暗号アルゴリズムについて見ていきましょう。最初に全*.go.jpドメインに対してです。
gojpa-3
独法を除いた場合のグラフは以下の通りです。
gojpa-4
どちらもAESはほとんどのサイトで利用できるようになっており、弱い暗号である3DESやRC4も8、9割のサイトで利用できるようになっています。また、国産の暗号であるCamelliaも2割程度のサイトで使えますが、SEEDやIDEAも同程度しかないというのは少し残念ですね。

ブロック暗号モードについては、GCMとCBCしかありませんが、全*.go.jpでのサポート状況は以下の通りになります。
gojpa-5
また、独法を抜いた場合以下のようになります。
gojpa-6
ブロック暗号を一切サポートせず、ストリーム暗号の暗号スイート、つまりRC4しかサポートしないサイトは無かったため、全数は722、333で同じになっています。

暗号スイート(鍵交換)

次に、暗号スイートで使われている鍵交換についてみてみましょう。

まず最初に気になるのが、スノーデンの暴露したNSAの盗聴問題をきっかけに、PFS(Perfect Forward Secrecy)をサポートする暗号スイートを使うことを推奨されるようになりました。 具体的にはDH、DHE、ECDH、ECHDEのいずれかを鍵交換に使う暗号スイートが推奨されています。 PFS、DH、DHE、ECDH、ECDHEの*.go.jpドメインでのサポート状況は以下の通りです。
gojpa-7
独法を除いた場合、以下のようになります。
gojpa-8
DHEやDHは処理パフォーマンスが悪かったり、長い鍵長をサポートする実装が少ないので、ECDHやECDHEを使えるようにして欲しいですね。

DH、DHEの暗号スイートで不十分な鍵長の脆弱なサイトが無いか確認するために、DHの鍵長別にサポート状況をみてみましょう。まずは全*go.jpドメインで見てみます。
gojpb-01
独法を除いた場合、以下のようになります。
gojpb-02
RSA 1024bit以下の証明書が使えなくなったのと同様にDiffie-Hellman(DH) 1024bit以下による鍵交換をするべきではないそうです。ただ、DH 1024bit以下しかサポートしない実装が多かったり、デフォルトでDH 1024bitであったりすることから、リスク回避のためにDHやDHEを使わないようにするのが良いと思います。

ECDH、ECDHEでは鍵パラメータ(=曲線名)はどうなっているでしょうか。まずは、全*.go.jpドメインで見てみましょう。
gojpb-03
独法を除いた場合、以下のようになります。
gojpb-04
ECDH、ECDHEをサポートする場合に、鍵交換で使われる名前付き曲線がNIST P-256(=secp256r1)なのは一般的だし、ブラウザでサポートされている事が多いのでいいですが、NIST B-571(=sect571r1)って世の中で使ってるところを見た事がなかったのでビックリしました。省庁の1サイトと独法の9サイトは先進的というか、デフォルトでは設定されず、意図的にやってるに決まってるので凄いなぁと思いました。そこにブラウザで繋いでみたんですが、TLS_RSA_WITH_RC4_128_SHAで接続してしまい残念orz。

暗号スイート(メッセージ認証(MAC))

世の中では、メッセージ認証に関してはMD5はダメ、SHA1からSHA2に移行している過程にあるのかなと思います。まず、全*.go.jpドメインについて見てみましょう。
gojpb-05
独法を除いた場合、以下のようになります。
gojpb-06
脆弱なHmacMD5を使った暗号スイートが利用できるサイトが4割近く残っているのは問題かなと思います。

SSL/TLS攻撃に脆弱なサイト

BEAST攻撃、POODLE攻撃、FREAK攻撃など、SSL/TLSプロトコルや暗号スイートの設定による脆弱性の影響をみてみましょう。全*.go.jpドメインでのこれらの攻撃の影響は以下のようになっています。 (少しグラフにゴミが入ったけど、まぁ、いっか)
gojpb-07
独法を除いた場合、以下のようになります。
gojpb-08

その他のSSL/TLSサーバーの設定

SSL/TLSでは接続する際、デフォルトではクライアントが提示する暗号スイートのリストの優先順位に基づいて、サーバーと使用する暗号スイートがされますが、これだと酷いクライアントの場合、脆弱な暗号スイートが使用されてしまう可能性があります。これを防止するために、設定によりサーバー側の持つリストを優先して使うようにすることができます。これが「サーバー側暗号スイート優先」です。ApacheであればSSLHonorCipherOrder "on"で設定できます。

OCSP Staplingとは、TLSの拡張でプライバシー保護と証明書失効検証の誤りへの対策です。 まずは全*go.jpドメインで見てみましょう。
gojpb-09
独法を除いた場合、以下のようになります。
gojpb-10
OCSP Staplingの導入はなかなか進んでいない現状がよくわかります。ただ、先進的な設定をしている政府系サイトもあることがわかります。

SSLサーバー証明書

全*.go.jpドメインのアクティブなサイトのサーバー証明書の発行元の 証明書発行サービスで分類したのが以下です。
gojpb-11
独法を除いた場合、以下のようになります。
gojpb-12
やはりVeriSignの比率がかなり高く、GPKI Application CA、GlobalSign、Cybertrustなども頑張っています。特に独法を除いたには、GPKI Application CA 2の比率もかなり高いです。 珍しい所ではServision、KAGOYA、Firstserver、AlphaSSLなどを使っているところもありました。 822枚のうちワイルドカード証明書は19枚、EV SSL証明書は24枚でした。

次に接続可能な全*.go.jp 723ドメインにおける、証明書の公開鍵アルゴリズムと鍵長についてみてみましょう。全てがRSA鍵であって、ECC鍵やDSA鍵はありませんでした。また、鍵長は2048bitがほとんどで、ほんの少し1024bitが残っており、4098bitなどの長いものはありませんでした。
gojpc-01
また、723のRSA鍵について公開指数は全て65537(0x10001)でした。公開指数に3などが使われているために秘密鍵が入手できるといった問題があるサイトは0でした。
gojpc-02

署名アルゴリズムについてはSHA256withRSA、SHA1withRSA、MD5withRSAのいずれかしかなく、SHA256withRSAの移行が30%以上とChromeやWindowsのSHA1の無効化が2017年1月に迫っていることから、SHA1からSHA2への移行はかなり進んでいます。
gojpc-03

証明書の有効期間については、1年物、3年物、2年物の順に多く、10年物は1サイトのみでした。
gojpc-04

Google Chromeが2017年1月までにSHA1証明書に対して段階的に警告を出していき、SHA2証明書への移行を促すというマイルストーンがアナウンスされていますが、有効期限がどの時期であるかを調べてみました。
gojpc-05
有効期限が2017年1月を超える証明書が144サイトであり、Chromeでの警告表示を避けるためにSHA2証明書へのリプレースが必要になります。

また、証明書のOCSPによる失効検証、EV SSLサーバー証明書、Certificate Transparency(CT)のための組込みのSigned Certificate Timestamp(SCT)拡張のサポート状況について調べてみました。CTサポートが11サイトもあったのには、少し驚きました。
gojpc-06

おわりに

以上、*.go.jp ドメインのHTTPSサイトについて自分なりに調査してみました。SSL Pulseとの状況と比較して、以下のポイントで若干コンサバティブというか古い設定になっているなという感じはします。

  • GCMがあまり使われていない
  • ECDHEよりもDHEが使われる
  • EXP、DESなどの古い暗号スイートがかなり残っている
  • SSLv2などもかなり残っている感じがする
サーバーがきちんと対応してくれないなら、クライアント側で最新のブラウザを使うなどで自衛するしかないのかなと思います。

今日はこの辺で。

追記

  • 2015.03.11 08:34 - 3/4から3/11 0:00頃の更新を確認したらgo.jpドメインのHTTPSサイトは3つしか増えていないようです。そんなに頻繁に更新確認しなくてよさそうなので、ちょっと安心しました。現時点では証明書の調査項目が十分でないので、そのうち追加しておきたいと思います。
  • 2015.03.12 00:11 - *.go.jpドメインのSSLサーバー証明書について調べた事を追記しました。
  • 2015.03.12 07:55 - 証明書の調査でなぜ722から723に増えたかというと、HTTPS通信はできて証明書は取れるんだけど、対応暗号スイートを調べようとするとタイムアウトしちゃうサイトが一つあったため、こんなことになってます。

(小ネタ)4月10日(金)のJNSA PKI Day 2015でSSL/TLSの話をさせてもらいます

毎年恒例、日本ネットワークセキュリティ協会(JNSA)の主催セミナー PKI Day 2015「サイバーセキュリティの要となるPKIを見直す」に出させて頂きます。

http://www.jnsa.org/seminar/pki-day/2015/index.html

私は第2部の「SSL/TLS実装の今とこれから」で

  • 「SSL/TLS生誕20年、脆弱性と対策を振返る」
  • パネル:「SSL/TLSの実装が進むべき道を語ろう」
でお話をさせて頂きます。会場は「ヒューリックカンファレンス秋葉原」とありますが、浅草橋駅なのだそうです。 無料セミナーですので、よかったらお気軽に参加ください。

個人的には米丸先生の電子署名法の話と、小谷さんの自動車のPKIの話がとても気になります。JNSAさんから転送自由と書いてあったパートを載せておきます。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
     <JNSA PKI相互運用技術WG・電子署名WG主催セミナー>
   PKI Day 2015「サイバーセキュリティの要となるPKIを見直す」
       http://www.jnsa.org/seminar/pki-day/2015/
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

■ 日 時: 2015年4月10日(金)9時30分〜17時40分(受付開始9時10分)

■ 場 所: ヒューリックカンファレンス秋葉原 ROOM 1
      (東京都台東区浅草橋1丁目22-16 ヒューリック浅草橋ビル3F)
      http://www.hulic-hall.com/access/

■ 主 催: NPO日本ネットワークセキュリティ協会(JNSA)
      PKI相互運用技術WG・電子署名WG

■ 定 員: 132名

■ 料 金: 無料

■ 申 込: 下記URLページ文末の申込フォームよりお申し込みください。
       http://www.jnsa.org/seminar/pki-day/2015/

■ 講演資料:
 講演資料は上記URLよりPDFにて事前公開いたします。
 当日は講演資料の配布はいたしませんので、参加される方はご自身で
 ダウンロードいただき、当日お持ち下さいますようお願いいたします。

■ 開催趣旨:
 今日、サイバー空間におけるセキュリティの確保や信頼関係の構築にPKIは
 欠かせない技術になっています。また、サイバー空間の広がりとともに、
 IoT/M2M等の新しいPKIの応用領域も期待されています。
 その一方、社会基盤としてのPKIは、制度的な課題や、更には実装や展開等
 において様々な課題も浮上しています。
 PKI Day 2015では、以上のことを踏まえ、「サイバーセキュリティの要となる
 PKIを見直す」をテーマに、今後の社会におけるPKIの在り方を議論します。

                 ■■■ プログラム ■■■

9:30-9:40
【ご挨拶】「PKI day 2015のオーバビュー」
  セコム株式会社 IS研究所/PKI相互運用技術WGリーダー 松本 泰 氏

9:40-10:25
【基調講演】「サイバーセキュリティの状況とPKIの取組み」
       講師:東京工科大学 教授 手塚 悟 氏

◆第1部 新しい時代の電子署名◆

10:30-10:35
【第1部のプログラム紹介】
  三菱電機株式会社 情報技術総合研究所 宮崎 一哉 氏

10:35-11:15
【講 演】「欧州の動向-電子署名指令からeIDAS規則へ」
      講師:株式会社コスモス・コーポレイション 濱口 総志 氏

11:15-11:50
【講 演】「トラストリストと信頼のグローバル化」
      講師:セイコーソリューションズ株式会社 村尾 進一 氏

11:50-12:30
【講 演】「電子署名法改正のポイント」
      講師:神戸大学大学院法学研究科・法学部 教授 米丸 恒治 氏

              === 昼休み (12:30-13:30) ===

◆第2部 SSL/TLS実装の今とこれから◆

13:30-13:40
【第2部のプログラム紹介】
  セコム株式会社 IS研究所 島岡 政基 氏

13:40-14:15
【講 演】「SSL/TLS生誕20年、脆弱性と対策を振返る」
      講師:富士ゼロックス株式会社 漆嶌 賢二 氏, CISSP

14:20-14:55
【講 演】「Windows, Internet Explorerのセキュリティのいま」
      講師:日本マイクロソフト セキュリティプログラムマネージャー 村木 由梨香 氏

15:00-15:30
【パネルディスカション】 「SSL/TLSの実装が進むべき道を語ろう」
 モデレータ: セコム株式会社 IS研究所 島岡 政基 氏
 パネリスト: 富士ゼロックス株式会社 漆嶌 賢二 氏, CISSP
        日本マイクロソフト セキュリティプログラムマネージャー 村木 由梨香 氏

◆第3部 広がるサイバー空間に対応するPKIの新しい応用領域◆

15:50-16:00
【第3部のプログラム紹介】
  セコム株式会社 IS研究所/PKI相互運用技術WGリーダー 松本 泰 氏

16:00-16:45
【講 演】「RPKIの技術課題と信頼構造」
      講師:一般社団法人日本ネットワークインフォメーションセンター(JPNIC)技術部
          インターネット基盤企画部 セキュリティ事業担当 木村 泰司 氏

16:50-17:40
【講 演】「PKIの新しい活躍の場=繋がる自動車。そこで生まれる恩恵と脅威、それらへの方策」
      − PC/サーバでの10年のセキュリティ経験を踏まえた提案、標準化活動 −
      講師:富士通研究所 R&D戦略本部IPR戦略室シニアエキスパート、博士(工学)、
         TCG理事 小谷 誠剛 氏


(※)予告無く講演内容が変更される場合がございます。予めご了承下さい

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

SSL Pulseの統計情報で見るSSL/TLS (2015年1月版)

前にもお話した通り、 SSL Pulse (https://www.trustworthyinternet.org/ssl-pulse/)サイトは、 ssllabsでも有名なQualys社が運営しているサイトで、 Webサイト調査のAlexa社による 世界のアクセストップ20万サイトを対象にSSL関係の統計情報を毎月公開しています。 以前、2014年11月のSSL PulseでのSSL/TLSの状況推移をグラフ化しましたが、 2ヶ月たってどうなったのか、また今月もグラフ化してみました。

脆弱性対応の推移


pulse201501-vuln2
BEAST対応(CBC対応?)を除いて、全体的に順調に良くなる方向にあります。 悪い状態が上、良い状態が下になるようにグラフを統一したので、見やすくなったかと思いますが、どうですかね。

SSL/TLSプロトコルの推移


pulse201501-proto

SSLサーバー証明書の鍵長、署名アルゴリズムの推移


pulse201501-cert

新しい技術のサポートの推移


pulse201501-adv
このあたりは、どれも普及が10%未満のままだと、、、

関連記事

W3C Web Cryptography APIとの果てしなき戦い(第3回 動くサンプル1)

前回はW3C Web Cryptography APIの鍵生成、署名などについて説明しましたが、実際に動く実例がないとAPIの有り難みもわかないのかなと思いまして、とりあえず3つのサンプルを作ってみました。サンプルはChromeやFirefoxでは動くようになっています。画像をクリックするとサンプルページが開くようになっています。

ハッシュ関数


wc-hash
ハッシュアルゴリズムを選んで、ハッシュ計算したい文字列(UTF-8だから日本語も可能)を入力して、「ハッシュ計算」のボタンを押すだけで、16進数でハッシュ計算結果が表示されます。

公開鍵ペアの生成


wc-genkey
RSA公開鍵ペアを生成します。W3C Web Cryptography APIでは、鍵生成やインポートの際、どのような用途で、どのようなハッシュ関数と一緒に使用するかを指定する必要があるようで、生成時に選択するようにしていますが、PKCS#8 で秘密鍵や公開鍵をエクスポートする際には、まぁ、関係のない話になってしまいます。PKCS#8のバイナリデータ(ArrayBufferView)をPEM形式に変換するのにjsrsasignライブラリを使っています。

RSA鍵による署名と検証


wc-sigver
RSA鍵でUTF-8の文字列に対してSHA256withRSA署名アルゴリズムで署名と署名検証ができます。鍵はW3C Web Cryptography APIで内部生成した鍵ペアで署名と署名検証することもできますし、PKCS#8 PEM形式やJSON Web Key(JWK)フォーマットの秘密鍵や公開鍵をインポートして署名や署名検証することもできます。

サンプルの動作環境

これらのサンプルページは新しいChromeのWindows、Android、Mac OS X、Linux版、新しいFirefoxのWindows、Mac OS X、Android版で動作します。Safariでは一部がMac OS X版、iOS8+などで動作します。Internet ExplorerではPromise APIをサポートしていないので動作しません。IEでも動作するようにコード書くのはちょっと面倒で、それらの相互運用性を持たせるような実装の仕方については別途紹介しようかと思っています。

おわりに

とりあえず、いろんなブラウザでW3C Cryptography APIの動作を試してみることができるので、遊んでやってください。ソースコードはgithubに置いてあるのでご覧ください。FirefoxとChromeだけでも相互運用性持たせるのに結構壁にぶちあたったりして、その上、SafariやIEなども一緒にサポートするコードを書くのはかなり骨が折れるんですよね。でも、AndroidのFirefoxでも動くのを見ると、ちょっと目がうるうるしてきたりしますw。今日はこのへんで。

関連記事

W3C Web Cryptography APIとの果てしなき戦い(第2回 RSA署名生成と検証)

前回は、 W3C Web Cryptography APIについて、一番簡単そうなハッシュの生成を紹介しながら、 幾つかの課題について紹介しました。

今回は、W3C Web Cryptography APIによる、 RSA公開鍵暗号によるデジタル署名の生成と検証を紹介していこうと思います。

署名と検証の例題って、よく一人の人というかプログラムが、 鍵ペアを生成して、署名して、検証するサンプルを出しますよね。( sjclの楕円暗号のテストコードとか・・・) 一人の人が同時に署名と検証を行うってユースケースとしてありえないと思うんですよね。 実際、私が見た当時、sjclでは鍵オブジェクトの秘密鍵と公開鍵を 分けてエクスポートができないようで、実際問題使えないことがありました。

そんなわけで、今回はまず、ちゃんとOpenSSLで生成した秘密鍵と公開鍵をインポートして、 署名の生成と検証をできるようにしたいと思います。 その後で、RSAの鍵ペアの生成をします。

データの準備

W3C Web Cryptoで鍵生成してもよいのですが、今回はOpenSSLで作ったRSA 2048bitの 秘密鍵で署名することにしたいと思います。PKCS#5 PEM形式の2048bit RSA秘密鍵を生成し、 それを平文のPKCS#8 DER形式に変換し、 bin2hexスクリプト で16進数文字列表現に変換します。

% openssl genrsa 2048 > k2048.p5p.pem % openssl pkcs8 -topk8 -nocrypt -in k2048.p5p.pem -outform DER -out k2048.p8p.der % bin2hex < k2048.p8p.der > k2048.p8p.hex #16進数形式のRSA秘密鍵
鍵ペアとなる公開鍵について、同様に16進数文字列形式のものを取得します。
% openssl rsa -in k2048.p5p.pem -pubout -out k2048.pub.pem # PEM形式の公開鍵 % openssl rsa -in k2048.p5p.pem -pubout -outform DER -out k2048.pub.der #DER形式の公開鍵 % bin2hex < k2048.pub.der > k2048.pub.hex # 16進数形式のRSA公開鍵
次に"aaa"という文字列に対して署名するとして、この文字列が含まれる署名対象 データファイルを作っておきます。
% echo -n aaa > aaa.txt
OpenSSLで前述の秘密鍵と署名対象データを使ってSHA1で署名すると結果のデータは以下のように 作られます。同様に16進数データを作っておきます。
% openssl dgst -sha -sign k2048.p5p.pem aaa.txt > k2048oaaa.sig.bin % bin2hex < k2048oaaa.sig.bin > k2048oaaa.sig.hex
OpenSSLで前述の公開鍵と署名対象データと生成された署名値データを使って検証するには 以下のように行います。
% openssl dgst -sha1 -verify k2048.pub.pem -signature k2048oaaa.sig.bin aaa.txt Verified OK
署名値は正しいことがわかります。

秘密鍵のインポートと署名の生成

秘密鍵の16進数値を使って文字列"aaa"に対してSHA1withRSAで署名する場合の、 W3C Web Cryptoのコードは以下のようになります。

var prvHex = "308204bd02010030..."; // 前節の16進数秘密鍵 var prvUint8a = hextouint8a(prvHex); // 秘密鍵のUint8Array var aaaUint8a = asciitouint8a("aaa"); // 署名対象aaaのUint8Array // PKCS8形式の秘密鍵を署名用にインポート window.crypto.subtle.importKey( "pkcs8", prvUint8a, { name: "RSASSA-PKCS1-v1_5", hash: {name: "SHA-1"} }, true, ["sign"] ).then( // 秘密鍵インポートに成功したら署名する function(prvKey) { console.log("**importKey** 成功"); console.log("prvkey=" + prvKey); return window.crypto.subtle.sign("RSASSA-PKCS1-v1_5", prvKey, aaaUint8a); }, function(e) { console.log("**importKey** エラー: " + e); } ).then( // 署名に成功したら署名値(ArrayBuffer)を16進数表示 function(sigVal) { console.log("**sign** 成功"); console.log("sigVal=" + abtohex(sigVal)); }, function(e) { console.log("**sign** エラー: " + e); } );
実装で注意しなければいけないポイントは以下の通りです。
  • OpenSSLの(平文の)PKCS#8秘密鍵を使うにはimportKeyで"pkcs8"を指定する。
  • 鍵使用目的で["sign"]を指定する。
コンソールに"sigVal="で表示された16進数の署名値は、 k2048oaaa.sig.hexファイルの値と同じになっていると思います。 hex2binスクリプト で署名値をバイナリデータに変換して、以下のようにOpenSSLで検証することが できます。うまく検証できたでしょうか。
署名値16進数をk2048waaa.sig.hexとして保存 % hex2bin < k2048waaa.sig.hex > k2048waaa.sig.bin openssl dgst -sha1 -verify k2048.pub.pem -signature k2048waaa.sig.bin aaa.txt Verified OK
hextouint8aについてはこちらをご覧ください。

公開鍵のインポートと署名の検証

前々節のOpenSSLで作った署名値でもよいですし、前節で生成された署名値でも よいですが、これをインポートした公開鍵で検証してみましょう。 以下のようなコードで検証することができます。

var pubHex = "30820122300d0609..."; // 前々節の16進公開鍵 var sigHex = "afd36b6f3f2af788..."; // 前節or前々節の16進署名値 var pubUint8a = hextouint8a(pubHex); // var sigUint8a = hextouint8a(sigHex); var aaaUint8a = asciitouint8a("aaa"); window.crypto.subtle.importKey( "spki", pubUint8a, { name: "RSASSA-PKCS1-v1_5", hash: {name: "SHA-1"} }, true, ["verify"] ).then( function(pubKey) { console.log("**importKey** 成功"); console.log("pubKey=" + pubKey); return window.crypto.subtle.verify("RSASSA-PKCS1-v1_5", pubKey, sigUint8a, aaaUint8a); }, function(e) { console.log("**importKey** エラー: " + e); } ).then( function(isValid) { console.log("**verify** 処理成功"); if (isValid == true) { console.log("**verify** 署名検証成功(一致)"); } else { console.log("**verify** 署名検証失敗(不一致)"); } }, function(e) { console.log("**verify** エラー: " + e); } );
実装で注意するポイントは以下の通りです。
  • OpenSSLの公開鍵をインポートする際には"spki"を指定する。
  • インポートする際の鍵使用目的に"verify"を指定する。
  • 署名検証の結果はブール値(isValid)で返されるのでこれに従う。 関数が呼ばれただけで安心して終わりにしない。

RSA鍵ペアの生成

上の例ではインポートした秘密鍵、公開鍵を使っていますが、 鍵ペアの生成だってできます。(現状RSAだけのようですが・・・) RSA 2048bitの鍵ペアは以下のように生成します。

var paramKeyGen = { name: "RSASSA-PKCS1-v1_5", // 現状ではRSA-PSS, RSA-OAEPは指定できなそう modulusLength: 2048, // 鍵長 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 公開指数 65537 hash: { name: "SHA-256" } // 署名のハッシュアルゴリズム?別に利用外のを指定しても良い? }; window.crypto.subtle.generateKey( paramKeyGen, // 生成する鍵ペアのための鍵長等の各種パラメータ true, // エクスポート可能にするかどうかのフラグ ["sign", "verify"] // 鍵使用目的 ).then( function(key) { console.log("**generateKey** 成功"); console.log("秘密鍵:" + key.privateKey); console.log("公開鍵:" + key.publicKey); }, function(e) { console.log("**generateKey** エラー: " + e); } );

Web Crypto APIの困った所5:importKeyの融通の利かなさ

こうしてこのブログをすんなり見ていただくと、「W3C Web Cryptoって簡単じゃん」と 思われるかもしれませんが、このような動く例を見つけるまで、かなりの紆余曲折があり 時間がかかっています。importKeyの正しく動く例というのが、仕様に記載されておらず、 他の方のサンプルも動くものあり、動かないものあり、何が正しいのかよくわかりません。 importKeyの引数には、

  • format - 鍵データの形式 (pkcs8, spki, jwk, raw)
  • keyData - 鍵データ (ArrayBufferView(Uint8Array)かJSONデータ)
  • algorithm - アルゴリズムのJSONデータ
  • exportable - エクスポート可能かのブール値
  • keyUsage - 鍵使用目的の配列 ["sign", "verify"] 等
を指定しますが、仕様がイケてないと思うのは
  • 鍵のデータ形式など指定させる必要があるのか。公開鍵か秘密鍵のバイナリかはASN.1構造を見ればわかる話。JWKだって区別はできる。
  • アルゴリズムの指定も必要性がよくわからない。pkcs8、spkiであれば、鍵アルゴリズムが何であるかわかるし、鍵のインポートの際に署名アルゴリズムやハッシュアルゴリズムを指定させる 意味がわからない。"RSASSA-PKCS1-v1_5"にするか"RSA-PSS"にするかは、鍵インポート時に決める必要がない。署名のハッシュアルゴリズムについても同様に決める必要がないのに、"MD-5"などサポート外のアルゴリズムを指定するとエラーとなる。JWKデータも同様に鍵アルゴリズムの指定の必要がない。
  • keyUsageの指定の必要性もよくわからない。例えば、RSASSA-PKCS1-v1_5で秘密鍵をインポートしたらkeyUsageはsignに決まっており、省略できることの方が多い。
  • JSON等指定の自由度が非常に高い割に、値の指定を間違えるとすぐにエラーとなり融通が利かない。省略可能やデフォルト値を持つ引数、パラメータがあっても良さそうだが、そのようにはなっていない。
  • algorithmのhashのパラメータ値でMozillaのテストコードでは"SHA-1"となっているが、仕様上は{name: "SHA-1"}となるのが正しいようでこれならChromeでもFirefoxでも動作する。前述のように必要の無いパラメータの指定方法が原因で実装により動作するもの、しないものがあり、相互運用性の問題が生じている。
そのような意味では、jsrsasignのKEYUTIL.getKey()メソッドでは入力は極力自動解析し最小のパラメータで動作するようになっていて、秘密鍵であろうが、公開鍵であろうが、JSON形式であろうが、鍵が暗号化されていようが、鍵アルゴリズムが何であろうが、許容範囲の広い実装となっています。

Web Crypto APIの困った所6:アルゴリズムサポート状況の不明瞭

前回紹介したCan I Use CryptographyのページでChrome等いろんなブラウザが フルサポートかのような記述になっていますが、W3Cの勧告候補でも特にどのアルゴリズムは 実装必須となっているわけではないようで、ECDSA、RSA-PSSなど サポートしていないアルゴリズムはかなり多いです。(IE11+ではSHA-1未サポートのよう) この辺りについてスペックがどうなっているのかブラウザベンダーから正式な開示が 無いようですし、仕様上も何をサポートしているかを知る術が特になく、 動かしてみて動かなかったら未サポートのような状況になっています。 そもそも、Java JCEやOpenSSLなどに比べたら、 アルゴリズムの数が圧倒的に少ないのですから、全アルゴリズムを実装必須(MUST) としても良いぐらいではないかと思います。 また、Java JCEではどのようなアルゴリズムをサポートしているかを知るためのAPIがあります。 ブラウザ毎のアルゴリズムや機能のサポート状況の比較は、 そのうち表などで比較できればと思っています。

Web Crypto APIの困った所7:サポートアルゴリズムの狭さと変なバランス感

W3C Web Crypto APIでは、 MD5、RSA暗号(RSAES-PKCS1-v1_5)など現時点で脆弱とされているアルゴリズムは除外されており、 サポートされているアルゴリズムはかなり限定的で狭いものです。 後方互換性や相互運用性のために使いたいというケースもあるでしょうから、暗号ライブラリとしては、 サポートしても良いのかなと思ったりもします。 その割には、例えばFirefoxではRSA鍵の鍵長が256bit〜7168bitをサポートしており、むしろそちらの方を制限すべきなのでは?とも思ってしまいます。 また、FirefoxではECDSAをサポートしていないのに、ECDHはサポートしているなど、同じECCの鍵生成なのに、このあたりのバランス感や優先順位も奇妙に思います。

Web Crypto APIの困った所8:鍵生成のパラメータ

例えばRSA鍵生成のパラメータですが、RSA署名やRSA暗号化のアルゴリズムを 指定しなければならないのかわからず、公開指数の指定の仕方も面倒で、 何故ハッシュを指定しなければならないのかわかりません。 また、これらのパラメータは省略は一切許されていません。 間違えるとエラーとなり、どこが間違っているのかに関するエラーメッセージは どの実装も非常に不親切です。

var paramKeyGen = { name: "RSASSA-PKCS1-v1_5", // RSA-PSS, RSA-OAEPなど指定する必要なくRSAで十分では? modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 整数65537でいいのでは?Uint8Array面倒 hash: { name: "SHA-256" } // hashが必須な意味がわからない };

高い相互運用性のために

一連のシリーズでは、最も汎用性が高くなるように、 window.crypto、window.crypto.subtleを使っており、 FirefoxやChromeでそのまま動く動作コードになっています。 これらに加え、IEやSafariなどいろんなブラウザで動かそうとする場合には、 以下のようなコード先頭に入れ、

var WC = null; var WCS = null; if (window.msCrypto) WC = window.msCrypto; // IE11+ if (window.crypto) WC = window.crypto; // FF34+,CH37+ and others if (WC.subtle) WCS = WC.subtle; // IE11+,FF34+,CH37+ and others if (WC.webkitSubtle) WCS = WC.webkitSubtle; // Safari 7.1+
window.cryptoの代わりにWCを、 window.crypto.subtleの代わりにWCSを使えば、 どこでも動く可能性が高くなるかと思います。

おわりに

今回は、RSA鍵ペアの生成、署名生成、署名検証についてみてみました。 今日はこんなとこで。

関連記事

ロシアの方が開発したJavaScript PKIライブラリPKI.jsをさわってみたぞ

私はJavaScript実装の暗号ライブラリ jsrsasign(注:RSAだけじゃないよ!) を開発などして遊んでいるわけですが、 そんな矢先、先週ぐらいですかねぇ、PKI.js(http://pkijs.org/) というJavaScript暗号ライブラリが公開されました。 ぶったまげたのはpure JavaScriptなのにOCSPやCMS SignedDataやTimeStampなんか に対応しているのだそうです。さらに凄いのはNIST PKITSのテストも通すせるような認証パス検証(証明書のチェーンの検証)機能も実装されているのだそうです。 先を越されて悔し〜〜〜って感じ。 ようやく時間ができたので、ちょっと動かしたりしてみたのでブログに書いておこうと思います。

WebCryptoを使っているのね

早速ダウンロードしてみて、サンプルには証明書の生成と、CMS SignedDataの生成があるんですが ブラウザで動かしてみようとするも動かない。ちょっと調べてみると W3C Web Cryptography API を使っているんですよね。 ええ?これってまともな実装あるんだっけ?と思ってTwitterでちょっと書いていたら 作者のYury Strozhevskyさんから連絡が来てメールでいろいろ質問をしてしまいました。 GlobalSignのgithubリポジトリなのでGlobalSignの人かとおもったら フリーランスのプログラマなのだそうです。 YuryさんはCAdESに興味があって ブログ記事書かれているみたいなのでそのうちPKI.jsがCAdESに 対応する日も近いのではと、、、

さて、WebCryptoの実装なんですが、普通のほとんどのブラウザではだめで Chromeのnightly buildを使えって言われました。 確認したところWebCryptoを今使うには方法は3つあるようで

  1. Chromiumを使って環境設定する
  2. Chrome nightly buildを使って環境設定する
  3. (Safari)WebKit Nightly Buildを使う
Chrome nightly/Chromiumの環境設定は以下のようにやればいいようです。(Yuryさんあざます。)
  1. アドレスバーでchrome://flagsを開く
  2. 次の4つを有効にする
    1. #extension-apis
    2. #enable-javascript-harmony
    3. #enable-experimental-web-platform-features
    4. #enable-devtools-experiments
  3. フラグ設定画面の一番したのボタンで再起動する
ChromiumのWebCrypto実装に関するIssue Trackerはここを参照すればよさそう。

早速動かしてみるぞ

githubで落としただけでは簡単に動かず、まぁ以下のようにやります。

  1. pkijs.orgからソースを落とす
  2. asn1js.orgからソースを落とす
  3. 解凍しasn1jsのorg/pkijs/asn1.jsをpkijsのorg/pkijs/にコピーする
  4. サンプルHTMLを解凍したpkijsの直下にコピーする(cd pkijs; cp examples/*/*.html .)
サンプルは以下があります。
  • CreateNewX509Certificate.html - RSA鍵ペア生成と証明書の生成
  • CreateCMSSignedData.html - RSA鍵ペア生成と証明書の生成とCMS SignedDataの生成
コピーしたHTMLをChromium等で開けば証明書のサンプルは動くんですが、 CMS SignedDataは生成されませんでした。コード追ってみると 以下のようにコメントアウトしてやればとりあえず動きました。
// in CreateCMSSignedData.html (line 341) //result_string = result_string + formatPEM(hex_coded);

48
ほら、ちゃんとPKCS#7 (まぁだいたいCMS SignedDataと同じ)署名データが できていますよね。 中身のぞいてみるとちゃんと内包形式のCMS SignedDataができてます。 証明書DNはBMPStringなんすよね〜〜。なんか、ロシアの人はBMPString好きですよね。

タイムスタンプを発行しようとするも

ちょっと格闘してタイムスタンプを発行しようとするも、 APIドキュメントがなかったり、タイムスタンプを発行するにも MessageImprintを作るのですら結構手間だったり、 TimeStampResponseに署名をしようとするようなちょっと メソッドがわかりにくかったりで一筋縄では発行できそうになく 心が折れてしまいましたorz

おわりに

W3C WebCrypto APIが一般のブラウザで使われるようになれば、 とても可能性が広がりそうなJavaScript PKIライブラリ PKI.js を さわってみました。とても悔しいのでjsrsasignでもCMS SignedData 対応をしようと思っています。

追記

PKI.jsのコードを眺めてみたりして気になった特徴をここにまとめておきます。

  • 現時点ではSHA1,SHA2(256,384,512)の証明書しか対応していない
  • 現時点ではRSA鍵しか扱えないようだ

(2014.05.11 23:14) 私がブログやTwitterで書いたことで、日本のプログラマの多くの方がYuryさんのPKI.js githubにLikeをしてくれたそうで、Yuryさんはとても喜んでくれました。ロシアからは何故かこのライブドアのブログが見えないそうで、どんな事が書かれているのか気になるので是非送ってほしいと言われてしまい、Google翻訳したページをメールで送ってあげました。YuryさんがCAdESの記事を書いていたのでETSIやECOMのCAdESの話を紹介してあげたら [1] [2] 喜んでくれました。

追記2(2014.05.12 23:49、2014.10.04更新)

簡単にPKI.jsとjsrsasignと比較をしてみましょう。

PKI.jsjsrsasign
暗号計算 W3C WebCryptoAPIを使ったネイティブ処理なので速いはず 各暗号ライブラリに依存するがpure JavaScript実装のため遅い
対応暗号アルゴリズム W3C WebCryptoAPIに依存しているが無いものも多い。現時点ではRSA, SHA1, SHA2のみ。 比較的豊富でRSA, DSA, ECDSA, SHA1, SHA2, MD5等幅広くサポート
APIドキュメント 現時点では無い 公開済
サンプル 公開されているが非常に少ない 公開済
テストコード 現時点では無い公開済
対応ブラウザ・動作環境 WebCryptoAPIを有効にしたChromium, Chrome, WebKit(Safari)等 開発用ブラウザのみ。スマートフォンは設定不能のため非サポート ブラウザ、動作環境をあまり選ばない。スマートフォンブラウザでも動作
Node.js対応 基本的にWebCryptoAPIはブラウザ必須なのでNodeは対応していないはず。 鍵生成/乱数生成に一部問題があるもののNode.jsに対応
証明書チェーンの検証機能 ありなし
RFC 3161デジタルタイムスタンプ ありあり(2014.05より)
CMS署名/暗号フォーマット あり署名のみ(2014.05より)
RFC5126CAdES長期署名 なしBES/EPES/T(2014.06より)
2014.10.04: Node.jsについて追記

(小ネタ)HeartBleed影響で証明書の再発行とそれに使うRSA鍵の事前チェック

OpenSSL HeartBleed問題で証明書の再発行やら説明やらなんやらに追われてたわけですが、再発行に際してちょっと鍵も事前チェックしてみるかなぁ、、、と。

Debianで生成するRSA鍵の乱数が固定の値になってしまい生成される全てのケースの秘密鍵がわかってブラックリスト化されたり[0]、因数分解の片方がわかっていれば秘密鍵は簡単に復元できちゃう問題とかあったり[1][2][3]で、鍵がそのような弱い鍵でないか調べるサイトとして米ミシガン大学のチームのfactorable.netというサイトがあり、PEM形式の証明書を貼れば調べることができます。

でも、これって発行済の(他のサイトの)証明書を調べるツールなわけで、自分の証明書を発行してもらってから鍵がダメだったってわかっても、再発行にはお金もかかるし、なんで公開鍵や証明書発行要求(CSR,PKCS#10)でチェックしてくれないのかなぁと思ったわけす。証明書発行要求時点でわかれば鍵ペア生成し直せばいいだけですから。

factorable.netの管理している方へ「証明書発行要求に対応してくんない?事前にチェックできた方が便利だと思うんだよねぇ。」みたいなメールを送ってもみたんですが「ナイスな改善提案ありがと。でも他にもToDoがあっていつ直せるかっていうのは約束できない。対応したら連絡するね。」という旨のメールが来てやんわり断られました。とほほ。

OpenSSLで鍵生成したならこんな感じで秘密鍵から自己署名証明書をとりあえず作ってチェックすればいいんだけど、

% openssl req -new -key aaa.prv -x509 -subj /C=JP/O=TEST1 -set_serial 1 -days 3652 -out aaa.cer
#できたaaa.cerをfactorable.netでチェックすればよいです。
WindowsやHSMなんか使っている場合には、やはり証明書発行要求で事前チェックをするのが王道かなと。

仕方ないので簡単なツールを作りました。

jsrsasign: CSR to certificate converter:
http://kjur.github.io/jsrsasign/tool_forfact.html
jsrsasignを使って証明書発行要求から公開鍵をひっこ抜いて、適当な公開鍵証明書の形にでっちあげて、証明書の署名値はいいかげんな値に設定したニセの証明書を作ってしまえば、factorable.net で公開鍵が弱くないかチェックできるようになります。

これから発行してもらおうとしている証明書発行要求をツールに貼付けて「Convert」ボタンを押せばニセ証明書ができます。 (署名値は0x0102030405060708です。適当すぎますか?(^^;)
CSR-Self Cert Converter
この生成されたニセ証明書をfactorable.netのチェッカーにかければ、証明書発行要求とそれに紐づく鍵が弱い鍵でないかチェックすることができます。めでたしめでたし。
factorable.net key checker

factorable.net keychecker result

というわけでひっそりとjsrsasign 4.2.2を昨晩リリースしました。AuthorityKeyIdentifier証明書拡張に対応してくんない?というリクエストもあったので追加しときました。

今日はこの辺で

(小ネタ)Android 4.0.4と4.3.1とでJCEプロバイダはどう違うのか

新しいNexus 5がリリースされ新しいOSであるAndroid 4.4 KitKatも お目見えしたわけで、Nexus 7 2013を持っている私としては 早くアップデートが出るのを心待ちにしています。

さて、アップデートが出てしまう前に、Android 4.0.4 (CUBE U20GT) と、Android 4.3.1 (Nexus 7 2013)とでJCEプロバイダがどう違うのかを みておきました。調べるのにはJCE Provider Checkerを使いました。

違いのまとめ

  • AndroidOpenSSLプロバイダ
    • Mac: HmacSHA{1,256,384,512}の追加
    • Cipher: AES,DES,3DES等追加
    • Signature: {MD5,SHA{1,256,384,512}with{RSA,ECDSA}, SHA1withDSAの追加
    • SecureRandom: SHA1RPNGの追加
    • SSLContext: TLSv1.1, TLSv1.2の追加
  • BCプロバイダ
    • バージョンが1.46から1.48へ
    • 実装クラス名やAliasの変更がほとんどか?
  • AndroidKeyStoreプロバイダが新たに追加された

AndroidOpenSSLでTLSv1.1, v1.2がサポートされるようになったのは重要ですかね。 JCE Provider Checkerはデータのコピペが面倒だとわかったのでこれは改善しないといけません。

最新記事
Categories
Archives
Twitter
記事Google検索

本ブログ内をGoogle検索
Yahoo!アクセス解析
Travel Advisor
記事検索
QRコード
QRコード
  • ライブドアブログ