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 | |
338 | QT_BEGIN_NAMESPACE |
339 | |
340 | QSslConfiguration 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 | |
351 | void 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 | |
376 | bool 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 | |
393 | bool 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 | |
406 | static 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 | */ |
420 | QDtlsClientVerifier::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 | */ |
432 | QDtlsClientVerifier::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 | */ |
441 | QDtlsClientVerifier::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 | */ |
458 | QDtlsClientVerifier::~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 | */ |
473 | bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters ¶ms) |
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 | */ |
490 | QDtlsClientVerifier::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 | */ |
512 | bool 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 | */ |
538 | QByteArray 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 | */ |
550 | QDtlsError 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 | */ |
562 | QString 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 | */ |
576 | QDtls::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 | */ |
588 | QDtls::~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 | */ |
599 | bool 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 | */ |
639 | bool 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 | */ |
660 | QHostAddress 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 | */ |
672 | quint16 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 | */ |
685 | QString 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 | */ |
698 | QSslSocket::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 | */ |
711 | void 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 | */ |
723 | quint16 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 | */ |
740 | bool QDtls::setCookieGeneratorParameters(const GeneratorParameters ¶ms) |
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 | */ |
758 | QDtls::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 | */ |
773 | bool 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 | */ |
793 | QSslConfiguration 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 | */ |
805 | QDtls::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 | */ |
831 | bool 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 | */ |
848 | bool 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 | */ |
886 | bool 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 | */ |
901 | bool 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 | */ |
928 | bool 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 | */ |
952 | bool 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 | */ |
978 | bool 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 | */ |
1003 | bool 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 | */ |
1022 | QSslCipher 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 | */ |
1039 | QSsl::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 | */ |
1054 | qint64 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 | */ |
1078 | QByteArray 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 | */ |
1104 | QDtlsError 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 | */ |
1117 | QString 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 | */ |
1130 | QVector<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 | */ |
1155 | void QDtls::ignoreVerificationErrors(const QVector<QSslError> &errorsToIgnore) |
1156 | { |
1157 | Q_D(QDtls); |
1158 | |
1159 | d->tlsErrorsToIgnore = errorsToIgnore; |
1160 | } |
1161 | |
1162 | QT_END_NAMESPACE |
1163 | |