Search code examples
rubymacosopenssl

Error Certificate verify failed (certificate has expired)): in Mac OSX 11.6.1 and ruby 3.0.3


I have a ruby on rails webapp sending requests to a third party SOAP API. When I request like:

endpoint = "https://www.booking-manager.com/cbm_web_service2/services/CBM?wsdl"
        client = Savon.client(wsdl: endpoint, 
                              #log_level: :info,
                              log_level: :debug,
                              log: true,
                              pretty_print_xml: true,
                              open_timeout: 300, 
                              read_timeout: 300)
      message = {'in0' => xxx, 
               'in1' => 'xxxx', 
               'in2' => 'xxx'}
response = client.call(:get_bases, message: message) 

I´m getting next error:

HTTPI::SSLError (SSL_connect returned=1 errno=0 state=error: certificate verify failed (certificate has expired)):

The webapp is running under:

Mac OSX Big Sur 11.6.1
ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-darwin20]

I have this issue for weeks and I don´t know what else to do. According to many posts, I tested

openssl s_client -showcerts -host valid-isrgrootx1.letsencrypt.org -port 443

and got:

CONNECTED(00000005)
depth=1 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=10:certificate has expired
notAfter=Sep 30 14:01:15 2021 GMT
verify return:0
depth=1 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=10:certificate has expired
notAfter=Sep 30 14:01:15 2021 GMT
verify return:0
depth=3 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=10:certificate has expired
notAfter=Sep 30 14:01:15 2021 GMT
verify return:0
---
Certificate chain
 0 s:/CN=origin.letsencrypt.org
   i:/C=US/O=Let's Encrypt/CN=R3

so, according to this: https://community.letsencrypt.org/t/help-thread-for-dst-root-ca-x3-expiration-september-2021/149190/970

I manually updated the file /etc/ssl/cert.pem to remove the DST Root CA X3 certificate. After that, I think that I moved one step forward. When running:

openssl s_client -showcerts -host valid-isrgrootx1.letsencrypt.org -port 443

Now, I don´t get the error and I think looks good:

CONNECTED(00000005)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = origin.letsencrypt.org
verify return:1
---
Certificate chain
 0 s:/CN=origin.letsencrypt.org
   i:/C=US/O=Let's Encrypt/CN=R3

However, unfortunately the error in my ruby app still remains the same. According to this, I understand ruby is running an openssl that is not getting the information from this certs. I´m not skilled with this at all and don´t know if this makes sense.

I just read other posts and checking openssl version

I got LibreSSL 2.8.3

which openssl
/usr/bin/openssl

In my /usr/local/opt I see three openssl versions folders:

  • openssl
  • openssl@1.1
  • openssl@3

I updated my .zshrc file and now openssl version notifies

OpenSSL 3.0.1 14 Dec 2021 (Library: OpenSSL 3.0.1 14 Dec 2021)

and ruby seems to be using:

ruby -ropenssl -e "puts OpenSSL::OPENSSL_VERSION"
OpenSSL 1.1.1l  24 Aug 2021

I´m aware that the ruby OpenSSL version is 1.1.1 and the system is running 3.0.1. I don´t know how to update ruby to run OpenSSL 3.0.1, although I´m not sure if this can be the root problem. I´m lost at this point.

UPDATE I think I´m narrowing the issue down. My guess is that Ruby is using a version of openSSL, in this case 1.1.1, that is pointing to /Users/Rober/.rbenv/versions/3.0.3/openssl/ssl/certs bundler instead of pointing to /etc/ssl/cert.pem

irb
irb(main):001:0> require "openssl"
=> true
irb(main):002:0> puts OpenSSL::OPENSSL_VERSION
OpenSSL 1.1.1l  24 Aug 2021
=> nil
irb(main):003:0> puts "SSL_CERT_FILE: %s" % OpenSSL::X509::DEFAULT_CERT_FILE
irb(main):004:0> puts "SSL_CERT_DIR: %s" % OpenSSL::X509::DEFAULT_CERT_DIR
SSL_CERT_FILE: /Users/Rober/.rbenv/versions/3.0.3/openssl/ssl/cert.pem
SSL_CERT_DIR: /Users/Rober/.rbenv/versions/3.0.3/openssl/ssl/certs

This file /Users/Rober/.rbenv/versions/3.0.3/openssl/ssl/cert.pem , unfortunately when I check the content is in the format:

-----BEGIN CERTIFICATE-----
certificate chain
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

I mean, in this file /etc/ssl/cert.pem I could read some readable headers that helped identify the certificate to remove, but in this case the headers are not present, so it´s not possible.

I think that I probably just need to config ruby to run openssl to point to this file /etc/ssl/cert.pem. According to mamy posts, I just added export SSL_CERT_FILE="/etc/ssl/cert.pem" to my .zshrc file, but still getting

OpenSSL::X509::DEFAULT_CERT_FILE
SSL_CERT_FILE: /Users/Rober/.rbenv/versions/3.0.3/openssl/ssl/cert.pem

SOLUTION Thanks to @JanGaraj that provided the right solution to this problem in my other production post: SSL_connect returned=1 errno=0 state=error: certificate verify failed in ruby and Ubuntu 14.04

Just to summarize, apart from the points depicted above, I just needed to update my web service request specifying my ca-certificates file, like: Savon.client(ssl_ca_cert_file: "/etc/ssl/certs/ca-certificates.crt ")


Solution

  • The solution to this question was provided in another post by @jangaraj

    It looks like you are using Ubuntu 14 and Savon 2 client. Savon 2 client doc: https://www.savonrb.com/version2/globals.html

    ssl_ca_cert_file

    Sets the SSL ca cert file to use.

    Savon.client(ssl_ca_cert_file: "lib/ca_cert.pem")

    I would point ssl_ca_cert_file to /etc/ssl/certs/ca-certificates.crt explicitly.