Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qdtls_openssl.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtNetwork/private/qnativesocketengine_p_p.h>
5
7#include "qdtls_openssl_p.h"
8#include "qx509_openssl_p.h"
9
10#include <QtNetwork/private/qsslpresharedkeyauthenticator_p.h>
11#include <QtNetwork/private/qsslcertificate_p.h>
12#include <QtNetwork/private/qssl_p.h>
13
14#include <QtNetwork/qudpsocket.h>
15
16#include <QtCore/qmessageauthenticationcode.h>
17#include <QtCore/qcryptographichash.h>
18
19#include <QtCore/qdebug.h>
20
21#include <cstring>
22#include <cstddef>
23
25
26#define QT_DTLS_VERBOSE 0
27
28#if QT_DTLS_VERBOSE
29
30#define qDtlsWarning(arg) qWarning(arg)
31#define qDtlsDebug(arg) qDebug(arg)
32
33#else
34
35#define qDtlsWarning(arg)
36#define qDtlsDebug(arg)
37
38#endif // QT_DTLS_VERBOSE
39
40namespace dtlsutil
41{
42
44{
45 Q_ASSERT(ssl);
46
47 // SSL_get_rbio does not increment the reference count
48 BIO *readBIO = q_SSL_get_rbio(ssl);
49 if (!readBIO) {
50 qCWarning(lcTlsBackend, "No BIO (dgram) found in SSL object");
51 return {};
52 }
53
54 auto listener = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(readBIO));
55 if (!listener) {
56 qCWarning(lcTlsBackend, "BIO_get_app_data returned invalid (nullptr) value");
57 return {};
58 }
59
60 const QHostAddress peerAddress(listener->remoteAddress);
61 const quint16 peerPort(listener->remotePort);
62 QByteArray peerData;
63 if (peerAddress.protocol() == QAbstractSocket::IPv6Protocol) {
64 const Q_IPV6ADDR sin6_addr(peerAddress.toIPv6Address());
65 peerData.resize(int(sizeof sin6_addr + sizeof peerPort));
66 char *dst = peerData.data();
67 std::memcpy(dst, &peerPort, sizeof peerPort);
68 dst += sizeof peerPort;
69 std::memcpy(dst, &sin6_addr, sizeof sin6_addr);
70 } else if (peerAddress.protocol() == QAbstractSocket::IPv4Protocol) {
71 const quint32 sin_addr(peerAddress.toIPv4Address());
72 peerData.resize(int(sizeof sin_addr + sizeof peerPort));
73 char *dst = peerData.data();
74 std::memcpy(dst, &peerPort, sizeof peerPort);
75 dst += sizeof peerPort;
76 std::memcpy(dst, &sin_addr, sizeof sin_addr);
77 } else {
78 Q_UNREACHABLE();
79 }
80
81 return peerData;
82}
83
85{
87 {
88 key.resize(32);
89 const int status = q_RAND_bytes(reinterpret_cast<unsigned char *>(key.data()),
90 key.size());
91 if (status <= 0)
92 key.clear();
93 }
94
96
97 Q_DISABLE_COPY_MOVE(FallbackCookieSecret)
98};
99
101{
102 static const FallbackCookieSecret generator;
103 return generator.key;
104}
105
106int next_timeoutMs(SSL *tlsConnection)
107{
108 Q_ASSERT(tlsConnection);
109 timeval timeLeft = {};
110 q_DTLSv1_get_timeout(tlsConnection, &timeLeft);
111 return timeLeft.tv_sec * 1000;
112}
113
114
115void delete_connection(SSL *ssl)
116{
117 // The 'deleter' for QSharedPointer<SSL>.
118 if (ssl)
119 q_SSL_free(ssl);
120}
121
122void delete_BIO_ADDR(BIO_ADDR *bio)
123{
124 // A deleter for QSharedPointer<BIO_ADDR>
125 if (bio)
126 q_BIO_ADDR_free(bio);
127}
128
129void delete_bio_method(BIO_METHOD *method)
130{
131 // The 'deleter' for QSharedPointer<BIO_METHOD>.
132 if (method)
133 q_BIO_meth_free(method);
134}
135
136// The path MTU discovery is non-trivial: it's a mix of getsockopt/setsockopt
137// (IP_MTU/IP6_MTU/IP_MTU_DISCOVER) and fallback MTU values. It's not
138// supported on all platforms, worse so - imposes specific requirements on
139// underlying UDP socket etc. So for now, we either try a user-proposed MTU
140// hint or rely on our own fallback value. As a fallback mtu OpenSSL uses 576
141// for IPv4 and 1280 for IPv6 (RFC 791, RFC 2460). To KIS we use 576. This
142// rather small MTU value does not affect the size that can be read/written
143// by QDtls, only a handshake (which is allowed to fragment).
144enum class MtuGuess : long
145{
146 defaultMtu = 576
147};
148
149} // namespace dtlsutil
150
152{
153
154extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
155 unsigned *cookieLength)
156{
157 if (!ssl || !dst || !cookieLength) {
158 qCWarning(lcTlsBackend,
159 "Failed to generate cookie - invalid (nullptr) parameter(s)");
160 return 0;
161 }
162
164 if (!generic) {
165 qCWarning(lcTlsBackend, "SSL_get_ex_data returned nullptr, cannot generate cookie");
166 return 0;
167 }
168
169 *cookieLength = 0;
170
171 auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
172 if (!dtls->secret.size())
173 return 0;
174
175 const QByteArray peerData(dtlsutil::cookie_for_peer(ssl));
176 if (!peerData.size())
177 return 0;
178
179 QMessageAuthenticationCode hmac(dtls->hashAlgorithm, dtls->secret);
180 hmac.addData(peerData);
181 const QByteArrayView cookie = hmac.resultView();
182 Q_ASSERT(cookie.size() >= 0);
183 // DTLS1_COOKIE_LENGTH is erroneously 256 bytes long, must be 255 - RFC 6347, 4.2.1.
184 *cookieLength = qMin(DTLS1_COOKIE_LENGTH - 1, cookie.size());
185 std::memcpy(dst, cookie.constData(), *cookieLength);
186
187 return 1;
188}
189
190extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
191 unsigned cookieLength)
192{
193 if (!ssl || !cookie || !cookieLength) {
194 qCWarning(lcTlsBackend, "Could not verify cookie, invalid (nullptr or zero) parameters");
195 return 0;
196 }
197
198 unsigned char newCookie[DTLS1_COOKIE_LENGTH] = {};
199 unsigned newCookieLength = 0;
200 if (q_generate_cookie_callback(ssl, newCookie, &newCookieLength) != 1)
201 return 0;
202
203 return newCookieLength == cookieLength
204 && !q_CRYPTO_memcmp(cookie, newCookie, size_t(cookieLength));
205}
206
207extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
208{
209 if (!ok) {
210 // Store the error and at which depth the error was detected.
212 if (!ssl) {
213 qCWarning(lcTlsBackend, "X509_STORE_CTX_get_ex_data returned nullptr, handshake failure");
214 return 0;
215 }
216
218 if (!generic) {
219 qCWarning(lcTlsBackend, "SSL_get_ex_data returned nullptr, handshake failure");
220 return 0;
221 }
222
223 auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
225 }
226
227 // Always return 1 (OK) to allow verification to continue. We handle the
228 // errors gracefully after collecting all errors, after verification has
229 // completed.
230 return 1;
231}
232
233extern "C" unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *identity,
234 unsigned max_identity_len, unsigned char *psk,
235 unsigned max_psk_len)
236{
237 auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
239 if (!dtls)
240 return 0;
241
242 Q_ASSERT(dtls->dtlsPrivate);
243 return dtls->dtlsPrivate->pskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
244}
245
246extern "C" unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
247 unsigned max_psk_len)
248{
249 auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
251 if (!dtls)
252 return 0;
253
254 Q_ASSERT(dtls->dtlsPrivate);
255 return dtls->dtlsPrivate->pskServerCallback(identity, psk, max_psk_len);
256}
257
258} // namespace dtlscallbacks
259
260namespace dtlsbio
261{
262
263extern "C" int q_dgram_read(BIO *bio, char *dst, int bytesToRead)
264{
265 if (!bio || !dst || bytesToRead <= 0) {
266 qCWarning(lcTlsBackend, "invalid input parameter(s)");
267 return 0;
268 }
269
271
272 auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
273 // It's us who set data, if OpenSSL does too, the logic here is wrong
274 // then and we have to use BIO_set_app_data then!
275 Q_ASSERT(dtls);
276 int bytesRead = 0;
277 if (dtls->dgram.size()) {
278 bytesRead = qMin(dtls->dgram.size(), bytesToRead);
279 std::memcpy(dst, dtls->dgram.constData(), bytesRead);
280
281 if (!dtls->peeking)
282 dtls->dgram = dtls->dgram.mid(bytesRead);
283 } else {
284 bytesRead = -1;
285 }
286
287 if (bytesRead <= 0)
289
290 return bytesRead;
291}
292
293extern "C" int q_dgram_write(BIO *bio, const char *src, int bytesToWrite)
294{
295 if (!bio || !src || bytesToWrite <= 0) {
296 qCWarning(lcTlsBackend, "invalid input parameter(s)");
297 return 0;
298 }
299
301
302 auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
303 Q_ASSERT(dtls);
304 if (dtls->writeSuppressed) {
305 // See the comment in QDtls::startHandshake.
306 return bytesToWrite;
307 }
308
309 QUdpSocket *udpSocket = dtls->udpSocket;
310 Q_ASSERT(udpSocket);
311
312 const QByteArray dgram(QByteArray::fromRawData(src, bytesToWrite));
313 qint64 bytesWritten = -1;
314 if (udpSocket->state() == QAbstractSocket::ConnectedState) {
315 bytesWritten = udpSocket->write(dgram);
316 } else {
317 bytesWritten = udpSocket->writeDatagram(dgram, dtls->remoteAddress,
318 dtls->remotePort);
319 }
320
321 if (bytesWritten <= 0)
323
324 Q_ASSERT(bytesWritten <= std::numeric_limits<int>::max());
325 return int(bytesWritten);
326}
327
328extern "C" int q_dgram_puts(BIO *bio, const char *src)
329{
330 if (!bio || !src) {
331 qCWarning(lcTlsBackend, "invalid input parameter(s)");
332 return 0;
333 }
334
335 return q_dgram_write(bio, src, int(std::strlen(src)));
336}
337
338extern "C" long q_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr)
339{
340 // This is our custom BIO_ctrl. bio.h defines a lot of BIO_CTRL_*
341 // and BIO_* constants and BIO_somename macros that expands to BIO_ctrl
342 // call with one of those constants as argument. What exactly BIO_ctrl
343 // does - depends on the 'cmd' and the type of BIO (so BIO_ctrl does
344 // not even have a single well-defined value meaning success or failure).
345 // We handle only the most generic commands - the ones documented for
346 // BIO_ctrl - and also DGRAM specific ones. And even for them - in most
347 // cases we do nothing but report a success or some non-error value.
348 // Documents also state: "Source/sink BIOs return an 0 if they do not
349 // recognize the BIO_ctrl() operation." - these are covered by 'default'
350 // label in the switch-statement below. Debug messages in the switch mean:
351 // 1) we got a command that is unexpected for dgram BIO, or:
352 // 2) we do not call any function that would lead to OpenSSL using this
353 // command.
354
355 if (!bio) {
356 qDebug(lcTlsBackend, "invalid 'bio' parameter (nullptr)");
357 return -1;
358 }
359
360 auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
361 Q_ASSERT(dtls);
362
363 switch (cmd) {
364 // Let's start from the most generic ones, in the order in which they are
365 // documented (as BIO_ctrl):
366 case BIO_CTRL_RESET:
367 // BIO_reset macro.
368 // From documentation:
369 // "BIO_reset() normally returns 1 for success and 0 or -1 for failure.
370 // File BIOs are an exception, they return 0 for success and -1 for
371 // failure."
372 // We have nothing to reset and we are not file BIO.
373 return 1;
374 case BIO_C_FILE_SEEK:
375 case BIO_C_FILE_TELL:
376 qDtlsWarning("Unexpected cmd (BIO_C_FILE_SEEK/BIO_C_FILE_TELL)");
377 // These are for BIO_seek, BIO_tell. We are not a file BIO.
378 // Non-negative return value means success.
379 return 0;
380 case BIO_CTRL_FLUSH:
381 // BIO_flush, nothing to do, we do not buffer any data.
382 // 0 or -1 means error, 1 - success.
383 return 1;
384 case BIO_CTRL_EOF:
385 qDtlsWarning("Unexpected cmd (BIO_CTRL_EOF)");
386 // BIO_eof, 1 means EOF read. Makes no sense for us.
387 return 0;
388 case BIO_CTRL_SET_CLOSE:
389 // BIO_set_close with BIO_CLOSE/BIO_NOCLOSE flags. Documented as
390 // always returning 1.
391 // From the documentation:
392 // "Typically BIO_CLOSE is used in a source/sink BIO to indicate that
393 // the underlying I/O stream should be closed when the BIO is freed."
394 //
395 // QUdpSocket we work with is not BIO's business, ignoring.
396 return 1;
397 case BIO_CTRL_GET_CLOSE:
398 // BIO_get_close. No, never, see the comment above.
399 return 0;
400 case BIO_CTRL_PENDING:
401 qDtlsWarning("Unexpected cmd (BIO_CTRL_PENDING)");
402 // BIO_pending. Not used by DTLS/OpenSSL (we are not buffering).
403 return 0;
404 case BIO_CTRL_WPENDING:
405 // No, we have nothing buffered.
406 return 0;
407 // The constants below are not documented as a part BIO_ctrl documentation,
408 // but they are also not type-specific.
409 case BIO_CTRL_DUP:
410 qDtlsWarning("Unexpected cmd (BIO_CTRL_DUP)");
411 // BIO_dup_state, not used by DTLS (and socket-related BIOs in general).
412 // For some very specific BIO type this 'cmd' would copy some state
413 // from 'bio' to (BIO*)'ptr'. 1 means success.
414 return 0;
415 case BIO_CTRL_SET_CALLBACK:
416 qDtlsWarning("Unexpected cmd (BIO_CTRL_SET_CALLBACK)");
417 // BIO_set_info_callback. We never call this, OpenSSL does not do this
418 // on its own (normally it's used if client code wants to have some
419 // debug information, for example, dumping handshake state via
420 // BIO_printf from SSL info_callback).
421 return 0;
422 case BIO_CTRL_GET_CALLBACK:
423 qDtlsWarning("Unexpected cmd (BIO_CTRL_GET_CALLBACK)");
424 // BIO_get_info_callback. We never call this.
425 if (ptr)
426 *static_cast<bio_info_cb **>(ptr) = nullptr;
427 return 0;
428 case BIO_CTRL_SET:
429 case BIO_CTRL_GET:
430 qDtlsWarning("Unexpected cmd (BIO_CTRL_SET/BIO_CTRL_GET)");
431 // Somewhat 'documented' as setting/getting IO type. Not used anywhere
432 // except BIO_buffer_get_num_lines (which contradics 'get IO type').
433 // Ignoring.
434 return 0;
435 // DGRAM-specific operation, we have to return some reasonable value
436 // (so far, I've encountered only peek mode switching, connect).
437 case BIO_CTRL_DGRAM_CONNECT:
438 // BIO_ctrl_dgram_connect. Not needed. Our 'dtls' already knows
439 // the peer's address/port. Report success though.
440 return 1;
441 case BIO_CTRL_DGRAM_SET_CONNECTED:
442 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_CONNECTED)");
443 // BIO_ctrl_dgram_set_connected. We never call it, OpenSSL does
444 // not call it on its own (so normally it's done by client code).
445 // Similar to BIO_CTRL_DGRAM_CONNECT, but it also informs the BIO
446 // that its UDP socket is connected. We never need it though.
447 return -1;
448 case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
449 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_RECV_TIMEOUT)");
450 // Essentially setsockopt with SO_RCVTIMEO, not needed, our sockets
451 // are non-blocking.
452 return -1;
453 case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
454 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_RECV_TIMEOUT)");
455 // getsockopt with SO_RCVTIMEO, not needed, our sockets are
456 // non-blocking. ptr is timeval *.
457 return -1;
458 case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
459 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_SEND_TIMEOUT)");
460 // setsockopt, SO_SNDTIMEO, cannot happen.
461 return -1;
462 case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
463 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_SEND_TIMEOUT)");
464 // getsockopt, SO_SNDTIMEO, cannot happen.
465 return -1;
466 case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
467 // BIO_dgram_recv_timedout. No, we are non-blocking.
468 return 0;
469 case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
470 // BIO_dgram_send_timedout. No, we are non-blocking.
471 return 0;
472 case BIO_CTRL_DGRAM_MTU_DISCOVER:
473 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_DISCOVER)");
474 // setsockopt, IP_MTU_DISCOVER/IP6_MTU_DISCOVER, to be done
475 // in QUdpSocket instead. OpenSSL never calls it, only client
476 // code.
477 return 1;
478 case BIO_CTRL_DGRAM_QUERY_MTU:
479 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_QUERY_MTU)");
480 // To be done in QUdpSocket instead.
481 return 1;
482 case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
483 qDtlsWarning("Unexpected command *BIO_CTRL_DGRAM_GET_FALLBACK_MTU)");
484 // Without SSL_OP_NO_QUERY_MTU set on SSL, OpenSSL can request for
485 // fallback MTU after several re-transmissions.
486 // Should never happen in our case.
488 case BIO_CTRL_DGRAM_GET_MTU:
489 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_MTU)");
490 return -1;
491 case BIO_CTRL_DGRAM_SET_MTU:
492 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_MTU)");
493 // Should not happen (we don't call BIO_ctrl with this parameter)
494 // and set MTU on SSL instead.
495 return -1; // num is mtu and it's a return value meaning success.
496 case BIO_CTRL_DGRAM_MTU_EXCEEDED:
497 qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_EXCEEDED)");
498 return 0;
499 case BIO_CTRL_DGRAM_GET_PEER:
500 qDtlsDebug("BIO_CTRL_DGRAM_GET_PEER");
501 // BIO_dgram_get_peer. We do not return a real address (DTLS is not
502 // using this address), but let's pretend a success.
503 switch (dtls->remoteAddress.protocol()) {
505 return sizeof(sockaddr_in6);
507 return sizeof(sockaddr_in);
508 default:
509 return -1;
510 }
511 case BIO_CTRL_DGRAM_SET_PEER:
512 // Similar to BIO_CTRL_DGRAM_CONNECTED.
513 return 1;
514 case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
515 // DTLSTODO: I'm not sure yet, how it's used by OpenSSL.
516 return 1;
517 case BIO_CTRL_DGRAM_SET_DONT_FRAG:
518 qDtlsDebug("BIO_CTRL_DGRAM_SET_DONT_FRAG");
519 // To be done in QUdpSocket, it's about IP_DONTFRAG etc.
520 return 1;
521 case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
522 // AFAIK it's 28 for IPv4 and 48 for IPv6, but let's pretend it's 0
523 // so that OpenSSL does not start suddenly fragmenting the first
524 // client hello (which will result in DTLSv1_listen rejecting it).
525 return 0;
526 case BIO_CTRL_DGRAM_SET_PEEK_MODE:
527 dtls->peeking = num;
528 return 1;
529 default:;
530#if QT_DTLS_VERBOSE
531 qWarning() << "Unexpected cmd (" << cmd << ")";
532#endif
533 }
534
535 return 0;
536}
537
538extern "C" int q_dgram_create(BIO *bio)
539{
540
541 q_BIO_set_init(bio, 1);
542 // With a custom BIO you'd normally allocate some implementation-specific
543 // data and append it to this new BIO using BIO_set_data. We don't need
544 // it and thus q_dgram_destroy below is a noop.
545 return 1;
546}
547
548extern "C" int q_dgram_destroy(BIO *bio)
549{
550 Q_UNUSED(bio);
551 return 1;
552}
553
554const char * const qdtlsMethodName = "qdtlsbio";
555
556} // namespace dtlsbio
557
558namespace dtlsopenssl
559{
560
561bool DtlsState::init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
562 const QHostAddress &remote, quint16 port,
563 const QByteArray &receivedMessage)
564{
565 Q_ASSERT(dtlsBase);
567
568 if (!tlsContext && !initTls(dtlsBase))
569 return false;
570
571 udpSocket = socket;
572
573 setLinkMtu(dtlsBase);
574
575 dgram = receivedMessage;
576 remoteAddress = remote;
577 remotePort = port;
578
579 // SSL_get_rbio does not increment a reference count.
580 BIO *bio = q_SSL_get_rbio(tlsConnection.data());
581 Q_ASSERT(bio);
582 q_BIO_set_app_data(bio, this);
583
584 return true;
585}
586
587void DtlsState::reset()
588{
589 tlsConnection.reset();
590 tlsContext.reset();
591}
592
593bool DtlsState::initTls(QDtlsBasePrivate *dtlsBase)
594{
595 if (tlsContext)
596 return true;
597
599 return false;
600
601 if (!initCtxAndConnection(dtlsBase))
602 return false;
603
604 if (!initBIO(dtlsBase)) {
605 tlsConnection.reset();
606 tlsContext.reset();
607 return false;
608 }
609
610 return true;
611}
612
613static QString msgFunctionFailed(const char *function)
614{
615 //: %1: Some function
616 return QDtls::tr("%1 failed").arg(QLatin1StringView(function));
617}
618
619bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
620{
621 Q_ASSERT(dtlsBase);
623
624 if (dtlsBase->mode == QSslSocket::UnencryptedMode) {
625 dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
626 QDtls::tr("Invalid SslMode, SslServerMode or SslClientMode expected"));
627 return false;
628 }
629
630 if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol())) {
631 dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
632 QDtls::tr("Invalid protocol version, DTLS protocol expected"));
633 return false;
634 }
635
636 const bool rootsOnDemand = QTlsBackend::rootLoadingOnDemandAllowed(dtlsBase->dtlsConfiguration);
637 TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode, dtlsBase->dtlsConfiguration,
638 rootsOnDemand));
639
640 if (newContext->error() != QSslError::NoError) {
641 dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString());
642 return false;
643 }
644
645 TlsConnection newConnection(newContext->createSsl(), dtlsutil::delete_connection);
646 if (!newConnection.data()) {
647 dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
648 msgFunctionFailed("SSL_new"));
649 return false;
650 }
651
652 const int set = q_SSL_set_ex_data(newConnection.data(),
654 this);
655
656 if (set != 1 && dtlsBase->dtlsConfiguration.peerVerifyMode() != QSslSocket::VerifyNone) {
657 dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
658 msgFunctionFailed("SSL_set_ex_data"));
659 return false;
660 }
661
662 if (dtlsBase->mode == QSslSocket::SslServerMode) {
663 if (dtlsBase->dtlsConfiguration.dtlsCookieVerificationEnabled())
664 q_SSL_set_options(newConnection.data(), SSL_OP_COOKIE_EXCHANGE);
666 } else {
668 }
669
670 tlsContext.swap(newContext);
671 tlsConnection.swap(newConnection);
672
673 return true;
674}
675
676bool DtlsState::initBIO(QDtlsBasePrivate *dtlsBase)
677{
678 Q_ASSERT(dtlsBase);
679 Q_ASSERT(tlsContext && tlsConnection);
680
681 BioMethod customMethod(q_BIO_meth_new(BIO_TYPE_DGRAM, dtlsbio::qdtlsMethodName),
683 if (!customMethod.data()) {
684 dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
685 msgFunctionFailed("BIO_meth_new"));
686 return false;
687 }
688
689 BIO_METHOD *biom = customMethod.data();
690 q_BIO_meth_set_create(biom, dtlsbio::q_dgram_create);
691 q_BIO_meth_set_destroy(biom, dtlsbio::q_dgram_destroy);
692 q_BIO_meth_set_read(biom, dtlsbio::q_dgram_read);
693 q_BIO_meth_set_write(biom, dtlsbio::q_dgram_write);
694 q_BIO_meth_set_puts(biom, dtlsbio::q_dgram_puts);
695 q_BIO_meth_set_ctrl(biom, dtlsbio::q_dgram_ctrl);
696
697 BIO *bio = q_BIO_new(biom);
698 if (!bio) {
699 dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
700 msgFunctionFailed("BIO_new"));
701 return false;
702 }
703
704 q_SSL_set_bio(tlsConnection.data(), bio, bio);
705
706 bioMethod.swap(customMethod);
707
708 return true;
709}
710
711void DtlsState::setLinkMtu(QDtlsBasePrivate *dtlsBase)
712{
713 Q_ASSERT(dtlsBase);
714 Q_ASSERT(udpSocket);
715 Q_ASSERT(tlsConnection.data());
716
717 long mtu = dtlsBase->mtuHint;
718 if (!mtu) {
719 // If the underlying QUdpSocket was connected, getsockopt with
720 // IP_MTU/IP6_MTU can give us some hint:
721 bool optionFound = false;
722 if (udpSocket->state() == QAbstractSocket::ConnectedState) {
723 const QVariant val(udpSocket->socketOption(QAbstractSocket::PathMtuSocketOption));
724 if (val.isValid() && val.canConvert<int>())
725 mtu = val.toInt(&optionFound);
726 }
727
728 if (!optionFound || mtu <= 0) {
729 // OK, our own initial guess.
731 }
732 }
733
734 // For now, we disable this option.
735 q_SSL_set_options(tlsConnection.data(), SSL_OP_NO_QUERY_MTU);
736
737 q_DTLS_set_link_mtu(tlsConnection.data(), mtu);
738}
739
740} // namespace dtlsopenssl
741
746
749{
751 Q_ASSERT(dgram.size());
752 Q_ASSERT(!address.isNull());
753 Q_ASSERT(port);
754
756 verifiedClientHello.clear();
757
758 if (!dtls.init(this, socket, address, port, dgram))
759 return false;
760
761 dtls.secret = secret;
763
765 QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
766 if (!peer.data()) {
768 QDtlsClientVerifier::tr("BIO_ADDR_new failed, ignoring client hello"));
769 return false;
770 }
771
772 const int ret = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
773 if (ret < 0) {
774 // Since 1.1 - it's a fatal error (not so in 1.0.2 for non-blocking socket)
776 return false;
777 }
778
779 if (ret > 0) {
780 verifiedClientHello = dgram;
781 return true;
782 }
783
784 return false;
785}
786
788{
789 return verifiedClientHello;
790}
791
792void QDtlsPrivateOpenSSL::TimeoutHandler::start(int hintMs)
793{
794 Q_ASSERT(timerId == -1);
795 timerId = startTimer(hintMs > 0 ? hintMs : timeoutMs, Qt::PreciseTimer);
796}
797
798void QDtlsPrivateOpenSSL::TimeoutHandler::doubleTimeout()
799{
800 if (timeoutMs * 2 < 60000)
801 timeoutMs *= 2;
802 else
803 timeoutMs = 60000;
804}
805
806void QDtlsPrivateOpenSSL::TimeoutHandler::stop()
807{
808 if (timerId != -1) {
809 killTimer(timerId);
810 timerId = -1;
811 }
812}
813
814void QDtlsPrivateOpenSSL::TimeoutHandler::timerEvent(QTimerEvent *event)
815{
817 Q_ASSERT(timerId != -1);
818
819 killTimer(timerId);
820 timerId = -1;
821
822 Q_ASSERT(dtlsConnection);
823 dtlsConnection->reportTimeout();
824}
825
827 : QDtlsBasePrivate(side, dtlsutil::fallbackSecret()), q(qObject)
828{
829 Q_ASSERT(qObject);
830
831 dtls.dtlsPrivate = this;
832}
833
838
845
850
855
860
865
870
875
877{
878 return handshakeState;
879}
880
882{
883 return connectionEncrypted;
884}
885
887{
889 Q_ASSERT(handshakeState == QDtls::HandshakeNotStarted);
890
892 connectionEncrypted = false;
893
894 if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
895 return false;
896
897 if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieVerificationEnabled()) {
898 dtls.secret = secret;
900 // Let's prepare the state machine so that message sequence 1 does not
901 // surprise DTLS/OpenSSL (such a message would be disregarded as
902 // 'stale or future' in SSL_accept otherwise):
903 int result = 0;
904 QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
905 if (!peer.data()) {
907 QDtls::tr("BIO_ADD_new failed, cannot start handshake"));
908 return false;
909 }
910
911 // If it's an invalid/unexpected ClientHello, we don't want to send
912 // VerifyClientRequest - it's a job of QDtlsClientVerifier - so we
913 // suppress any attempts to write into socket:
914 dtls.writeSuppressed = true;
915 result = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
916 dtls.writeSuppressed = false;
917
918 if (result <= 0) {
920 QDtls::tr("Cannot start the handshake, verified client hello expected"));
921 dtls.reset();
922 return false;
923 }
924 }
925
926 handshakeState = QDtls::HandshakeInProgress;
927 opensslErrors.clear();
928 tlsErrors.clear();
929
930 return continueHandshake(socket, dgram);
931}
932
934{
936
937 Q_ASSERT(handshakeState == QDtls::HandshakeInProgress);
938
940
941 if (timeoutHandler.data())
942 timeoutHandler->stop();
943
944 if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
945 return false;
946
947 dtls.x509Errors.clear();
948
949 int result = 0;
952 else
954
955 // DTLSTODO: Investigate/test if it makes sense - QSslSocket can emit
956 // peerVerifyError at this point (and thus potentially client code
957 // will close the underlying TCP connection immediately), but we are using
958 // QUdpSocket, no connection to close, our verification callback returns 1
959 // (verified OK) and this probably means OpenSSL has already sent a reply
960 // to the server's hello/certificate.
961
962 opensslErrors << dtls.x509Errors;
963
964 if (result <= 0) {
965 const auto code = q_SSL_get_error(dtls.tlsConnection.data(), result);
966 switch (code) {
967 case SSL_ERROR_WANT_READ:
968 case SSL_ERROR_WANT_WRITE:
969 // DTLSTODO: to be tested - in principle, if it was the first call to
970 // continueHandshake and server for some reason discards the client
971 // hello message (even the verified one) - our 'this' will probably
972 // forever stay in this strange InProgress state? (the client
973 // will dully re-transmit the same hello and we discard it again?)
974 // SSL_get_state can provide more information about state
975 // machine and we can switch to NotStarted (since we have not
976 // replied with our hello ...)
977 if (!timeoutHandler.data()) {
978 timeoutHandler.reset(new TimeoutHandler);
979 timeoutHandler->dtlsConnection = this;
980 } else {
981 // Back to 1s.
982 timeoutHandler->resetTimeout();
983 }
984
985 timeoutHandler->start();
986
987 return true; // The handshake is not yet complete.
988 default:
989 storePeerCertificates();
992 dtls.reset();
993 handshakeState = QDtls::HandshakeNotStarted;
994 return false;
995 }
996 }
997
998 storePeerCertificates();
999 fetchNegotiatedParameters();
1000
1001 const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode() == QSslSocket::VerifyPeer
1004
1005 if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) {
1006 connectionEncrypted = true;
1007 handshakeState = QDtls::HandshakeComplete;
1008 return true;
1009 }
1010
1011 setDtlsError(QDtlsError::PeerVerificationError, QDtls::tr("Peer verification failed"));
1012 handshakeState = QDtls::PeerVerificationFailed;
1013 return false;
1014}
1015
1016
1018{
1020
1021 Q_ASSERT(timeoutHandler.data());
1022 Q_ASSERT(dtls.tlsConnection.data());
1023
1025
1026 dtls.udpSocket = socket;
1027
1028 if (q_DTLSv1_handle_timeout(dtls.tlsConnection.data()) > 0) {
1029 timeoutHandler->doubleTimeout();
1030 timeoutHandler->start();
1031 } else {
1032 timeoutHandler->start(dtlsutil::next_timeoutMs(dtls.tlsConnection.data()));
1033 }
1034
1035 return true;
1036}
1037
1039{
1042 Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed);
1043
1045
1046 if (tlsErrorsWereIgnored()) {
1047 handshakeState = QDtls::HandshakeComplete;
1048 connectionEncrypted = true;
1049 tlsErrors.clear();
1050 tlsErrorsToIgnore.clear();
1051 return true;
1052 }
1053
1054 return false;
1055}
1056
1058{
1060 Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed
1061 || handshakeState == QDtls::HandshakeInProgress);
1062
1064
1065 if (handshakeState == QDtls::PeerVerificationFailed) {
1066 // Yes, while peer verification failed, we were actually encrypted.
1067 // Let's play it nice - inform our peer about connection shut down.
1069 } else {
1070 resetDtls();
1071 }
1072}
1073
1075{
1077
1079
1080 if (connectionEncrypted && !connectionWasShutdown) {
1081 dtls.udpSocket = socket;
1082 Q_ASSERT(dtls.tlsConnection.data());
1084 }
1085
1086 resetDtls();
1087}
1088
1090{
1091 return tlsErrors;
1092}
1093
1094void QDtlsPrivateOpenSSL::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
1095{
1096 tlsErrorsToIgnore = errorsToIgnore;
1097}
1098
1103
1108
1110 const QByteArray &dgram)
1111{
1113 Q_ASSERT(dtls.tlsConnection.data());
1114 Q_ASSERT(connectionEncrypted);
1115
1117
1118 dtls.udpSocket = socket;
1119 const int written = q_SSL_write(dtls.tlsConnection.data(),
1120 dgram.constData(), dgram.size());
1121 if (written > 0)
1122 return written;
1123
1124 const unsigned long errorCode = q_ERR_get_error();
1125 if (!dgram.size() && errorCode == SSL_ERROR_NONE) {
1126 // With OpenSSL <= 1.1 this can happen. For example, DTLS client
1127 // tries to reconnect (while re-using the same address/port) -
1128 // DTLS server drops a message with unexpected epoch but says - no
1129 // error. We leave to client code to resolve such problems until
1130 // OpenSSL provides something better.
1131 return 0;
1132 }
1133
1134 switch (errorCode) {
1135 case SSL_ERROR_WANT_WRITE:
1136 case SSL_ERROR_WANT_READ:
1137 // We do not set any error/description ... a user can probably re-try
1138 // sending a datagram.
1139 break;
1140 case SSL_ERROR_ZERO_RETURN:
1141 connectionWasShutdown = true;
1142 setDtlsError(QDtlsError::TlsFatalError, QDtls::tr("The DTLS connection has been closed"));
1143 handshakeState = QDtls::HandshakeNotStarted;
1144 dtls.reset();
1145 break;
1146 case SSL_ERROR_SYSCALL:
1147 case SSL_ERROR_SSL:
1148 default:
1149 // DTLSTODO: we don't know yet what to do. Tests needed - probably,
1150 // some errors can be just ignored (it's UDP, not TCP after all).
1151 // Unlike QSslSocket we do not abort though.
1153 if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) {
1155 } else {
1157 QDtls::tr("Error while writing: %1").arg(description));
1158 }
1159 }
1160
1161 return -1;
1162}
1163
1165{
1167 Q_ASSERT(tlsdgram.size());
1168
1169 Q_ASSERT(dtls.tlsConnection.data());
1170 Q_ASSERT(connectionEncrypted);
1171
1172 dtls.dgram = tlsdgram;
1173 dtls.udpSocket = socket;
1174
1176
1177 QByteArray dgram;
1178 dgram.resize(tlsdgram.size());
1179 const int read = q_SSL_read(dtls.tlsConnection.data(), dgram.data(),
1180 dgram.size());
1181
1182 if (read > 0) {
1183 dgram.resize(read);
1184 return dgram;
1185 }
1186
1187 dgram.clear();
1188 unsigned long errorCode = q_ERR_get_error();
1189 if (errorCode == SSL_ERROR_NONE) {
1190 const int shutdown = q_SSL_get_shutdown(dtls.tlsConnection.data());
1191 if (shutdown & SSL_RECEIVED_SHUTDOWN)
1192 errorCode = SSL_ERROR_ZERO_RETURN;
1193 else
1194 return dgram;
1195 }
1196
1197 switch (errorCode) {
1198 case SSL_ERROR_WANT_READ:
1199 case SSL_ERROR_WANT_WRITE:
1200 return dgram;
1201 case SSL_ERROR_ZERO_RETURN:
1202 // "The connection was shut down cleanly" ... hmm, whatever,
1203 // needs testing (DTLSTODO).
1204 connectionWasShutdown = true;
1206 QDtls::tr("The DTLS connection has been shutdown"));
1207 dtls.reset();
1208 connectionEncrypted = false;
1209 handshakeState = QDtls::HandshakeNotStarted;
1210 return dgram;
1211 case SSL_ERROR_SYSCALL: // some IO error
1212 case SSL_ERROR_SSL: // error in the SSL library
1213 // DTLSTODO: Apparently, some errors can be ignored, for example,
1214 // ECONNRESET etc. This all needs a lot of testing!!!
1215 default:
1217 QDtls::tr("Error while reading: %1")
1219 return dgram;
1220 }
1221}
1222
1223unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity,
1224 unsigned max_identity_len,
1225 unsigned char *psk,
1226 unsigned max_psk_len)
1227{
1228 // The code below is taken (with some modifications) from qsslsocket_openssl
1229 // - alas, we cannot simply re-use it, it's in QSslSocketPrivate.
1230 {
1231 QSslPreSharedKeyAuthenticator authenticator;
1232 // Fill in some read-only fields (for client code)
1233 if (hint) {
1234 identityHint.clear();
1235 identityHint.append(hint);
1236 }
1237
1238 QTlsBackend::setupClientPskAuth(&authenticator, hint ? identityHint.constData() : nullptr,
1239 hint ? int(std::strlen(hint)) : 0, max_identity_len, max_psk_len);
1240 pskAuthenticator.swap(authenticator);
1241 }
1242
1243 // Let the client provide the remaining bits...
1244 emit q->pskRequired(&pskAuthenticator);
1245
1246 // No PSK set? Return now to make the handshake fail
1247 if (pskAuthenticator.preSharedKey().isEmpty())
1248 return 0;
1249
1250 // Copy data back into OpenSSL
1251 const int identityLength = qMin(pskAuthenticator.identity().size(),
1252 pskAuthenticator.maximumIdentityLength());
1253 std::memcpy(identity, pskAuthenticator.identity().constData(), identityLength);
1254 identity[identityLength] = 0;
1255
1256 const int pskLength = qMin(pskAuthenticator.preSharedKey().size(),
1257 pskAuthenticator.maximumPreSharedKeyLength());
1258 std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
1259
1260 return pskLength;
1261}
1262
1263unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned char *psk,
1264 unsigned max_psk_len)
1265{
1266 {
1267 QSslPreSharedKeyAuthenticator authenticator;
1268 // Fill in some read-only fields (for the user)
1270 max_psk_len);
1271 pskAuthenticator.swap(authenticator);
1272 }
1273
1274 // Let the client provide the remaining bits...
1275 emit q->pskRequired(&pskAuthenticator);
1276
1277 // No PSK set? Return now to make the handshake fail
1278 if (pskAuthenticator.preSharedKey().isEmpty())
1279 return 0;
1280
1281 // Copy data back into OpenSSL
1282 const int pskLength = qMin(pskAuthenticator.preSharedKey().size(),
1283 pskAuthenticator.maximumPreSharedKeyLength());
1284
1285 std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
1286
1287 return pskLength;
1288}
1289
1290bool QDtlsPrivateOpenSSL::verifyPeer()
1291{
1292 QList<QSslError> errors;
1293
1294 // Check the whole chain for blacklisting (including root, as we check for
1295 // subjectInfo and issuer)
1296 const auto &peerCertificateChain = dtlsConfiguration.peerCertificateChain();
1297 for (const QSslCertificate &cert : peerCertificateChain) {
1300 }
1301
1302 const auto peerCertificate = dtlsConfiguration.peerCertificate();
1303 if (peerCertificate.isNull()) {
1305 } else if (mode == QSslSocket::SslClientMode) {
1306 // Check the peer certificate itself. First try the subject's common name
1307 // (CN) as a wildcard, then try all alternate subject name DNS entries the
1308 // same way.
1309
1310 // QSslSocket has a rather twisted logic: if verificationPeerName
1311 // is empty, we call QAbstractSocket::peerName(), which returns
1312 // either peerName (can be set by setPeerName) or host name
1313 // (can be set as a result of connectToHost).
1315 if (name.isEmpty()) {
1316 Q_ASSERT(dtls.udpSocket);
1317 name = dtls.udpSocket->peerName();
1318 }
1319
1320 if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(peerCertificate, name))
1321 errors << QSslError(QSslError::HostNameMismatch, peerCertificate);
1322 }
1323
1324 // Translate errors from the error list into QSslErrors
1325 using CertClass = QTlsPrivate::X509CertificateOpenSSL;
1326 errors.reserve(errors.size() + opensslErrors.size());
1327 for (const auto &error : std::as_const(opensslErrors)) {
1328 const auto value = peerCertificateChain.value(error.depth);
1329 errors << CertClass::openSSLErrorToQSslError(error.code, value);
1330 }
1331
1332 tlsErrors = errors;
1333 return tlsErrors.isEmpty();
1334}
1335
1336void QDtlsPrivateOpenSSL::storePeerCertificates()
1337{
1338 Q_ASSERT(dtls.tlsConnection.data());
1339 // Store the peer certificate and chain. For clients, the peer certificate
1340 // chain includes the peer certificate; for servers, it doesn't. Both the
1341 // peer certificate and the chain may be empty if the peer didn't present
1342 // any certificate.
1343 X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data());
1344 const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
1345 QTlsBackend::storePeerCertificate(dtlsConfiguration, peerCertificate);
1346 q_X509_free(x509);
1347
1348 auto peerCertificateChain = dtlsConfiguration.peerCertificateChain();
1349 if (peerCertificateChain.isEmpty()) {
1350 auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
1352 if (!peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
1353 peerCertificateChain.prepend(peerCertificate);
1354 QTlsBackend::storePeerCertificateChain(dtlsConfiguration, peerCertificateChain);
1355 }
1356}
1357
1358bool QDtlsPrivateOpenSSL::tlsErrorsWereIgnored() const
1359{
1360 // check whether the errors we got are all in the list of expected errors
1361 // (applies only if the method QDtlsConnection::ignoreTlsErrors(const
1362 // QList<QSslError> &errors) was called)
1363 for (const QSslError &error : tlsErrors) {
1364 if (!tlsErrorsToIgnore.contains(error))
1365 return false;
1366 }
1367
1368 return !tlsErrorsToIgnore.empty();
1369}
1370
1371void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
1372{
1373 Q_ASSERT(dtls.tlsConnection.data());
1374
1375 if (const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data()))
1377 else
1378 sessionCipher = {};
1379
1380 // Note: cipher's protocol version will be reported as either TLS 1.0 or
1381 // TLS 1.2, that's how it's set by OpenSSL (and that's what they are?).
1382
1383 switch (q_SSL_version(dtls.tlsConnection.data())) {
1386 case DTLS1_VERSION:
1387 sessionProtocol = QSsl::DtlsV1_0;
1388 break;
1390 case DTLS1_2_VERSION:
1392 break;
1393 default:
1394 qCWarning(lcTlsBackend, "unknown protocol version");
1396 }
1397}
1398
1399void QDtlsPrivateOpenSSL::reportTimeout()
1400{
1401 emit q->handshakeTimeout();
1402}
1403
1404void QDtlsPrivateOpenSSL::resetDtls()
1405{
1406 dtls.reset();
1407 connectionEncrypted = false;
1408 tlsErrors.clear();
1409 tlsErrorsToIgnore.clear();
1410 QTlsBackend::clearPeerCertificates(dtlsConfiguration);
1411 connectionWasShutdown = false;
1412 handshakeState = QDtls::HandshakeNotStarted;
1413 sessionCipher = {};
1415}
1416
static constexpr auto IPv4Protocol
QString peerName() const
Returns the name of the peer as specified by connectToHost(), or an empty QString if connectToHost() ...
SocketState state() const
Returns the state of the socket.
static constexpr auto IPv6Protocol
SocketError error() const
Returns the type of error that last occurred.
constexpr qsizetype size() const noexcept
constexpr const_pointer constData() const noexcept
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
void clear()
Clears the contents of the byte array and makes it null.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
QSsl::SslProtocol sessionProtocol
QSslCipher sessionCipher
QHostAddress remoteAddress
QCryptographicHash::Algorithm hashAlgorithm
QDtlsError error() const override
QDtlsError errorCode
QSslSocket::SslMode mode
void clearDtlsError() override
QByteArray secret
void setDtlsError(QDtlsError code, const QString &description) override
Definition qdtls_base.cpp:8
QSslConfiguration dtlsConfiguration
static bool isDtlsProtocol(QSsl::SslProtocol protocol)
QByteArray verifiedHello() const override
bool verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port) override
void abortHandshake(QUdpSocket *socket) override
virtual QDtls::HandshakeState state() const override
QHostAddress peerAddress() const override
QSslSocket::SslMode cryptographMode() const override
void ignoreVerificationErrors(const QList< QSslError > &errorsToIgnore) override
QSslCipher dtlsSessionCipher() const override
bool startHandshake(QUdpSocket *socket, const QByteArray &datagram) override
QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode mode)
bool resumeHandshake(QUdpSocket *socket) override
unsigned pskServerCallback(const char *identity, unsigned char *psk, unsigned max_psk_len)
bool handleTimeout(QUdpSocket *socket) override
virtual void setDtlsMtuHint(quint16 mtu) override
quint16 peerPort() const override
qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override
void sendShutdownAlert(QUdpSocket *socket) override
unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len, unsigned char *psk, unsigned max_psk_len)
void setPeer(const QHostAddress &addr, quint16 port, const QString &name) override
QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override
QSsl::SslProtocol dtlsSessionProtocol() const override
virtual bool isConnectionEncrypted() const override
bool continueHandshake(QUdpSocket *socket, const QByteArray &datagram) override
QList< QSslError > peerVerificationErrors() const override
void setPeerVerificationName(const QString &name) override
virtual quint16 dtlsMtuHint() const override
QString peerVerificationName() const override
This class provides encryption for UDP sockets.
Definition qdtls.h:83
HandshakeState
Describes the current state of DTLS handshake.
Definition qdtls.h:89
@ HandshakeComplete
Definition qdtls.h:93
@ PeerVerificationFailed
Definition qdtls.h:92
@ HandshakeNotStarted
Definition qdtls.h:90
@ HandshakeInProgress
Definition qdtls.h:91
The QHostAddress class provides an IP address.
quint32 toIPv4Address(bool *ok=nullptr) const
Returns the IPv4 address as a number.
Q_IPV6ADDR toIPv6Address() const
Returns the IPv6 address as a Q_IPV6ADDR structure.
NetworkLayerProtocol protocol() const
Returns the network layer protocol of the host address.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
bool empty() const noexcept
Definition qlist.h:685
void clear()
Definition qlist.h:434
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
Definition qobject.cpp:1817
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
static Q_NETWORK_EXPORT bool isBlacklisted(const QSslCertificate &certificate)
The QSslCertificate class provides a convenient API for an X509 certificate.
The QSslCipher class represents an SSL cryptographic cipher.
Definition qsslcipher.h:22
QSslSocket::PeerVerifyMode peerVerifyMode() const
Returns the verify mode.
QByteArray preSharedKeyIdentityHint() const
QList< QSslCertificate > peerCertificateChain() const
Returns the peer's chain of digital certificates, starting with the peer's immediate certificate and ...
QSslCertificate peerCertificate() const
Returns the peer's digital certificate (i.e., the immediate certificate of the host you are connected...
static std::shared_ptr< QSslContext > sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
The QSslError class provides an SSL error.
Definition qsslerror.h:21
@ CertificateBlacklisted
Definition qsslerror.h:49
@ HostNameMismatch
Definition qsslerror.h:47
@ NoPeerCertificate
Definition qsslerror.h:46
The QSslPreSharedKeyAuthenticator class provides authentication data for pre shared keys (PSK) cipher...
void swap(QSslPreSharedKeyAuthenticator &other) noexcept
Swaps the QSslPreSharedKeyAuthenticator object authenticator with this object.
Q_NETWORK_EXPORT QByteArray preSharedKey() const
Returns the pre shared key.
Q_NETWORK_EXPORT int maximumIdentityLength() const
Returns the maximum length, in bytes, of the PSK client identity.
Q_NETWORK_EXPORT QByteArray identity() const
Returns the PSK client identity.
Q_NETWORK_EXPORT int maximumPreSharedKeyLength() const
Returns the maximum length, in bytes, of the pre shared key.
The QSslSocket class provides an SSL encrypted socket for both clients and servers.
Definition qsslsocket.h:29
SslMode
Describes the connection modes available for QSslSocket.
Definition qsslsocket.h:33
@ UnencryptedMode
Definition qsslsocket.h:34
static bool supportsSsl()
Returns true if this platform supports SSL; otherwise, returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
\inmodule QtCore
Definition qcoreevent.h:366
static QSslCipher qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher)
static QString msgErrorsDuringHandshake()
static QString getErrorsFromOpenSsl()
static void setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint, int hintLength, unsigned maxIdentityLen, unsigned maxPskLen)
static void setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity, const QByteArray &identityHint, unsigned maxPskLen)
static QSslErrorEntry errorEntryFromStoreContext(X509_STORE_CTX *ctx)
static QSslCertificate certificateFromX509(X509 *x)
static QList< QSslCertificate > stackOfX509ToQSslCertificates(STACK_OF(X509) *x509)
\reentrant
Definition qudpsocket.h:21
qint64 writeDatagram(const QNetworkDatagram &datagram)
\inmodule QtCore
Definition qvariant.h:65
bool init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket, const QHostAddress &remote, quint16 port, const QByteArray &receivedMessage)
QCryptographicHash::Algorithm hashAlgorithm
QDtlsPrivateOpenSSL * dtlsPrivate
TlsConnection tlsConnection
QList< QSslErrorEntry > x509Errors
EGLContext ctx
SslProtocol
Describes the protocol of the cipher.
Definition qssl.h:50
@ DtlsV1_2
Definition qssl.h:63
@ UnknownProtocol
Definition qssl.h:69
Combined button and popup list for selecting options.
Definition qcompare.h:63
int q_dgram_create(BIO *bio)
int q_dgram_read(BIO *bio, char *dst, int bytesToRead)
int q_dgram_write(BIO *bio, const char *src, int bytesToWrite)
int q_dgram_puts(BIO *bio, const char *src)
const char *const qdtlsMethodName
long q_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr)
int q_dgram_destroy(BIO *bio)
unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len, unsigned char *psk, unsigned max_psk_len)
unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned max_psk_len)
int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
int q_generate_cookie_callback(SSL *ssl, unsigned char *dst, unsigned *cookieLength)
int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie, unsigned cookieLength)
static QString msgFunctionFailed(const char *function)
void delete_connection(SSL *ssl)
void delete_bio_method(BIO_METHOD *method)
QByteArray cookie_for_peer(SSL *ssl)
QByteArray fallbackSecret()
int next_timeoutMs(SSL *tlsConnection)
void delete_BIO_ADDR(BIO_ADDR *bio)
#define QT_WARNING_POP
#define QT_WARNING_DISABLE_DEPRECATED
#define QT_WARNING_PUSH
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
@ TlsInitializationError
@ UnderlyingSocketError
@ PeerVerificationError
@ RemoteClosedConnectionError
#define qDtlsWarning(arg)
#define qDtlsDebug(arg)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputPortEXT port
QIPv6Address Q_IPV6ADDR
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
#define qCWarning(category,...)
return ret
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLenum GLsizei GLuint GLint * bytesWritten
GLenum mode
GLuint64 key
GLenum src
GLenum GLenum dst
GLuint name
struct _cl_event * event
GLuint GLfloat * val
GLenum const void * addr
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLuint num
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
void q_SSL_free(SSL *a)
const SSL_CIPHER * q_SSL_get_current_cipher(SSL *a)
int q_SSL_get_ex_data_X509_STORE_CTX_idx()
unsigned long q_ERR_get_error()
int q_SSL_get_error(SSL *a, int b)
X509 * q_SSL_get_peer_certificate(SSL *a)
void * q_X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx)
#define q_BIO_get_app_data(s)
#define q_BIO_set_retry_read(b)
int q_SSL_accept(SSL *a)
unsigned long q_SSL_set_options(SSL *s, unsigned long op)
int q_SSL_get_shutdown(const SSL *ssl)
int q_SSL_shutdown(SSL *a)
void q_BIO_set_init(BIO *a, int init)
BIO * q_BIO_new(const BIO_METHOD *a)
int q_SSL_write(SSL *a, const void *b, int c)
#define q_BIO_set_retry_write(b)
void * q_SSL_get_ex_data(const SSL *ssl, int idx)
int q_SSL_read(SSL *a, void *b, int c)
int q_CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len)
#define q_BIO_set_app_data(s, arg)
BIO * q_SSL_get_rbio(const SSL *s)
int q_SSL_version(const SSL *a)
int q_RAND_bytes(unsigned char *b, int n)
void q_SSL_set_bio(SSL *a, BIO *b, BIO *c)
void q_X509_free(X509 *a)
int q_SSL_connect(SSL *a)
void q_SSL_set_psk_server_callback(SSL *ssl, q_psk_server_callback_t callback)
#define q_BIO_clear_retry_flags(b)
void q_SSL_set_psk_client_callback(SSL *ssl, q_psk_client_callback_t callback)
int q_SSL_set_ex_data(SSL *ssl, int idx, void *arg)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned short quint16
Definition qtypes.h:48
long long qint64
Definition qtypes.h:60
ReturnedValue read(const char *data)
QFuture< QSet< QChar > > set
[10]
QRandomGenerator generator(sseq)
QTcpSocket * socket
[1]
QList< QSslCertificate > cert
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:45