Secure Networking with QtSSLSocket

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
Image:qt-logo_new.png Image:qq-title-article.png
Qt Quarterly | Выпуск 10 | Документация

by Andreas Aardal Hanssen

Secure networking has two main requirements. Firstly, you must besure that you are communicating with your intended recipient.Secondly, you need to be confident that the data exchanged has notbeen tampered with or even read by a third party; and that even if itwas read, it could not be deciphered. This article shows how to create a secure client using the OpenSSL library and theQtSSLSocket Qt Solution that meets these requirements.

The SSL (Secure Sockets Layer) is the standard protocol providingnetwork level security. SSL is a software layer on top of the TCPlayer, that uses TCP packets to send encrypted data. [1]

An SSL transmission has three phases: the negotiation (or handshake)phase, the data exchange phase, and the shutdown phase. During thehandshake phase, the server's (and optionally the client's) identityis verified through the exchange of public keys. The peers then agreeon a common algorithm to use for encrypting data in the data exchangephase. The cryptographic algorithms are seeded with random data, andthe data exchange phase begins.

At this point you know who your client has connected to (or whoconnected to your server). The data exchange phase is where the realuser data is sent between the client and the server. This data isencrypted with algorithms such as "DES3" or "Blowfish". Thesealgorithms are considered to be safe from tapping, tampering, andreplaying. When the data exchange phase ends, the shutdown phasestarts. Here, the client and the server ensure that each hasterminated the secure channel and that it is no longer carrying data.The socket connection is then closed.

The number of professional networking services on the Internet thatrequire SSL is both vast and growing. For example, you may want tosubmit purchase orders or to perform credit card transactions, and forthese, banks will insist upon the use of SSL. But Qt's networkingsupport, though good, does not include provision for SSL"out-of-the-box"; indeed there is no straightforward way to enableSSL in Qt applications.

One obvious solution is to link your Qt application against an SSLlibrary. But many of these libraries are complex, with difficult APIs,and either little or poor documentation. And all of them requirein-depth knowledge of the SSL procotol and its implementation. So whatcan you do if you don't know what an X.509 certificate looks like, butneed secure networking?

The answer is to use the QtSSLSocket from the QtSolutions team. QtSSLSocket allows QSocket-based networking applications to addSSL cryptographic support. This class has an easy-to-use interface,and requires no prior knowledge about the SSL protocol. This classprovides a socket for your data blocks, conveniently encrypting whatyou send and decrypting what you receive from your peer. UsingQtSSLSocket, you can easily add SSL to both your client andserver applications, while leaving elbow room for providing SSLencryption for protocols of any level of complexity. And the little SSLknowledge you need to know is in the documentation.

How secure is SSL?
Without a secure networking model, you cannot be certain of who youare really connecting to on the Internet. DNS entries may be forged,the Internet host may be replaced, the data transmission may becompromised or tapped, and so on. On the other hand, the SSL securitymodel provides a very reliable guarantee of the identity of the hostyou are connecting to, by allowing you to verify the host's identitythrough a trusted third party, known as a Certificate Authority (CA).Using the CA's certificate, you can verify the authenticity of thepeer's certificate, and therefore the peer's identity. The mechanismdoes of course depend on the CA being trusted.

But how can you verify the identity of the CA'scertificate? SSL requires that each application has access to a staticbundle of certificates for all the trusted CAs. If you don't have thecertificate of the CA that issued your peer's certificate, you cannotverify the host's identity. But how can the end user safely obtainsuch a bundle of CA certificates? Obviously they cannot be downloadedfrom the Internet using an SSL connection. Therefore, most modernoperating systems include a vendor-supplied package that contains abundle of CA certificates. But if your operating system was installedfrom a CD you bought at a store or got delivered by mail, you musttrust all the postal services involved in the delivery, and theemployees at the store, and of course the manufacturer of the CD. Andif you downloaded your operating system from the Internet, are yousure that your connection was secure?

Let's make a simple SSL client. We can write a complete example injust 50 lines. Let's start with the definition of our Clientclass.

