TIdTCPClient 连接后启动 TLS

TIdTCPClient start TLS after connected

我正在处理连接和握手后需要启动 TLS 的协议,如下所示:

procedure TForm1.Button1Click(Sender: TObject);
var
  SSL: TIdSSLIOHandlerSocketOpenSSL;
begin
  SSL:= TIdSSLIOHandlerSocketOpenSSL.Create;
  SSL.SSLOptions.Method:= sslvTLSv1_2;
  IdTCPClient1.Connect;
  if IdTCPClient1.Connected then
  begin
    //plain-text operations
    HandShake;
    CheckAnswer;
    //finish plain-text start TLS
    IdTCPClient1.IOHandler:= SSL;
    SendTLSSecureBytes;
  end;
end;

进入 SendTLSSecureBytes 过程并通过连接发送内容后,我得到异常:"Connection closed gracefully"

做这项工作缺少什么?

您需要在调用TIdTCPClient.Connect()之前将SSLIOHandler对象分配给TIdTCPClient.IOHandler属性。如果你不分配一个 IOHandler 对象,Connect() 将创建一个默认的 TCP-only 对象,一旦套接字连接打开你就不能分配一个新的 IOHandler 对象。

然后,当您准备调用 TLS 握手时,将 SSLIOHandler.PassThrough 属性 设置为 False:

procedure TForm1.Button1Click(Sender: TObject);
var
  SSL: TIdSSLIOHandlerSocketOpenSSL;
begin
  SSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdTCPClient1);
  SSL.SSLOptions.Method := sslvTLSv1_2;
  IdTCPClient1.Connect; // raises exception if failed
  // do plain-text operations, then...
  SSL.PassThrough := False // do TLS handshake
  SendTLSSecureBytes; // will be encrypted by TLS
end;

注意,为了以后参考(不适用于这种情况),如果您需要在建立套接字连接时立即执行TLS握手,可以将SSLIOHandler.PassThrough 属性设置为False在调用 TIdTCPClient.Connect() 之前,握手将在 Connect() 退出之前完成:

procedure TForm1.Button1Click(Sender: TObject);
var
  SSL: TIdSSLIOHandlerSocketOpenSSL;
begin
  SSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdTCPClient1);
  SSL.SSLOptions.Method := sslvTLSv1_2;
  SSL.PassThrough := False // do TLS handshake upon connect
  IdTCPClient1.Connect; // raises exception if failed
  SendTLSSecureBytes; // will be encrypted by TLS
end;