← Blog

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は次のことを行います。

  1. Windowsのシステムストアから信頼されたルート証明書を読み出します(Fiddleを使って crypt32 のAPIを呼び出します)。
  2. それらをPEMファイルとして、gemのディレクトリ内の pem フォルダに書き出します。ファイル名は、OpenSSLが証明書ディレクトリに期待する形式になっています。
  3. そのフォルダを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

注意点

私の関わり

Ruby 3.2が出たとき、このgemは動かなくなりました。Ruby 3.2で削除された File.exists? を呼んでいたためです。file_exists gemの記事で書いたのと同じ問題です。そこで、一語だけ直すpull requestを出しました。

また、私はRubyGems上でこのgemの2人のオーナーのひとりで、2023年1月に自分のforkからバージョン1.1.2を公開しました。このリリースでの変更はごくわずかです。

それ以外の部分、つまりアイデアも実装も、すべてStasさんの仕事です。

リンク