Coverage Report

Created: 2026-04-29 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/network/ssl/qdtls.cpp
Line
Count
Source
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
5
#include "qsslconfiguration.h"
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
302
QT_BEGIN_NAMESPACE
303
304
static QString msgUnsupportedMulticastAddress()
305
0
{
306
0
    return QDtls::tr("Multicast and broadcast addresses are not supported");
307
0
}
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
 */
318
QDtlsClientVerifier::GeneratorParameters::GeneratorParameters()
319
0
{
320
0
}
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
 */
330
QDtlsClientVerifier::GeneratorParameters::GeneratorParameters(QCryptographicHash::Algorithm algorithm, const QByteArray &secret)
331
0
    : hash(algorithm), secret(secret)
332
0
{
333
0
}
334
335
QDtlsClientVerifierPrivate::QDtlsClientVerifierPrivate()
336
0
{
337
0
    const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
338
0
    if (!tlsBackend) {
339
0
        qCWarning(lcSsl, "No TLS backend is available, cannot verify DTLS client");
340
0
        return;
341
0
    }
342
0
    backend.reset(tlsBackend->createDtlsCookieVerifier());
343
0
    if (!backend.get())
344
0
        qCWarning(lcSsl) << "The backend" << tlsBackend->backendName() << "does not support DTLS cookies";
345
0
}
346
347
0
QDtlsClientVerifierPrivate::~QDtlsClientVerifierPrivate() = default;
348
349
/*!
350
    Constructs a QDtlsClientVerifier object, \a parent is passed to QObject's
351
    constructor.
352
*/
353
QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent)
354
0
    : QObject(*new QDtlsClientVerifierPrivate, parent)
355
0
{
356
0
    Q_D(QDtlsClientVerifier);
357
358
0
    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
0
        auto conf = QSslConfiguration::defaultDtlsConfiguration();
363
0
        conf.setPeerVerifyMode(QSslSocket::VerifyNone);
364
0
        backend->setConfiguration(conf);
365
0
    }
366
0
}
367
368
/*!
369
    Destroys the QDtlsClientVerifier object.
370
*/
371
QDtlsClientVerifier::~QDtlsClientVerifier()
372
0
{
373
0
}
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
*/
386
bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters &params)
387
0
{
388
0
    Q_D(QDtlsClientVerifier);
389
0
    if (auto *backend = d->backend.get())
390
0
        return backend->setCookieGeneratorParameters(params);
391
392
0
    return false;
393
0
}
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
*/
405
QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorParameters() const
406
0
{
407
0
    Q_D(const QDtlsClientVerifier);
408
409
0
    if (const auto *backend = d->backend.get())
410
0
        return backend->cookieGeneratorParameters();
411
412
0
    return {};
413
0
}
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
*/
430
bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgram,
431
                                       const QHostAddress &address, quint16 port)
432
0
{
433
0
    Q_D(QDtlsClientVerifier);
434
435
0
    auto *backend = d->backend.get();
436
0
    if (!backend)
437
0
        return false;
438
439
0
    if (!socket || address.isNull() || !dgram.size()) {
440
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters,
441
0
                              tr("A valid UDP socket, non-empty datagram, and valid address/port were expected"));
442
0
        return false;
443
0
    }
444
445
0
    if (address.isBroadcast() || address.isMulticast()) {
446
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters,
447
0
                              msgUnsupportedMulticastAddress());
448
0
        return false;
449
0
    }
450
451
0
    return backend->verifyClient(socket, dgram, address, port);
