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).
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/emailAddressemail@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 = firstname.lastname@example.org [ 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:
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.
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:
- 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.
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.