Ruby Net::HTTP 在证书续订后以 OpenSSL::SSL::SSLError "certificate verify failed" 响应

Ruby Net::HTTP responds with OpenSSL::SSL::SSLError "certificate verify failed" after certificate renewal

我们最近更新了我们网站的 SSL 证书,以下发生在 Mac OS El Capitan 10.11.3:

require 'net/http'

Net::HTTP.get URI('https://www.google.com')
# => "<HTML>...</HTML>"

# The site whose certificate got renewed
Net::HTTP.get URI('https://www.example.com')
# => OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=error: certificate verify failed

我在 Google 和 Whosebug 上的所有搜索都得到了提示 Ruby 安装有问题的答案,但它们似乎与旧的 Ruby 版本有关,我不知道不认为这里是这种情况。这是我尝试过的:

我该如何解决这个问题?

备注:


解决方案

在 BoraMa 的大力帮助下,现在很清楚发生了什么。 COMODO 添加了一个名为 COMODO RSA Certification Authority 的新根,而不是之前的 COMODO Certification Authority。新根未在 Mac 的钥匙串中注册,导致此问题。

我们尝试调试的一种方法是 运行:

openssl s_client -connect www.mysite.com:443

显示警告 verify error:num=20:unable to get local issuer certificate。此警告不是问题,因为 openssl s_client 默认不使用任何证书。 运行 以下内容在下载证书 from COMODO into comodo.pem (index here 后能够防止警告:

openssl s_client -connect www.mysite.com:443 -CAfile comodo.pem

但是,这不能也没有影响 Ruby OpenSSL 接口。 This article made things much clearer for me, and the SSL doctor script created by its author was also helpful, as it confirmed the hypothesis. The article suggested to look at OpenSSL::X509::DEFAULT_CERT_FILE, which for me was /usr/local/etc/openssl/cert.pem. That file did not exist on my machine, which meant Apple's patch for OpendSSL was using the Keychain App. For whatever reason, importing comodo.pem into my keychain and marking it as trusted based on this post 无效。

因此,解决方案是手动创建 cert.pem 文件。我去了钥匙串应用程序,并将所有系统根证书导出到 system_root.pem。然后: cat system_root.pem comodo.pem > cert.pem 并将该文件移动到 /usr/local/etc/openssl/ 就成功了。 运行 Net::HTTP.get in Ruby 不再失败。

听起来问题出在您的 OSX 证书缓存上。我猜你在旧证书过期之前更新了证书?

尝试通过 运行 这个命令清除 OSX 系统范围的 CRL 缓存:

crlrefresh rpv

# p - purges cache, r - refreshes them, v - run in verbose mode

这是一个内置的命令行工具,可以更新和维护系统范围的 CRL 缓存。在其 man 页面 (mand crlrefresh) 中阅读更多相关信息。

我会尝试仔细检查受信任的证书库是否包含 COMODO_RSA_Certification_Authority.pem 证书。在我的 (Linux) 设置中,该站点工作正常,但是当我暂时从证书存储中删除 COMODO 证书颁发机构的证书时,我得到与您完全相同的错误(而在浏览器中它仍然可以正常工作他们自己的证书商店)。

顺便说一句,使用 curl 也可以识别相同的错误,因为它似乎也使用与 ruby 相同的受信任证书存储,因此您可能首先确保该站点在 curl 下工作。

在 linux 中,证书存储通常位于 /etc/ssl/certs 而在 OSX 中,它可能应该是 /System/Library/OpenSSL(其他选项见 this article ).

您应该会在证书存储目录中看到如下内容:

root@apsara:/etc/ssl/certs$ ls -l | grep COMODO_RSA_Certification_Authority.pem
lrwxrwxrwx 1 root root     73 úno 28 10:24 COMODO_RSA_Certification_Authority.pem -> /usr/share/ca-certificates/mozilla/COMODO_RSA_Certification_Authority.crt
lrwxrwxrwx 1 root root     38 úno 28 10:24 d4c339cb.0 -> COMODO_RSA_Certification_Authority.pem
lrwxrwxrwx 1 root root     38 úno 28 10:24 d6325660.0 -> COMODO_RSA_Certification_Authority.pem

以下是此根 CA 证书的一些属性的片段:

$ openssl x509 -in COMODO_RSA_Certification_Authority.pem -noout -text
Certificate:
Data:
    Version: 3 (0x2)
    Serial Number:
        4c:aa:f9:ca:db:63:6f:e0:1f:f7:4e:d8:5b:03:86:9d
Signature Algorithm: sha384WithRSAEncryption
    Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority
    Validity
        Not Before: Jan 19 00:00:00 2010 GMT
        Not After : Jan 18 23:59:59 2038 GMT
    Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority
    Subject Public Key Info:
        Public Key Algorithm: rsaEncryption
            Public-Key: (4096 bit)
            Modulus:
                00:91:e8:54:92:d2:0a:56:b1:ac:0d:24:dd:c5:cf:
                ...
            Exponent: 65537 (0x10001)
    X509v3 extensions:
        X509v3 Subject Key Identifier: 
            BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4
        X509v3 Key Usage: critical
            Certificate Sign, CRL Sign
        X509v3 Basic Constraints: critical
            CA:TRUE
Signature Algorithm: sha384WithRSAEncryption
     ...

证书可以从Comodo下载here (index of all certs is here).

更多信息:在调查时,事实证明 Comodo CA 实际上有两个不同的证书认证链。一个是较旧的,是具有上面列出的根 CA 的那个。较新的验证链在链中使用 "External CA root" 个证书。 This forum post 进一步解释,针对 OSX 将这些证书标记为受信任的具体说明。

我整个早上都在为这个错误烦恼。这个问题和答案使我找到了适合我的解决方案。我不会在此处添加新信息,而只是说明我所做的细节,以防在与我的平台类似的平台上出现此错误的任何其他人都可以使用它。

我正在使用:

Ubuntu 16.04
ruby 2.3.0
rails 4.2.7.1
HTTParty

我正在访问使用 COMODO SSL 证书保护的 API。在我的代码中,当我尝试时:

HTTParty.get(secured_url).tap{|response| puts response}

我得到了:

SSL_connect returned=1 errno=0 state=error: certificate verify failed (OpenSSL::SSL::SSLError)

我也使用了上面提到的 SSL doctor 脚本。当我 运行 脚本(用我的实际 api 服务器地址代替 host)时,我得到:

$ ruby doctor.rb host:443
/home/<redacted>/.rvm/rubies/ruby-2.3.0/bin/ruby (2.3.0-p0)
OpenSSL 1.0.2g  1 Mar 2016: /usr/lib/ssl
SSL_CERT_DIR=""
SSL_CERT_FILE=""

HEAD https://host:443
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=error: certificate verify failed

The server presented a certificate that could not be verified:
  subject: <redacted>
  issuer: /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA
  error code 20: unable to get local issuer certificate

在一个单独的终端中,我进入了我的证书目录:

$ cd /etc/ssl/certs

并做了(使用 COMODO_RSA_Organization_Validation_Secure_Server_CA 从上面的 issuer 文本派生而来):

<redacted>:/etc/ssl/certs$ openssl x509 -in COMODO_RSA_Organization_Validation_Secure_Server_CA.pem -noout -text
Error opening Certificate COMODO_RSA_Organization_Validation_Secure_Server_CA.pem
140455648364184:error:02001002:system library:fopen:No such file or directory:bss_file.c:398:fopen('COMODO_RSA_Organization_Validation_Secure_Server_CA.pem','r')
140455648364184:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:400:
unable to load certificate

我去了 COMODO RSA Organization Validation Secure Server CA pem 所在的 COMODO 站点。我将证书复制到桌面上名为 COMODO_RSA_Organization_Validation_Secure_Server_CA.crt 的新文件中(有些说明说使用 crt 扩展名而不是 pem,即使您需要 pem 证书内容)。

然后,在 these instructions 之后,我做了:

<redacted>:~/Desktop$ sudo cp COMODO_RSA_Organization_Validation_Secure_Server_CA.crt /usr/share/ca-certificates/COMODO_RSA_Organization_Validation_Secure_Server_CA.crt
<redacted>:~/Desktop$ sudo dpkg-reconfigure ca-certificates

然后我做了:

sudo dpkg-reconfigure ca-certificates

然后:

<redacted>:~/Desktop$ ruby doctor.rb host:443
/home/<redacted>/.rvm/rubies/ruby-2.3.0/bin/ruby (2.3.0-p0)
OpenSSL 1.0.2g  1 Mar 2016: /usr/lib/ssl
SSL_CERT_DIR=""
SSL_CERT_FILE=""

HEAD https://host:443
OK

之后我的代码 运行 没问题。谢谢谢谢谢谢!