c++qtsslwebserverqsslsocket

How to use the TLS protocol on Qt?


Please give an example of the server side, which shows use TLS.

Now I have the following code:

#include <QCoreApplication>
#include "server.h"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    Server h;
    return a.exec();
}

///////////////////////////////////////

#ifndef SERVER_H
#define SERVER_H

#include <QTcpServer>

class Server : public QTcpServer {
    public:
    Server();

    void incomingConnection(int);
};

#endif // SERVER_H


///////////////////////////////////////////

#include "server.h"

#include <QSslSocket>
#include <QSslCertificate>

Server::Server() {
    if (!listen(QHostAddress::Any, 80)) {
        //error
    }
}

void Server::incomingConnection(int d) {
    QSslSocket * socket = new QSslSocket();
    if(socket->setSocketDescriptor(d)) {
        QString c, k;
        c = "site.crt";
        k = "site.key";
        socket->setLocalCertificate(c);
        socket->setPrivateKey(k);
        socket->startServerEncryption();
        if(socket->waitForEncrypted()) {
            if(socket->waitForReadyRead()) {
                socket->write(socket->readAll());
                socket->waitForBytesWritten();
                socket->disconnectFromHost();
                if(socket->state() == QTcpSocket::UnconnectedState) {
                    socket->waitForDisconnected();
                }
                socket->close();
                socket->deleteLater();
            }
            else {
                delete socket;
            }
        }
        else {
            delete socket;
        }
    }
}

How can I change it to first use protocol TLS, and then SSL?

Common task is to write a server with support for SNI.


Solution

  • Here is a sample SSL or TLS server which uses a server.key and a server.crt file for encryption:

    #include <QtNetwork>
    #include <QMessageBox>
    
    class server : public QTcpServer
    {
        Q_OBJECT
    public:
        explicit server(QObject *parent = 0);
        ~server();
    
        QSslSocket server_socket;
    
    public slots:
    
    
          void tcpReady();
    
          void encrypted();
    
          void sslError( QList<QSslError> errors );
    
          bool start_listen(int port_no);
    
    protected:
        void incomingConnection(qintptr descriptor );
    
    };
    
    server::server(QObject *parent) :
        QTcpServer(parent)
    {
    
        server_socket.setProtocol(QSsl::AnyProtocol);
    
        QByteArray key;
        QByteArray cert;
    
        QFile file_key("server.key");
        if(file_key.open(QIODevice::ReadOnly))
        {
            key = file_key.readAll();
            file_key.close();
        }
        else
        {
            qDebug() << file_key.errorString();
        }
    
        QFile file_cert("server.crt");
        if(file_cert.open(QIODevice::ReadOnly))
        {
            cert = file_cert.readAll();
            file_cert.close();
        }
        else
        {
            qDebug() << file_cert.errorString();
        }
    
    
        QSslKey ssl_key(key, QSsl::Rsa,QSsl::Pem,QSsl::PrivateKey,"server");
    
        QSslCertificate ssl_cert(cert);
    
        server_socket.addCaCertificate(ssl_cert);
        server_socket.setLocalCertificate(ssl_cert);
        server_socket.setPrivateKey(ssl_key);
    
    
        connect( &server_socket, SIGNAL(sslErrors(QList<QSslError>)),
                this, SLOT(sslError(QList<QSslError>)) );
    
        connect(&server_socket,SIGNAL(encrypted()),this,SLOT(encrypted()));
    
        server_socket.setSocketOption(QAbstractSocket::KeepAliveOption, true );
    }
    
    server::~server()
    {
        server_socket.disconnectFromHost();
        server_socket.waitForDisconnected();
    }
    
    void server::tcpReady()
    {
        QByteArray array = server_socket.read( server_socket.bytesAvailable() );
        //...
    }
    
    void server::encrypted()
    {
        connect( &server_socket, SIGNAL(readyRead()),
                 this, SLOT(tcpReady()) );
        emit connection_established();
    }
    
    void server::sslError(QList<QSslError> errors)
    {
        QString erroStr="";
        foreach (const QSslError &e, errors)
            erroStr.append(e.errorString()).append("\n");
    
        QMessageBox::warning( (QWidget *)this->parent(), tr("Error"),erroStr );
    
        server_socket.ignoreSslErrors();
    }
    
    
    bool server::start_listen(int port_no)
    {
        if( !this->listen( QHostAddress::Any, port_no ) )
        {
            QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Cannot listen to port %1").arg(port_no) );
    
        }
        else
            return true;
    }
    
    void server::incomingConnection(qintptr descriptor)
    {
        if(server_socket.state()!=QAbstractSocket::UnconnectedState)
            return;
        if( !server_socket.setSocketDescriptor( descriptor ) )
        {
            QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Socket error!") );
            return;
        }
        else
        {
            server_socket.startServerEncryption();
        }
    }
    

    you can set the protocol to QSsl::SslV3 or QSsl::TlsV1 to only accept SSL or TLS connections.