私は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について追記