We are using a TIdCmdTCPServer
with a TIdServerIOHandlerSSLOpenSSL
server-side and TIdTCPClient
with TIdSSLIOHandlerSocketOpenSSL
client-side in Delphi 10.1.
I can successfully establish an encrypted connection when setting PassThrough to false before calling FTCPClient.Connect
and having
procedure TIndyTcpCommandReceiver.TCPServerConnect(AContext: TIdContext);
begin
if AContext.Connection.IOHandler is TIdSSLIOHandlerSocketOpenSSL then
TIdSSLIOHandlerSocketOpenSSL(AContext.Connection.IOHandler).PassThrough := false;
end;
We deploy the same server.exe to various servers. Some of them have certificates installed, others don't.
I only want to establish an encrypted connection, if there is a certificate.
I modified my client side code following the instructions from https://stackoverflow.com/a/46412958/865602, initially setting PassThrough := true
and setting PassThrough := false
once a connection has been established.
procedure TTCPConnector.Connect;
begin
FSSLIOHandler.PassThrough := true;
FTCPClient.Connect(FServerName, FPort); // succeeds
FSSLIOHandler.PassThrough := false ; // fails
end;
However, I can't find an answer on how to modify my server-side code. I can only establish the initial connection if I don't use the code in the TCPServerConnect
event.
What do I have to change in the server to switch to an encrypted connection after the client set PassThrough to false?
I only want to establish an encrypted connection, if there is a certificate.
Then you need to change your protocol to a STARTTLS model, where the client asks the server for permission to encrypt the connection before actually doing so.
Have the client connect normally with PassThrough=True
on both sides. Then have the client send an unencrypted command to the server, and have the server respond with whether permission is granted or denied based on whether a certificate is installed. If granted, then both parties can set PassThrough=False
to encrypt the connection before any further data is exchanged.
For example:
procedure TIndyTcpCommandReceiver.TCPServerConnect(AContext: TIdContext);
begin
if AContext.Connection.IOHandler is TIdSSLIOHandlerSocketBase then
TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := true;
end;
procedure TIndyTcpCommandReceiver.TCPServerSTARTTLSCommand(ASender: TIdCommand);
begin
if (ASender.Context.Connection.IOHandler is TIdSSLIOHandlerSocketBase) and
TIdSSLIOHandlerSocketBase(ASender.Context.Connection.IOHandler).PassThrough and
(Certificate Is Installed) then // <-- implement as needed...
begin
ASender.Reply.SetReply(220, 'Send TLS handshake');
ASender.SendReply;
TIdSSLIOHandlerSocketBase(ASender.Context.Connection.IOHandler).PassThrough := False;
end
else
ASender.Reply.SetReply(454, 'Dont send TLS handshake');
end;
procedure TTCPConnector.Connect;
begin
FSSLIOHandler.PassThrough := true;
FTCPClient.Connect(FServerName, FPort);
FTCPClient.GetResponse; // read greeting if needed
if FTCPClient.SendCmd('STARTTLS') = 220 then
FSSLIOHandler.PassThrough := false;
end;