我被一个与证书有关的问题困扰了两天,其中一些客户端连接成功,而另一些客户端的证书验证失败。
我正在使用 CentOS 7.3 和 Nginx 1.15.4。我创建了 3 个级别的证书:
- 根 CA,secp384r1 + sha256 上的 ECDSA
- 中级 CA,RSA 2048 + sha256
- 服务器证书,RSA 2048 + sha256
- 中级 CA,RSA 2048 + sha256
根 CA 已在系统上受到信任,中间 CA 和服务器证书捆绑在一个文件中,并且 Nginx 配置为使用它们:
ssl_certificate /etc/nginx/ssl_certs/server-chain.crt;
ssl_certificate_key /etc/nginx/ssl_certs/server.key;
ssl_protocols TLSv1.2 ;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!SSLv3;
ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
现在,Nginx 很高兴能以此配置启动,并且我可以使用 openssl 进行故障排除:
$ openssl s_client -connect www.example.com:39200 < /dev/null 2>&1
CONNECTED(00000003)
depth=2 C = GB, ST = London, L = London, O = Example Ltd, OU = Example Hosting Team, CN = Example Root Certificate Authority, emailAddress = [email protected]
verify return:1
depth=1 C = GB, ST = London, L = London, O = Example Ltd, OU = Example Hosting Team, CN = Example Intermediate CA for project example, emailAddress = [email protected]
verify return:1
depth=0 C = GB, ST = London, L = London, O = Example Ltd, OU = Example Hosting Team, CN = www.example.com, emailAddress = [email protected]
verify return:1
---
Certificate chain
0 s:/C=GB/ST=London/L=London/O=Example Ltd/OU=Example Hosting Team/CN=www.example.com/[email protected]
i:/C=GB/ST=London/L=London/O=Example Ltd/OU=Example Hosting Team/CN=Example Intermediate CA for project example/[email protected]
1 s:/C=GB/ST=London/L=London/O=Example Ltd/OU=Example Hosting Team/CN=Example Intermediate CA for project example/[email protected]
i:/C=GB/ST=London/L=London/O=Example Ltd/OU=Example Hosting Team/CN=Example Root Certificate Authority/[email protected]
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=/C=GB/ST=London/L=London/O=Example Ltd/OU=Example Hosting Team/CN=www.example.com/[email protected]
issuer=/C=GB/ST=London/L=London/O=Example Ltd/OU=Example Hosting Team/CN=Example Intermediate CA for project example/[email protected]
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 2630 bytes and written 415 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: EEE677FB7C38DF8AEBEF68D22E67499D8D05710D819D5AB92BEF1B0A009DD818
Session-ID-ctx:
Master-Key: E423843C77F304B5D1D384DEA115AA2320128BCC824EC2B1C2F02D63A4F7B1671602F96C50DFFB9B7674C25466CF6162
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1538060858
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
DONE
请注意Verify return code: 0 (ok)
,openssl 正在使用系统信任存储来验证我的链。
我也在 Microsoft Edge 中测试了证书并且它可以运行,证书没有问题。
但是其他客户端(如 curl 和 Firefox)抱怨严重,我无法使其工作。以下是 curl:
curl -v --cacert Example_root_ca.crt https://example-elastic-data-vm.Example.com:39200
* About to connect() to example-elastic-data-vm.Example.com port 39200 (#0)
* Trying 192.168.0.123...
* Connected to example-elastic-data-vm.Example.com (192.168.0.123) port 39200 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: Example_root_ca.crt
CApath: none
* Server certificate:
* subject: [email protected],CN=example-elastic-data-vm.Example.com,OU=Example Hosting Team,O=Example Ltd,L=London,ST=London,C=GB
* start date: Sep 27 14:53:14 2018 GMT
* expire date: Sep 26 14:53:14 2020 GMT
* common name: example-elastic-data-vm.Example.com
* issuer: [email protected],CN=Example Intermediate CA for project example,OU=Example Hosting Team,O=Example Ltd,L=London,ST=London,C=GB
* NSS error -8182 (SEC_ERROR_BAD_SIGNATURE)
* Peer's certificate has an invalid signature.
* Closing connection 0
curl: (60) Peer's certificate has an invalid signature.
...
Firefox 却给我带来了这个错误:
An error occurred during a connection to example-elastic-data-vm.example.com:39200. security library: improperly formatted DER-encoded message. Error code: SEC_ERROR_BAD_DER
在我看来,这看起来像是一个兼容性问题。我做了很多研究和测试:
- MS Windows 很乐意验证整个链条
- OpenSSL 愉快地验证了整个链条
- 使用所有 RSA 证书进行测试:有效!但在我的公司,我们更喜欢 ECDSA
- 在不同的浏览器/客户端上进行了测试:如前所述,它适用于 openssl 和 Edge,但不适用于 curl 和 Firefox
- 研究兼容性指南和错误
- 测试了不同的曲线,如 secp256r1、secp384r1 和 prime256v1,但没有成功
- 尝试了不同的签名算法、密钥用法、扩展密钥用法、证书的基本约束。结果相同。
- 使用 curl 时明确指向 CA
我不知道该把头撞到哪里了,谁能给我指明正确的方向?
更新:我创建了测试清理证书,以便可以将它们上传到这里:
笔记:命令的输出已用“示例”进行了清理,因此某些名称可能不正确