You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 12:43:19