如何强制 Apache 2.2 发送完整的证书链?
How to force Apache 2.2 to send the full certificate chain?
我们使用 Apache 2.2.25 和 mod_ssl 在反向代理模式下使用 mod_proxy。它有一个我们用于测试目的的服务器证书,由 GoDaddy 颁发。链中有 3 个证书,server cert -> GoDaddy intermediate CA -> GoDaddy Root CA
。中间 CA(Go Daddy Secure Certificate Authority - G2)并不总能在客户端的受信任 CA 列表中找到。
与服务器的 SSL 连接适用于浏览器(至少对于某些浏览器),但不适用于某些其他客户端。我们注意到我们的服务器没有通过使用以下命令发送完整的证书链:openssl s_client -showcerts -connect SERVER_URL:443
,实际上该命令报告了错误 Verify return code: 21 (unable to verify the first certificate)
我们在每个 VirtualHost 中使用 SSLCertificateFile
指令:
SSLCertificateFile certificate.crt
其中 certificate.crt 文件包含私钥和链中的所有证书。
我们尝试将其拆分为以下内容:
SSLCertificateFile server.crt
SSLCertificateKeyFile server.key
SSLCertificateChainFile chain.crt
但这并没有改变任何东西。
感谢您的帮助!
编辑
情节变浓了 - 它似乎是证书和服务器的某种组合。
(使用 SSL Shopper 工具进行测试)
- Apache 2.2 (RHEL) 上的 Go Daddy 证书(如上所述)- 不起作用
- 相同的证书,在 IIS7 上 - 有效
- Apache 2.2 RHEL 上的客户证书(来自 Comodo)- 有效
你走在正确的轨道上。
SSLCertificateFile server.crt >> Your public certificate
SSLCertificateKeyFile server.key >> Your private key
SSLCertificateChainFile chain.crt >> List of intermediate certificates;
in your case, only one - GoDaddy intermediate CA
使用 SSL Labs 等工具检查您的服务器配置,以确定您发送的中间证书是否正确。
您也可以使用SSLCACertificatePath
指令并将原始.crt
文件放入指定目录。但是,您还必须为它们创建哈希符号链接。这是使用 c_rehash
工具完成的,它是 openssl
的一部分。例如,
sudo c_rehash /etc/apache2/ssl/certs
但是请注意,使用了两种哈希算法。新的是openssl
1.0引入的,升级openssl
到1.0或更高版本后需要重新运行 c_rehash
。这将同时创建旧式和新式符号链接。
如果您不这样做,openssl
(因此 apache
)将无法找到中间证书,因此它们不会被发送到客户端。在将 Ubuntu 服务器从 Lucid 升级到 Precise 之后,我花了令人沮丧的几个小时来调试 SSL 错误,其中包括将 openssl
从 0.9.8 升级到 1.0.1。我进行了搜索,但在网上找不到任何关于问题所在的线索,所以我不得不自己弄清楚。
郑重声明,我们没有在浏览器中遇到错误,因为它有更大的根集,而且我们的一个中间证书一定在该集中。该问题仅在使用基于 openssl
的命令行程序时出现,例如 wget
、curl
和 openssl s_client
.
如果以后有人遇到类似问题:
在我的情况下,一台服务器没有发送已配置的中间证书(但其他服务器发送了)——这似乎是证书文件中行结尾的问题。显然,2019 年之前的 Apache 版本可能相当挑剔——只接受以换行符结尾的证书(NL、char 10、Unix 行结尾),并默默地忽略以回车符 return、换行符(CR)结尾的行的证书+NL,字符 13 和 10,Windows 行尾),或仅回车 return(CR,字符 13,Mac OS <10)。
我的中间证书有 CR 行结尾(在这个时代很奇怪)- 使用文本编辑器将它转换为 NL 结尾修复它,Apache 现在正确发送中间证书。
我的 httpd 2.4 没有发送用 SSLCertificateChainFile
定义的中间证书。
事实证明,证书文件在文件系统上的权限有误,apache 只是忽略了它们。
正确的权限掩码是 400 :
[root@server ~]# ll /etc/httpd/conf/tls/certs/intermediate_chain.crt
-rw-r--r-- 1 root root 1728 Mar 2 14:20 /etc/httpd/conf/tls/certs/intermediate_chain.crt
# ^ ^ wrong permissions
[root@server conf.d]# chmod 400 /etc/httpd/conf/tls/certs/intermediate_chain.crt
[root@server ~]# ll /etc/httpd/conf/tls/certs/intermediate_chain.crt
-rw------- 1 root root 1728 Mar 2 14:20 /etc/httpd/conf/tls/certs/intermediate_chain.crt
# ^ ^ correct permissions
也许这对某人有帮助
我们使用 Apache 2.2.25 和 mod_ssl 在反向代理模式下使用 mod_proxy。它有一个我们用于测试目的的服务器证书,由 GoDaddy 颁发。链中有 3 个证书,server cert -> GoDaddy intermediate CA -> GoDaddy Root CA
。中间 CA(Go Daddy Secure Certificate Authority - G2)并不总能在客户端的受信任 CA 列表中找到。
与服务器的 SSL 连接适用于浏览器(至少对于某些浏览器),但不适用于某些其他客户端。我们注意到我们的服务器没有通过使用以下命令发送完整的证书链:openssl s_client -showcerts -connect SERVER_URL:443
,实际上该命令报告了错误 Verify return code: 21 (unable to verify the first certificate)
我们在每个 VirtualHost 中使用 SSLCertificateFile
指令:
SSLCertificateFile certificate.crt
其中 certificate.crt 文件包含私钥和链中的所有证书。 我们尝试将其拆分为以下内容:
SSLCertificateFile server.crt
SSLCertificateKeyFile server.key
SSLCertificateChainFile chain.crt
但这并没有改变任何东西。
感谢您的帮助!
编辑
情节变浓了 - 它似乎是证书和服务器的某种组合。
(使用 SSL Shopper 工具进行测试)
- Apache 2.2 (RHEL) 上的 Go Daddy 证书(如上所述)- 不起作用
- 相同的证书,在 IIS7 上 - 有效
- Apache 2.2 RHEL 上的客户证书(来自 Comodo)- 有效
你走在正确的轨道上。
SSLCertificateFile server.crt >> Your public certificate
SSLCertificateKeyFile server.key >> Your private key
SSLCertificateChainFile chain.crt >> List of intermediate certificates;
in your case, only one - GoDaddy intermediate CA
使用 SSL Labs 等工具检查您的服务器配置,以确定您发送的中间证书是否正确。
您也可以使用SSLCACertificatePath
指令并将原始.crt
文件放入指定目录。但是,您还必须为它们创建哈希符号链接。这是使用 c_rehash
工具完成的,它是 openssl
的一部分。例如,
sudo c_rehash /etc/apache2/ssl/certs
但是请注意,使用了两种哈希算法。新的是openssl
1.0引入的,升级openssl
到1.0或更高版本后需要重新运行 c_rehash
。这将同时创建旧式和新式符号链接。
如果您不这样做,openssl
(因此 apache
)将无法找到中间证书,因此它们不会被发送到客户端。在将 Ubuntu 服务器从 Lucid 升级到 Precise 之后,我花了令人沮丧的几个小时来调试 SSL 错误,其中包括将 openssl
从 0.9.8 升级到 1.0.1。我进行了搜索,但在网上找不到任何关于问题所在的线索,所以我不得不自己弄清楚。
郑重声明,我们没有在浏览器中遇到错误,因为它有更大的根集,而且我们的一个中间证书一定在该集中。该问题仅在使用基于 openssl
的命令行程序时出现,例如 wget
、curl
和 openssl s_client
.
如果以后有人遇到类似问题:
在我的情况下,一台服务器没有发送已配置的中间证书(但其他服务器发送了)——这似乎是证书文件中行结尾的问题。显然,2019 年之前的 Apache 版本可能相当挑剔——只接受以换行符结尾的证书(NL、char 10、Unix 行结尾),并默默地忽略以回车符 return、换行符(CR)结尾的行的证书+NL,字符 13 和 10,Windows 行尾),或仅回车 return(CR,字符 13,Mac OS <10)。
我的中间证书有 CR 行结尾(在这个时代很奇怪)- 使用文本编辑器将它转换为 NL 结尾修复它,Apache 现在正确发送中间证书。
我的 httpd 2.4 没有发送用 SSLCertificateChainFile
定义的中间证书。
事实证明,证书文件在文件系统上的权限有误,apache 只是忽略了它们。 正确的权限掩码是 400 :
[root@server ~]# ll /etc/httpd/conf/tls/certs/intermediate_chain.crt
-rw-r--r-- 1 root root 1728 Mar 2 14:20 /etc/httpd/conf/tls/certs/intermediate_chain.crt
# ^ ^ wrong permissions
[root@server conf.d]# chmod 400 /etc/httpd/conf/tls/certs/intermediate_chain.crt
[root@server ~]# ll /etc/httpd/conf/tls/certs/intermediate_chain.crt
-rw------- 1 root root 1728 Mar 2 14:20 /etc/httpd/conf/tls/certs/intermediate_chain.crt
# ^ ^ correct permissions
也许这对某人有帮助