1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5/*!
6 \class QSslServer
7
8 \ingroup network
9 \ingroup ssl
10 \inmodule QtNetwork
11 \since 6.4
12
13 \brief Implements an encrypted, secure TCP server over TLS.
14
15 Class to use in place of QTcpServer to implement TCP server using
16 Transport Layer Security (TLS).
17
18 To configure the secure handshake settings, use the applicable setter
19 functions on a QSslConfiguration object, and then use it as an argument
20 to the setSslConfiguration() function. All following incoming
21 connections handled will use these settings.
22
23 To start listening to incoming connections use the listen() function
24 inherited from QTcpServer. Other settings can be configured by using the
25 setter functions inherited from the QTcpServer class.
26
27 Connect to the signals of this class to respond to the incoming connection
28 attempts. They are the same as the signals on QSslSocket, but also
29 passes a pointer to the socket in question.
30
31 When responding to the pendingConnectionAvailable() signal, use the
32 nextPendingConnection() function to fetch the next incoming connection and
33 take it out of the pending connection queue. The QSslSocket is a child of
34 the QSslServer and will be deleted when the QSslServer is deleted. It is
35 still a good idea to destroy the object explicitly when you are done
36 with it, to avoid wasting memory.
37
38 \sa QTcpServer, QSslConfiguration, QSslSocket
39*/
40
41/*!
42 \fn void QSslServer::peerVerifyError(QSslSocket *socket, const QSslError &error)
43
44 QSslServer can emit this signal several times during the SSL handshake,
45 before encryption has been established, to indicate that an error has
46 occurred while establishing the identity of the peer. The \a error is
47 usually an indication that \a socket is unable to securely identify the
48 peer.
49
50 This signal provides you with an early indication when something's wrong.
51 By connecting to this signal, you can manually choose to tear down the
52 connection from inside the connected slot before the handshake has
53 completed. If no action is taken, QSslServer will proceed to emitting
54 sslErrors().
55
56 \sa sslErrors()
57*/
58
59/*!
60 \fn void QSslServer::sslErrors(QSslSocket *socket, const QList<QSslError> &errors);
61
62 QSslServer emits this signal after the SSL handshake to indicate that one
63 or more errors have occurred while establishing the identity of the
64 peer. The errors are usually an indication that \a socket is unable to
65 securely identify the peer. Unless any action is taken, the connection
66 will be dropped after this signal has been emitted.
67
68 If you want to continue connecting despite the errors that have occurred,
69 you must call QSslSocket::ignoreSslErrors() from inside a slot connected to
70 this signal. If you need to access the error list at a later point, you
71 can call sslHandshakeErrors().
72
73 \a errors contains one or more errors that prevent QSslSocket from
74 verifying the identity of the peer.
75
76 \note You cannot use Qt::QueuedConnection when connecting to this signal,
77 or calling QSslSocket::ignoreSslErrors() will have no effect.
78
79 \sa peerVerifyError()
80*/
81
82/*!
83 \fn void QSslServer::errorOccurred(QSslSocket *socket, QAbstractSocket::SocketError socketError)
84
85 This signal is emitted after an error occurred during handshake. The
86 \a socketError parameter describes the type of error that occurred.
87
88 The \a socket is automatically deleted after this signal is emitted if the
89 socket handshake has not reached encrypted state. But if the \a socket is
90 successfully encrypted, it is inserted into the QSslServer's pending
91 connections queue. When the user has called
92 QTcpServer::nextPendingConnection() it is the user's responsibility to
93 destroy the \a socket or the \a socket will not be destroyed until the
94 QSslServer object is destroyed. If an error occurs on a \a socket after
95 it has been inserted into the pending connections queue, this signal
96 will not be emitted, and the \a socket will not be removed or destroyed.
97
98 \note You cannot use Qt::QueuedConnection when connecting to this signal,
99 or the \a socket will have been already destroyed when the signal is
100 handled.
101
102 \sa QSslSocket::error(), errorString()
103*/
104
105/*!
106 \fn void QSslServer::preSharedKeyAuthenticationRequired(QSslSocket *socket,
107 QSslPreSharedKeyAuthenticator *authenticator)
108
109 QSslServer emits this signal when \a socket negotiates a PSK ciphersuite,
110 and therefore PSK authentication is then required.
111
112 When using PSK, the server must supply a valid identity and a valid pre
113 shared key, in order for the SSL handshake to continue.
114 Applications can provide this information in a slot connected to this
115 signal, by filling in the passed \a authenticator object according to their
116 needs.
117
118 \note Ignoring this signal, or failing to provide the required credentials,
119 will cause the handshake to fail, and therefore the connection to be aborted.
120
121 \note The \a authenticator object is owned by the \a socket and must not be
122 deleted by the application.
123
124 \sa QSslPreSharedKeyAuthenticator
125*/
126
127/*!
128 \fn void QSslServer::alertSent(QSslSocket *socket, QSsl::AlertLevel level, QSsl::AlertType type,
129 const QString &description)
130
131 QSslServer emits this signal if an alert message was sent from \a socket
132 to a peer. \a level describes if it was a warning or a fatal error.
133 \a type gives the code of the alert message. When a textual description
134 of the alert message is available, it is supplied in \a description.
135
136 \note This signal is mostly informational and can be used for debugging
137 purposes, normally it does not require any actions from the application.
138 \note Not all backends support this functionality.
139
140 \sa alertReceived(), QSsl::AlertLevel, QSsl::AlertType
141*/
142
143/*!
144 \fn void QSslServer::alertReceived(QSslSocket *socket, QSsl::AlertLevel level, QSsl::AlertType
145 type, const QString &description)
146
147 QSslServer emits this signal if an alert message was received by the
148 \a socket from a peer. \a level tells if the alert was fatal or it was a
149 warning. \a type is the code explaining why the alert was sent.
150 When a textual description of the alert message is available, it is
151 supplied in \a description.
152
153 \note The signal is mostly for informational and debugging purposes and does not
154 require any handling in the application. If the alert was fatal, underlying
155 backend will handle it and close the connection.
156 \note Not all backends support this functionality.
157
158 \sa alertSent(), QSsl::AlertLevel, QSsl::AlertType
159*/
160
161/*!
162 \fn void QSslServer::handshakeInterruptedOnError(QSslSocket *socket, const QSslError &error)
163
164 QSslServer emits this signal if a certificate verification error was found
165 by \a socket and if early error reporting was enabled in QSslConfiguration.
166 An application is expected to inspect the \a error and decide if it wants
167 to continue the handshake, or abort it and send an alert message to the
168 peer. The signal-slot connection must be direct.
169
170 \sa QSslSocket::continueInterruptedHandshake(), sslErrors(),
171 QSslConfiguration::setHandshakeMustInterruptOnError()
172*/
173
174/*!
175 \fn void QSslServer::startedEncryptionHandshake(QSslSocket *socket)
176
177 This signal is emitted when the client, connected to \a socket,
178 initiates the TLS handshake.
179*/
180
181#include "qsslserver.h"
182#include "qsslserver_p.h"
183
184#include <QtNetwork/QSslSocket>
185#include <QtNetwork/QSslCipher>
186
187QT_BEGIN_NAMESPACE
188
189/*!
190 \internal
191*/
192QSslServerPrivate::QSslServerPrivate() :
193 sslConfiguration(QSslConfiguration::defaultConfiguration())
194{
195}
196
197/*!
198 Constructs a new QSslServer with the given \a parent.
199*/
200QSslServer::QSslServer(QObject *parent) :
201 QTcpServer(QAbstractSocket::TcpSocket, *new QSslServerPrivate, parent)
202{
203}
204
205/*!
206 Destroys the QSslServer.
207
208 All open connections are closed.
209*/
210QSslServer::~QSslServer()
211{
212}
213
214/*!
215 Sets the \a sslConfiguration to use for all following incoming connections.
216
217 This must be called before listen() to ensure that the desired
218 configuration was in use during all handshakes.
219
220 \sa QSslSocket::setSslConfiguration()
221*/
222void QSslServer::setSslConfiguration(const QSslConfiguration &sslConfiguration)
223{
224 Q_D(QSslServer);
225 d->sslConfiguration = sslConfiguration;
226}
227
228/*!
229 Returns the current ssl configuration.
230*/
231QSslConfiguration QSslServer::sslConfiguration() const
232{
233 const Q_D(QSslServer);
234 return d->sslConfiguration;
235}
236
237/*!
238 Sets the \a timeout to use for all incoming handshakes, in milliseconds.
239
240 This is relevant in the scenario where a client, whether malicious or
241 accidental, connects to the server but makes no attempt at communicating or
242 initiating a handshake. QSslServer will then automatically end the
243 connection after \a timeout milliseconds have elapsed.
244
245 By default the timeout is 5000 milliseconds (5 seconds).
246
247 \note The underlying TLS framework may have their own timeout logic now or
248 in the future, this function does not affect that.
249
250 \note The \a timeout passed to this function will only apply to \e{new}
251 connections. If a client is already connected it will use the timeout which
252 was set when it connected.
253
254 \sa handshakeTimeout()
255*/
256void QSslServer::setHandshakeTimeout(int timeout)
257{
258 Q_D(QSslServer);
259 d->handshakeTimeout = timeout;
260}
261
262/*!
263 Returns the currently configured handshake timeout.
264
265 \sa setHandshakeTimeout()
266*/
267int QSslServer::handshakeTimeout() const
268{
269 const Q_D(QSslServer);
270 return d->handshakeTimeout;
271}
272
273/*!
274 Called when a new connection is established.
275
276 Converts \a socket to a QSslSocket.
277
278 \reimp
279*/
280void QSslServer::incomingConnection(qintptr socket)
281{
282 QSslSocket *pSslSocket = new QSslSocket(this);
283
284 pSslSocket->setSslConfiguration(sslConfiguration());
285
286 if (Q_LIKELY(pSslSocket->setSocketDescriptor(socket))) {
287 connect(sender: pSslSocket, signal: &QSslSocket::peerVerifyError, context: this,
288 slot: [this, pSslSocket](const QSslError &error) {
289 Q_EMIT peerVerifyError(socket: pSslSocket, error);
290 });
291 connect(sender: pSslSocket, signal: &QSslSocket::sslErrors, context: this,
292 slot: [this, pSslSocket](const QList<QSslError> &errors) {
293 Q_EMIT sslErrors(socket: pSslSocket, errors);
294 });
295 connect(sender: pSslSocket, signal: &QAbstractSocket::errorOccurred, context: this,
296 slot: [this, pSslSocket](QAbstractSocket::SocketError error) {
297 Q_EMIT errorOccurred(socket: pSslSocket, error);
298 if (!pSslSocket->isEncrypted())
299 pSslSocket->deleteLater();
300 });
301 connect(sender: pSslSocket, signal: &QSslSocket::encrypted, context: this, slot: [this, pSslSocket]() {
302 Q_D(QSslServer);
303 d->removeSocketData(socket: quintptr(pSslSocket));
304 pSslSocket->disconnect(receiver: this);
305 addPendingConnection(socket: pSslSocket);
306 });
307 connect(sender: pSslSocket, signal: &QSslSocket::preSharedKeyAuthenticationRequired, context: this,
308 slot: [this, pSslSocket](QSslPreSharedKeyAuthenticator *authenticator) {
309 Q_EMIT preSharedKeyAuthenticationRequired(socket: pSslSocket, authenticator);
310 });
311 connect(sender: pSslSocket, signal: &QSslSocket::alertSent, context: this,
312 slot: [this, pSslSocket](QSsl::AlertLevel level, QSsl::AlertType type,
313 const QString &description) {
314 Q_EMIT alertSent(socket: pSslSocket, level, type, description);
315 });
316 connect(sender: pSslSocket, signal: &QSslSocket::alertReceived, context: this,
317 slot: [this, pSslSocket](QSsl::AlertLevel level, QSsl::AlertType type,
318 const QString &description) {
319 Q_EMIT alertReceived(socket: pSslSocket, level, type, description);
320 });
321 connect(sender: pSslSocket, signal: &QSslSocket::handshakeInterruptedOnError, context: this,
322 slot: [this, pSslSocket](const QSslError &error) {
323 Q_EMIT handshakeInterruptedOnError(socket: pSslSocket, error);
324 });
325
326 d_func()->initializeHandshakeProcess(socket: pSslSocket);
327 }
328}
329
330void QSslServerPrivate::initializeHandshakeProcess(QSslSocket *socket)
331{
332 Q_Q(QSslServer);
333 QMetaObject::Connection readyRead = QObject::connect(
334 sender: socket, signal: &QSslSocket::readyRead, context: q, slot: [this]() { checkClientHelloAndContinue(); });
335
336 QMetaObject::Connection destroyed =
337 QObject::connect(sender: socket, signal: &QSslSocket::destroyed, context: q, slot: [this](QObject *obj) {
338 // This cast is not safe to use since the socket is inside the
339 // QObject dtor, but we only use the pointer value!
340 removeSocketData(socket: quintptr(obj));
341 });
342 auto it = socketData.emplace(key: quintptr(socket), args&: readyRead, args&: destroyed, args: std::make_shared<QTimer>());
343 it->timeoutTimer->setSingleShot(true);
344 it->timeoutTimer->callOnTimeout(args: [this, socket]() { handleHandshakeTimedOut(socket); });
345 it->timeoutTimer->setInterval(handshakeTimeout);
346 it->timeoutTimer->start();
347}
348
349// This function may be called while in the socket's QObject dtor, __never__ use
350// the socket for anything other than a lookup!
351void QSslServerPrivate::removeSocketData(quintptr socket)
352{
353 auto it = socketData.find(key: socket);
354 if (it != socketData.end()) {
355 it->disconnectSignals();
356 socketData.erase(it);
357 }
358}
359
360int QSslServerPrivate::totalPendingConnections() const
361{
362 // max pending connections is int, so this cannot exceed that
363 return QTcpServerPrivate::totalPendingConnections() + int(socketData.size());
364}
365
366void QSslServerPrivate::checkClientHelloAndContinue()
367{
368 Q_Q(QSslServer);
369 QSslSocket *socket = qobject_cast<QSslSocket *>(object: q->sender());
370 if (Q_UNLIKELY(!socket) || socket->bytesAvailable() <= 0)
371 return;
372
373 char byte = '\0';
374 if (socket->peek(data: &byte, maxlen: 1) != 1) {
375 socket->deleteLater();
376 return;
377 }
378
379 auto it = socketData.find(key: quintptr(socket));
380 const bool foundData = it != socketData.end();
381 if (foundData && it->readyReadConnection)
382 QObject::disconnect(std::exchange(obj&: it->readyReadConnection, new_val: {}));
383
384 constexpr char CLIENT_HELLO = 0x16;
385 if (byte != CLIENT_HELLO) {
386 socket->disconnectFromHost();
387 socket->deleteLater();
388 return;
389 }
390
391 // Be nice and restart the timeout timer since some progress was made
392 if (foundData)
393 it->timeoutTimer->start();
394
395 socket->startServerEncryption();
396 Q_EMIT q->startedEncryptionHandshake(socket);
397}
398
399void QSslServerPrivate::handleHandshakeTimedOut(QSslSocket *socket)
400{
401 Q_Q(QSslServer);
402 removeSocketData(socket: quintptr(socket));
403 socket->disconnectFromHost();
404 Q_EMIT q->errorOccurred(socket, error: QAbstractSocket::SocketTimeoutError);
405 socket->deleteLater();
406 if (!socketEngine->isReadNotificationEnabled() && totalPendingConnections() < maxConnections)
407 q->resumeAccepting();
408}
409
410QT_END_NAMESPACE
411
412#include "moc_qsslserver.cpp"
413

source code of qtbase/src/network/ssl/qsslserver.cpp