I am trying to find out where Ruby expects to find its openssl CA list. My environment is:
- Mac OS 10.7.5
- OpenSSL from homebrew
- Rbenv from homebrew
- Ruby 1.9.3, installed using rbenv and CONFIGURE_OPTS="--with-openssl-dir=`brew --prefix openssl`"
Confirmation that my Ruby is using homebrew OpenSSL (note: /Users/me
is a redacted version of the user directory in all examples below):
$ otool -L /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/x86_64-darwin11.4.2/openssl.bundle
/Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/x86_64-darwin11.4.2/openssl.bundle:
/usr/local/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
To test, I have written the following script:
#!/usr/bin/env ruby
require 'net/https'
https = Net::HTTP.new('encrypted.google.com', 443)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.request_get('/')
puts 'success!'
If I manually specify the path to my SSL_CERT_FILE, it works:
$ SSL_CERT_FILE=/Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/ssl_certs/ca-bundle.pem ./test_ssl.rb
success!
If not, it breaks:
$ ./test_ssl.rb
/Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/net/http.rb:799:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/net/http.rb:799:in `block in connect'
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/timeout.rb:54:in `timeout'
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/timeout.rb:99:in `timeout'
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/net/http.rb:799:in `connect'
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/net/http.rb:755:in `do_start'
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/net/http.rb:744:in `start'
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1284:in `request'
from /Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/net/http.rb:1195:in `request_get'
from ./test_ssl.rb:6:in `<main>'
As an aside, I am already aware that I could manually check various paths for the CA file from my script. However the script is a test of similar net/http operations within Ruby gem "faraday" on my system. I do not want to hack the faraday gem to work around this problem.
So I used dtruss to look for stat commands and see if any of them are attempted CA file lookups:
$ sudo dtruss -f -t stat64 ./test_ssl.rb
PID/THRD SYSCALL(args) = return
96741/0x6b4be4: stat64("/usr/lib/dtrace/libdtrace_dyld.dylib\0", 0x7FFF6A9BE810, 0x7FFF6A9BF700) = 0 0
96741/0x6b4be4: stat64("/usr/lib/libSystem.B.dylib\0", 0x7FFF6A9BE650, 0x7FFF6A9BF4D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libcache.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libcommonCrypto.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libcompiler_rt.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libcopyfile.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libdispatch.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libdnsinfo.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libdyld.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libkeymgr.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/liblaunch.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libmacho.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libmathCommon.A.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libquarantine.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libremovefile.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_blocks.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_c.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_dnssd.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_info.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_kernel.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_network.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_notify.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libsystem_sandbox.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libunc.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libunwind.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/system/libxpc.dylib\0", 0x7FFF6A9BE350, 0x7FFF6A9BF1D0) = 0 0
96741/0x6b4be4: stat64("/AppleInternal\0", 0x7FFF6A9BEFF8, 0x0) = -1 Err#2
96741/0x6b4be4: stat64("/usr/lib/libstdc++.6.dylib\0", 0x7FFF6A9BE640, 0x7FFF6A9BF4C0) = 0 0
96741/0x6b4be4: stat64("/usr/lib/libc++abi.dylib\0", 0x7FFF6A9BE550, 0x7FFF6A9BF3D0) = 0 0
None of the file stats look like a CA file lookup! Am I using dtruss correctly? Is there some other way for me to find out where the CA certificates file should be placed?