Thanks to NSA, most probably every developer is aware of the HTTPS and the underlying TLS (or older SSL). While most scenarios involve authentication of a server, authentication of a client is often overlooked.
If you wonder what you gain, just be reminded of key-based authentication in the SSH. No need to exchange username/password with every client. You just exchange a (safely stored) key and you know who is on the other side.
Distribution and a safe storage of the client certificate is a non-trivial problem but easily handable on a smaller scale. Windows certificate store is not too bad and the client authentication makes it easy to block keys that aren’t trusted any more.
Here is the example code of a simple TLS encrypted TCP client/server with a self-signed certificates. Of course, one would expect proper certificates to be used in any production environment, but these will do in a pinch.
First we need to setup a server using just a standard TCP listener with a twist:
var serverCertificate = new X509Certificate2(ServerCertificateFile);
var listener = new TcpListener(IPAddress.Any, ServerPort);
listener.Start();
while (true) {
using (var client = listener.AcceptTcpClient())
using (var sslStream = new SslStream(client.GetStream(), false, App_CertificateValidation)) {
sslStream.AuthenticateAsServer(serverCertificate, true, SslProtocols.Tls12, false);
``//send/receive from the sslStream``
}
}
Client is equally simple:
var clientCertificate = new X509Certificate2(ClientCertificateFile);
var clientCertificateCollection = new X509CertificateCollection(new X509Certificate[] { clientCertificate });
using (var client = new TcpClient(ServerHostName, ServerPort))
using (var sslStream = new SslStream(client.GetStream(), false, App_CertificateValidation)) {
sslStream.AuthenticateAsClient(ServerCertificateName, clientCertificateCollection, SslProtocols.Tls12, false);
``//send/receive from the sslStream``
}
Only trick in validation is to allow certificate chain errors. That is needed for self-signed certificates to work:
bool App_CertificateValidation(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None) { return true; }
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return true; } //we don't have a proper certificate tree
return false;
}
It is really this simple to convert any TCP socket code into the encrypted TLS.
Full example is available for download.