【问题标题】:Ruby Net::HTTP responds with OpenSSL::SSL::SSLError "certificate verify failed" after certificate renewalRuby Net::HTTP 在证书更新后响应 OpenSSL::SSL::SSLError "certificate verify failed"
【发布时间】:2016-08-26 06:52:03
【问题描述】:

我们最近更新了我们网站的 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 和 StackOverflow 上的所有搜索都给出了表明 Ruby 安装存在问题的答案,但它们似乎与旧 Ruby 版本有关,我认为这里不是这种情况。这是我尝试过的:

  • brew update
  • brew upgrade openssl
  • rvm osx-ssl-certs update all
  • rvm install ruby-2.3.1 --disable-binary --with-openssl-dir="$(brew --prefix openssl)"(我之前没有这个版本)
  • rvm requirements
  • 根据 Uzbekjon 的建议,crlrefresh rpv 清除 OSX 系统范围的 CRL 缓存。

我该如何解决这个问题?

注意事项:

  • 在新安装的具有裸露 Ruby 2.2.3 的 linux Docker 容器上不会出现此问题。因此,这可能与 Mac OS 或 SSL 本地缓存有关。
  • 此问题可能在证书续订之前就已存在。我不能确定。但是,正如我在this question 中讨论的那样,续订确实导致我们使用的第 3 方出现类似问题。
  • Namecheap 验证证书安装正确,在线检查器显示一切正常,所有主要浏览器都显示证书有效。

解决方案

在 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 下载到comodo.pem(索引here)后,运行以下命令可以防止出现警告:

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

但是,这不会也不会影响 Ruby OpenSSL 接口。 This article 让我更清楚了,作者创建的 SSL doctor script 也很有帮助,因为它证实了这个假设。文章建议看OpenSSL::X509::DEFAULT_CERT_FILE,对我来说是/usr/local/etc/openssl/cert.pem。我的机器上不存在该文件,这意味着 Apple 的 OpendSSL 补丁正在使用 Keychain 应用程序。无论出于何种原因,将comodo.pem 导入我的钥匙串并根据this post 将其标记为受信任都不起作用。

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

【问题讨论】:

  • (新)证书来自哪个证书颁发机构?或者,您能否显示站点 URL,以便我们研究证书本身?也许证书更新时证书颁发机构发生了变化,而您的 OSX 上还没有它(而它已经在新的 linux 上)。
  • 感谢 BoraMa。来自 COMODO。
  • testing tool like this 是否表明它已正确配置?有时链文件的顺序不正确,一些测试人员没有验证这一点。

标签: ruby ssl openssl ssl-certificate net-http


【解决方案1】:

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

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

crlrefresh rpv

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

这是一个内置的命令行工具,用于更新和维护系统范围的 CRL 缓存。在其man 页面 (mand crlrefresh) 中了解更多信息。

【讨论】:

  • 感谢乌兹别克斯坦。我尝试运行crlrefresh rpvsudo crlrefresh rpv,但不幸的是我仍然遇到同样的错误。 crlrefresh 都没有任何输出。不过,我正在更新答案以包含您的建议。
  • 你的 OSX 版本是多少?而且,新证书是什么?旧 OSX 上的 DigiSign 证书存在问题。但是,话又说回来,它应该由rvm osx-ssl-certs update all 修复。顺便说一句,在您刷新证书后,您应该“重新安装”您的 openssl。或者,重新散列 openssl 的证书。
  • 我使用的是 Mac OS El Capitan 10.11.3。我刚刚用brew reinstall openssl 重新安装了openssl。它没有解决问题。我正在使用 --disable-binaries 重新安装 ruby​​-2.3.1,如果它有效,我会通知您。
  • 在安装 ruby​​ 时不要忘记指定--with-openssl-dir="$(brew --prefix openssl)" 选项。
  • 感谢乌兹别克斯坦。我尝试使用这些标志,启动了一个新的终端窗口,但仍然没有运气。我可以看到openssl version 返回0.9.8zg,而$(brew --prefix openssl)/bin/openssl version 返回1.0.2g。有没有办法让我测试我的 Ruby 二进制文件确实使用了正确的引擎盖?
【解决方案2】:

如果受信任的证书存储包含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 下载(所有证书的索引是here)。

更多信息:通过调查发现,Comodo CA 的证书实际上有两个不同的认证链。一种,较旧的一种,是上面列出的根 CA。较新的验证链在链中使用“外部 CA 根”证书。 This forum post 进一步解释说,带有针对 OSX 的具体说明,用于将这些证书标记为受信任。

【讨论】:

  • 感谢 BoraMa。有趣的是,我的网站上的curl 可以毫无问题地为我工作。该问题仅在使用 Ruby 时才明显。我的/System/Library/OpenSSL/certs 文件夹是空的,并且文章中的所有其他位置在我的系统上都不存在。我相信 Mac OS 将所有证书放在 Keychain 应用程序中,而我的 Keychain 应用程序包含“COMODO 证书颁发机构”证书。
  • 啊哈,确实是 curl uses the keychain。嗯,你可能见过this?我猜你尝试过的步骤类似......
  • 谢谢。我还没有看到那个特别的,但它谈到了软件包的全面升级。在我的情况下,升级并没有导致问题 - 只是更新证书,就我的测试而言,只有当我为该站点运行 Net::HTTP.get 时,我才会收到错误。所以我很困惑。
  • 我理解但很抱歉,我的 OSX 知识相当有限,所以我有点想至少有助于缩小问题范围... openssl s_client 是否适合您? openssl s_client -host DOMAIN -port 443 -CApath 'a' - 您可以将任何内容放入 CApath 参数中,如文档中的 here (这可能也值得您阅读)。同样,除非我从商店中删除证书文件,否则它对我有用。
  • 哦,我做到了,对不起。 :) 我还发现了这一点:当我在 ruby​​ 控制台下运行File.dirname OpenSSL::Config::DEFAULT_CONFIG_FILE 时,我得到/etc/lib/ssl,它在我的系统上指向/etc/ssl/ 目录——受信任证书目录的根目录。也许你会通过这种方式找到你的。
【解决方案3】:

由于这个错误,我整个早上都在拔头发。这个问题和答案使我找到了适合我的解决方案。我不会在这里添加新信息,而只是详细说明我所做的事情,以防在类似于我的平台上出现此错误的任何其他人使用它。

我正在使用:

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 医生脚本。当我运行脚本时(用我的实际 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

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

$ cd /etc/ssl/certs

并且做到了(使用上面的issuer 文本派生的COMODO_RSA_Organization_Validation_Secure_Server_CA):

<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

之后我的代码运行良好。谢谢,谢谢,谢谢!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-30
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 2016-01-26
    相关资源
    最近更新 更多