9

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?

5
  • I hate to send you elsewhere, but this should get re-asked on the main ruby programming site IMO. stackoverflow.com I don't see any Mac specific items other than that you got the packages using homebrew. Let me know if I can help refine your post on SO.
    – bmike
    Apr 5, 2013 at 12:59
  • @bmike This is a Mac-specific question due to the debugging techniques used. On Linux I would use "strace" and find out what files were being looked for but not found. On Mac I tried to use dtruss the same way but failed. Also, on a stock Linux Ruby I'm guessing this problem won't happen due to tighter integration between SSL and Ruby packages. So this again points to a Mac-specific/Homebrew problem. Thus I don't see any other SO sites that would be as suitable for this question as the Mac site. Apr 5, 2013 at 13:22
  • You are totally right. I was confusing dtruss with dtrace - I need more coffee (and potentially more sleep) apparently. Let me bounty this up to see if we can attract more eyes to your dilemma.
    – bmike
    Apr 5, 2013 at 13:31
  • @EdwardTeach - Are you still using the SSL_CERT_DIR environment variable as a workaround?
    – pingu
    Nov 3, 2013 at 20:22
  • @pingu Yep I'm still using this workaround; no solution yet. Nov 8, 2013 at 3:42

2 Answers 2

4
+50

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.

1
  • 1
    Thanks, but this is for a command-line application and not for Rails. So Apache is not in play. I am currently using the "SSL_CERT_DIR" environment variable as a workaround, though I would rather put the certificate file whereever it is that Ruby expects to find it. Which leads to the question: where does Ruby expect to find it? I can't seem to figure that out. Jan 4, 2013 at 17:51
0

Although I don't figure out where ruby expects to find it, you may want to try and add

export SSL_CERT_FILE=/Users/me/.rbenv/versions/1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/ssl_certs/ca-bundle.pem

to ~/.bash_profile to make it work with the command line tools (note the 'export' in front of SSL_CERT_FILE, on Windows systems (off topic, I know) this would be 'set')

1
  • 1
    I would like something more robust than setting environment variables, thus the question. Mar 5, 2013 at 23:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .