Pixabay

There are various ways to ensure the security of the communication between a kbmMW based client and server. kbmMW comes with built in support for major synchronous encryption methods, and has 3.party support from for example StreamSec for public key encryption.

However you can also use OpenSSL as explained in this post, or you can use the HTTP.sys transport on Windows if you are creating a web site, and protecting it using the SSL features supported by HTTP.sys as explained in this post.

But what if you are using standard kbmMW client and server transports? Then OpenSSL is also an option, as I will describe here (32 bit version).

Contents

A certificate

First we need to generate or obtain a certificate. There are many places on the net where you can get an official certificate both for free and by paying. Alternatively you can make a self signed certificate. That is a certificate that only you can verify, and thus there are no 3.party instances that will assist you with verifying the integrity of the certificate. But it will be fine for internal servers and clients.

There are a number of steps to be able to make a self signed certificate.

First we need to download a version of OpenSSL that we can use together with kbmMW.

Visit https://indy.fulgan.com/SSL/ to download up to date versions that work well with the Indy transport in kbmMW.

For this blogpost sample I downloaded openssl-1.0.2q-i386-win32.zip.

Extract it to a directory. You will find 2 DLL files within the directory: libeay32.dll and ssleay32.dll. We will use them later.

Further you will find one EXE named openssl.exe. We need that to be able to create the self signed certificate.

But before doing that openSSL require us to provide a configuration file for it. The file can be quite complex, but for our self signed certificate I have prepared one that you can reuse with modifications.

#
# Example OpenSSL configuration file.
#

# This definition stops the following lines choking if HOME isn't
# defined.
HOME					= .
RANDFILE				= $ENV::HOME/.rnd

[ req ]
default_bits			= 2048
distinguished_name		= req_distinguished_name
attributes				= req_attributes

# Stop confirmation prompts. All information is contained below.
prompt					= no

# The extensions to add to a certificate request - see [ v3_req ]
req_extensions			= v3_req

[ req_distinguished_name ]
# Describe the Subject (ie the origanisation).
# The first 6 below could be shortened to: C ST L O OU CN
# The short names are what are shown when the certificate is displayed.
# Eg the details below would be shown as:
#    Subject: C=UK, ST=Hertfordshire, L=My Town, O=Some Organisation, OU=Some Department, CN=www.example.com/emailAddress=bofh@example.com

# Leave as long names as it helps documentation

countryName				= DK
stateOrProvinceName		= Aarhus
localityName			= Hjortshoej
organizationName		= Components4Developers
organizationalUnitName	= R&D
commonName				= www.components4developers.com
emailAddress			= kbm@components4developers.com

[ req_attributes ]
# None. Could put Challenge Passwords, don't want them, leave empty

[ v3_req ]

# X509v3 extensions to add to a certificate request
# See x509v3_config

# What the key can/cannot be used for:
basicConstraints		= CA:FALSE
keyUsage				= nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage		= clientAuth,serverAuth

# The subjectAltName is where you give the names of extra web sites.
# You may have more than one of these, so put in the section [ alt_names ]
# If you do not have any extra names, comment the next line out.
#subjectAltName			= @alt_names

# List of all the other DNS names that the certificate should work for.
# alt_names is a name of my own invention
[ alt_names ]
DNS.1					= devel.example.com
DNS.2					= ipv6.example.com
DNS.3					= ipv4.example.com
DNS.4					= test.example.com
DNS.5					= party.example.com

Save the above text to a file called yourdomain.cnf (yourdomain is anything that makes sense to you, but you should ensure the extension is .cnf).

Then open cmd.exe (a command console) and write the following:

set OPENSSL_CONF=c:\yourdirectory\mydomain.cnf

Where yourdirectory is the directory containing your configuration file and mydomain.cnf the name of your configuration file.

To generate a certificate and a key file (without password protection) which we will use later, type:

openssl req -newkey rsa:2048 -nodes -keyout domain.key -x509 -days 365 -out domain.crt

It will leave a domain.key and domain.crt file for you. These two file will be used along with the 2 DLL’s in our server.

The server

To protect the server which is using a kbmMW Indy TCP transport, we do like this:

    • Add a TIdServerIOHandlerSSLOpenSSL component to the same form/datamodule as the Indy server transport.
    • Set its properties:
      • Mode = sslmServer
      • Method = sslvSSLv23
      • CertFile = the path and name of your domain.crt file
      • KeyFile = the path and name of your domain.key file.
      • If you do not want to use a self signed certificate, but have one that can be verified on the internet, you will also need to set RootCertFile to point on the CA root crt file provided by the online certificate producer (like GoDaddy or others).
      • Write an event handler for the OnConnect event:
        procedure TForm1.kbmMWTCPIPIndyServerTransport1Connect(AContext: TIdContext);
        begin
             TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough:=false;
        end;

        It ensures that the server immediately communicates SSL secured with the client.

      • If you are using a key file that require a password to be entered, you will need to write some code for the eventhandler OnGetPassword. In our case it is not required, but the code could look like this:
        procedure TForm1.IdServerIOHandlerSSLOpenSSL1GetPassword(var Password: string);
        begin
             Password:=CertPassword;
        end;
      • Copy the DLL files to the directory where the server’s executable exists.
    • Somewhere in your code before the server transport is activated, hook up the TIdServerIOHandlerSSLOpenSSL instance to the transport:
           kbmMWTCPIPIndyServerTransport1.IdTCPServer.IOHandler:=IdServerIOHandlerSSLOpenSSL1;
      
    • You need to ensure that the units IdContext, IdServerIOHandler, IdSSL, IdSSLOpenSSL are all in your units uses clause.

Now your server is ready to serve, protected by SSL and your self signed certificate. Let us look at the client.

Start your server. If the certificate and key file is not found, you most likely will see this error:

But if all is in place, your server should start up without problems.

The client

Again we choose to use the kbmMW Indy transport which we easily can hook SSL support into.

To the form/datamodule holding your kbmMW client Indy transport, add a TIdSSLIOHandlerSocketOpenSSL instance.

Set it’s Mode = sslmClient

Using the standard request/response Indy TCP client transport, you will need to write an eventhandler for OnBeforeConnect (available in kbmMW v. 5.12.00):

procedure TForm1.kbmMWTCPIPIndyClientTransport1BeforeConnect(Sender: TObject);
begin
     kbmMWTCPIPIndyClientTransport1.IdTCPClient.IOHandler:=IdSSLIOHandlerSocketOpenSSL1;
     IdSSLIOHandlerSocketOpenSSL1.PassThrough:=false;
end;

The above code, ensures that the client is talking SSL from start.

Copy the 2 DLL files to the same directory where the client’s executable is found, but (IMPORTANT!!!) do not distribute the key or crt files to clients as that would totally ruin your security. Those files needs to be kept safe from prying eyes!

Run the client.

Now the client will communicate SSL secured with the server.

Loading

9 thoughts on “Did you know? #4 – Using SSL between your client and server”
  1. Can I use Method = sslvTLS1.2 at server with these 2 crt and key files created by cmd: “openssl req -newkey rsa:2048 -nodes -keyout domain.key -x509 -days 365 -out domain.crt”

  2. Hi Kim
    I hate to be pain in the neck. I did EXACTLY what this article says (triple checked it) and my client cannot connect to the server (message ‘Connection lost.’).

    I guess my .cnf file has some wrong settings. In your .cnf example file I just changed [ req_distinguished_name ] section to reflect my settings. I generated .crt and .key files on my VPS Win Server 2019 machine in the cloud where my kbm server is. All openssl.exe files and .dll files are in my kbm server folder. Server starts ok, but from my client (there are ssl dll’s in client folder) I get this Connection lost message.

    Is there anything you can suggest me to do? On my Win Server 2019 I don’t have IIS installed. Could that be a problem?

    1. Hi, Kim

      We followed your above instructions, and we also get ‘Connection Lost’ from client, we have checked all the source codes, nothing is missing. At this point, we don’t know how to implement this new feature. Please advice

  3. First of try to run them on the same computer to rule out any intermediate filtering.
    Secondly check that the demo server and client application here in your kbmMW installation (\Demo\Other\OpenSSL) works untouched.
    If it works for you, then progress from there to figure out where the difference is.

    1. Just tried the demo, Start SrvDemo first, Click Listen, no error, then start CliDemo, Click Connect button, no error, switch to Query services tab, click Query button, got ‘Connection Lost’.

    2. Also tried the “Query all” and “Query selected” buttons at Named query services tab, got “Connection Lost” error too, even though I assigned SimpleClient1 to the Client property of query components.

Leave a Reply to William Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.