OpenSSL まわりでちょっとハマったのでメモ。 こんな Ruby のコードを動かすと環境によって warning になったりエラーになったりする。
require 'faraday' ssl_opts = {ca_file: OpenSSL::X509::DEFAULT_CERT_FILE} Faraday::Connection.new('https://tmtms.net', ssl: ssl_opts).get puts 'OK'
環境1:
warning になるが成功する。
% ruby -w hoge.rb /usr/local/lib/ruby/3.1.0/net/http.rb:1081: warning: can't set verify locations OK
環境2:
エラーになる。
% ruby -w hoge.rb /usr/lib/ruby/3.0.0/net/http.rb:1030:in `initialize': SSL_CTX_load_verify_file: system lib (Faraday::SSLError) from /usr/lib/ruby/3.0.0/net/http.rb:1030:in `new' from /usr/lib/ruby/3.0.0/net/http.rb:1030:in `connect' from /usr/lib/ruby/3.0.0/net/http.rb:970:in `do_start' from /usr/lib/ruby/3.0.0/net/http.rb:959:in `start' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:112:in `request_with_wrapped_block' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:102:in `perform_request' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:66:in `block in call' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/adapter.rb:45:in `connection' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:65:in `call' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/request/url_encoded.rb:25:in `call' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/rack_builder.rb:153:in `build_response' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/connection.rb:445:in `run_request' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/connection.rb:200:in `get' from hoge.rb:3:in `<main>' /usr/lib/ruby/3.0.0/net/http.rb:1030:in `initialize': SSL_CTX_load_verify_file: system lib (OpenSSL::SSL::SSLError) from /usr/lib/ruby/3.0.0/net/http.rb:1030:in `new' from /usr/lib/ruby/3.0.0/net/http.rb:1030:in `connect' from /usr/lib/ruby/3.0.0/net/http.rb:970:in `do_start' from /usr/lib/ruby/3.0.0/net/http.rb:959:in `start' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:112:in `request_with_wrapped_block' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:102:in `perform_request' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:66:in `block in call' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/adapter.rb:45:in `connection' from /var/lib/gems/3.0.0/gems/faraday-net_http-3.0.2/lib/faraday/adapter/net_http.rb:65:in `call' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/request/url_encoded.rb:25:in `call' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/rack_builder.rb:153:in `build_response' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/connection.rb:445:in `run_request' from /var/lib/gems/3.0.0/gems/faraday-2.7.2/lib/faraday/connection.rb:200:in `get' from hoge.rb:3:in `<main>'
Faraday 使わずに OpenSSL だけで再現させるとこんな感じ。
require 'openssl' sock = Socket.tcp('tmtms.net', 443) store = OpenSSL::X509::Store.new store.set_default_paths ctx = OpenSSL::SSL::SSLContext.new ctx.set_params(ca_file: OpenSSL::X509::DEFAULT_CERT_FILE, cert_store: store) tls = OpenSSL::SSL::SSLSocket.new(sock, ctx) tls.hostname = 'tmtms.net' tls.sync_close = true tls.connect puts 'OK'
環境1:
% ruby -w hoge.rb hoge.rb:7: warning: can't set verify locations OK
環境2:
% ruby -w hoge.rb hoge.rb:7:in `initialize': SSL_CTX_load_verify_file: system lib (OpenSSL::SSL::SSLError) from hoge.rb:7:in `new' from hoge.rb:7:in `<main>'
エラーになるのは、Ruby の openssl ライブラリが 3.0 で、かつ OS の OpenSSL ライブラリ(libssl)が 3.x で、OpenSSL::X509::DEFAULT_CERT_FILE
のファイルが存在していない場合。たとえば、Ubuntu 22.04 とか。
Ubuntu では以前から OpenSSL::X509::DEFAULT_CERT_FILE
が存在ないファイル(/usr/lib/ssl/cert.pem
)になってるんだけど、Ubuntu 22.04 で libssl が 3.0 になって発生するようになった。
libssl の問題かと思ったんだけど、調べてみたら Ruby の openssl の方だった。
#ifdef HAVE_SSL_CTX_LOAD_VERIFY_FILE if (ca_file && !SSL_CTX_load_verify_file(ctx, ca_file)) ossl_raise(eSSLError, "SSL_CTX_load_verify_file"); if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path)) ossl_raise(eSSLError, "SSL_CTX_load_verify_dir"); #else if(ca_file || ca_path){ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) rb_warning("can't set verify locations"); } #endif
ca_file
が読めないときに OpenSSL 3.x (HAVE_SSL_CTX_LOAD_VERIFY_FILE
が真) だと SSLError 例外になるけど、OpenSSL 1.x だと warning になる。
ca_file
に存在しないファイルを指定するのが悪いんだけど、Ubuntu では OpenSSL::X509::DEFAULT_CERT_FILE
が存在してないファイルというところが罠。
デフォルトでいいなら ca_file
は指定しない方がいいんだろうな。