C++ Builder中Indy10设置SSL RootCertFile出现乱码路径报错怎么办
故障原因
- 编码转换Bug:C++ Builder 10.3自带的Indy 10构建版本存在属性传参缺陷。OpenSSL底层仅接受UTF-8编码的文件路径,该版本Indy在处理
RootCertFile属性时,遗漏了Unicode到UTF-8的编码转换步骤,错误地按本地ANSI编码处理字符串,当路径包含中文、或内存读取偏移异常时,就会生成乱码文件名,与当前可执行文件工作目录拼接后成为无效路径,触发文件找不到异常。同版本Indy对CertFile、KeyFile属性的编码转换逻辑是正常的,因此仅设置这两个参数时不会报错。 - 配置项认知偏差:
RootCertFile的作用是存储客户端用于校验服务端证书合法性的根CA证书链,并非提供给服务端校验客户端身份使用。客户端身份校验只需要配置正确的CertFile(客户端证书)和KeyFile(客户端私钥)即可完成,RootCertFile留空时仅代表客户端不主动校验服务端证书,不影响服务端对客户端的证书校验流程。
解决方案
按照改造成本从低到高可选以下方案:
- 临时规避方案:将根证书文件放在纯英文、无空格和特殊字符的路径下,例如直接放在可执行文件同级目录,命名为
rootca.crt这类纯英文文件名,给RootCertFile赋值时直接使用相对路径,避开会触发编码错误的非ASCII字符即可正常加载。 - 稳定绕开Bug方案:不依赖Indy的
RootCertFile属性传参,在调用Open()建立连接前,直接调用OpenSSL原生API加载根证书,完全绕开Indy的编码转换逻辑。示例代码如下:
// 需提前引入OpenSSL相关头文件 #include <openssl/ssl.h> #include <IdSSLOpenSSL.hpp> // 完成其他SSL参数初始化,RootCertFile属性保持留空 net->IdSSLIOHandlerSocketOpenSSL->SSLOptions->Mode = sslmClient; net->IdSSLIOHandlerSocketOpenSSL->Host = net->hostname; net->IdSSLIOHandlerSocketOpenSSL->Port = net->port; net->IdSSLIOHandlerSocketOpenSSL->SSLOptions->Method = sslvTLSv1_2; net->IdSSLIOHandlerSocketOpenSSL->SSLOptions->VerifyMode = TIdSSLVerifyModeSet(sslvrfClientOnce); net->IdSSLIOHandlerSocketOpenSSL->SSLOptions->VerifyDepth = 10; net->IdSSLIOHandlerSocketOpenSSL->OnVerifyPeer = MainForm->VerifyCertFile; net->IdSSLIOHandlerSocketOpenSSL->ReadTimeout = 10000; net->IdSSLIOHandlerSocketOpenSSL->SSLOptions->CertFile = net->clientname; net->IdSSLIOHandlerSocketOpenSSL->SSLOptions->KeyFile = net->keyname; // 手动获取底层SSL_CTX指针加载根证书 SSL_CTX* sslCtx = static_cast<SSL_CTX*>(net->IdSSLIOHandlerSocketOpenSSL->SSLContext->fContext); UTF8String utf8RootCertPath = UnicodeToUtf8(net->certname); if (SSL_CTX_load_verify_locations(sslCtx, utf8RootCertPath.c_str(), nullptr) != 1) { // 可通过ERR_get_error()获取具体OpenSSL错误码 throw Exception("根证书加载失败"); } // 加载完成后再建立连接 net->IdSSLIOHandlerSocketOpenSSL->Open();
- 根治方案:升级Indy 10到官方最新修复版本。该编码转换Bug已经在后续Indy代码提交中修复,新版本统一了所有证书路径属性的UTF-8转换逻辑,直接给
RootCertFile赋值含非ASCII字符的路径也不会出现乱码问题,项目依赖允许的话直接替换C++ Builder内置的Indy版本即可。
注意:如果开启了服务端证书校验,需要确保
OnVerifyPeer回调事件的逻辑符合预期,避免回调返回false导致连接被主动断开。
内容的提问来源于stack exchange,提问作者Barry Andrews
相关产品推荐
相关产品推荐