class Client : public QObject
{
    Q_OBJECT
 
public:
    Client(const QString &host, int port);
 
signals:
    void responseReceived();
 
private slots:
    void waitForGreeting();
    void readResponse();
 
private:
    QtSSLSocket *socket;
};

Just like any other QSocket client, we create a subclass with asocket (the QtSSLSocket in this case) as a private member.

Client::Client(const QString &host, int port)
{
    socket = new QtSSLSocket();
    connect(socket, SIGNAL(connected()), SLOT(waitForGreeting()));
    connect(socket, SIGNAL(readyRead()), SLOT(readResponse()));
    connect(socket, SIGNAL(connectionClosed()), qApp, SLOT(quit()));
    connect(socket, SIGNAL(delayedCloseFinished()), qApp, SLOT(quit()));
    socket->connectToHost(host, port);
}

In the constructor, we create our SSL socket and connect its signals,then connect to the host.

void Client::waitForGreeting()
{
    qDebug("Connected; now waiting for the greeting");
}

The waitForGreeting() slot is called when the connection has beenestablished.

void Client::readResponse()
{
    if (socket->canReadLine()) {
        qDebug("Received: %s", socket->readLine().latin1());
        socket->close();
    }
}

The readResponse() slot is just as easy as it would be witha normal QSocket subclass.

When the connection has been closed, the application will terminate.And that's it! For the sake of completeness, here's the main function.We used this example to connect to our IMAP server, which runs on port993:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv, false);
    Client client("imap", 993);
    return app.exec();
}

Running this application gives the following output to the console,depending on what IMAP software you are running:

Connected! Now waiting for the greeting
Received: * OK imap Cyrus IMAP4 v2.1.12 server ready
center

So, is this all that's needed to communicate safely with SSL? Well,not quite. We can't tell whether or not the host's identity checksucceeded during the negotiation phase; there is no code in ourexample handling this important security feature. Let's add thenecessary code to rectify this deficiency.

First, we set the location of the CA certificate bundle. For the sakeof this example, we use the path /etc/ssl/certs, but thelocation of the bundle is different for different operating systemsand distributions. We insert this line into the constructor:

 socket->setPathToCACertDir("/etc/ssl/certs");

Then, we add a slot to catch certificate check failures:

private slots:
    void displayCertError(int, const QString &reason)

Next we connect our socket's signal to this slot:

  connect(socket, SIGNAL(certCheckFailed(int, const QString &)),
                  SLOT(displayCertError(int, const QString &)));

Now we implement the displayCertError() slot.

void Client::displayCertError(int, const QString &reason)
{
    qDebug("Certificate check failed: %s", reason.latin1());
    socket->close();
}

The slot's implementation outputs an error message and closes theconnection. This means that if the certificate cannot be verified, thecommunication is terminated rather than risking an insecureconnection.

The output from the modified program:

Certificate check failed: Self signed certificate in certificate chain

This is all that you need to do to add secure networking to your Qtapplications.

If you want to learn more, the QtSSLSocket documentation has aguide to handling SSL private keys, certificates and CertificateAuthorities.

Note that QtSSLSocket depends on OpenSSL. The OpenSSL library islicenced under an Apache-stylelicense, which essentially means that you are free to use it for bothcommercial and non-commercial purposes subject to some simple licenseconditions; see www.OpenSSL.org.

SSL Tunneling
A common alternative to using SSL from an application is to use an SSLtunnel such as Stunnel (available fromwww.Stunnel.org).Stunnel runs as a separate service which your application can connectto. Stunnel connects to the SSL host on your behalf, encrypting youroutgoing data before it is sent, and decrypting incoming data as itarrives.

Unfortunately, an SSL tunnel is not a general solution.It doesn't solve client side networking in general, as each tunnelserver in client mode can only forward data to one server while yourapplication often needs to send to several servers. Also, although itworks fine with single connection client-server protocols such asHTTP, it can't help you add SSL to FTP, where the port on which youlisten for incoming connections is only known at run-time. Mostimportantly though, an SSL tunnel requires you to run a separateserver alongside your application. This means that you must distributeextra software, and for commercial applications, this may involveadditional licensing costs.


[1] Because of the unreliable nature of UDP datagrams, the SSL protocoldoesn't support UDP.