452
0
}
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
*/
460
QByteArray QDtlsClientVerifier::verifiedHello() const
461
0
{
462
0
    Q_D(const QDtlsClientVerifier);
463
464
0
    if (const auto *backend = d->backend.get())
465
0
        return backend->verifiedHello();
466
467
0
    return {};
468
0
}
469
470
/*!
471
    Returns the last error that occurred or QDtlsError::NoError.
472
473
    \sa QDtlsError, dtlsErrorString()
474
*/
475
QDtlsError QDtlsClientVerifier::dtlsError() const
476
0
{
477
0
    Q_D(const QDtlsClientVerifier);
478
479
0
    if (const auto *backend = d->backend.get())
480
0
        return backend->error();
481
482
0
    return QDtlsError::TlsInitializationError;
483
0
}
484
485
/*!
486
    Returns a textual description of the last error, or an empty string.
487
488
    \sa dtlsError()
489
 */
490
QString QDtlsClientVerifier::dtlsErrorString() const
491
0
{
492
0
    Q_D(const QDtlsClientVerifier);
493
494
0
    if (const auto *backend = d->backend.get())
495
0
        return backend->errorString();
496
497
0
    return QStringLiteral("No TLS backend is available, no client verification");
498
0
}
499
500
0
QDtlsPrivate::QDtlsPrivate() = default;
501
0
QDtlsPrivate::~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
*/
510
QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent)
511
0
    : QObject(*new QDtlsPrivate, parent)
512
0
{
513
0
    Q_D(QDtls);
514
0
    const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
515
0
    if (!tlsBackend) {
516
0
        qCWarning(lcSsl, "No TLS backend found, QDtls is unsupported");
517
0
        return;
518
0
    }
519
0
    d->backend.reset(tlsBackend->createDtlsCryptograph(this, mode));
520
0
    if (!d->backend.get()) {
521
0
        qCWarning(lcSsl) << "TLS backend" << tlsBackend->backendName()
522
0
                         << "does not support the protocol DTLS";
523
0
    }
524
0
    setDtlsConfiguration(QSslConfiguration::defaultDtlsConfiguration());
525
0
}
526
527
/*!
528
    Destroys the QDtls object.
529
*/
530
QDtls::~QDtls()
531
0
{
532
0
}
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
 */
541
bool QDtls::setPeer(const QHostAddress &address, quint16 port,
542
                    const QString &verificationName)
543
0
{
544
0
    Q_D(QDtls);
545
546
0
    auto *backend = d->backend.get();
547
0
    if (!backend)
548
0
        return false;
549
550
0
    if (backend->state() != HandshakeNotStarted) {
551
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
552
0
                              tr("Cannot set peer after handshake started"));
553
0
        return false;
554
0
    }
555
556
0
    if (address.isNull()) {
557
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters,
558
0
                              tr("Invalid address"));
559
0
        return false;
560
0
    }
561
562
0
    if (address.isBroadcast() || address.isMulticast()) {
563
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters,
564
0
                              msgUnsupportedMulticastAddress());
565
0
        return false;
566
0
    }
567
568
0
    backend->clearDtlsError();
569
0
    backend->setPeer(address, port, verificationName);
570
571
0
    return true;
572
0
}
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
*/
582
bool QDtls::setPeerVerificationName(const QString &name)
583
0
{
584
0
    Q_D(QDtls);
585
586
0
    auto *backend = d->backend.get();
587
0
    if (!backend)
588
0
        return false;
589
590
0
    if (backend->state() != HandshakeNotStarted) {
591
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
592
0
                        tr("Cannot set verification name after handshake started"));
593
0
        return false;
594
0
    }
595
596
0
    backend->clearDtlsError();
597
0
    backend->setPeerVerificationName(name);
598
599
0
    return true;
