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

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