/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 ¶ms) |
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 ¶ms) |
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" |