600
0
}
601
602
/*!
603
    Returns the peer's address, set by setPeer(), or QHostAddress::Null.
604
605
    \sa setPeer()
606
*/
607
QHostAddress QDtls::peerAddress() const
608
0
{
609
0
    Q_D(const QDtls);
610
611
0
    if (const auto *backend = d->backend.get())
612
0
        return backend->peerAddress();
613
614
0
    return {};
615
0
}
616
617
/*!
618
    Returns the peer's port number, set by setPeer(), or 0.
619
620
    \sa setPeer()
621
*/
622
quint16 QDtls::peerPort() const
623
0
{
624
0
    Q_D(const QDtls);
625
626
0
    if (const auto *backend = d->backend.get())
627
0
        return backend->peerPort();
628
629
0
    return 0;
630
0
}
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
*/
638
QString QDtls::peerVerificationName() const
639
0
{
640
0
    Q_D(const QDtls);
641
642
0
    if (const auto *backend = d->backend.get())
643
0
        return backend->peerVerificationName();
644
645
0
    return {};
646
0
}
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
*/
654
QSslSocket::SslMode QDtls::sslMode() const
655
0
{
656
0
    Q_D(const QDtls);
657
658
0
    if (const auto *backend = d->backend.get())
659
0
        return backend->cryptographMode();
660
661
0
    return QSslSocket::UnencryptedMode;
662
0
}
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
 */
670
void QDtls::setMtuHint(quint16 mtuHint)
671
0
{
672
0
    Q_D(QDtls);
673
674
0
    if (auto *backend = d->backend.get())
675
0
        backend->setDtlsMtuHint(mtuHint);
676
0
}
677
678
/*!
679
    Returns the value previously set by setMtuHint(). The default value is 0.
680
681
    \sa setMtuHint()
682
 */
683
quint16 QDtls::mtuHint() const
684
0
{
685
0
    Q_D(const QDtls);
686
687
0
    if (const auto *backend = d->backend.get())
688
0
        return backend->dtlsMtuHint();
689
690
0
    return 0;
691
0
}
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
*/
703
bool QDtls::setCookieGeneratorParameters(const GeneratorParameters &params)
704
0
{
705
0
    Q_D(QDtls);
706
707
0
    if (auto *backend = d->backend.get())
708
0
        backend->setCookieGeneratorParameters(params);
709
710
0
    return false;
711
0
}
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
*/
724
QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const
725
0
{
726
0
    Q_D(const QDtls);
727
728
0
    if (const auto *backend = d->backend.get())
729
0
        return backend->cookieGeneratorParameters();
730
731
0
    return {};
732
0
}
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
*/
742
bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
743
0
{
744
0
    Q_D(QDtls);
745
746
0
    auto *backend = d->backend.get();
747
0
    if (!backend)
748
0
        return false;
749
750
0
    if (backend->state() != HandshakeNotStarted) {
751
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
752
0
                              tr("Cannot set configuration after handshake started"));
753
0
        return false;
754
0
    }
755
756
0
    backend->setConfiguration(configuration);
757
0
    return true;
758
0
}
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
*/
766
QSslConfiguration QDtls::dtlsConfiguration() const
767
0
{
768
0
    Q_D(const QDtls);
769
0
    if (const auto *backend = d->backend.get())
770
0
        return backend->configuration();
771
772
0
    return {};
773
0
}
774
775
/*!
776
    Returns the current handshake state for this QDtls.
777
778
    \sa doHandshake(), QDtls::HandshakeState
779
 */
780
QDtls::HandshakeState QDtls::handshakeState()const
781
0
{
782
0
    Q_D(const QDtls);
783
784
0
    if (const auto *backend = d->backend.get())
785
0
        return backend->state();
786
787
0
    return QDtls::HandshakeNotStarted;
788
0
}
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
*/
809
bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram)
810
0
{
811
0
    Q_D(QDtls);
812
813
0
    auto *backend = d->backend.get();
814
0
    if (!backend)
815
0
        return false;
816
817
0
    if (backend->state() == HandshakeNotStarted)
818
0
        return startHandshake(socket, dgram);
819
0
    else if (backend->state() == HandshakeInProgress)
820
0
        return continueHandshake(socket, dgram);
821
822
0
    backend->setDtlsError(QDtlsError::InvalidOperation,
823
0
                          tr("Cannot start/continue handshake, invalid handshake state"));
824
0
    return false;
825
0
}
826
827
/*!
828
    \internal
829
*/
830
bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram)
831
0
{
832
0
    Q_D(QDtls);
833
834
0
    auto *backend = d->backend.get();
835
0
    if (!backend)
836
0
        return false;
837
838
0
    if (!socket) {
839
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
840
0
        return false;
841
0
    }
842
843
0
    if (backend->peerAddress().isNull()) {
844
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
845
0
                              tr("To start a handshake you must set peer's address and port first"));
846
0
        return false;
847
0
    }
