TIdTCPServer停止时SSL_accept中的Indy / Libssl32访问冲突

时间:2018-07-03 08:44:47

标签: delphi ssl indy

我使用Delphi 10.1 Update 2和Indy 10.6.2.5341。

我们遇到SSL_accept中的访问冲突。如果使用SSL设置了TIdTCPServer,并且TIdTCPServer停止,则存在尚未协商TLS的开放连接。

这看起来像Libssl32或Indy中的问题。使用RAW连接,可以使用以下代码和Putty简单地复制此代码。有谁知道防止这些崩溃的解决方案(或解决方法)?

procedure TSslCrash.HandlerOnExecute(AContext: TIdContext);
begin
  //
end;

procedure TSslCrash.HandlerOnConnect(AContext: TIdContext);
begin
  TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;
end;

procedure TSslCrash.ButtonStartClick(Sender: TObject);
begin
  LServer := TIdTCPServer.Create;
  LIOHandler := TIdServerIOHandlerSSLOpenSSL.Create;

  LIOHandler.SSLOptions.Mode := sslmServer;
  LIOHandler.SSLOptions.Method := sslvTLSv1_2;
  LIOHandler.SSLOptions.VerifyMode := [];
  LIOHandler.SSLOptions.VerifyDepth := 0;
  LIOHandler.SSLOptions.CertFile := 'localhost.crt';
  LIOHandler.SSLOptions.RootCertFile := 'localhost.crt';
  LIOHandler.SSLOptions.KeyFile := 'localhost.key';

  LServer.Bindings.Add.Port := 10000;
  LServer.IOHandler := LIOHandler;
  LServer.OnExecute := HandlerOnExecute;
  LServer.OnConnect := HandlerOnConnect;
  LServer.Active := True;

  //Now open a RAW connection with Putty on port 10000 and keep it open
end;

procedure TSslCrash.ButtonStopClick(Sender: TObject);
begin
  if Assigned(LServer) then begin
    LServer.Active := False;  //This causes an AV in TIdSSLSocket.Accept

    FreeAndNil(LIOHandler);
    FreeAndNil(LServer);
  end;
end;

1 个答案:

答案 0 :(得分:0)

当Putty以Raw模式连接时,没有执行SSL / TLS握手,因此SSL_accept()被困在等待从未到达的握手请求。

停用TIdTCPServer时,它将断开活动的套接字连接,从而使其他线程中正在进行的任何阻塞套接字操作失败。在SSL_accept()的情况下,应该对其进行解锁,以便它退出并显示错误代码,然后TIdSSLSocket.Accept()可以检测并包装为引发的异常(EIdOSSLUnderlyingCryptoErrorEIdOSSLAcceptErrorEIdSocketError,具体取决于错误代码的性质)在等待握手完成的客户端线程的上下文中。

但是,当TIdTCPServer在停用期间断开套接字连接时,将调用TIdTCPConnection.Disconnect()TIdIOHandler.Close()TIdSSLIOhandlerSocketOpenSSL覆盖以释放其内部{{1 }}对象-调用TIdSSLSocket的对象。因此,很有可能在停用线程的上下文中,底层的OpenSSL SSL_accept()对象在SSL(调用TIdSSLSocket.Destroy()SSL_shutdown())中被释放,同时仍在活跃地被释放。在客户端线程的上下文中用在SSL_free()(调用TIdSSLObject.Accept())中,从而导致访问冲突。

在不更改Indy的源代码的情况下,无法做很多事情。例如,也许将SSL_accept()更改为调用TIdCustomTCPServer.DoTerminateContext()而不是AContext.Binding.CloseSocket(),这样AContext.Connection.Disconnect(False)本身就不会被关闭,只是底层套接字(类似于IOHandler的作用)终止其正在监听的TIdCustomTCPServer.StopListening()线程时)。

我已经在Indy的问题跟踪器中为您打开了一张票证:

#218: Access Violation in SSL_accept() when deactivating TIdTCPServer