Hatena::ブログ(Diary)

あまつぶ@はてなダイアリー RSSフィード

あまつぶWikiあまつぶ過去ログMacソフトWinソフト掲示板
<カレンダー>
2003 | 09 | 10 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 03 | 04 | 05 | 06 | 07 | 09 | 11 |
2011 | 02 | 07 | 08 | 11 |
2012 | 04 | 11 |
2013 | 07 | 09 | 10 |
2014 | 11 |
2015 | 11 |

<< 2014/11 >>
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30

<最近の見出し>




POPFile の Mac OS X(Panther/Tiger/Leopard/Snow Leopard/Lion/Mountain Lion/Mavericks/Yosemite)用インストーラをお探しの方は、POPFile プロジェクトのダウンロードページへ。
 | 

2014-11-01 IO::Socket::SSL で証明書の検証をする

[] IO::Socket::SSL で証明書の検証をする  IO::Socket::SSL で証明書の検証をするを含むブックマーク

久々に更新。

Twitter でぼちぼち書いてたけど、まとめておこうかなと。

IO::Socket::SSL には、接続先の証明書を検証する機能があるが、検索してもあまりその使い方が出てこない。いつかのバージョンで、「SSL_verify_mode」を設定せずに使おうとすると警告が出るようになったため、「とりあえず SSL_VERIFY_NONE に設定したら動くよ」っていう情報があちこち見つかるのだが、「SSL_VERIFY_PEER」を使うのが推奨されているにもかかわらず、そうした場合に証明書をどうやって検証するかっていう情報がなぜかあまり出てこない。

証明書の検証をするためには、SSL_ca_file あるいは SSL_ca_path で CA の証明書のファイルが入っている場所を指定すればよい(ドキュメント)ということなのだが、どこにどういう形式で保存されているかは OS によって異なる。また、Web ブラウザとかもそれぞれ持っていたりする。Perl で使うのだから、OS による違いを気にしなくてよいような方法を採りたいところ。

探してみると、Mozilla::CA というモジュールを見つけた。モジュールには Mozilla が使用している CA の証明書のファイルを変換したものが含まれておりそれを、IO::Socket::SSL の SSL_ca_file に指定できる(Mozilla::CA::SSL_ca_file() で)ようになっている。これならば OS 間の違いを気にすることなく動くではないか。すばらしい。モジュール自体のバージョンはちょっと古いが、証明書のファイルを更新するためのスクリプトも含まれており、モジュールのバージョンアップが止まっても更新していくことができそうだ。

と、一旦はうまい方法を見つけたと思ったのだが、Mozilla::CA のバグ情報に気になる情報を発見。Mozilla::CA に含まれている更新用のスクリプトが古く、参照しているファイルがずっと更新されていないというではないか。

どうも、この更新用スクリプトは curl に含まれているもののようで、curl の最新バージョンから持ってきたものを使えば新しいファイルを入手することができるらしい。ということで試してみると、ちゃんと更新され、うまくいった、かに見えた。というか、最初に試した imap.gmail.com に対しては問題なく動いた。

これで一安心かと思ったが、imap.mail.me.com で試すと、エラー。原因はわからなかったが、IO::Socket::SSL のバージョンを落とすとエラーが起らなくなったためモジュールが悪いのかと考えた。いくつかのバージョンを試していくと、1.974 までは大丈夫で、 1.975 からエラーが起こることがわかった。

1.974 と 1.975 の違いを見ると、Mac OS X だけのために修正された部分を見つけた。そこに示されたリンクを辿ると、Apple が OpenSSL に独自のパッチをあてており、指定された証明書ファイルで検証ができないばあいに、OS が持っているものを使って検証するようになっている、ということらしい(たぶん)。で、1.974 まではその機能が有効になっていたが、1.975 ではそれが働かないようになった、ということのようだ。要は、バージョンが変わったことが原因ではなく、新しいバージョンの mk-ca-bundle.pl で作成したファイルでは、証明書の検証ができていなかったのだ。

