TIdTCPClient start TLS after connected

Viewed 627

I'm dealing with a protocol that needs to start TLS after connected and handshaked, something like this:

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;

Once I get inside SendTLSSecureBytes procedure, and send something over the connection, I get the exception: "Connection closed gracefully"

Something missing to do this work?

1 Answers

You need to assign the SSLIOHandler object to the TIdTCPClient.IOHandler property before you call TIdTCPClient.Connect(). If you do not assign an IOHandler object, Connect() will create a default TCP-only object, and you can't assign a new IOHandler object once the socket connection has been opened.

Then, set the SSLIOHandler.PassThrough property to False when you are ready to invoke the TLS handshake:

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;

Note, for future reference (not applicable to this situation), if you need the TLS handshake to be performed immediately upon establishing the socket connection, you can set the SSLIOHandler.PassThrough property to False before calling TIdTCPClient.Connect(), and the handshake will be completed before Connect() exits:

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;
Related