848
849
0
    if (sslMode() == QSslSocket::SslServerMode && !datagram.size()) {
850
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters,
851
0
                              tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
852
0
        return false;
853
0
    }
854
855
0
    if (backend->state() != HandshakeNotStarted) {
856
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
857
0
                              tr("Cannot start handshake, already done/in progress"));
858
0
        return false;
859
0
    }
860
861
0
    return backend->startHandshake(socket, datagram);
862
0
}
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
*/
872
bool QDtls::handleTimeout(QUdpSocket *socket)
873
0
{
874
0
    Q_D(QDtls);
875
876
0
    auto *backend = d->backend.get();
877
0
    if (!backend)
878
0
        return false;
879
880
0
    if (!socket) {
881
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
882
0
        return false;
883
0
    }
884
885
0
    return backend->handleTimeout(socket);
886
0
}
887
888
/*!
889
    \internal
890
*/
891
bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram)
892
0
{
893
0
    Q_D(QDtls);
894
895
0
    auto *backend = d->backend.get();
896
0
    if (!backend)
897
0
        return false;
898
899
0
    if (!socket || !datagram.size()) {
900
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters,
901
0
                              tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
902
0
        return false;
903
0
    }
904
905
0
    if (backend->state() != HandshakeInProgress) {
906
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
907
0
                              tr("Cannot continue handshake, not in InProgress state"));
908
0
        return false;
909
0
    }
910
911
0
    return backend->continueHandshake(socket, datagram);
912
0
}
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
*/
922
bool QDtls::resumeHandshake(QUdpSocket *socket)
923
0
{
924
0
    Q_D(QDtls);
925
926
0
    auto *backend = d->backend.get();
927
0
    if (!backend)
928
0
        return false;
929
930
0
    if (!socket) {
931
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
932
0
        return false;
933
0
    }
934
935
0
    if (backend->state() != PeerVerificationFailed) {
936
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
937
0
                              tr("Cannot resume, not in VerificationError state"));
938
0
        return false;
939
0
    }
940
941
0
    return backend->resumeHandshake(socket);
942
0
}
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
 */
950
bool QDtls::abortHandshake(QUdpSocket *socket)
951
0
{
952
0
    Q_D(QDtls);
953
954
0
    auto *backend = d->backend.get();
955
0
    if (!backend)
956
0
        return false;
957
958
0
    if (!socket) {
959
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
960
0
        return false;
961
0
    }
962
963
0
    if (backend->state() != PeerVerificationFailed && backend->state() != HandshakeInProgress) {
964
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
965
0
                              tr("No handshake in progress, nothing to abort"));
966
0
        return false;
967
0
    }
968
969
0
    backend->abortHandshake(socket);
970
0
    return true;
971
0
}
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
 */
980
bool QDtls::shutdown(QUdpSocket *socket)
981
0
{
982
0
    Q_D(QDtls);
983
984
0
    auto *backend = d->backend.get();
985
0
    if (!backend)
986
0
        return false;
987
988
0
    if (!socket) {
989
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters,
990
0
                              tr("Invalid (nullptr) socket"));
991
0
        return false;
992
0
    }
993
994
0
    if (!backend->isConnectionEncrypted()) {
995
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
996
0
                              tr("Cannot send shutdown alert, not encrypted"));
997
0
        return false;
998
0
    }
999
1000
0
    backend->sendShutdownAlert(socket);
1001
0
    return true;
1002
0
}
1003
1004
/*!
1005
    Returns \c true if DTLS handshake completed successfully.
1006
1007
    \sa doHandshake(), handshakeState()
1008
 */
