用OpenSSL排查HTTPS证书,明明指定了ECDSA套件,结果却协商TLS1.3、拿到RSA证书。先别判定Nginx配置没生效:**-cipher只管TLS1.2及以下,不能拿它给TLS1.3划范围。**下面把协议、套件、认证和验证拆开,避免拿错尺子量证书。
一、这个"参数失效"其实有适用范围
OpenSSL 1.1.1的s_client文档明确区分-cipher与-ciphersuites。前者修改TLS1.2及以下列表,后者修改TLS1.3列表;两份列表可以同时存在。只传-cipher,并不等于禁用TLS1.3,也不保证最终一定协商某个旧套件。
本文命令针对支持TLS1.3的OpenSSL 1.1.1环境;先用openssl version -a确认版本和构建。参数没有请假,只是你问的那一层还没轮到它上班。

二、固定终点和名称,先保留原始现象
下面203.0.113.10是文档占位IP,example.com是占位名称,root.pem要换成经授权信任的CA文件。请固定同一入口和SNI,不要一次测CDN、一次测源站。-servername负责发送SNI,-verify_hostname负责名称检查,二者不能互相替代。
bash
openssl s_client -connect 203.0.113.10:443 \
-servername example.com -verify_hostname example.com \
-CAfile /path/to/root.pem -verify_return_error -brief \
-cipher ECDHE-ECDSA-AES128-GCM-SHA256 </dev/null
先看Protocol version,再看Ciphersuite和Signature type,同时检查退出状态与Verification。这里没有限定协议:若输出TLSv1.3,就不能用命令里的ECDHE-ECDSA套件名宣称"已经验证ECDSA分支"。成功握手也只证明这一组参数,不代表所有客户端都兼容。
三、要检查TLS1.2认证分支,显式限定协议
对同一终点加入-tls1_2,再使用ECDHE-ECDSA套件,才是在TLS1.2范围测试ECDSA认证的交集。RSA分支可将套件换成ECDHE-RSA-AES128-GCM-SHA256。两次都要独立新建连接,不能拿一次握手枚举服务器全部备选证书。
bash
openssl s_client -connect 203.0.113.10:443 \
-servername example.com -verify_hostname example.com \
-CAfile /path/to/root.pem -verify_return_error -brief \
-tls1_2 -cipher ECDHE-ECDSA-AES128-GCM-SHA256 </dev/null
如果服务端只有RSA证书,该ECDSA测试可能在协商阶段失败。不要立即得出"链不完整":还要核对服务端允许的协议、套件、签名算法、曲线和所选虚拟主机。限制协议是定位手段,不是建议把生产服务降级或关闭TLS1.3。
四、TLS1.3套件不再写RSA或ECDSA
RFC8446把TLS1.3套件和认证、密钥交换选择分开。TLS_AES_128_GCM_SHA256描述记录保护与相关哈希,不代表"必须用RSA证书"或"必须用ECDSA证书"。如果目标是TLS1.3套件测试,应使用对应参数:
bash
openssl s_client -connect 203.0.113.10:443 \
-servername example.com -verify_hostname example.com \
-CAfile /path/to/root.pem -verify_return_error -brief \
-tls1_3 -ciphersuites TLS_AES_128_GCM_SHA256 </dev/null
若目标是签名算法兼容性,另看-sigalgs。例如ecdsa_secp256r1_sha256可用于限制ECDSA签名方案,但仍需考虑证书曲线、链签名与对端支持;不是任意服务器都应成功。叶证书的Public Key Algorithm、CA签证书所用的Signature Algorithm、握手Signature type也是不同字段,不能看见一个RSA字符串就混为一谈。
五、回环正反例告诉了我们什么
本次用OpenSSL 1.1.1k FIPS在随机回环端口运行独立s_server,加载同一RSA测试证书,并显式信任该测试证书。没有修改Nginx、系统信任库或时钟;测试进程和临时私钥在结束后清理。这是工具行为实验,不是线上双证书部署验收。
| 客户端条件 | 本轮结果 | 能说明什么 |
|---|---|---|
| 仅-cipher指定ECDSA套件 | TLS1.3成功 | 旧套件列表未关闭TLS1.3 |
| TLS1.2加ECDSA套件 | 握手失败 | 与RSA-only服务无此认证交集 |
| TLS1.2加RSA套件 | 验证通过 | 该分支可用 |
| TLS1.3加AES128套件 | 成功,RSA-PSS签名 | 套件名称不绑定ECDSA |
| TLS1.3仅ECDSA签名方案 | 握手失败 | 签名方案约束另行生效 |
错误名称和错误信任材料的负例仍然失败。没有删除验证条件来让测试变绿;错误文本随版本变化,要保留完整上下文。
六、证书正确之后,再检查HTTP
上面三段只做握手。下面给Bash中的HTTP观察示例,保留TLS1.2 RSA分支和证书验证;路径需换成允许访问的只读接口。-ign_eof让客户端在标准输入结束后继续读响应,服务端不关闭时可能等待,因此自动化还需按环境设置总超时。
bash
set -o pipefail
printf 'GET / HTTP/1.0\r\nHost: example.com\r\n\r\n' |
openssl s_client -connect 203.0.113.10:443 \
-servername example.com -verify_hostname example.com \
-CAfile /path/to/root.pem -verify_return_error -brief \
-tls1_2 -cipher ECDHE-RSA-AES128-GCM-SHA256 -ign_eof
pipefail避免前段发送失败被后段掩盖,但仍要检查HTTP状态及预期正文:s_client不会把HTTP500自动变成失败退出码。这里只展示观察命令,不把它包装成完整业务健康检查。真实应用还要验证实际TLS库、CA来源、运行身份和业务结果。
七、排错时别扩大修复范围
固定终点、SNI与参数。没有取得证书不能归因过期,验证错误不能只改套件。多入口测试保留节点和时间,避免混用结果。
八、验收清单与参考资料
- 版本和TLS后端已记录,命令选项确实支持。
- 终点、SNI、验证名称与CA来源固定。
- 按实际协商协议解释-cipher与-ciphersuites。
- 协议、套件、签名、证书验证分别有证据。
- 正例通过,错误名称和信任负例被阻断。
- HTTP状态与业务内容另验,不以握手代替业务。
参数作用范围以官方文档为准;下面最后一项为证书自动化平台资料,不承担本文套件语义的规范依据。