使用OpenSSL搭建客户端服务端安全连接时自签名证书验证失败
问题根因与解决方法
你遇到的报错是服务端验证客户端证书失败,对应你配置的SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT规则,服务端要求客户端必须出示合法且被信任的证书才允许连接,按照以下顺序排查即可:
服务端未加载信任的客户端证书列表
自签名证书不会被系统默认信任库识别,你需要显式调用SSL_CTX_load_verify_locations函数将客户端的自签名证书(或你自建的CA根证书,如果客户端证书是该CA签发的)加入服务端的信任列表,示例代码:// 第二个参数为信任证书的PEM文件路径,第三个参数为存放多个信任证书的目录路径,二选一即可 if (!SSL_CTX_load_verify_locations(ctx, "./client_cert.pem", NULL)) { // 错误处理,打印错误栈 ERR_print_errors_fp(stderr); exit(1); }客户端未正确加载自身的证书与私钥
客户端侧必须调用以下两个接口加载自己的证书和对应的私钥,否则服务端会收不到客户端证书直接触发报错:// 加载客户端证书 SSL_CTX_use_certificate_file(client_ctx, "./client_cert.pem", SSL_FILETYPE_PEM); // 加载客户端私钥 SSL_CTX_use_PrivateKey_file(client_ctx, "./client_key.pem", SSL_FILETYPE_PEM); // 可选:校验私钥和证书是否匹配 if (!SSL_CTX_check_private_key(client_ctx)) { ERR_print_errors_fp(stderr); exit(1); }客户端证书属性不符合要求
自签名生成客户端证书时如果缺少必要扩展,也会触发验证失败,需要确认客户端证书包含TLS Web Client Authentication密钥用法扩展,可用以下命令查看证书属性:openssl x509 -in client_cert.pem -text -noout
查看输出的X509v3 Extended Key Usage字段是否包含TLS Web Client Authentication,没有的话需要重新生成证书时加上对应扩展配置。补充排查技巧
可以先临时将服务端的验证规则改为SSL_VERIFY_NONE确认底层TCP、TLS版本、密码套件等配置无问题,再逐步开启验证;也可以用OpenSSL命令行工具替代你写的客户端测试,快速定位是程序配置问题还是证书本身问题:openssl s_client -connect 127.0.0.1:你的服务端口 -cert ./client_cert.pem -key ./client_key.pem
注意你提供的
ShowCerts函数注释有误:服务端调用SSL_get_peer_certificate拿到的是客户端的证书,你当前的输出注释把主体和颁发者的角色标反了,排查时注意不要被误导。
内容的提问来源于stack exchange,提问作者SiriusA1V

