c++qtsslopensslqtcpserver

How to handle TLS handshake timeout in QTcpServer?


I'm trying to figure out how to create a timeout for the handshake process in a TLS connection in a QTcpServer.

I tried something like this in the overriden incomingConnection function:

QSslSocket * const tlsSocket = static_cast<QSslSocket*>(socket);
    connect(tlsSocket, &QSslSocket::encrypted, this, [this, tlsSocket](){ addPendingConnection(tlsSocket); });
    tlsSocket->setLocalCertificate(m_serverCertificate);
    tlsSocket->setPrivateKey(m_serverPrivateKey);
    tlsSocket->setProtocol(QSsl::SecureProtocols);
    tlsSocket->startServerEncryption();

    // We will have a handshake timeout of 30 seconds
    QTimer::singleShot(30*1000, this, [this, tlsSocket]() {
        if(!tlsSocket->isEncrypted()) {
            // If no handshake initialized from the client close the connection
            delete tlsSocket;
        }
    });

But this doesn't seem to work because I am not calling directly addPendingConnection function (it get's called in a slot/lamdba which seems to break the pendingConnection chain.

Does anybody know how can I achieve this timeout in Qt? The problem at the moment is that a client can open a connection with the server and it never answers the TLS handshake which leads to an useless open connection (that is never closed).


Solution

  • I ended implementing the TLS handshake timeout this way:

    // We will have a handshake timeout of 30 seconds (same as firefox today)
    QTimer::singleShot(30*1000, this, [this]() {
    
        // we use dynamic_cast because this may be or not an encrypted socket
        QSslSocket * const tlsSocket = dynamic_cast<QSslSocket*>(m_socket);
    
        if(tlsSocket != nullptr && !tlsSocket->isEncrypted()) {
            qWarning() << "TLS Handshake timeout for connection from " <<
                          tlsSocket->peerAddress().toString() << ":" << tlsSocket->peerPort();
            tlsSocket->close();
        }
    });
    

    This code can be added anywhere where is more practical for your project. I added it in a session class that we have (which owns the created socket), this class is created in the end of newConnection slot. I have tested it and works perfectly.