Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Indy TCPServer/TCPClient
#1
Hello,

We have developed a thread-based TCPServer-application running on company machine (Windows 7) with fixed IP and fixed Port.
We also developed a standalone TCPClient application distributed to our customers.
We are now planning to change this Client-Server model to use SSL encryption (a server certificate does exist).

Can you please point me to some sample code how to implement SSL on server and on client  side.

Thanks in advance,
Wolfgang
Reply
#2
(05-03-2018, 02:44 PM)wzehntner Wrote: We are now planning to change this Client-Server model to use SSL encryption (a server certificate does exist).

Can you please point me to some sample code how to implement SSL on server and on client  side.

There is really not much to it.

On the server side:
  • Assign a TIdServerIOHandlerSSLBase-derived component, such as TIdServerIOHandlerSSLOpenSSL, to the TIdTCPServer.IOHandler property before activating the server, and configure the IOHandler as needed (certificate, etc).  If you do use OpenSSL, deploy the two OpenSSL library binaries, libeay32 and ssleay32, with your server app.

  • When you are ready to begin listening for an SSL/TLS handshake from the client, either in the TIdTCPServer.OnConnect or TIdTCPServer.OnExecute event, typecast the client's IOHandler property to TIdSSLIOHandlerSocketBase and set its PassThrough property to false:

    Code:
    TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;

    If you set the PassThrough to false at the top of the OnConnect event, the handshake will be performed immediately upon the client connecting to the server, before any other data is exchanged.

    If you set the PassThrough to false in the middle of the OnConnect event, or in the OnExecute event, that gives the client the opportunity to exchange commands and responses unencrypted as before, and then explicitly request permission to perform an SSL/TLS handshake before actually performing it.  This is useful when you need to continue supporting older clients that do not use SSL/TLS encryption.

On the client side:
  • Assign a TIdSSLIOHandlerSocketBase-derived component, such as TIdSSLIOHandlerSocketOpenSSL, to the TIdTCPClient.IOHandler property.  If you do use OpenSSL, deploy the two OpenSSL library binaries, libeay32 and ssleay32, with your client app.

  • When you are ready to initiate an SSL/TLS handshake with the server, set the IOHandler's PassThrough property to false:

    Code:
    TIdSSLIOHandlerSocketBase(IdTCPClient1.IOHandler).PassThrough := False;

    If you set the PassThrough to false before calling TIdTCPClient.Connect(), the handshake will be performed immediately upon the client connecting to the server, before any other data is exchanged.

    If you set the PassThrough to false after calling TIdTCPClient.Connect(), that gives the client the opportunity to exchange commands and responses unencrypted as before, and then explicitly request permission to perform an SSL/TLS handshake before actually performing it.  This is useful when you need to continue supporting older servers that do not use SSL/TLS encryption.

Reply
#3
(05-03-2018, 07:32 PM)rlebeau Wrote: If you set the PassThrough to false after calling TIdTCPClient.Connect(), that gives the client the opportunity to exchange commands and responses unencrypted as before, and then explicitly request permission to perform an SSL/TLS handshake before actually performing it.  This is useful when you need to continue supporting older servers that do not use SSL/TLS encryption.

Thanks a lot, that will get me started. I will probably come back to you on how to request permission (activate the SSL/TSL handshake) on the client side ...
Reply
#4
(05-04-2018, 08:53 AM)wzehntner Wrote: I will probably come back to you on how to request permission (activate the SSL/TSL handshake) on the client side ...

Simply have the client connect initially unencrypted and then send an appropriate command to the server, and wait for the server to reply success, before then performing the SSL/TLS handshake on both ends. Internet protocols like POP3, SMTP, IMAP, etc have commands for this very purpose (STLS, STARTTLS, etc). Simply add a similar command to your existing protocol.

Reply
#5
Hello,

Finally I managed to implement a SSL server (with self-signed certificate) and a separate client.
Basically I followed these examples:
https://github.com/rlove/Indy-SSL-Examples (for Server and client application)

https://github.com/rlove/OpenSSL-WinCmd-Snippets (for a self-signed certificate)

