Technology Musings

ActiveMerchant, Authorize.Net Root Certificates, and Linux SSL

JB

This week, Authorize.net is starting its rollout of new server certificates, signed by a new certificate authority - Entrust.  If you are using ActiveMerchant, this could break your stuff!  It may or may not affect newer versions of ActiveMerchant - I don't know, I only have sites using old versions (like 1.18).  So, even if it breaks, the solution may be different depending on your version of ActiveMerchant.  Still, I'll try to keep the info detailed enough that you can find the solution yourself.

First, the problem.  This affects you if, when ActiveMerchant tries to connect to Authorize.net, you receive the error:

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

Note that you may not get this error when trying to connect to Authorize.net via manual Ruby code, but only via ActiveMerchant.

The reason for this is ActiveMerchant maintains its own list of Root CAs!

Therefore, to fix, you have to, (a) make sure that the new Root CAs for authorize.net are stored in your server's root CA list, and (b) make sure that ActiveMerchant is using your server's list rather than its own.  For good measure, you can also copy ActiveMerchant's CA list to yours.

So, first, to add the Entrust root CAs to your Linux server (assuming it is a fairly recent CentOS-based distro), do the following as root:

  1. Enable the trust infrastructure with the following command:update-ca-trust enable
  2. Go to /etc/pki/ca-trust/source/anchors
  3. Grab the .cer files from https://www.entrust.net/downloads/root_request.cfm (just right-click on the links, copy the URLs, and download them to the current directory with wget)
  4. Go to wherever the gem files for your project are, and find the active_utils gem.  In the lib/certs directory, there is a file called cacert.ca or something like that.  Copy that to /etc/pki/ca-trust/source/anchors
  5. Now run the following command to update your CA list:
    update-ca-trust

Now you have all of the certs installed.  Now we need to tell ActiveMerchant to use your own certs rather than its internal list.  However, again, this is in the active_utils gem, not the activemerchant gem.  Within the gem, find the file called lib/active_utils/common/connection.rb.  Now look for a function called configure_ssl.  Copy that function to your clipboard.

Now create a file in your own project called config/initializers/active_merchant_pem_fix.rb (the name doesn't matter as long as it is in config/initializers).  In this file you need to have:

module ActiveMerchant
  class Connection
    # Paste the configure_ssl function you copied from lib/active_utils/common/connection.rb here.
  end
end

Now, there will be a line that says something like this:

        http.ca_file = File.dirname(__FILE__) + '/../../certs/cacert.pem'

This is the offending line!!!  Comment that sucker out!!!

For my version of ActiveMerchant, this is what my file looks like:

   def configure_ssl(http)
      return unless endpoint.scheme == "https"

      http.use_ssl = true

      if verify_peer
        http.verify_mode = OpenSSL::SSL::VERIFY_PEER
        # http.ca_file = File.dirname(__FILE__) + '/../../certs/cacert.pem'
      else
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      end
    end

Now that you have the updated root CA on your server, and ActiveMerchant is using your server's list rather than your own, you are all set!