その後、OpenSSL とともにインストールされたと思われる「/usr/local/etc/openssl/cert.pem」を指定した場合には問題ないことがわかり、さらに、Mozilla::CA に最初から入っていたものでも問題ないことがわかった。そこから先がなかなかわからなかったのだが、本日、mk-ca-bundle.pl を読んでいたところ、「-p」オプションで証明書の利用目的とレベルの指定ができることがわかった。試しに、すべてが含まれる、「-p ALL:ALL」を指定すると、問題なく動いた。いろいろとオプションを試していくと、「-p EMAIL_PROTECTION:TRUSTED_DELEGATOR」の指定でエラーなく検証できることを発見。デフォルトの「SERVER_AUTH:TRUSTED_DELEGATOR」ではだめなのが納得いかないが、まあ、とりあえず。

では、どの部分が原因だったのか。「openssl s_client -showcerts -connect imap.mail.me.com:993」を実行してみると、「*.mail.me.com」の issuer は「VeriSign Class 3 Secure Server CA - G3」となっており、そこから、「VeriSign Class 3 Public Primary Certification Authority - G5」、「Class 3 Public Primary Certification Authority」という順で検証されているらしい。ここで、mk-ca-bundle.pl のデフォルトで作ったファイルを見ると、「G3」と「G5」はあるが、素のものはない。その元になっている「certdata.txt」を見ると、

CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST

となっている。EMAIL_PROTECTION については TRUSTED_DELEGATOR だが、SERVER_AUTH では MUST_VERIFY_TRUST だそうだ。んで、MUST_VERIFY_TRUST ってのはどういう意味よ、と検索してみたのだが、結局よくわからなかった。信頼してもよいかどうか検証しろよってことなのかしら?

なんだか釈然としないが、現状では上に書いたように EMAIL_PROTECTION の方を使えばうまくいくので他の方法が見つかるまではこれでいくしかないのかな。というか、Perl で書かれていてマルチプラットフォームで動くものならみんな同じ条件のはずだけど、全然情報が見つからないのはなぜなんだろう。証明書の検証なんて別に、、、ってことなの? 「IO::Socket::SSL VERIFY_PEER」でぐぐると、トップは CPAN の IO::Socket::SSL のページで、次が私が POPFile のフォーラムに書いた書き込みなんだよね。。。

他のモジュールではどうしているんだろうと、LWP を見てみたら、LWP::Protocol::https にその処理が入っているらしい。内容はというと、SSL_ca_file または SSL_ca_path オプションが指定された場合はそれを、指定がないばあいは Mozilla::CA を使うというもの。Mozilla::CA に含まれているファイルが古いだなんてことはまったく気にされていないよう。んー、それでいいのか?? まあ、それがいやな人は SSL_ca_file とかのオプションを使えばってことなのかね。


ということで、Perl で IO::Socket::SSL を使っていて、マルチプラットフォームで動く証明書の検証方法のベストプラクティスを誰か教えてください。。。

kazuhookukazuhooku 2014/11/07 10:59 EMAIL_PROTECTION は確か S/MIME 関連の設定なので関係ないと思います。

当該証明書は http://www.confusedamused.com/notebook/fixing-verisign-certificates-on-windows-servers/ にあるようにクロスルートで署名されているものです。
#「VeriSign Class 3 Public Primary Certification Authority - G5」という証明書が2種類あることに注意

で、直面されている現象は、

- G5 2036がルートとして登録されているのであれば、IO::Socket::SSLがクロスルートの証明書検証に失敗している
- G5 2036がルートとして登録されていないのであれば、(G5 2036もClass 3 Public Primary Certification Authorityもないため)証明書の検証結果が「信頼できない」となった

のいずれかだと思います。

ですので、G5 2036がルートストアにインストールされているかご確認いただくことが問題の切り分けに有効かと思いました。

amatubuamatubu 2014/11/07 12:43 貴重な情報ありがとうございます。
元になっているものは
http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
で、中を見るとG5はひとつ(2036のほう)しか入っていないようです。これですと、無印のがなくても大丈夫なはず、ということなのでしょうか。

 | 
468820