Recently, I needed to implement safe online communication in C++ and Qt with an online server. Obviously, QSslSocket on the client side and a modified QTcpServer (like the one by Rich Moore (maintainer of Qt Network) over at his github) is the way to go here. The basic setup was quickly implemented but securing it correctly was a bit more of a challenge than expected and took quite a bit of googling as I’m not an expert on SSL and/or network security.

In the end I think I have a pretty good and actually easy setup, so I wanted to share it here. First of all, I wanted to use a real certificate from an established CA. As I’m currently on a budget, Let’s Encrypt is a perfect choice there. It took me about 5 minutes to read the instructions, installing it on my server, and generating the first certificates. To use those certificates, I added the following code to an init() method in my SslServer:

QFile certFile("/etc/letsencrypt/live/<your domain>/cert.pem");
if( !certFile.open( QIODevice::ReadOnly ) )
{
	qCritical() << "Unable to open the certificate!!!";
	return false;
}
m_cert = QSslCertificate( &certFile );
if( m_cert.isNull() )
{
	qCritical() << "Certificate was not valid!";
	return false;
}

QFile keyFile("/etc/letsencrypt/live/<your domain>/privkey.pem");
if( !keyFile.open( QIODevice::ReadOnly ) )
{
	qCritical() << "Unable to open the key!!!";
	return false;
}
m_key = QSslKey( &keyFile, QSsl::Rsa );
if( m_key.isNull() )
{
	qCritical() << "Key was not valid!";
	return false;
}

m_cert and m_key are member variables for the certificate and private key. Unfortunately that means, that you have to either start your server as root or make the key and certificate readable for your program. The “cleanest” way I found was to create a new group sslUsers and add every user that needs access to it and use chown to make the files accessible by that group.

After that, I added the following code to the incommingConnection() method of the server just before the addPendingConnection() and socket->startServerEncryption():

socket->setLocalCertificate( m_cert );
socket->setPrivateKey( m_key );

The last thing you have to do after all this is to package your client with the chain.pem also found in /etc/letsencrypt/live/<your domain>/ and load it into the QSslSocket before establishing the connection like this:

QFile chain("chain.pem");
if( chain.open( QIODevice::ReadOnly ) )
{
	QSslCertificate chainCert( &chain );
	if( !chainCert.isNull() )
		socket->addCaCertificate( chainCert );
	else
		qWarning() << "Chain certificate is invalid.";
}
else
	qWarning() << "Unable to read chain certificate.";

Now you can establish a secure connection without ever using QSslSocket::ignoreSslErrors().

I hope this little entry helped you in some way. If it didn’t or you have some comments, please let me know! If it did help you, let me know too! :)