编译带-DENABLE_SSL=WINDOWS的mongocxx驱动时带密码PEM密钥连接失败
问题背景
你遇到的情况是:当编译mongocxx驱动时指定-DENABLE_SSL=WINDOWS(使用Windows Secure Channel/Schannel作为SSL后端),客户端使用带密码的PEM私钥连接MongoDB时失败,报错:
[error@stream-secure-channel] Failed to parse private key. ASN1 bad tag value met. (0x8009310B)
[warning@stream-secure-channel] a client certificate has been requested
而用mongo.exe却能正常连接,且切换到-DENABLE_SSL=OPENSSL编译驱动后问题消失。
原因分析
Windows Schannel对PEM格式私钥的处理逻辑和OpenSSL有差异:
- 你用
openssl genrsa -des3 -out server.key 2048生成的是PKCS#1格式的加密私钥,Schannel对这种格式的加密私钥兼容性较差; mongo.exe可能在Windows环境下默认仍使用OpenSSL处理SSL,或者内部做了格式兼容转换,所以能正常解析;- 当驱动用Schannel后端时,它严格遵循Schannel的要求,无法直接解析PKCS#1格式的加密私钥,导致ASN1解析错误。
解决方案
1. 将PKCS#1私钥转换为PKCS#8格式
Schannel对PKCS#8格式的加密私钥支持更好,用OpenSSL命令转换:
# 转换私钥为PKCS#8格式,会提示输入原密码和设置新密码(可设为原密码1234) openssl pkcs8 -topk8 -in server.key -out server_pkcs8.key -v2 des3
然后将转换后的server_pkcs8.key和你的证书合并成新的PEM文件(如果之前是证书+私钥合并的cry.pem):
cat your_cert.pem server_pkcs8.key > new_cry.pem
之后在mongocxx中使用这个新的new_cry.pem文件尝试连接。
2. 确保代码中正确传递私钥密码
检查你的mongocxx客户端代码,是否明确设置了PEM私钥的密码。示例代码如下:
#include <mongocxx/client.hpp> #include <mongocxx/instance.hpp> #include <mongocxx/uri.hpp> #include <mongocxx/options/client.hpp> #include <mongocxx/options/ssl.hpp> int main() { mongocxx::instance instance{}; // 构建连接URI mongocxx::uri uri("mongodb://user1:123@10.154.10.39/?authSource=admin&ssl=true"); // 配置SSL选项 mongocxx::options::ssl ssl_opts; ssl_opts.ca_file("d:/ca.pem"); ssl_opts.pem_file("d:/cry.pem"); // 或转换后的new_cry.pem ssl_opts.pem_password("1234"); // 必须明确设置私钥密码 // 配置客户端选项 mongocxx::options::client client_opts; client_opts.ssl_opts(ssl_opts); // 尝试连接 try { auto client = mongocxx::client(uri, client_opts); // 连接成功,执行后续操作 std::cout << "Connected successfully!" << std::endl; } catch (const std::exception& e) { std::cerr << "Connection failed: " << e.what() << std::endl; } return 0; }
如果之前的代码遗漏了pem_password的设置,Schannel无法解密私钥,也会导致解析失败。
3. 辅助检查:确认系统证书信任(可选)
如果转换格式和设置密码后仍有问题,可以尝试将CA证书导入到Windows的受信任根证书颁发机构存储中:
- 右键点击
ca.pem,选择「安装证书」 - 选择「本地计算机」,然后按向导将证书放入「受信任的根证书颁发机构」目录
这一步主要解决证书信任问题,但你的错误是私钥解析,所以优先级低于前两个方案。
验证
完成上述步骤后,重新编译运行mongocxx客户端,应该能正常连接MongoDB了。
内容的提问来源于stack exchange,提问作者winnie_quest




