以下は
ruby 2.2.4p230 (2015-12-16 revision 53155) [x64-mingw32]
で検証しています。
RubyでSSL通信するにはルート証明書が必要
まずは試しにgithubにHTTPSで接続してみる
ruby -rnet/http -e"Net::HTTP.get URI('https://github.com')"
Rubyには信頼された証明書リストがバンドルされていないので多くの環境でエラーがでるはずです
対処法はcurlの人がMozillaのソースから変換した信頼された証明書リスト
をダウンロードしてそのパスをENV['SSL_CERT_FILE']に入れるのが個人的な見解としてはオススメです
注意点として、require 'openssl'より前に環境変数を設定しないとダメなようです
信頼された証明書リスト自体がHTTPSで配信されてるので外部コマンドを使わないと安全にダウンロードできません。
curl/wgetが使えるならcurl/wgetでいいのですが
Windowsだと標準では入ってないのでpowershell使う方法を参考までに
# Windows用自動でcacert.pemをダウンロードしてENV['SSL_CERT_FILE']に入れる
certfile = File.expand_path('../cacert.pem', __FILE__)
if !File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE) && !File.exist?(ENV['SSL_CERT_FILE']) && !File.exist?('cacert.pem')
# コマンド長いので適当に分割
psmagic = 'powershell -NoProfile -ExecutionPolicy Bypass -Command'
`#{psmagic} "(new-object net.webclient).DownloadFile('https://curl.haxx.se/ca/cacert.pem','#{certfile}')"`
end
ENV['SSL_CERT_FILE'] = certfile
証明書入れたし解決!……のはずが
これでgithubを含む多くのHTTPSサイトへの接続ができるようになりました。
ではコレを試してみましょう
ruby -rnet/http -e"Net::HTTP.get URI('https://www.rapid-ssl.jp')"
なんと不思議な事にまだエラーがでます。
(エラーのでない環境の場合は信頼された証明書リストが更新されてない可能性があります)
ではコレは無効な証明書のでしょうか?
原因究明
Firefoxでhttps://www.rapid-ssl.jp を開いてみます
あれ? 特に警告やエラーもなく開けてしまいました。
念のため証明書ビューアを開いてみます
GeoTrustをルートに持つ普通の証明書に見えます
opensslで接続して証明書チェーンを表示してみます
openssl s_client -connect www.rapid-ssl.jp:443
Equifax + SSL + Firefoxでググると、
どうやらEquifax Secure Certificate Authority の証明書はRSA1024bitだったため
信頼された証明書リストから削除されたようです。
普通のブラウザはdepth=2のGeoTrust Global CAが信頼された証明書リストに存在するため
そちらをルートとしてdepth=3 Equifax Secure Certificate Authorityを検証しないのかな
応急処置
cacert.pem末尾に
https://www.geotrust.com/resources/root_certificates/certificates/Equifax_Secure_Certificate_Authority.pem
の内容を追加する事でとりあえずエラーはなくなります。
ただしSSL詳しくないので断言できませんが、セキュリティリスクがありそうです。
追記 2016/03/14
CentOS 7 on Vagrantで試したところデフォルト状態だと
/etc/pki/tls/cert.pem (実体は/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem)
にある信頼された証明書リストを用いるようでエラーなく表示されたが、
/etc/pki/tls/cert.pem をhttps://curl.haxx.se/ca/cacert.pem で上書きするとエラーが出るようになりました。