3

I want to access Twitter and upon using Net::HTTP's POST function I get this error.

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

Yes I know everyone gets this message.

Here are viable solutions I found.

First, manually set the cert file:

#! /usr/bin/env ruby
require 'net/https'
require 'uri'
 
uri = URI.parse(ARGV[0] || 'https://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == "https"
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.ca_file = File.join(File.dirname(__FILE__), "cacert.pem")
end
http.start {
  http.request_get(uri.path) {|res|
    print res.body
  }
}

This was provided by Ariejan de Vroom: https://www.kabisa.nl/tech/ruby-and-ssl-certificate-validation/

Many people have given a similar answer to this. This did not work for me.

Then I found something that brought me along the right path. This guy Mislav Marohnić https://mislav.net/2013/07/ruby-openssl/ nailed the area of concern. It has to do with OpenSSL::X509::DEFAULT_CERT_FILE and OpenSSL::X509::DEFAULT_CERT_DIR. Which turns out are hard coded into my Ruby 1.9.3 through it's source code. Mislav gives his workaround like so:

require 'https'

http = Net::HTTP.new('example.com', 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER

http.cert_store = OpenSSL::X509::Store.new
http.cert_store.set_default_paths
http.cert_store.add_file('/path/to/cacert.pem')
# ...or:
cert = OpenSSL::X509::Certificate.new(File.read('mycert.pem'))
http.cert_store.add_cert(cert)

I dabbled around with this and I would always get this error:

OpenSSL::X509::StoreError: cert already in hash table

Bah humbug and all that stuff!

I should also mention he has written a script that should help debug what's going on. It may help you, but not in my case. The link is on his page.

I also set

ENV['SSL_CERT_FILE']
ENV['SSL_CERT_DIR']

in my ruby code without success.

Then I proceeded to set the environment variables in windows by Start -> Control Panel -> System -> Advanced System Settings -> Advanced(tab) -> Environment Variables -> System variables New and added the SSL_CERT_DIR and SSL_CERT_FILE. This didn't work either.

And the certified gem didn't work for me... https://github.com/stevegraham/certified

So I will now provide you with my hack answer for all you Windows 7 users out there below.

Dave Powers
  • 2,051
  • 2
  • 30
  • 34
6ft Dan
  • 2,365
  • 1
  • 33
  • 46
  • If you know how the inner code is written for OpenSSL::X509 I suppose you could overwrite the code with your own ruby functions/methods/classes/modules/etc. It's a project. – 6ft Dan Apr 24 '14 at 08:01

4 Answers4

7

So I dug around and basically stared at the hard coded path of the certs. By typing this at the command line

ruby -ropenssl -e 'puts OpenSSL::X509::DEFAULT_CERT_FILE'

I got the following...

c:/Users/Luis/Code/openknapsack/knap-build/var/knapsack/software/x86-windows/openssl/1.0.0k/ssl/cert.pem

So my solution was to first download cacert.pem from http://curl.haxx.se/ca/cacert.pem to c:\ . Then open up Windows Control Panel -> Administrative Tools -> Windows PowerShell Modules. Then I proceeded to type out:

cd \
cd users
mkdir Luis
cd Luis
mkdir Code
cd Code
mkdir openknapsack
cd openknapsack
mkdir knap-build
cd knap-build
mkdir var
cd var
mkdir knapsack
cd knapsack
mkdir software
cd software
mkdir x86-windows
cd x86-windows
mkir openssl
cd openssl
mkdir 1.0.0k
cd 1.0.0k
mkdir ssl
cd ssl
cp c:\cacert.pem .\cert.pem

And now everything works! Yes it's a cheap hack and it's ugly. But now both you and I can get back to doing serious coding and not worry about pesky problems.

I know it's not a great fix, but it's the only thing that worked for me, and it should for you too.

If some one would like to write a PowerShell script to auto install the cert file into this directory then you could more easily deploy your Ruby project to Windows 7. Just a thought.

By the way, you can duplicate this process for any operating system should the need arise. Just find the path the cert file belongs in with:

ruby -ropenssl -e 'puts OpenSSL::X509::DEFAULT_CERT_FILE'

And be sure to rename the file as it appears in the ouput!

6ft Dan
  • 2,365
  • 1
  • 33
  • 46
  • NOTE: Twitter themselves recommend getting your certs from the original source... such as Verisign. This link ... http://curl.haxx.se/ca/cacert.pem is the source that's largely propagated over the internet. There may be a trust issue. But then if you wan to get technical, who's Verisign right? ;-) – 6ft Dan Apr 24 '14 at 08:14
  • Where as this is the solution that does work... for some reason the Heroku-Toolbelt won't work with any of these fixes for me. But that belongs as a different question. Also Heroku-Toolbelt provides it's own copy of Ruby. – 6ft Dan Apr 27 '14 at 21:36
  • should this also work on Windows 8? Like you, I have tried all the various solutions to the problem, but none seem to work for me. The path in my case is slightly different to yours, but I have followed the same process, but still get the SSL Error. Any thoughts? Also, which version of Ruby were you working with? I am trying to get ruby 2.0.0p481 (2014-05-08) [x64-mingw32] to work. – Gary Ewan Park Sep 10 '14 at 20:13
  • 1
    The hardcoded path is a failure in design of OpenSSL, which takes the build-time information and don't allow relative paths to be used. See this thread for details: https://groups.google.com/d/topic/rubyinstaller/DVIDvs7xKC0/discussion – Luis Lavena Sep 10 '14 at 23:18
  • I believe I was using the latest Ruby 2.1.2 on a 64bit system. I'm not too sure about your path and system. But I would advise you treat it as being very picky about path and the file/filename you provide. My thoughts are check the path to match, the file name to match, file and folder permissions, and that the content must be what it's expecting. Beyond that is a puzzle to me. This solution worked for my Twitter issue. I believe there was another instance where I still go the same error... I'm thinking it was with Heroku client but I don't remember. – 6ft Dan Sep 11 '14 at 05:17
  • Thank you for getting back to me anyway. I have tried all the solutions that are out there, but I am yet to find a solution. I will keep digging, and if I find out anything, I will post back here. – Gary Ewan Park Sep 11 '14 at 06:37
  • Luis, thank you for your help. I have read through that forum thread, but I am still at a loss as to what is going on. I can get some requests to an https address to work, namely google, but as soon as I try to access flickr, I still get the same SSL Error. Any thoughts about what I need to do to handle Flickr specifically? Thanks! – Gary Ewan Park Sep 11 '14 at 06:48
  • FYI, at least on Windows 10, you can do the whole mkdir as one command. It'll create parent directories as necessary. – fxtentacle Mar 09 '20 at 21:22
0

If you are facing this problem then download http://curl.haxx.se/ca/cacert.pem and export to your bash_profile

export SSL_CERT_FILE=PATH_TO_THe_DOWNLOADED_FILE/cacert.pem

This works for me :-)

Babu Rao
  • 71
  • 1
  • 4
0

If you already have downloaded Git for Windows, it has a CA-bundle which you can use.

Set SSL_CERT_DIR to the location where Git was installed, which will be C:\Program Files\Git\mingw32\ssl\certs (if on a 32-bit system) or C:\Program Files\Git\mingw64\ssl\certs (if on a 64-bit system). Also, you will need to set SSL_CERT_FILE to C:\Program Files\Git\mingw32\ssl\cert.pem (if on a 32-bit system) or C:\Program Files\Git\mingw64\ssl\cert.pem (if on a 64-bit system).

Blake Pettersson
  • 8,927
  • 3
  • 27
  • 36
0

just found this made by @photonstorm. Worked for me:

1 - Download R1 GlobalSign Root Certificate: https://secure.globalsign.net/cacert/Root-R1.crt

2- Save it somewhere local, so you can easily access it from a command prompt. It should save with the name Root-R1.crt.

3- Convert to a PEM file. Here is where the post above didn't work for me, but this did: openssl x509 -in Root-R1.crt -out mycert.pem -outform PEM -inform DEF

4- Copy the new mycert.pem file that it creates into: D:\Ruby23-x64\lib\ruby\2.3.0\rubygems\ssl_certs <-- this path will obviously be different depending on where you've got Ruby installed!

Felipe Maion
  • 336
  • 1
  • 12