1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsslconfiguration.h"
5#include "qsslsocket_p.h"
6#include "qudpsocket.h"
7#include "qsslcipher.h"
8#include "qdtls_p.h"
9#include "qssl_p.h"
10#include "qdtls.h"
11
12#include "qglobal.h"
13
14/*!
15 \class QDtlsClientVerifier
16 \brief This class implements server-side DTLS cookie generation and verification.
17 \since 5.12
18
19 \ingroup network
20 \ingroup ssl
21 \inmodule QtNetwork
22
23 The QDtlsClientVerifier class implements server-side DTLS cookie generation
24 and verification. Datagram security protocols are highly susceptible to a
25 variety of Denial-of-Service attacks. According to \l {RFC 6347, section 4.2.1},
26 these are two of the more common types of attack:
27
28 \list
29 \li An attacker transmits a series of handshake initiation requests, causing
30 a server to allocate excessive resources and potentially perform expensive
31 cryptographic operations.
32 \li An attacker transmits a series of handshake initiation requests with
33 a forged source of the victim, making the server act as an amplifier.
34 Normally, the server would reply to the victim machine with a Certificate message,
35 which can be quite large, thus flooding the victim machine with datagrams.
36 \endlist
37
38 As a countermeasure to these attacks, \l {RFC 6347, section 4.2.1}
39 proposes a stateless cookie technique that a server may deploy:
40
41 \list
42 \li In response to the initial ClientHello message, the server sends a HelloVerifyRequest,
43 which contains a cookie. This cookie is a cryptographic hash and is generated using the
44 client's address, port number, and the server's secret (which is a cryptographically strong
45 pseudo-random sequence of bytes).
46 \li A reachable DTLS client is expected to reply with a new ClientHello message
47 containing this cookie.
48 \li When the server receives the ClientHello message with a cookie, it
49 generates a new cookie as described above. This new cookie is compared to the
50 one found in the ClientHello message.
51 \li In the cookies are equal, the client is considered to be real, and the
52 server can continue with a TLS handshake procedure.
53 \endlist
54
55 \note A DTLS server is not required to use DTLS cookies.
56
57 QDtlsClientVerifier is designed to work in pair with QUdpSocket, as shown in
58 the following code-excerpt:
59
60 \snippet code/src_network_ssl_qdtlscookie.cpp 0
61
62 QDtlsClientVerifier does not impose any restrictions on how the application uses
63 QUdpSocket. For example, it is possible to have a server with a single QUdpSocket
64 in state QAbstractSocket::BoundState, handling multiple DTLS clients
65 simultaneously:
66
67 \list
68 \li Testing if new clients are real DTLS-capable clients.
69 \li Completing TLS handshakes with the verified clients (see QDtls).
70 \li Decrypting datagrams coming from the connected clients (see QDtls).
71 \li Sending encrypted datagrams to the connected clients (see QDtls).
72 \endlist
73
74 This implies that QDtlsClientVerifier does not read directly from a socket,
75 instead it expects the application to read an incoming datagram, extract the
76 sender's address, and port, and then pass this data to verifyClient().
77 To send a HelloVerifyRequest message, verifyClient() can write to the QUdpSocket.
78
79 \note QDtlsClientVerifier does not take ownership of the QUdpSocket object.
80
81 By default QDtlsClientVerifier obtains its secret from a cryptographically
82 strong pseudorandom number generator.
83
84 \note The default secret is shared by all objects of the classes QDtlsClientVerifier
85 and QDtls. Since this can impose security risks, RFC 6347 recommends to change
86 the server's secret frequently. Please see \l {RFC 6347, section 4.2.1}
87 for hints about possible server implementations. Cookie generator parameters
88 can be set using the class QDtlsClientVerifier::GeneratorParameters and
89 setCookieGeneratorParameters():
90
91 \snippet code/src_network_ssl_qdtlscookie.cpp 1
92
93 The \l{secureudpserver}{DTLS server} example illustrates how to use
94 QDtlsClientVerifier in a server application.
95
96 \sa QUdpSocket, QAbstractSocket::BoundState, QDtls, verifyClient(),
97 GeneratorParameters, setCookieGeneratorParameters(), cookieGeneratorParameters(),
98 QDtls::setCookieGeneratorParameters(),
99 QDtls::cookieGeneratorParameters(),
100 QCryptographicHash::Algorithm,
101 QDtlsError, dtlsError(), dtlsErrorString()
102*/
103
104/*!
105 \class QDtlsClientVerifier::GeneratorParameters
106 \brief This class defines parameters for DTLS cookie generator.
107 \since 5.12
108
109 \ingroup network
110 \ingroup ssl
111 \inmodule QtNetwork
112
113 An object of this class provides the parameters that QDtlsClientVerifier
114 will use to generate DTLS cookies. They include a cryptographic hash
115 algorithm and a secret.
116
117 \note An empty secret is considered to be invalid by
118 QDtlsClientVerifier::setCookieGeneratorParameters().
119
120 \sa QDtlsClientVerifier::setCookieGeneratorParameters(),
121 QDtlsClientVerifier::cookieGeneratorParameters(),
122 QDtls::setCookieGeneratorParameters(),
123 QDtls::cookieGeneratorParameters(),
124 QCryptographicHash::Algorithm
125*/
126
127/*!
128 \enum QDtlsError
129 \brief Describes errors that can be found by QDtls and QDtlsClientVerifier.
130 \relates QDtls
131 \since 5.12
132
133 \ingroup network
134 \ingroup ssl
135 \inmodule QtNetwork
136
137 This enum describes general and TLS-specific errors that can be encountered
138 by objects of the classes QDtlsClientVerifier and QDtls.
139
140 \value NoError No error occurred, the last operation was successful.
141 \value InvalidInputParameters Input parameters provided by a caller were
142 invalid.
143 \value InvalidOperation An operation was attempted in a state that did not
144 permit it.
145 \value UnderlyingSocketError QUdpSocket::writeDatagram() failed, QUdpSocket::error()
146 and QUdpSocket::errorString() can provide more specific information.
147 \value RemoteClosedConnectionError TLS shutdown alert message was received.
148 \value PeerVerificationError Peer's identity could not be verified during the
149 TLS handshake.
150 \value TlsInitializationError An error occurred while initializing an underlying
151 TLS backend.
152 \value TlsFatalError A fatal error occurred during TLS handshake, other
153 than peer verification error or TLS initialization error.
154 \value TlsNonFatalError A failure to encrypt or decrypt a datagram, non-fatal,
155 meaning QDtls can continue working after this error.
156*/
157
158/*!
159 \class QDtls
160 \brief This class provides encryption for UDP sockets.
161 \since 5.12
162
163 \ingroup network
164 \ingroup ssl
165 \inmodule QtNetwork
166
167 The QDtls class can be used to establish a secure connection with a network
168 peer using User Datagram Protocol (UDP). DTLS connection over essentially
169 connectionless UDP means that two peers first have to successfully complete
170 a TLS handshake by calling doHandshake(). After the handshake has completed,
171 encrypted datagrams can be sent to the peer using writeDatagramEncrypted().
172 Encrypted datagrams coming from the peer can be decrypted by decryptDatagram().
173
174 QDtls is designed to work with QUdpSocket. Since QUdpSocket can receive
175 datagrams coming from different peers, an application must implement
176 demultiplexing, forwarding datagrams coming from different peers to their
177 corresponding instances of QDtls. An association between a network peer
178 and its QDtls object can be established using the peer's address and port
179 number. Before starting a handshake, the application must set the peer's
180 address and port number using setPeer().
181
182 QDtls does not read datagrams from QUdpSocket, this is expected to be done by
183 the application, for example, in a slot attached to the QUdpSocket::readyRead()
184 signal. Then, these datagrams must be processed by QDtls.
185
186 \note QDtls does \e not take ownership of the QUdpSocket object.
187
188 Normally, several datagrams are to be received and sent by both peers during
189 the handshake phase. Upon reading datagrams, server and client must pass these
190 datagrams to doHandshake() until some error is found or handshakeState()
191 returns HandshakeComplete:
192
193 \snippet code/src_network_ssl_qdtls.cpp 0
194
195 For a server, the first call to doHandshake() requires a non-empty datagram
196 containing a ClientHello message. If the server also deploys QDtlsClientVerifier,
197 the first ClientHello message is expected to be the one verified by QDtlsClientVerifier.
198
199 In case the peer's identity cannot be validated during the handshake, the application
200 must inspect errors returned by peerVerificationErrors() and then either
201 ignore errors by calling ignoreVerificationErrors() or abort the handshake
202 by calling abortHandshake(). If errors were ignored, the handshake can be
203 resumed by calling resumeHandshake().
204
205 After the handshake has been completed, datagrams can be sent to and received
206 from the network peer securely:
207
208 \snippet code/src_network_ssl_qdtls.cpp 2
209
210 A DTLS connection may be closed using shutdown().
211
212 \snippet code/src_network_ssl_qdtls.cpp 3
213
214 \warning It's recommended to call shutdown() before destroying the client's QDtls
215 object if you are planning to re-use the same port number to connect to the
216 server later. Otherwise, the server may drop incoming ClientHello messages,
217 see \l {RFC 6347, section 4.2.8}
218 for more details and implementation hints.
219
220 If the server does not use QDtlsClientVerifier, it \e must configure its
221 QDtls objects to disable the cookie verification procedure:
222
223 \snippet code/src_network_ssl_qdtls.cpp 4
224
225 A server that uses cookie verification with non-default generator parameters
226 \e must set the same parameters for its QDtls object before starting the handshake.
227
228 \note The DTLS protocol leaves Path Maximum Transmission Unit (PMTU) discovery
229 to the application. The application may provide QDtls with the MTU using
230 setMtuHint(). This hint affects only the handshake phase, since only handshake
231 messages can be fragmented and reassembled by the DTLS. All other messages sent
232 by the application must fit into a single datagram.
233 \note DTLS-specific headers add some overhead to application data further
234 reducing the possible message size.
235 \warning A server configured to reply with HelloVerifyRequest will drop
236 all fragmented ClientHello messages, never starting a handshake.
237
238 The \l{secureudpserver}{DTLS server} and \l{secureudpclient}{DTLS client}
239 examples illustrate how to use QDtls in applications.
240
241 \sa QUdpSocket, QDtlsClientVerifier, HandshakeState, QDtlsError, QSslConfiguration
242*/
243
244/*!
245 \typedef QDtls::GeneratorParameters
246*/
247
248/*!
249 \fn void QDtls::handshakeTimeout()
250
251 Packet loss can result in timeouts during the handshake phase. In this case
252 QDtls emits a handshakeTimeout() signal. Call handleTimeout() to retransmit
253 the handshake messages:
254
255 \snippet code/src_network_ssl_qdtls.cpp 1
256
257 \sa handleTimeout()
258*/
259
260/*!
261 \fn void QDtls::pskRequired(QSslPreSharedKeyAuthenticator *authenticator)
262
263 QDtls emits this signal when it negotiates a PSK ciphersuite, and therefore
264 a PSK authentication is then required.
265
266 When using PSK, the client must send to the server a valid identity and a
267 valid pre shared key, in order for the TLS handshake to continue.
268 Applications can provide this information in a slot connected to this
269 signal, by filling in the passed \a authenticator object according to their
270 needs.
271
272 \note Ignoring this signal, or failing to provide the required credentials,
273 will cause the handshake to fail, and therefore the connection to be aborted.
274
275 \note The \a authenticator object is owned by QDtls and must not be deleted
276 by the application.
277
278 \sa QSslPreSharedKeyAuthenticator
279*/
280
281/*!
282 \enum QDtls::HandshakeState
283 \brief Describes the current state of DTLS handshake.
284 \since 5.12
285
286 \ingroup network
287 \ingroup ssl
288 \inmodule QtNetwork
289
290 This enum describes the current state of DTLS handshake for a QDtls
291 connection.
292
293 \value HandshakeNotStarted Nothing done yet.
294 \value HandshakeInProgress Handshake was initiated and no errors were found so far.
295 \value PeerVerificationFailed The identity of the peer can't be established.
296 \value HandshakeComplete Handshake completed successfully and encrypted connection
297 was established.
298
299 \sa QDtls::doHandshake(), QDtls::handshakeState()
300*/
301
302
303QT_BEGIN_NAMESPACE
304
305static QString msgUnsupportedMulticastAddress()
306{
307 return QDtls::tr(s: "Multicast and broadcast addresses are not supported");
308}
309
310/*!
311 Default constructs GeneratorParameters object with QCryptographicHash::Sha1
312 as its algorithm and an empty secret.
313
314 \sa QDtlsClientVerifier::setCookieGeneratorParameters(),
315 QDtlsClientVerifier::cookieGeneratorParameters(),
316 QDtls::setCookieGeneratorParameters(),
317 QDtls::cookieGeneratorParameters()
318 */
319QDtlsClientVerifier::GeneratorParameters::GeneratorParameters()
320{
321}
322
323/*!
324 Constructs GeneratorParameters object from \a algorithm and \a secret.
325
326 \sa QDtlsClientVerifier::setCookieGeneratorParameters(),
327 QDtlsClientVerifier::cookieGeneratorParameters(),
328 QDtls::setCookieGeneratorParameters(),
329 QDtls::cookieGeneratorParameters()
330 */
331QDtlsClientVerifier::GeneratorParameters::GeneratorParameters(QCryptographicHash::Algorithm algorithm, const QByteArray &secret)
332 : hash(algorithm), secret(secret)
333{
334}
335
336QDtlsClientVerifierPrivate::QDtlsClientVerifierPrivate()
337{
338 const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
339 if (!tlsBackend) {
340 qCWarning(lcSsl, "No TLS backend is available, cannot verify DTLS client");
341 return;
342 }
343 backend.reset(p: tlsBackend->createDtlsCookieVerifier());
344 if (!backend.get())
345 qCWarning(lcSsl) << "The backend" << tlsBackend->backendName() << "does not support DTLS cookies";
346}
347
348QDtlsClientVerifierPrivate::~QDtlsClientVerifierPrivate() = default;
349
350/*!
351 Constructs a QDtlsClientVerifier object, \a parent is passed to QObject's
352 constructor.
353*/
354QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent)
355 : QObject(*new QDtlsClientVerifierPrivate, parent)
356{
357 Q_D(QDtlsClientVerifier);
358
359 if (auto *backend = d->backend.get()) {
360 // The default configuration suffices: verifier never does a full
361 // handshake and upon verifying a cookie in a client hello message,
362 // it reports success.
363 auto conf = QSslConfiguration::defaultDtlsConfiguration();
364 conf.setPeerVerifyMode(QSslSocket::VerifyNone);
365 backend->setConfiguration(conf);
366 }
367}
368
369/*!
370 Destroys the QDtlsClientVerifier object.
371*/
372QDtlsClientVerifier::~QDtlsClientVerifier()
373{
374}
375
376/*!
377 Sets the secret and the cryptographic hash algorithm from \a params. This
378 QDtlsClientVerifier will use these to generate cookies. If the new secret
379 has size zero, this function returns \c false and does not change the
380 cookie generator parameters.
381
382 \note The secret is supposed to be a cryptographically secure sequence of bytes.
383
384 \sa QDtlsClientVerifier::GeneratorParameters, cookieGeneratorParameters(),
385 QCryptographicHash::Algorithm
386*/
387bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters &params)
388{
389 Q_D(QDtlsClientVerifier);
390 if (auto *backend = d->backend.get())
391 return backend->setCookieGeneratorParameters(params);
392
393 return false;
394}
395
396/*!
397 Returns the current secret and hash algorithm used to generate cookies.
398 The default hash algorithm is QCryptographicHash::Sha256 if Qt was configured
399 to support it, QCryptographicHash::Sha1 otherwise. The default secret is
400 obtained from the backend-specific cryptographically strong pseudorandom
401 number generator.
402
403 \sa QCryptographicHash::Algorithm, QDtlsClientVerifier::GeneratorParameters,
404 setCookieGeneratorParameters()
405*/
406QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorParameters() const
407{
408 Q_D(const QDtlsClientVerifier);
409
410 if (const auto *backend = d->backend.get())
411 return backend->cookieGeneratorParameters();
412
413 return {};
414}
415
416/*!
417 \a socket must be a valid pointer, \a dgram must be a non-empty
418 datagram, \a address cannot be null, broadcast, or multicast.
419 \a port is the remote peer's port. This function returns \c true
420 if \a dgram contains a ClientHello message with a valid cookie.
421 If no matching cookie is found, verifyClient() will send a
422 HelloVerifyRequest message using \a socket and return \c false.
423
424 The following snippet shows how a server application may check for errors:
425
426 \snippet code/src_network_ssl_qdtlscookie.cpp 2
427
428 \sa QHostAddress::isNull(), QHostAddress::isBroadcast(), QHostAddress::isMulticast(),
429 setCookieGeneratorParameters(), cookieGeneratorParameters()
430*/
431bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgram,
432 const QHostAddress &address, quint16 port)
433{
434 Q_D(QDtlsClientVerifier);
435
436 auto *backend = d->backend.get();
437 if (!backend)
438 return false;
439
440 if (!socket || address.isNull() || !dgram.size()) {
441 backend->setDtlsError(code: QDtlsError::InvalidInputParameters,
442 description: tr(s: "A valid UDP socket, non-empty datagram, and valid address/port were expected"));
443 return false;
444 }
445
446 if (address.isBroadcast() || address.isMulticast()) {
447 backend->setDtlsError(code: QDtlsError::InvalidInputParameters,
448 description: msgUnsupportedMulticastAddress());
449 return false;
450 }
451
452 return backend->verifyClient(socket, dgram, address, port);
453}
454
455/*!
456 Convenience function. Returns the last ClientHello message that was successfully
457 verified, or an empty QByteArray if no verification has completed.
458
459 \sa verifyClient()
460*/
461QByteArray QDtlsClientVerifier::verifiedHello() const
462{
463 Q_D(const QDtlsClientVerifier);
464
465 if (const auto *backend = d->backend.get())
466 return backend->verifiedHello();
467
468 return {};
469}
470
471/*!
472 Returns the last error that occurred or QDtlsError::NoError.
473
474 \sa QDtlsError, dtlsErrorString()
475*/
476QDtlsError QDtlsClientVerifier::dtlsError() const
477{
478 Q_D(const QDtlsClientVerifier);
479
480 if (const auto *backend = d->backend.get())
481 return backend->error();
482
483 return QDtlsError::TlsInitializationError;
484}
485
486/*!
487 Returns a textual description of the last error, or an empty string.
488
489 \sa dtlsError()
490 */
491QString QDtlsClientVerifier::dtlsErrorString() const
492{
493 Q_D(const QDtlsClientVerifier);
494
495 if (const auto *backend = d->backend.get())
496 return backend->errorString();
497
498 return QStringLiteral("No TLS backend is available, no client verification");
499}
500
501QDtlsPrivate::QDtlsPrivate() = default;
502QDtlsPrivate::~QDtlsPrivate() = default;
503
504/*!
505 Creates a QDtls object, \a parent is passed to the QObject constructor.
506 \a mode is QSslSocket::SslServerMode for a server-side DTLS connection or
507 QSslSocket::SslClientMode for a client.
508
509 \sa sslMode(), QSslSocket::SslMode
510*/
511QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent)
512 : QObject(*new QDtlsPrivate, parent)
513{
514 Q_D(QDtls);
515 const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
516 if (!tlsBackend) {
517 qCWarning(lcSsl, "No TLS backend found, QDtls is unsupported");
518 return;
519 }
520 d->backend.reset(p: tlsBackend->createDtlsCryptograph(qObject: this, mode));
521 if (!d->backend.get()) {
522 qCWarning(lcSsl) << "TLS backend" << tlsBackend->backendName()
523 << "does not support the protocol DTLS";
524 }
525 setDtlsConfiguration(QSslConfiguration::defaultDtlsConfiguration());
526}
527
528/*!
529 Destroys the QDtls object.
530*/
531QDtls::~QDtls()
532{
533}
534
535/*!
536 Sets the peer's address, \a port, and host name and returns \c true
537 if successful. \a address must not be null, multicast, or broadcast.
538 \a verificationName is the host name used for the certificate validation.
539
540 \sa peerAddress(), peerPort(), peerVerificationName()
541 */
542bool QDtls::setPeer(const QHostAddress &address, quint16 port,
543 const QString &verificationName)
544{
545 Q_D(QDtls);
546
547 auto *backend = d->backend.get();
548 if (!backend)
549 return false;
550
551 if (backend->state() != HandshakeNotStarted) {
552 backend->setDtlsError(code: QDtlsError::InvalidOperation,
553 description: tr(s: "Cannot set peer after handshake started"));
554 return false;
555 }
556
557 if (address.isNull()) {
558 backend->setDtlsError(code: QDtlsError::InvalidInputParameters,
559 description: tr(s: "Invalid address"));
560 return false;
561 }
562
563 if (address.isBroadcast() || address.isMulticast()) {
564 backend->setDtlsError(code: QDtlsError::InvalidInputParameters,
565 description: msgUnsupportedMulticastAddress());
566 return false;
567 }
568
569 backend->clearDtlsError();
570 backend->setPeer(addr: address, port, name: verificationName);
571
572 return true;
573}
574
575/*!
576 Sets the host \a name that will be used for the certificate validation
577 and returns \c true if successful.
578
579 \note This function must be called before the handshake starts.
580
581 \sa peerVerificationName(), setPeer()
582*/
583bool QDtls::setPeerVerificationName(const QString &name)
584{
585 Q_D(QDtls);
586
587 auto *backend = d->backend.get();
588 if (!backend)
589 return false;
590
591 if (backend->state() != HandshakeNotStarted) {
592 backend->setDtlsError(code: QDtlsError::InvalidOperation,
593 description: tr(s: "Cannot set verification name after handshake started"));
594 return false;
595 }
596
597 backend->clearDtlsError();
598 backend->setPeerVerificationName(name);
599
600 return true;
601}
602
603/*!
604 Returns the peer's address, set by setPeer(), or QHostAddress::Null.
605
606 \sa setPeer()
607*/
608QHostAddress QDtls::peerAddress() const
609{
610 Q_D(const QDtls);
611
612 if (const auto *backend = d->backend.get())
613 return backend->peerAddress();
614
615 return {};
616}
617
618/*!
619 Returns the peer's port number, set by setPeer(), or 0.
620
621 \sa setPeer()
622*/
623quint16 QDtls::peerPort() const
624{
625 Q_D(const QDtls);
626
627 if (const auto *backend = d->backend.get())
628 return backend->peerPort();
629
630 return 0;
631}
632
633/*!
634 Returns the host name set by setPeer() or setPeerVerificationName().
635 The default value is an empty string.
636
637 \sa setPeerVerificationName(), setPeer()
638*/
639QString QDtls::peerVerificationName() const
640{
641 Q_D(const QDtls);
642
643 if (const auto *backend = d->backend.get())
644 return backend->peerVerificationName();
645
646 return {};
647}
648
649/*!
650 Returns QSslSocket::SslServerMode for a server-side connection and
651 QSslSocket::SslClientMode for a client.
652
653 \sa QDtls(), QSslSocket::SslMode
654*/
655QSslSocket::SslMode QDtls::sslMode() const
656{
657 Q_D(const QDtls);
658
659 if (const auto *backend = d->backend.get())
660 return backend->cryptographMode();
661
662 return QSslSocket::UnencryptedMode;
663}
664
665/*!
666 \a mtuHint is the maximum transmission unit (MTU), either discovered or guessed
667 by the application. The application is not required to set this value.
668
669 \sa mtuHint(), QAbstractSocket::PathMtuSocketOption
670 */
671void QDtls::setMtuHint(quint16 mtuHint)
672{
673 Q_D(QDtls);
674
675 if (auto *backend = d->backend.get())
676 backend->setDtlsMtuHint(mtuHint);
677}
678
679/*!
680 Returns the value previously set by setMtuHint(). The default value is 0.
681
682 \sa setMtuHint()
683 */
684quint16 QDtls::mtuHint() const
685{
686 Q_D(const QDtls);
687
688 if (const auto *backend = d->backend.get())
689 return backend->dtlsMtuHint();
690
691 return 0;
692}
693
694/*!
695 Sets the cryptographic hash algorithm and the secret from \a params.
696 This function is only needed for a server-side QDtls connection.
697 Returns \c true if successful.
698
699 \note This function must be called before the handshake starts.
700
701 \sa cookieGeneratorParameters(), doHandshake(), QDtlsClientVerifier,
702 QDtlsClientVerifier::cookieGeneratorParameters()
703*/
704bool QDtls::setCookieGeneratorParameters(const GeneratorParameters &params)
705{
706 Q_D(QDtls);
707
708 if (auto *backend = d->backend.get())
709 backend->setCookieGeneratorParameters(params);
710
711 return false;
712}
713
714/*!
715 Returns the current hash algorithm and secret, either default ones or previously
716 set by a call to setCookieGeneratorParameters().
717
718 The default hash algorithm is QCryptographicHash::Sha256 if Qt was
719 configured to support it, QCryptographicHash::Sha1 otherwise. The default
720 secret is obtained from the backend-specific cryptographically strong
721 pseudorandom number generator.
722
723 \sa QDtlsClientVerifier, cookieGeneratorParameters()
724*/
725QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const
726{
727 Q_D(const QDtls);
728
729 if (const auto *backend = d->backend.get())
730 return backend->cookieGeneratorParameters();
731
732 return {};
733}
734
735/*!
736 Sets the connection's TLS configuration from \a configuration
737 and returns \c true if successful.
738
739 \note This function must be called before the handshake starts.
740
741 \sa dtlsConfiguration(), doHandshake()
742*/
743bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
744{
745 Q_D(QDtls);
746
747 auto *backend = d->backend.get();
748 if (!backend)
749 return false;
750
751 if (backend->state() != HandshakeNotStarted) {
752 backend->setDtlsError(code: QDtlsError::InvalidOperation,
753 description: tr(s: "Cannot set configuration after handshake started"));
754 return false;
755 }
756
757 backend->setConfiguration(configuration);
758 return true;
759}
760
761/*!
762 Returns either the default DTLS configuration or the configuration set by an
763 earlier call to setDtlsConfiguration().
764
765 \sa setDtlsConfiguration(), QSslConfiguration::defaultDtlsConfiguration()
766*/
767QSslConfiguration QDtls::dtlsConfiguration() const
768{
769 Q_D(const QDtls);
770 if (const auto *backend = d->backend.get())
771 return backend->configuration();
772
773 return {};
774}
775
776/*!
777 Returns the current handshake state for this QDtls.
778
779 \sa doHandshake(), QDtls::HandshakeState
780 */
781QDtls::HandshakeState QDtls::handshakeState()const
782{
783 Q_D(const QDtls);
784
785 if (const auto *backend = d->backend.get())
786 return backend->state();
787
788 return QDtls::HandshakeNotStarted;
789}
790
791/*!
792 Starts or continues a DTLS handshake. \a socket must be a valid pointer.
793 When starting a server-side DTLS handshake, \a dgram must contain the initial
794 ClientHello message read from QUdpSocket. This function returns \c true if
795 no error was found. Handshake state can be tested using handshakeState().
796 \c false return means some error occurred, use dtlsError() for more
797 detailed information.
798
799 \note If the identity of the peer can't be established, the error is set to
800 QDtlsError::PeerVerificationError. If you want to ignore verification errors
801 and continue connecting, you must call ignoreVerificationErrors() and then
802 resumeHandshake(). If the errors cannot be ignored, you must call
803 abortHandshake().
804
805 \snippet code/src_network_ssl_qdtls.cpp 5
806
807 \sa handshakeState(), dtlsError(), ignoreVerificationErrors(), resumeHandshake(),
808 abortHandshake()
809*/
810bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram)
811{
812 Q_D(QDtls);
813
814 auto *backend = d->backend.get();
815 if (!backend)
816 return false;
817
818 if (backend->state() == HandshakeNotStarted)
819 return startHandshake(socket, dgram);
820 else if (backend->state() == HandshakeInProgress)
821 return continueHandshake(socket, dgram);
822
823 backend->setDtlsError(code: QDtlsError::InvalidOperation,
824 description: tr(s: "Cannot start/continue handshake, invalid handshake state"));
825 return false;
826}
827
828/*!
829 \internal
830*/
831bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram)
832{
833 Q_D(QDtls);
834
835 auto *backend = d->backend.get();
836 if (!backend)
837 return false;
838
839 if (!socket) {
840 backend->setDtlsError(code: QDtlsError::InvalidInputParameters, description: tr(s: "Invalid (nullptr) socket"));
841 return false;
842 }
843
844 if (backend->peerAddress().isNull()) {
845 backend->setDtlsError(code: QDtlsError::InvalidOperation,
846 description: tr(s: "To start a handshake you must set peer's address and port first"));
847 return false;
848 }
849
850 if (sslMode() == QSslSocket::SslServerMode && !datagram.size()) {
851 backend->setDtlsError(code: QDtlsError::InvalidInputParameters,
852 description: tr(s: "To start a handshake, DTLS server requires non-empty datagram (client hello)"));
853 return false;
854 }
855
856 if (backend->state() != HandshakeNotStarted) {
857 backend->setDtlsError(code: QDtlsError::InvalidOperation,
858 description: tr(s: "Cannot start handshake, already done/in progress"));
859 return false;
860 }
861
862 return backend->startHandshake(socket, dgram: datagram);
863}
864
865/*!
866 If a timeout occurs during the handshake, the handshakeTimeout() signal
867 is emitted. The application must call handleTimeout() to retransmit handshake
868 messages; handleTimeout() returns \c true if a timeout has occurred, false
869 otherwise. \a socket must be a valid pointer.
870
871 \sa handshakeTimeout()
872*/
873bool QDtls::handleTimeout(QUdpSocket *socket)
874{
875 Q_D(QDtls);
876
877 auto *backend = d->backend.get();
878 if (!backend)
879 return false;
880
881 if (!socket) {
882 backend->setDtlsError(code: QDtlsError::InvalidInputParameters, description: tr(s: "Invalid (nullptr) socket"));
883 return false;
884 }
885
886 return backend->handleTimeout(socket);
887}
888
889/*!
890 \internal
891*/
892bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram)
893{
894 Q_D(QDtls);
895
896 auto *backend = d->backend.get();
897 if (!backend)
898 return false;
899
900 if (!socket || !datagram.size()) {
901 backend->setDtlsError(code: QDtlsError::InvalidInputParameters,
902 description: tr(s: "A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
903 return false;
904 }
905
906 if (backend->state() != HandshakeInProgress) {
907 backend->setDtlsError(code: QDtlsError::InvalidOperation,
908 description: tr(s: "Cannot continue handshake, not in InProgress state"));
909 return false;
910 }
911
912 return backend->continueHandshake(socket, dgram: datagram);
913}
914
915/*!
916 If peer verification errors were ignored during the handshake,
917 resumeHandshake() resumes and completes the handshake and returns
918 \c true. \a socket must be a valid pointer. Returns \c false if
919 the handshake could not be resumed.
920
921 \sa doHandshake(), abortHandshake() peerVerificationErrors(), ignoreVerificationErrors()
922*/
923bool QDtls::resumeHandshake(QUdpSocket *socket)
924{
925 Q_D(QDtls);
926
927 auto *backend = d->backend.get();
928 if (!backend)
929 return false;
930
931 if (!socket) {
932 backend->setDtlsError(code: QDtlsError::InvalidInputParameters, description: tr(s: "Invalid (nullptr) socket"));
933 return false;
934 }
935
936 if (backend->state() != PeerVerificationFailed) {
937 backend->setDtlsError(code: QDtlsError::InvalidOperation,
938 description: tr(s: "Cannot resume, not in VerificationError state"));
939 return false;
940 }
941
942 return backend->resumeHandshake(socket);
943}
944
945/*!
946 Aborts the ongoing handshake. Returns true if one was on-going on \a socket;
947 otherwise, sets a suitable error and returns false.
948
949 \sa doHandshake(), resumeHandshake()
950 */
951bool QDtls::abortHandshake(QUdpSocket *socket)
952{
953 Q_D(QDtls);
954
955 auto *backend = d->backend.get();
956 if (!backend)
957 return false;
958
959 if (!socket) {
960 backend->setDtlsError(code: QDtlsError::InvalidInputParameters, description: tr(s: "Invalid (nullptr) socket"));
961 return false;
962 }
963
964 if (backend->state() != PeerVerificationFailed && backend->state() != HandshakeInProgress) {
965 backend->setDtlsError(code: QDtlsError::InvalidOperation,
966 description: tr(s: "No handshake in progress, nothing to abort"));
967 return false;
968 }
969
970 backend->abortHandshake(socket);
971 return true;
972}
973
974/*!
975 Sends an encrypted shutdown alert message and closes the DTLS connection.
976 Handshake state changes to QDtls::HandshakeNotStarted. \a socket must be a
977 valid pointer. This function returns \c true on success.
978
979 \sa doHandshake()
980 */
981bool QDtls::shutdown(QUdpSocket *socket)
982{
983 Q_D(QDtls);
984
985 auto *backend = d->backend.get();
986 if (!backend)
987 return false;
988
989 if (!socket) {
990 backend->setDtlsError(code: QDtlsError::InvalidInputParameters,
991 description: tr(s: "Invalid (nullptr) socket"));
992 return false;
993 }
994
995 if (!backend->isConnectionEncrypted()) {
996 backend->setDtlsError(code: QDtlsError::InvalidOperation,
997 description: tr(s: "Cannot send shutdown alert, not encrypted"));
998 return false;
999 }
1000
1001 backend->sendShutdownAlert(socket);
1002 return true;
1003}
1004
1005/*!
1006 Returns \c true if DTLS handshake completed successfully.
1007
1008 \sa doHandshake(), handshakeState()
1009 */
1010bool QDtls::isConnectionEncrypted() const
1011{
1012 Q_D(const QDtls);
1013
1014
1015 if (const auto *backend = d->backend.get())
1016 return backend->isConnectionEncrypted();
1017
1018 return false;
1019}
1020
1021/*!
1022 Returns the cryptographic \l {QSslCipher} {cipher} used by this connection,
1023 or a null cipher if the connection isn't encrypted. The cipher for the
1024 session is selected during the handshake phase. The cipher is used to encrypt
1025 and decrypt data.
1026
1027 QSslConfiguration provides functions for setting the ordered list of ciphers
1028 from which the handshake phase will eventually select the session cipher.
1029 This ordered list must be in place before the handshake phase begins.
1030
1031 \sa QSslConfiguration, setDtlsConfiguration(), dtlsConfiguration()
1032*/
1033QSslCipher QDtls::sessionCipher() const
1034{
1035 Q_D(const QDtls);
1036
1037 if (const auto *backend = d->backend.get())
1038 return backend->dtlsSessionCipher();
1039
1040 return {};
1041}
1042
1043/*!
1044 Returns the DTLS protocol version used by this connection, or UnknownProtocol
1045 if the connection isn't encrypted yet. The protocol for the connection is selected
1046 during the handshake phase.
1047
1048 setDtlsConfiguration() can set the preferred version before the handshake starts.
1049
1050 \sa setDtlsConfiguration(), QSslConfiguration, QSslConfiguration::defaultDtlsConfiguration(),
1051 QSslConfiguration::setProtocol()
1052*/
1053QSsl::SslProtocol QDtls::sessionProtocol() const
1054{
1055 Q_D(const QDtls);
1056
1057 if (const auto *backend = d->backend.get())
1058 return backend->dtlsSessionProtocol();
1059
1060 return QSsl::UnknownProtocol;
1061}
1062
1063/*!
1064 Encrypts \a dgram and writes the encrypted data into \a socket. Returns the
1065 number of bytes written, or -1 in case of error. The handshake must be completed
1066 before writing encrypted data. \a socket must be a valid
1067 pointer.
1068
1069 \sa doHandshake(), handshakeState(), isConnectionEncrypted(), dtlsError()
1070*/
1071qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)
1072{
1073 Q_D(QDtls);
1074
1075 auto *backend = d->backend.get();
1076 if (!backend)
1077 return -1;
1078
1079 if (!socket) {
1080 backend->setDtlsError(code: QDtlsError::InvalidInputParameters, description: tr(s: "Invalid (nullptr) socket"));
1081 return -1;
1082 }
1083
1084 if (!isConnectionEncrypted()) {
1085 backend->setDtlsError(code: QDtlsError::InvalidOperation,
1086 description: tr(s: "Cannot write a datagram, not in encrypted state"));
1087 return -1;
1088 }
1089
1090 return backend->writeDatagramEncrypted(socket, dgram);
1091}
1092
1093/*!
1094 Decrypts \a dgram and returns its contents as plain text. The handshake must
1095 be completed before datagrams can be decrypted. Depending on the type of the
1096 TLS message the connection may write into \a socket, which must be a valid
1097 pointer.
1098*/
1099QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
1100{
1101 Q_D(QDtls);
1102
1103 auto *backend = d->backend.get();
1104 if (!backend)
1105 return {};
1106
1107 if (!socket) {
1108 backend->setDtlsError(code: QDtlsError::InvalidInputParameters, description: tr(s: "Invalid (nullptr) socket"));
1109 return {};
1110 }
1111
1112 if (!isConnectionEncrypted()) {
1113 backend->setDtlsError(code: QDtlsError::InvalidOperation,
1114 description: tr(s: "Cannot read a datagram, not in encrypted state"));
1115 return {};
1116 }
1117
1118 if (!dgram.size())
1119 return {};
1120
1121 return backend->decryptDatagram(socket, dgram);
1122}
1123
1124/*!
1125 Returns the last error encountered by the connection or QDtlsError::NoError.
1126
1127 \sa dtlsErrorString(), QDtlsError
1128*/
1129QDtlsError QDtls::dtlsError() const
1130{
1131 Q_D(const QDtls);
1132
1133 if (const auto *backend = d->backend.get())
1134 return backend->error();
1135
1136 return QDtlsError::NoError;
1137}
1138
1139/*!
1140 Returns a textual description for the last error encountered by the connection
1141 or empty string.
1142
1143 \sa dtlsError()
1144*/
1145QString QDtls::dtlsErrorString() const
1146{
1147 Q_D(const QDtls);
1148
1149 if (const auto *backend = d->backend.get())
1150 return backend->errorString();
1151
1152 return {};
1153}
1154
1155/*!
1156 Returns errors found while establishing the identity of the peer.
1157
1158 If you want to continue connecting despite the errors that have occurred,
1159 you must call ignoreVerificationErrors().
1160*/
1161QList<QSslError> QDtls::peerVerificationErrors() const
1162{
1163 Q_D(const QDtls);
1164
1165 if (const auto *backend = d->backend.get())
1166 return backend->peerVerificationErrors();
1167
1168 //return d->tlsErrors;
1169 return {};
1170}
1171
1172/*!
1173 This method tells QDtls to ignore only the errors given in \a errorsToIgnore.
1174
1175 If, for instance, you want to connect to a server that uses a self-signed
1176 certificate, consider the following snippet:
1177
1178 \snippet code/src_network_ssl_qdtls.cpp 6
1179
1180 You can also call this function after doHandshake() encountered the
1181 QDtlsError::PeerVerificationError error, and then resume the handshake by
1182 calling resumeHandshake().
1183
1184 Later calls to this function will replace the list of errors that were
1185 passed in previous calls. You can clear the list of errors you want to ignore
1186 by calling this function with an empty list.
1187
1188 \sa doHandshake(), resumeHandshake(), QSslError
1189*/
1190void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
1191{
1192 Q_D(QDtls);
1193
1194 if (auto *backend = d->backend.get())
1195 backend->ignoreVerificationErrors(errorsToIgnore);
1196}
1197
1198QT_END_NAMESPACE
1199
1200#include "moc_qdtls.cpp"
1201

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