Solved 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).
-
@RandomGuy said in How to handle TLS handshake timeout in QTcpServer?:
QSslSocket
Instead of worrying about getting a timeout, I'd check for any SSL errors, so you may want to listen to the sslErrors signal.
I expect that any handshake timeout happening between your clients and your server will fire up such signal.
-
@Pablo-J-Rogina said in How to handle TLS handshake timeout in QTcpServer?:
@RandomGuy said in How to handle TLS handshake timeout in QTcpServer?:
QSslSocket
Instead of worrying about getting a timeout, I'd check for any SSL errors, so you may want to listen to the sslErrors signal.
I expect that any handshake timeout happening between your clients and your server will fire up such signal.
Thanks I tried that. I added this in the server:
connect(tlsSocket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), [](const QList<QSslError> &errors) { for(const QSslError &error:errors) qWarning() << error.errorString(); });
But I don't see any error after some minutes, after the connection has been opened by the client. Also if the client sends invalid bytes to start the handshake, the server automatically closes the connection (which is good) but I also don't get an error for that.
The client is not a Qt program. I am using putty directly through a raw connection to test this.
-
@RandomGuy said in How to handle TLS handshake timeout in QTcpServer?:
QSslSocket * const tlsSocket = static_cast<QSslSocket*>(socket);
What is this supposed to do? What is
socket
? TheincomingConnection
gives you a socket descriptor, a.k.a. a handle - and opaque pointer, ifsocket
is the descriptor you can't just arbitrarily cast it, instead attach it withQTcpSocket::setSocketDescriptor
. -
@RandomGuy you may want to check this project, especially the Tcp Server class with SSL support using QTcpServer and QSslSocket
-
@kshegunov said in How to handle TLS handshake timeout in QTcpServer?:
@RandomGuy said in How to handle TLS handshake timeout in QTcpServer?:
QSslSocket * const tlsSocket = static_cast<QSslSocket*>(socket);
What is this supposed to do? What is
socket
? TheincomingConnection
gives you a socket descriptor, a.k.a. a handle - and opaque pointer, ifsocket
is the descriptor you can't just arbitrarily cast it, instead attach it withQTcpSocket::setSocketDescriptor
.socket, is simply the QTcpSocket that I created:
// Create socket QTcpSocket *socket = nullptr; if(!m_tlsEnabled) { socket = new QTcpSocket(this); } else { socket = new QSslSocket(this); } if(!socket->setSocketDescriptor(socketDescriptor)) { return; }
As my code can work with TLS or without.
@Pablo-J-Rogina said in How to handle TLS handshake timeout in QTcpServer?:
@RandomGuy you may want to check this project, especially the Tcp Server class with SSL support using QTcpServer and QSslSocket
Thanks I will have a look for handshake timeout handling.
-
@RandomGuy said in How to handle TLS handshake timeout in QTcpServer?:
socket, is simply the QTcpSocket that I created:
Then I don't understand the need for a static cast, but anyway.
Do you listen to the state changes? Do you listen to peer verification errors? -
Hi @Pablo-J-Rogina and @kshegunov ,
Thanks for your help. The project https://github.com/GuiTeK/Qt-SslServer didn't solve my issue but it gave me some ideas.
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.
-
@RandomGuy said in How to handle TLS handshake timeout in QTcpServer?:
I have tested it and works perfectly.
Calling
close()
whenever SSL has raised an error is ill advised[1]. -
@kshegunov said in How to handle TLS handshake timeout in QTcpServer?:
@RandomGuy said in How to handle TLS handshake timeout in QTcpServer?:
I have tested it and works perfectly.
Calling
close()
whenever SSL has raised an error is ill advised[1].Thanks for the information. I will keep this in mind in case problems arise.