Ruby SSL Error: certificate verify failed

Facebook
Twitter
LinkedIn

Error certificate

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.

You might also like:   Sending iOS Push Notifications via APNs

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.

Scale performance. Not price. Try Engine Yard today and enjoy our great support and huge scaling potential for 14 days.
Deploy your app for free with Engine Yard.

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.

You might also like:   Rails encrypted credentials on 6.2
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

Want more posts like this?

What you should do now:

Facebook
Twitter
LinkedIn

Easy Application Deployment to AWS

Focus on development, not on managing infrastructure

Deploying, running and managing your Ruby on Rails app is taking away precious resources? Engine Yard takes the operational overhead out of the equation, so you can keep innovating.

  • Fully-managed Ruby DevOps
  • Easy to use, Git Push deployment
  • Auto scaling, boost performance
  • Private, fully-configured Kubernetes cluster
  • Linear pricing that scales, no surprises
  • Decades of Ruby and AWS experience

14 day trial. No credit card required.

Sign Up for Engine Yard

14 day trial. No credit card required.

Book a Demo