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