1009
bool QDtls::isConnectionEncrypted() const
1010
0
{
1011
0
    Q_D(const QDtls);
1012
1013
1014
0
    if (const auto *backend = d->backend.get())
1015
0
        return backend->isConnectionEncrypted();
1016
1017
0
    return false;
1018
0
}
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
*/
1032
QSslCipher QDtls::sessionCipher() const
1033
0
{
1034
0
    Q_D(const QDtls);
1035
1036
0
    if (const auto *backend = d->backend.get())
1037
0
        return backend->dtlsSessionCipher();
1038
1039
0
    return {};
1040
0
}
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
*/
1052
QSsl::SslProtocol QDtls::sessionProtocol() const
1053
0
{
1054
0
    Q_D(const QDtls);
1055
1056
0
    if (const auto *backend = d->backend.get())
1057
0
        return backend->dtlsSessionProtocol();
1058
1059
0
    return QSsl::UnknownProtocol;
1060
0
}
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
*/
1070
qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)
1071
0
{
1072
0
    Q_D(QDtls);
1073
1074
0
    auto *backend = d->backend.get();
1075
0
    if (!backend)
1076
0
        return -1;
1077
1078
0
    if (!socket) {
1079
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
1080
0
        return -1;
1081
0
    }
1082
1083
0
    if (!isConnectionEncrypted()) {
1084
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
1085
0
                              tr("Cannot write a datagram, not in encrypted state"));
1086
0
        return -1;
1087
0
    }
1088
1089
0
    return backend->writeDatagramEncrypted(socket, dgram);
1090
0
}
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
*/
1098
QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
1099
0
{
1100
0
    Q_D(QDtls);
1101
1102
0
    auto *backend = d->backend.get();
1103
0
    if (!backend)
1104
0
        return {};
1105
1106
0
    if (!socket) {
1107
0
        backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
1108
0
        return {};
1109
0
    }
1110
1111
0
    if (!isConnectionEncrypted()) {
1112
0
        backend->setDtlsError(QDtlsError::InvalidOperation,
1113
0
                              tr("Cannot read a datagram, not in encrypted state"));
1114
0
        return {};
1115
0
    }
1116
1117
0
    if (!dgram.size())
1118
0
        return {};
1119
1120
0
    return backend->decryptDatagram(socket, dgram);
1121
0
}
1122
1123
/*!
1124
    Returns the last error encountered by the connection or QDtlsError::NoError.
1125
1126
    \sa dtlsErrorString(), QDtlsError
1127
*/
1128
QDtlsError QDtls::dtlsError() const
1129
0
{
1130
0
    Q_D(const QDtls);
1131
1132
0
    if (const auto *backend = d->backend.get())
1133
0
        return backend->error();
1134
1135
0
    return QDtlsError::NoError;
1136
0
}
1137
1138
/*!
1139
    Returns a textual description for the last error encountered by the connection
1140
    or empty string.
1141
1142
    \sa dtlsError()
1143
*/
1144
QString QDtls::dtlsErrorString() const
1145
0
{
1146
0
    Q_D(const QDtls);
1147
1148
0
    if (const auto *backend = d->backend.get())
1149
0
        return backend->errorString();
1150
1151
0
    return {};
1152
0
}
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
*/
1160
QList<QSslError> QDtls::peerVerificationErrors() const
1161
0
{
1162
0
    Q_D(const QDtls);
1163
1164
0
    if (const auto *backend = d->backend.get())
1165
0
        return backend->peerVerificationErrors();
1166
1167
    //return d->tlsErrors;
1168
0
    return {};
1169
0
}
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
*/
1189
void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
1190
0
{
1191
0
    Q_D(QDtls);
1192
1193
0
    if (auto *backend = d->backend.get())
1194
0
        backend->ignoreVerificationErrors(errorsToIgnore);
1195
0
}
1196
1197
QT_END_NAMESPACE
1198
1199
#include "moc_qdtls.cpp"