A while ago I wrote a little piece that was ment to safe people from the SSL-certificate problems that might occur using RVM.
For the past year this problem has not gone away and still exists today.
Since I just had to fix it on Windows, I thought I’d also about the solution I discovered there. Sadly Windows is a totally different beast regarding Ruby.
System Requirements
For the following solution I’m assuming that you have installed Ruby using RubyInstaller and are using GitBash as a command-shell, which comes with the Standard Windows GIT Installer. If not I’d suggest you move over to that way of doing things. Otherwise the instructions here will just be hints.
Error when connecting to SSL or HTTPS-destinations
So the error will appear somewhat like this. I’m running a script here that tries to do some geocoding using Google APIs:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
The same script showed no problems on my machine (a Mac/OSX, fixed up with the instructions described in this article).
Since I already knew from my hunt for a solution under OSX that the problem must be in the missing local SSL-certificates that OpenSSL uses to verify other certificates (e.g. Google’s) against.
I couldn’t be sure if OpenSSL was even on that colleagues Windows-machine. So I checked that first. Please note again: Everything is executed in GitBash, which is why - as under OSX/Linux - you’ll always see a $
at the beginning of the commands:
$ openssl
OpenSSL> exit
So OpenSSL is there. Knowing that doesn’t make things exactly easy, cause under OSX it is fixable by reinstalling a locally compiled Ruby, which uses the correct OpenSSL-installation.
We’ll not be able to do that, because there are no build-tools under Windows. So let’s first know more about the problem.
Still a statically linked OpenSSL installation
Using the famous ssl-tools/doctor.rb again, I saw this:
$ ruby doctor.rb accounts.google.com:443
C:/Ruby23-x64/bin/ruby (2.3.1-p112)
OpenSSL 1.0.1l 15 Jan 2015: C:/Users/Justin/Projects/knap-build/var/knapsack/software/x64-windows/openssl/1.0.1l/ssl
SSL_CERT_DIR=""
SSL_CERT_FILE=""
HEAD https://accounts.google.com:443
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
The server presented a certificate that could not be verified:
subject: /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
issuer: /C=US/O=Equifax/OU=Equifax Secure Certificate Authority
error code 20: unable to get local issuer certificate
Possible causes:
`C:/Users/Justin/Projects/knap-build/var/knapsack/software/x64-windows/openssl/1.0.1l/ssl/cert.pem' does not exist
`C:/Users/Justin/Projects/knap-build/var/knapsack/software/x64-windows/openssl/1.0.1l/ssl/certs/' is empty
Little known facts about the RubyInstaller: The guy who compiles it seems to be called Justin
and we can also see how his local projects are organized.
So we have the problem that our installed Ruby’s OpenSSL looks into C:/Users/Justin/Projects/knap-build/var/knapsack/software/x64-windows/openssl/1.0.1l/ssl/
for those certificates.
At first I tried to copy over my OSX’s cert.pem
and the content of my ssl/certs
-directory to a folder like Justin
’s which I created manually. Long story short: That doesn’t work. I can’t actually tell why. But I suppose that my colleague’s user actually can’t access that user Justin
’s folders. Therefore the missing certificates problem stays.
Solved by finding the correct certificate locations
So if copying over SSL-certificates does not help, I thought there must be certificates installed with GitBash since I found out earlier that openssl
is present in GitBash.
So how to find the correct paths for GitBash’s OpenSSL?
$ which openssl
/mingw64/bin/openssl
Reveals that openssl
is actually in /mingw64/bin/openssl
. The directory-name mingw64
points to MinGW which is what GitBash is based on.
So now where are the certificates exactly? Since Linux-distros typically scatter things around a bit, I was a bit anxious that they would be difficult to find.
They were not.
$ cd /mingw64/
user@PC MINGW64 /mingw64
$ ll
total 40
drwxr-xr-x 1 user 197121 0 Aug 18 09:32 bin/
drwxr-xr-x 1 user 197121 0 Aug 18 09:31 doc/
drwxr-xr-x 1 user 197121 0 Aug 18 09:32 etc/
drwxr-xr-x 1 user 197121 0 Aug 18 09:31 lib/
drwxr-xr-x 1 user 197121 0 Aug 18 09:31 libexec/
drwxr-xr-x 1 user 197121 0 Aug 18 09:31 share/
drwxr-xr-x 1 user 197121 0 Aug 18 09:31 ssl/
user@PC MINGW64 /mingw64
$ cd ssl/
user@PC MINGW64 /mingw64/ssl
$ ll
total 260
-rw-r--r-- 1 user 197121 251072 Nov 30 2015 cert.pem
drwxr-xr-x 1 user 197121 0 Aug 18 09:31 certs/
-rw-r--r-- 1 user 197121 10835 Mai 10 08:55 openssl.cnf
So here they are. Lucky punch.
Now the last thing is to tell Ruby to look into /mingw64/ssl
without recompiling.
The doctor.rb
gives the correct hint:
$ ruby doctor.rb accounts.google.com:443
C:/Ruby23-x64/bin/ruby (2.3.1-p112)
OpenSSL 1.0.1l 15 Jan 2015: C:/Users/Justin/Projects/knap-build/var/knapsack/software/x64-windows/openssl/1.0.1l/ssl
SSL_CERT_DIR=""
SSL_CERT_FILE=""
So there is actually two variables that we can use to point Ruby the right direction: SSL_CERT_DIR
and SSL_CERT_FILE
. Note to self: Perhaps even for this thiy might be an alternative solution.
Let’s do that:
$ export SSL_CERT_DIR=/mingw64/ssl/certs
$ export SSL_CERT_FILE=/mingw64/ssl/cert.pem
Then try again:
$ ruby doctor.rb accounts.google.com:443
C:/Ruby23-x64/bin/ruby (2.3.1-p112)
OpenSSL 1.0.1l 15 Jan 2015: C:/Users/Justin/Projects/knap-build/var/knapsack/software/x64-windows/openssl/1.0.1l/ssl
SSL_CERT_DIR="C:/Users/hanse/AppData/Local/Programs/Git/mingw64/ssl/certs/"
SSL_CERT_FILE="C:/Users/hanse/AppData/Local/Programs/Git/mingw64/ssl/cert.pem"
HEAD https://accounts.google.com:443
OK
Works.
The way we did this up to this point will NOT persist over opening a new shell-window. Meaning you’ll have to execute the given commands again, when you open a new shell-window.
Therefore lets add it to our .profile
-file.
$ echo "export SSL_CERT_DIR=/mingw64/ssl/certs" >> .profile
$ echo "export SSL_CERT_FILE=/mingw64/ssl/cert.pem" >> .profile
Problem solved. Carry on please. Nothing to see here.