openssl-win-root:RubyでWindowsの証明書ストアを使う
WindowsでRubyを使っていると、ブラウザでは普通に開けるサイトなのに、HTTPSリクエストが証明書の検証エラーで失敗することがあります。openssl-win-root は、まさにこの問題のための小さなgemです。
最初にお断りしておくと、このgemを作ったのは Stas Ukolov さんで、オリジナルのリポジトリは github.com/ukoloff/openssl-win-root です。最初のリリースは2015年でした。私が関わった部分はごくわずかで、それについては後半で説明します。
問題
RubyのOpenSSLはWindowsの証明書ストアを参照せず、独自のCA証明書を必要とします。RubyInstallerには cacert.pem が同梱されていますが、gemのREADMEにもあるとおり、このファイルは自動では更新されません。中身はそのRubyがビルドされた時点のものなので、新しいルート証明書が含まれていない可能性があります。
一方、Windowsは信頼されたルート証明書のストアを自分で最新の状態に保っています。そこには、グループポリシーなどで会社が配布した証明書も入っています。ただ、Rubyからはそれが見えていないのです。
gemがすること
Windows上でrequireすると、openssl-win-rootは次のことを行います。
- Windowsのシステムストアから信頼されたルート証明書を読み出します(Fiddleを使って
crypt32のAPIを呼び出します)。 - それらをPEMファイルとして、gemのディレクトリ内の
pemフォルダに書き出します。ファイル名は、OpenSSLが証明書ディレクトリに期待する形式になっています。 - そのフォルダをOpenSSLのデフォルトの証明書ストアに追加し、環境変数
SSL_CERT_DIRにも設定します。
ネットワークアクセスは必要ありません。Windows以外のOSでは何もしないので、クロスプラットフォームのプロジェクトに入れておいても問題ありません。
使い方
Windowsのときだけ使うように、Gemfileに追加します。
gem 'openssl-win-root' if Gem.win_platform?
そのあと bundle を実行するか、直接インストールします。
gem install openssl-win-root
HTTPSリクエストを送る前にrequireします。
require 'openssl/win/root'
require 'net/http'
Net::HTTP.get(URI('https://www.ruby-lang.org/')).length
Railsのように Bundler.require を使っているプロジェクトなら、明示的な require は不要です。
書き出された証明書は、Ruby以外からも使えます。次のメソッドが返すフォルダを、SSL_CERT_DIR や openssl コマンドの -CApath オプションに指定してください。
OpenSSL::Win::Root.path
注意点
- 証明書は
requireのたびにgem自身のディレクトリへ書き出されるので、プロセスにはそこへの書き込み権限が必要です。 - Windows Serverでは、証明書ストアがまだルート証明書を有効にしていないことがあります。READMEに書かれている回避策は、そのサイトを一度(Microsoftの)ブラウザで開くか、
win32ole経由でWinHttpRequestを使ってリクエストすることです。理由ははっきりしませんが、これでWindowsが足りないルート証明書を有効にしてくれます。 - 最新のバージョン1.1.2は2023年1月のもので、Windows APIの呼び出しにはFiddleを使っています。実際に使うRubyのバージョンで動作を確認してください。
私の関わり
Ruby 3.2が出たとき、このgemは動かなくなりました。Ruby 3.2で削除された File.exists? を呼んでいたためです。file_exists gemの記事で書いたのと同じ問題です。そこで、一語だけ直すpull requestを出しました。
また、私はRubyGems上でこのgemの2人のオーナーのひとりで、2023年1月に自分のforkからバージョン1.1.2を公開しました。このリリースでの変更はごくわずかです。
File.exists?をFile.exist?に変更し、Ruby 3.2でも動くようにしました。- 使われていなかった拡張ビルドの手順をgemspecから削除しました。
- READMEに、RubyInstallerの
cacert.pemと、上で触れたWindows Serverでの注意点を追記しました。
それ以外の部分、つまりアイデアも実装も、すべてStasさんの仕事です。