I also assigned a verifyonpeer-event:
Code:
function TForm2.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509;
  AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
  memoResults.Lines.Add('OpenSSL1VerifyPeer: '+
            'AOk='+BoolToStr(AOK,true)+' ADepth='+inttostr(ADepth)+' AError='+inttostr(AError) );
  // ^ PS: I am aware that above code is not thread safe; only for test-phase
  if ADepth = 0 then
  begin
    Result := true; //AOk;
  end
  else
  begin
    Result := True;
  end;
end;

As you can see from this code I forced 'Result := true'
I tried for ADepth = 0 and also ADepth = 1
The AError that is returned is always = 19
1. Where can I find a list of AError-codes ?

2. Does a self-signed certificate always return this error-code or am I missing something ?

3. I also noticed that the Verify-event is triggered 3 times when ADepth = 1
Why is that so ?

4. How can I display (on the client side) some information about the server-certificate (thus giving the client a chance to accept and trust the certificate)?

Any help is greatly appreciated !
Reply
#6
could someone explain me how to install ssl into intraweb
Reply
#7
I would suggest you ask in the IntraWeb areas.
Reply
#8
(05-14-2018, 07:11 AM)wzehntner Wrote: The AError that is returned is always = 19
Where can I find a list of AError-codes ?

They come from OpenSSL's X509_STORE_CTX_get_error() function. Error 19 is X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN. Most of the X509_V_ERR_... error codes are defined in Indy's IdSSLOpenSSLHeaders unit (the rest are in the x509_vfy.h header file in OpenSSL's SDK).

(05-14-2018, 07:11 AM)wzehntner Wrote: Does a self-signed certificate always return this error-code

Yes.

(05-14-2018, 07:11 AM)wzehntner Wrote: I also noticed that the Verify-event is triggered 3 times when ADepth = 1
Why is that so ?

I can't answer that.

(05-14-2018, 07:11 AM)wzehntner Wrote: How can I display (on the client side) some information about the server-certificate (thus giving the client a chance to accept and trust the certificate)?

All the certificate information is available via the TIdX509 object that is provided in the OnVerifyPeer event. Some details are exposed in nice property wrappers. Other details you will have to query manually from OpenSSL directly, using the raw PX509 handle from the TIdX509.Certificate property.

Reply
#9
(05-14-2018, 06:27 PM)rlebeau Wrote: All the certificate information is available via the TIdX509 object that is provided in the OnVerifyPeer event.  Some details are exposed in nice property wrappers.  Other details you will have to query manually from OpenSSL directly, using the raw PX509 handle from the TIdX509.Certificate property.

Hello,

I can successfully display Certificate.FingerprintAsString, Certificate.Issuer.OneLine and other properties (in my OnVerifyPeer-Event)
but did not succeed in showing the public key (in my case RSA 2048 bits)
We do not supply OpenSSL.exe to our customers, we only supply our Client-application together with libeay32.dll and ssleay32.dll
I am a bit confused what you mean with "query manually from OpenSSL ..."
How can I access the public key within our Client-application ? Do you have some sample code?
Please help.
Reply
#10
(05-17-2018, 08:21 AM)wzehntner Wrote: I can successfully display Certificate.FingerprintAsString, Certificate.Issuer.OneLine and other properties (in my OnVerifyPeer-Event)
but did not succeed in showing the public key (in my case RSA 2048 bits)
We do not supply OpenSSL.exe to our customers, we only supply our Client-application together with libeay32.dll and ssleay32.dll
I am a bit confused what you mean with "query manually from OpenSSL ..."

As I said, not everything in an OpenSSL certificate is exposed by Indy in nice property wrappers.  In the case of the public key, try accessing the TIdX509.Certificate.cert_info.key field.

But, to be safer, you really should be using OpenSSL functions that are designed to access that data for you.  See this discussion:

X509* and Extract Public Key?

Indy does have a definition for the X509_PUBKEY record, but it does not import any of the X509 functions mentioned in that discussion.  You would have to import those functions yourself from the OpenSSL DLLs. But, you can get the required X509 record pointer from Indy's TIdX509.Certificate property, at least.

Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)