Ruby SSL Error: certificate verify failed

  

Ruby SSL Error

When working on your Rails app or when installing gems, you might get this Ruby SSL error:

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

This post explains what the error is and provides some possible solutions.

This error, as you can see on the message, has something to do with SSL and certificates. First, let's discuss why you need to use SSL. When your app connects to a 3rd-party API or when the gem command connects to rubygems.org, you need to use the HTTPS version e.g. https://api.example.com or https://rubygems.org.

If you don't use the HTTPS version and use the non-secure HTTP version, the data you receive can be altered by anyone on the path from the user to your server. And you wouldn't know it was altered. If you request a gem from http://rubygems.org from your laptop, and say you're using public WiFi, the WiFi provider can give you a modified gem.

In short, you should always use HTTPS, which is secured using an SSL certificate.

Secure Sockets Layer or SSL is the security protocol that provides secure communication between two machines. In the cases above, between the machines of your app and the 3rd-party API or between your machine and the rubygems.org machine.

How does SSL work? Machine 1 initiates the connection and looks at the SSL certificate of machine 2. This certificate contains numbers that machine 1 will use to encrypt their communication. This is a simple and incomplete description of the whole process. We'll not go into details on how the encryption or the SSL handshake works.

The encrypted communication makes sure that what you send to the server and vice versa isn't altered. However, the initial connection is done in clear text since it comes before encrypted communication is set up. So, while you're sure that communication is secure, how do you know you're talking to the correct server?

SSL certificates are signed by a Certificate Authority. The signature tells you that the certificates are real. The Certificate Authorities are also signed for the same reason. This can go on until you reach a root certificate. This setup creates a chain of trust. As long as you trust the root certificate, you can trust the certificate of the website you're communicating with.

The root certificates are installed on your machine and there's an implied trust that the existing certificates are valid.

When machine 1 connects to machine 2, machine 1 has to verify that the certificate is real. If this verification fails, you'll get the error certificate verify failed.

When verification fails, it can mean one of two things. Either your machine doesn't have the correct root certificates or you're connecting to a URL that has a problem with the certificates.

If it's the latter, the best (if not only) option is to ask the 3rd-party site to fix their certificates. The solutions mentioned below are for the first scenario where the problem is on your machine.

The Problem

The error certificate verify failed happens when a machine can't verify the certificate of the machine it's connecting to. What does this mean in practice?

When developing Rails applications, this can happen when

  • you run gem install or bundle install. Your machine needs to connect to the gem sources like https://rubygems.org
  • your app connects to a 3rd-party API like GitHub API
  • you use a gem like ActiveMerchant to connect to payment sites like PayPal

Solutions

Update CA certificates

The correct solution depends on which code connects to an HTTPS URL. The first thing you can try is to update the root certificates on your machine.

If you're using Linux, you can use your package manager to update the CA certificates.

apt-get update ca-certificates
yum update ca-certificates

On RVM on OSX, you can run

rvm osx-ssl-certs update all

If you don't use RVM, you can extract the certificates from Apple's Keychain yourself.

cert_file="$( openssl version -d | awk -F'"' '{print $2}' )/cert.pem"
mkdir -p "${cert_file%/*}"
security find-certificate -a -p /Library/Keychains/System.keychain > "$cert_file"
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain >> "$cert_file"

For more information, check out the SSL documentation.

Update Gems

In some cases, updating the system CA certificates doesn't work because some gems specify their own CA certificates. ActiveMerchant provides its own cacert.pem at https://github.com/activemerchant/active_merchant/tree/master/lib/certs. If your errors come from ActiveMerchant, try updating the gem to the latest version.

rubygems.org in 2014 had to update their SSL certificate. RubyGems also provides CA certificates and a newer RubyGems version had to be manually installed to get it working again. You can read more about this issue in the Ruby Gems guides here. This is unlikely to happen again but if you're having issues with RubyGems, check your system certificates first then the RubyGems issues.

Bad Solutions

There are other solutions to this error but are not considered best practices.

Turn off verification

You can turn off verification when using net-http. However, this isn't recommended.

http.verify_mode = OpenSSL::SSL::VERIFY_NONE
Use http version

When you encounter the certificate verify failed error when installing gems, some suggest using http://rubygems.org as the source instead of https://rubygems.org. This is bad as you're installing gems in clear text. Turning off verification is better than using clear text because even without verification, you're still using encrypted communication. But make no mistake, both of these solutions aren't recommended.

Set SSL_CERT_FILE

This isn't a bad solution if you know what you're doing. However, there are a lot of solutions out there that suggest downloading CA certificates to your machine and setting the SSL_CERT_FILE environment variable to its location.

The problem with this approach is you don't know if you can trust the CA certificates you're downloading. In some cases, the CA certificates are even downloaded in clear text. Double trouble if you ask me.

Summary

The Ruby OpenSSL error certificate verify failed means your code can't verify that the SSL certificate of the website or API you're connecting to is the real one. It's important to solve this issue correctly to keep your communication secure.

If you are interested on security issues, make sure to check out this Engine Yard's blog section

Start a Free Trial:

Engine Yard is so much more than just a Ruby on Rails PaaS platform. But don't just take our word for it. Request a free trial of Engine Yard platform today, and one of our Engineers will be in contact within one business day to get you going.

START MY TRIAL!
development-user.png

Related posts

Take Out The Papers And The Trash

August 17, 2018

How to clean and clear large tables in MySQL

From time to time our data team gets requests for

Read More

Ruby on Rails vs PHP

May 16, 2018

There’s more than one way to build a web application. No matter what type of application you are

Read More

What to Look for When Considering Application Hosting

May 8, 2018

Cloud computing has made hosting business-critical applications easier and less expensive.

Read More

Christopher Rigor

 
Christopher Rigor is a Senior Technical Evangelist at Engine Yard. He’s a long time Rails user, system administrator, and recently became a contributor of RailsInstaller. Previously, he was the DevOps Support Manager for Asia-Pacific at Engine Yard.
Find me on:

Comments

Subscribe Here!