skip to Main Content

There are a ton of posts about this. I have looked at so many of them. Zero of the fixes seem to work.

(main)> PayPal::SDK::Subscriptions::Plan.all
Request[post]: https://api.sandbox.paypal.com/v1/oauth2/token
Request.body=grant_type=client_credentials  request.header={"User-Agent"=>"PayPalSDK/PayPal-Subscriptions-Ruby-SDK 0.3.1 (paypal-sdk-core 1.7.4; ruby 2.6.6p146-x86_64-linux;OpenSSL 1.1.1d  10 Sep 2019)", "Content-Type"=>"application/x-www-form-urlencoded", "Authorization"=>"Basic xxx"}
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate)
from /usr/local/lib/ruby/2.6.0/net/protocol.rb:44:in `connect_nonblock'

I have tried rvm 2.6.6, 2.7.0, and Debian Buster system ruby.

I followed all of these:
https://bundler.io/v2.0/guides/rubygems_tls_ssl_troubleshooting_guide.html#troubleshooting-certificate-errors

I ran the automated SSL check and everything is roses:
https://bundler.io/v2.0/guides/rubygems_tls_ssl_troubleshooting_guide.html#automated-ssl-check

root@19ab47f15632:/usr/src/app# curl -Lks 'https://git.io/rg-ssl' | ruby
Here's your Ruby and OpenSSL environment:

Ruby:           2.6.6p146 (2020-03-31 revision 67876) [x86_64-linux]
RubyGems:       3.0.3
Bundler:        2.1.2
Compiled with:  OpenSSL 1.1.1d  10 Sep 2019
Loaded version: OpenSSL 1.1.1d  10 Sep 2019
SSL_CERT_FILE:  /usr/lib/ssl/cert.pem
SSL_CERT_DIR:   /usr/lib/ssl/certs

With that out of the way, let's see if you can connect to rubygems.org...

Bundler connection to rubygems.org:       success ✅
RubyGems connection to rubygems.org:      success ✅
Ruby net/http connection to rubygems.org: success ✅

Hooray! This Ruby can connect to rubygems.org. You are all set to use Bundler and RubyGems. 👌

I tried gem update --system, bundler is updated.

I tried curling the new CA to the location of ruby’s default SSL file:

curl -fsSL curl.haxx.se/ca/cacert.pem -o "$(ruby -ropenssl -e 'puts OpenSSL::X509::DEFAULT_CERT_FILE')"

I checked that my system’s time was accurate (it’s accurate to UTC).

I have no earthly idea what to do from here. The PayPal SDK subscription gem is using net/http under the covers because it relies on the core PayPal SDK gem. I tried increasing the loglevel to DEBUG but it prints out no additional details as it appears to fail in the same exact place, and I can’t figure out where that failure actually is.

I’m at a loss. Short of disabling SSL verification, I don’t know what to do. Is there some way to get more traceback / more error here to troubleshoot further? Using net/http directly against the PayPal API works fine (no SSL error). So it’s something that happens after the initial request

6

Answers


  1. I’m leaving this here, but the answer by RidingRails is what I consider "correct". It is the proper solution to dealing with this longer-term, although the real solution is to move to PayPal’s newer gem.

    My answer below is to help you quickly get PayPal working again without having to push out an update to your code.


    This is really ugly, as PayPal packages the certs with their gem. To get up and running, you need to find the gem in your bundle and specifically find the file "paypal.crt". At the end, you need to add the two certificates that are missing. I am not going to copy/paste them here, but they are easily found. Actually, they were already on my Ubuntu system in /etc/ssl/certs:

    DigiCert_Global_Root_G2.pem

    DigiCert_High_Assurance_EV_Root_CA.pem

    PayPal provides links here:

    https://www.paypal.com/va/smarthelp/article/discontinue-use-of-verisign-g5-root-certificates-ts2240

    Steps to fix:

    1. Find the paypal.crt file in the version of the gem that you are using. Here’s what that looked like for me:

      cd app/production/shared/bundle

      find . -name paypal.crt

      At this point, I had a file in version 1.7.3 and 1.7.4 of the gem. I’m using the 1.7.4 version, so I edited that file.

    2. Add those two certificates to the bottom. You should put the name of the certificate on a line, a line with "=" repeated to make a nice separator, and then the entire certificate including the BEGIN and END lines.

    3. Restart your application.

    This is not a long-term solution but will get you back running quickly. Long term – upgrade to the new gem.

    Login or Signup to reply.
  2. Here is what we ended up doing on my team.

    We added the 2 certs that Michael mentioned in

    config/api.paypal.com.crt
    
    

    Then in paypal.yml

     ssl_options:
        ca_file: config/api.paypal.com.crt
    

    We left the Gem as is. Initially we tore through the gem looking for answers but ultimately we left the gem as is and added the crt and updated yaml as show above.

    Login or Signup to reply.
  3. Its possible to fix this by using the server’s own CA file.

    Try setting ssl_options: { ca_file: nil }.

    This causes the paypal.crt CA file bundled with the paypal-sdk gem to be ignored.

    For apps using PayPal::SDK.configure(…)

    PayPal::SDK.configure(
      mode: ...,
      client_id: ...,
      client_secret: ...,
    
      # Deliberately set ca_file to nil so the system's Cert Authority is used,
      # instead of the bundled paypal.crt file which is out-of-date due to:
      # https://www.paypal.com/va/smarthelp/article/discontinue-use-of-verisign-g5-root-certificates-ts2240
      ssl_options: { ca_file: nil }
    )
    

    For apps using a YAML config file

    In config/paypal.yml or wherever your config file is located:

    ssl_options:
      ca_file: null
    
    Login or Signup to reply.
  4. If you don’t use PayPal::SDK.configure. In paypal.yml add

      ssl_options:
        ca_file: null
    
    Login or Signup to reply.
  5. As PayPal has changed TLS, so the easiest way (fastest) was to resolve as monkey patch. This patch says to use all default settings

    module PayPal::SDK::Core
      module Util
        module HTTPHelper
          def configure_ssl(http)
            http.tap do |https|
              https.use_ssl = true
              https.verify_mode = OpenSSL::SSL::VERIFY_PEER
              add_certificate(https)
            end
          end
        end
      end
    end
    
    Login or Signup to reply.
  6. A similar but slightly less invasive solution than @kritik

    module PayPal::SDK::Core::Util::HTTPHelper
      def default_ca_file
        nil # packaged CA file was out of date, use the system file
      end
    end
    

    This still allows you to change other SSL settings in initializers and only removes the default CA file.

    You want to create a file in config/initializers and put the above code in it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search