MacOS – where is Ruby looking for SSL_CERT_FILE

macosopensslruby

I am trying to find out where Ruby expects to find its openssl CA list. My environment is:

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?

Best Answer

I experienced the same problem under Ubuntu. There seems no longer to be a compiled in default (if it ever had, in theory it could also have been the distributors' work).

I opted to set the path in apache config (my rails app is controlled by passenger).

SetEnv SSL_CERT_DIR /usr/share/ca-certificates/mozilla

It now works.

There is also an SSL_CERT_FILE for a single certificate.

You have to adjust the paths.

Just check the main pages, and this page. Even line 4 over here says so: https://github.com/google/signet/blob/master/lib/signet/ssl_config.rb

I could also have set the path system-wide in /etc/environment and restarted the system.