Indy 10 TCPServer SSL证书验证异常(错误20、SSL警报48)
Indy 10 + OpenSSL双向认证:X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY(错误20)解决方案
核心原因排查与修复步骤
1. 根CA证书路径未正确指定
Indy的RootCertFile必须用绝对路径,相对路径会因为程序运行时工作目录变化导致找不到文件。比如直接写'ca.crt',如果程序从其他目录启动,就会加载失败。
- 修复:用程序所在目录拼接绝对路径,示例:
IdServerIOHandlerSSLOpenSSL1.RootCertFile := ExtractFilePath(ParamStr(0)) + 'ca.crt';
2. SSL验证选项配置不全
光指定RootCertFile不够,必须明确开启peer验证并设置验证深度,否则Indy不会启用完整的证书链校验。
- 修复:在服务器启动前设置以下选项:
with IdServerIOHandlerSSLOpenSSL1.SSLOptions do begin VerifyMode := [sslvrfPeer, sslvrfFailIfNoPeerCert]; // 要求客户端提供证书并强制验证 VerifyDepth := 1; // 自签名根CA的链深度设为1即可 end; IdServerIOHandlerSSLOpenSSL1.RootCertFile := '你的根CA绝对路径';
3. Indy与OpenSSL版本不兼容
Indy 10对OpenSSL版本有严格要求:旧版Indy(比如10.6.2之前)只支持OpenSSL 1.0.x,新版才支持1.1.x,完全不支持3.x。版本不匹配会导致证书加载、校验逻辑异常。
- 修复:
- 查看你的Indy版本,下载对应兼容的OpenSSL库(比如Indy 10.6.2.5366+用OpenSSL 1.1.1系列)
- 将对应的
libcrypto-1_1.dll和libssl-1_1.dll(或1.0.x的libeay32.dll/ssleay32.dll)放到程序运行目录
4. 根CA未被正确加入验证链
如果你的根CA证书是单独的PEM文件,部分Indy版本不会自动将其加入SSL验证存储,需要手动添加。
- 修复:用
AddRootCertificate方法手动加载根CA:IdServerIOHandlerSSLOpenSSL1.SSLOptions.Certificates.AddRootCertificate('你的根CA绝对路径');
5. SSL上下文初始化时机错误
如果在服务器启动后(Active := True)才设置证书路径或SSL选项,Indy已经初始化了SSL上下文,新设置不会生效。
- 修复:确保所有SSL相关配置都在
IdTCPServer1.Active := True之前完成。
替代方案:正确的验证回调实现
如果上述步骤都无效,可以用OnVerifyPeer回调手动完成证书验证,避免临时跳过校验的风险:
function TForm1.IdServerIOHandlerSSLOpenSSL1VerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean; var LX509: PX509; LStore: PX509_STORE; LCtx: PX509_STORE_CTX; LVerifyResult: Integer; begin Result := False; LX509 := Certificate.X509; // 创建证书存储并加载根CA LStore := X509_STORE_new(); try if X509_STORE_load_locations(LStore, PAnsiChar(AnsiString(ExtractFilePath(ParamStr(0)) + 'ca.crt')), nil) = 0 then Exit; // 初始化验证上下文 LCtx := X509_STORE_CTX_new(); try if X509_STORE_CTX_init(LCtx, LStore, LX509, nil) = 0 then Exit; // 执行证书验证 LVerifyResult := X509_verify_cert(LCtx); if LVerifyResult = 1 then Result := True else ShowMessage('证书验证失败,错误码:' + IntToStr(X509_STORE_CTX_get_error(LCtx))); finally X509_STORE_CTX_free(LCtx); end; finally X509_STORE_free(LStore); end; end;
内容的提问来源于stack exchange,提问作者loltrol
相关产品推荐
相关产品推荐

