OpenSSL 未在证书文件夹中获取 CA

OpenSSL 未在证书文件夹中获取 CA

我们遇到了curl无法连接到 HTTPS 服务器的问题:

$ curl https://the-problem-site.com    (not the real URL!)   
curl: (35) error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)

1112SSL_R_TLSV1_UNRECOGNIZED_NAMEssl.h

如果我尝试openssl s_client -connect the-problem-site.com:443的话,我就会发现

CONNECTED(00000003)   
depth=1 /C=US/O=GeoTrust, Inc./CN=GeoTrust SSL CA   
verify error:num=20:unable to get local issuer certificate   
verify return:0   

Certificate chain   
0 s:/serialNumber=xx/C=xx/ST=xx/L=xxxx/O=xx/OU=xx/CN=the-problem-site.com   
i:/C=US/O=GeoTrust, Inc./CN=GeoTrust SSL CA   
1 s:/C=US/O=GeoTrust, Inc./CN=GeoTrust SSL CA   
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA   

也就是说,问题似乎在于它不信任/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA。但是该证书已安装:它是/etc/ssl/certs/GeoTrust_Global_CA.pem,如果我运行

openssl s_client -connect the-problem-site.com:443 -CAfile /etc/ssl/certs/GeoTrust_Global_CA.pem

然后一切正常。证书也以哈希命名文件的形式存在b0f3e76e.0,位于 中ca-certificates.crt。但是,据我所知,curl 和 openssl 都没有尝试读取任何证书;如果我strace尝试,则不会尝试从/usr/lib/ssl/certs/etc/ssl/certs读取,甚至不会出现错误。但它确实读取了 openssl.cnf。我们已经运行了update-ca-certificates

这是带有 openssl 0.9.8k 的 Ubuntu 10.04。我们可以在两个单独的安装上重现该问题(尽管其中一个可能是另一个的克隆)。如果我在带有 openssl 0.9.8e 的 CentOS VM 上尝试相同的测试,那么它工作正常,我可以看到它读取证书文件strace。在 Ubuntu straces 中的同一点没有等效的文件访问。如果我将文件openssl.cnf从 CentOS VM 复制到 Ubuntu 机器,则没有任何区别。环境或 .rc 文件中没有明显可能导致此问题的东西。

你知道我做错了什么吗?这应该有效吗?也就是说,openssl 和 curl 应该从命令行自动获取已安装的 CA 吗?这是如何配置的?谢谢!


另一个数据点:在全新安装的 13 台服务器上,curl确实可以获取证书文件并正常工作。openssl s_client但仍然不行。为什么会这样?

答案1

您的系统上有多个加密库:

  • OpenSSL(黄金标准,采用 BSD 风格(非常免费)的许可证,其中包含一些有问题的条款(阻止与 GPL 兼容,但并不“坏”),限制了其在 GNU 世界中的采用)
  • GnuTLS(来自 FSF 的替代品;有两种版本,LGPLv2 许可(但无人维护)和 LGPLv3 许可(因此与仅 GPLv2 的程序不兼容);历史上功能不如 OpenSSL 丰富,漏洞较多,但也更严格,从而增强了安全性)
  • NSS(Netscape/Mozilla 的库,很少在外面使用;采用新标准的速度很慢)
  • 次要的如 PolarSSL、MatrixSSL、NaCl/Salt

当然,它们都有相似之处和不同之处。使用它们的软件(用于加密目的或使用 SSL/TLS)有时支持使用多个库(例如,网络浏览器 Lynx 通常与 OpenSSL 链接,但也支持 GnuTLS(只是不那么好)以安抚 GNU 人员)。

cURL 也是支持使用三个主要加密库之一的项目之一。这主要是因为 cURL 主要是供其他程序使用,当它们想要使用 http、ftp 等连接下载(甚至上传)内容时使用的库。命令curl行工具可以来自这些变体中的任何一个。

现在,我很确定您在未新安装的系统中遇到的问题如下:

OpenSSL 和 GnuTLS 都支持使用/etc/ssl/certs/<hash>.<number>-style CA 目录。但是 OpenSSL 版本 0.x 和 GnuTLS 使用不同的算法来计算上述哈希比 OpenSSL 1.x 版使用的功能更多。(两者可以在一个系统上共存;如果不同的证书具有相同的哈希你只需要使用不同的数字对他们来说。但出于某种原因,Debian/Ubuntu 的ca-certificates软件包似乎没有这样做。)此外,某些版本的 GnuTLS 不支持使用目录,而只支持使用文件/etc/ssl/certs/ca-certificates.crt(通常也由ca-certificates软件包的维护者脚本管理,但可能会有偏差);您似乎正在使用旧版本,所以这可能是您遇到的问题。

openssl s_client默认情况下(即没有-CApath-CAfile选项)看起来不任何地方用于证书。

升级后的安装很可能使用与全新安装curl不同的加密库。curl

尝试openssl s_client -CAfile /etc/ssl/certs/ca-certificates.crt -connect the-problem-site.com:443模仿openssl s_client -CApath /etc/ssl/certs -connect the-problem-site.com:443旧版 GnuTLS 的行为。

仔细检查是否有 OpenSSL 1.x任何地方在你的系统上(Ubuntu 以偷偷发布重大更新而闻名,即使是在 LTS 版本中),如果是,请检查文件的哈希值:

openssl x509 -noout -hash -in /etc/ssl/certs/GeoTrust_Global_CA.pem
openssl x509 -noout -subject_hash_old -in /etc/ssl/certs/GeoTrust_Global_CA.pem
openssl x509 -noout -subject_hash -in /etc/ssl/certs/GeoTrust_Global_CA.pem

通常,第二和第三个命令应该失败(OpenSSL 0.x),或者第一和第三个命令应该显示相同的哈希,但第二命令应该显示不同的哈希(OpenSSL 1.x)。GnuTLS 将使用第二条命令的输出(如果安装了 OpenSSL 1.x);如果安装了 OpenSSL 0.x,则哈希相同。您可以手动创建此类符号链接。

一旦您提供调试反馈,我就可以更新此帖子。

相关内容