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.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 "qsslconfiguration.h"
5#include "qsslsocket_p.h"
6#include "qudpsocket.h"
7#include "qsslcipher.h"
8#include "qdtls_p.h"
9#include "qssl_p.h"
10#include "qdtls.h"
11
12#include "qglobal.h"
13
304
306{
307 return QDtls::tr("Multicast and broadcast addresses are not supported");
308}
309
322
332 : hash(algorithm), secret(secret)
333{
334}
335
337{
338 const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
339 if (!tlsBackend) {
340 qCWarning(lcSsl, "No TLS backend is available, cannot verify DTLS client");
341 return;
342 }
343 backend.reset(tlsBackend->createDtlsCookieVerifier());
344 if (!backend.get())
345 qCWarning(lcSsl) << "The backend" << tlsBackend->backendName() << "does not support DTLS cookies";
346}
347
349
356{
358
359 if (auto *backend = d->backend.get()) {
360 // The default configuration suffices: verifier never does a full
361 // handshake and upon verifying a cookie in a client hello message,
362 // it reports success.
363 auto conf = QSslConfiguration::defaultDtlsConfiguration();
364 conf.setPeerVerifyMode(QSslSocket::VerifyNone);
365 backend->setConfiguration(conf);
366 }
367}
368
375
388{
390 if (auto *backend = d->backend.get())
391 return backend->setCookieGeneratorParameters(params);
392
393 return false;
394}
395
407{
408 Q_D(const QDtlsClientVerifier);
409
410 if (const auto *backend = d->backend.get())
411 return backend->cookieGeneratorParameters();
412
413 return {};
414}
415
433{
435
436 auto *backend = d->backend.get();
437 if (!backend)
438 return false;
439
440 if (!socket || address.isNull() || !dgram.size()) {
441 backend->setDtlsError(QDtlsError::InvalidInputParameters,
442 tr("A valid UDP socket, non-empty datagram, and valid address/port were expected"));
443 return false;
444 }
445
446 if (address.isBroadcast() || address.isMulticast()) {
447 backend->setDtlsError(QDtlsError::InvalidInputParameters,
449 return false;
450 }
451
452 return backend->verifyClient(socket, dgram, address, port);
453}
454
462{
463 Q_D(const QDtlsClientVerifier);
464
465 if (const auto *backend = d->backend.get())
466 return backend->verifiedHello();
467
468 return {};
469}
470
477{
478 Q_D(const QDtlsClientVerifier);
479
480 if (const auto *backend = d->backend.get())
481 return backend->error();
482
484}
485
492{
493 Q_D(const QDtlsClientVerifier);
494
495 if (const auto *backend = d->backend.get())
496 return backend->errorString();
497
498 return QStringLiteral("No TLS backend is available, no client verification");
499}
500
503
512 : QObject(*new QDtlsPrivate, parent)
513{
514 Q_D(QDtls);
515 const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
516 if (!tlsBackend) {
517 qCWarning(lcSsl, "No TLS backend found, QDtls is unsupported");
518 return;
519 }
520 d->backend.reset(tlsBackend->createDtlsCryptograph(this, mode));
521 if (!d->backend.get()) {
522 qCWarning(lcSsl) << "TLS backend" << tlsBackend->backendName()
523 << "does not support the protocol DTLS";
524 }
525 setDtlsConfiguration(QSslConfiguration::defaultDtlsConfiguration());
526}
527
532{
533}
534
543 const QString &verificationName)
544{
545 Q_D(QDtls);
546
547 auto *backend = d->backend.get();
548 if (!backend)
549 return false;
550
551 if (backend->state() != HandshakeNotStarted) {
552 backend->setDtlsError(QDtlsError::InvalidOperation,
553 tr("Cannot set peer after handshake started"));
554 return false;
555 }
556
557 if (address.isNull()) {
558 backend->setDtlsError(QDtlsError::InvalidInputParameters,
559 tr("Invalid address"));
560 return false;
561 }
562
563 if (address.isBroadcast() || address.isMulticast()) {
564 backend->setDtlsError(QDtlsError::InvalidInputParameters,
566 return false;
567 }
568
569 backend->clearDtlsError();
570 backend->setPeer(address, port, verificationName);
571
572 return true;
573}
574
584{
585 Q_D(QDtls);
586
587 auto *backend = d->backend.get();
588 if (!backend)
589 return false;
590
591 if (backend->state() != HandshakeNotStarted) {
592 backend->setDtlsError(QDtlsError::InvalidOperation,
593 tr("Cannot set verification name after handshake started"));
594 return false;
595 }
596
597 backend->clearDtlsError();
598 backend->setPeerVerificationName(name);
599
600 return true;
601}
602
609{
610 Q_D(const QDtls);
611
612 if (const auto *backend = d->backend.get())
613 return backend->peerAddress();
614
615 return {};
616}
617
624{
625 Q_D(const QDtls);
626
627 if (const auto *backend = d->backend.get())
628 return backend->peerPort();
629
630 return 0;
631}
632
640{
641 Q_D(const QDtls);
642
643 if (const auto *backend = d->backend.get())
644 return backend->peerVerificationName();
645
646 return {};
647}
648
656{
657 Q_D(const QDtls);
658
659 if (const auto *backend = d->backend.get())
660 return backend->cryptographMode();
661
663}
664
672{
673 Q_D(QDtls);
674
675 if (auto *backend = d->backend.get())
676 backend->setDtlsMtuHint(mtuHint);
677}
678
685{
686 Q_D(const QDtls);
687
688 if (const auto *backend = d->backend.get())
689 return backend->dtlsMtuHint();
690
691 return 0;
692}
693
705{
706 Q_D(QDtls);
707
708 if (auto *backend = d->backend.get())
709 backend->setCookieGeneratorParameters(params);
710
711 return false;
712}
713
726{
727 Q_D(const QDtls);
728
729 if (const auto *backend = d->backend.get())
730 return backend->cookieGeneratorParameters();
731
732 return {};
733}
734
744{
745 Q_D(QDtls);
746
747 auto *backend = d->backend.get();
748 if (!backend)
749 return false;
750
751 if (backend->state() != HandshakeNotStarted) {
752 backend->setDtlsError(QDtlsError::InvalidOperation,
753 tr("Cannot set configuration after handshake started"));
754 return false;
755 }
756
757 backend->setConfiguration(configuration);
758 return true;
759}
760
768{
769 Q_D(const QDtls);
770 if (const auto *backend = d->backend.get())
771 return backend->configuration();
772
773 return {};
774}
775
782{
783 Q_D(const QDtls);
784
785 if (const auto *backend = d->backend.get())
786 return backend->state();
787
789}
790
811{
812 Q_D(QDtls);
813
814 auto *backend = d->backend.get();
815 if (!backend)
816 return false;
817
818 if (backend->state() == HandshakeNotStarted)
819 return startHandshake(socket, dgram);
820 else if (backend->state() == HandshakeInProgress)
821 return continueHandshake(socket, dgram);
822
823 backend->setDtlsError(QDtlsError::InvalidOperation,
824 tr("Cannot start/continue handshake, invalid handshake state"));
825 return false;
826}
827
831bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram)
832{
833 Q_D(QDtls);
834
835 auto *backend = d->backend.get();
836 if (!backend)
837 return false;
838
839 if (!socket) {
840 backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
841 return false;
842 }
843
844 if (backend->peerAddress().isNull()) {
845 backend->setDtlsError(QDtlsError::InvalidOperation,
846 tr("To start a handshake you must set peer's address and port first"));
847 return false;
848 }
849
850 if (sslMode() == QSslSocket::SslServerMode && !datagram.size()) {
851 backend->setDtlsError(QDtlsError::InvalidInputParameters,
852 tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
853 return false;
854 }
855
856 if (backend->state() != HandshakeNotStarted) {
857 backend->setDtlsError(QDtlsError::InvalidOperation,
858 tr("Cannot start handshake, already done/in progress"));
859 return false;
860 }
861
862 return backend->startHandshake(socket, datagram);
863}
864
874{
875 Q_D(QDtls);
876
877 auto *backend = d->backend.get();
878 if (!backend)
879 return false;
880
881 if (!socket) {
882 backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
883 return false;
884 }
885
886 return backend->handleTimeout(socket);
887}
888
892bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram)
893{
894 Q_D(QDtls);
895
896 auto *backend = d->backend.get();
897 if (!backend)
898 return false;
899
900 if (!socket || !datagram.size()) {
901 backend->setDtlsError(QDtlsError::InvalidInputParameters,
902 tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
903 return false;
904 }
905
906 if (backend->state() != HandshakeInProgress) {
907 backend->setDtlsError(QDtlsError::InvalidOperation,
908 tr("Cannot continue handshake, not in InProgress state"));
909 return false;
910 }
911
912 return backend->continueHandshake(socket, datagram);
913}
914
924{
925 Q_D(QDtls);
926
927 auto *backend = d->backend.get();
928 if (!backend)
929 return false;
930
931 if (!socket) {
932 backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
933 return false;
934 }
935
936 if (backend->state() != PeerVerificationFailed) {
937 backend->setDtlsError(QDtlsError::InvalidOperation,
938 tr("Cannot resume, not in VerificationError state"));
939 return false;
940 }
941
942 return backend->resumeHandshake(socket);
943}
944
952{
953 Q_D(QDtls);
954
955 auto *backend = d->backend.get();
956 if (!backend)
957 return false;
958
959 if (!socket) {
960 backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
961 return false;
962 }
963
964 if (backend->state() != PeerVerificationFailed && backend->state() != HandshakeInProgress) {
965 backend->setDtlsError(QDtlsError::InvalidOperation,
966 tr("No handshake in progress, nothing to abort"));
967 return false;
968 }
969
970 backend->abortHandshake(socket);
971 return true;
972}
973
982{
983 Q_D(QDtls);
984
985 auto *backend = d->backend.get();
986 if (!backend)
987 return false;
988
989 if (!socket) {
990 backend->setDtlsError(QDtlsError::InvalidInputParameters,
991 tr("Invalid (nullptr) socket"));
992 return false;
993 }
994
995 if (!backend->isConnectionEncrypted()) {
996 backend->setDtlsError(QDtlsError::InvalidOperation,
997 tr("Cannot send shutdown alert, not encrypted"));
998 return false;
999 }
1000
1001 backend->sendShutdownAlert(socket);
1002 return true;
1003}
1004
1011{
1012 Q_D(const QDtls);
1013
1014
1015 if (const auto *backend = d->backend.get())
1016 return backend->isConnectionEncrypted();
1017
1018 return false;
1019}
1020
1034{
1035 Q_D(const QDtls);
1036
1037 if (const auto *backend = d->backend.get())
1038 return backend->dtlsSessionCipher();
1039
1040 return {};
1041}
1042
1054{
1055 Q_D(const QDtls);
1056
1057 if (const auto *backend = d->backend.get())
1058 return backend->dtlsSessionProtocol();
1059
1060 return QSsl::UnknownProtocol;
1061}
1062
1072{
1073 Q_D(QDtls);
1074
1075 auto *backend = d->backend.get();
1076 if (!backend)
1077 return -1;
1078
1079 if (!socket) {
1080 backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
1081 return -1;
1082 }
1083
1084 if (!isConnectionEncrypted()) {
1085 backend->setDtlsError(QDtlsError::InvalidOperation,
1086 tr("Cannot write a datagram, not in encrypted state"));
1087 return -1;
1088 }
1089
1090 return backend->writeDatagramEncrypted(socket, dgram);
1091}
1092
1100{
1101 Q_D(QDtls);
1102
1103 auto *backend = d->backend.get();
1104 if (!backend)
1105 return {};
1106
1107 if (!socket) {
1108 backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
1109 return {};
1110 }
1111
1112 if (!isConnectionEncrypted()) {
1113 backend->setDtlsError(QDtlsError::InvalidOperation,
1114 tr("Cannot read a datagram, not in encrypted state"));
1115 return {};
1116 }
1117
1118 if (!dgram.size())
1119 return {};
1120
1121 return backend->decryptDatagram(socket, dgram);
1122}
1123
1130{
1131 Q_D(const QDtls);
1132
1133 if (const auto *backend = d->backend.get())
1134 return backend->error();
1135
1136 return QDtlsError::NoError;
1137}
1138
1146{
1147 Q_D(const QDtls);
1148
1149 if (const auto *backend = d->backend.get())
1150 return backend->errorString();
1151
1152 return {};
1153}
1154
1161QList<QSslError> QDtls::peerVerificationErrors() const
1162{
1163 Q_D(const QDtls);
1164
1165 if (const auto *backend = d->backend.get())
1166 return backend->peerVerificationErrors();
1167
1168 //return d->tlsErrors;
1169 return {};
1170}
1171
1190void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
1191{
1192 Q_D(QDtls);
1193
1194 if (auto *backend = d->backend.get())
1195 backend->ignoreVerificationErrors(errorsToIgnore);
1196}
1197
1199
1200#include "moc_qdtls.cpp"
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
This class implements server-side DTLS cookie generation and verification.
Definition qdtls.h:44
~QDtlsClientVerifier()
Destroys the QDtlsClientVerifier object.
Definition qdtls.cpp:372
QString dtlsErrorString() const
Returns a textual description of the last error, or an empty string.
Definition qdtls.cpp:491
GeneratorParameters cookieGeneratorParameters() const
Returns the current secret and hash algorithm used to generate cookies.
Definition qdtls.cpp:406
QByteArray verifiedHello() const
Convenience function.
Definition qdtls.cpp:461
bool verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port)
socket must be a valid pointer, dgram must be a non-empty datagram, address cannot be null,...
Definition qdtls.cpp:431
QDtlsError dtlsError() const
Returns the last error that occurred or QDtlsError::NoError.
Definition qdtls.cpp:476
bool setCookieGeneratorParameters(const GeneratorParameters &params)
Sets the secret and the cryptographic hash algorithm from params.
Definition qdtls.cpp:387
QDtlsClientVerifier(QObject *parent=nullptr)
Constructs a QDtlsClientVerifier object, parent is passed to QObject's constructor.
Definition qdtls.cpp:354
This class provides encryption for UDP sockets.
Definition qdtls.h:83
HandshakeState
Describes the current state of DTLS handshake.
Definition qdtls.h:89
@ PeerVerificationFailed
Definition qdtls.h:92
@ HandshakeNotStarted
Definition qdtls.h:90
@ HandshakeInProgress
Definition qdtls.h:91
bool setPeer(const QHostAddress &address, quint16 port, const QString &verificationName={})
Sets the peer's address, port, and host name and returns true if successful.
Definition qdtls.cpp:542
bool handleTimeout(QUdpSocket *socket)
If a timeout occurs during the handshake, the handshakeTimeout() signal is emitted.
Definition qdtls.cpp:873
QSslConfiguration dtlsConfiguration() const
Returns either the default DTLS configuration or the configuration set by an earlier call to setDtlsC...
Definition qdtls.cpp:767
qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)
Encrypts dgram and writes the encrypted data into socket.
Definition qdtls.cpp:1071
bool setDtlsConfiguration(const QSslConfiguration &configuration)
Sets the connection's TLS configuration from configuration and returns true if successful.
Definition qdtls.cpp:743
bool doHandshake(QUdpSocket *socket, const QByteArray &dgram={})
Starts or continues a DTLS handshake.
Definition qdtls.cpp:810
QString peerVerificationName() const
Returns the host name set by setPeer() or setPeerVerificationName().
Definition qdtls.cpp:639
bool shutdown(QUdpSocket *socket)
Sends an encrypted shutdown alert message and closes the DTLS connection.
Definition qdtls.cpp:981
bool resumeHandshake(QUdpSocket *socket)
If peer verification errors were ignored during the handshake, resumeHandshake() resumes and complete...
Definition qdtls.cpp:923
quint16 peerPort() const
Returns the peer's port number, set by setPeer(), or 0.
Definition qdtls.cpp:623
void ignoreVerificationErrors(const QList< QSslError > &errorsToIgnore)
This method tells QDtls to ignore only the errors given in errorsToIgnore.
Definition qdtls.cpp:1190
QString dtlsErrorString() const
Returns a textual description for the last error encountered by the connection or empty string.
Definition qdtls.cpp:1145
~QDtls()
Destroys the QDtls object.
Definition qdtls.cpp:531
QDtls(QSslSocket::SslMode mode, QObject *parent=nullptr)
Creates a QDtls object, parent is passed to the QObject constructor.
Definition qdtls.cpp:511
QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
Decrypts dgram and returns its contents as plain text.
Definition qdtls.cpp:1099
bool setCookieGeneratorParameters(const GeneratorParameters &params)
Sets the cryptographic hash algorithm and the secret from params.
Definition qdtls.cpp:704
bool isConnectionEncrypted() const
Returns true if DTLS handshake completed successfully.
Definition qdtls.cpp:1010
QList< QSslError > peerVerificationErrors() const
Returns errors found while establishing the identity of the peer.
Definition qdtls.cpp:1161
void setMtuHint(quint16 mtuHint)
mtuHint is the maximum transmission unit (MTU), either discovered or guessed by the application.
Definition qdtls.cpp:671
QSslSocket::SslMode sslMode() const
Returns QSslSocket::SslServerMode for a server-side connection and QSslSocket::SslClientMode for a cl...
Definition qdtls.cpp:655
HandshakeState handshakeState() const
Returns the current handshake state for this QDtls.
Definition qdtls.cpp:781
QDtlsError dtlsError() const
Returns the last error encountered by the connection or QDtlsError::NoError.
Definition qdtls.cpp:1129
quint16 mtuHint() const
Returns the value previously set by setMtuHint().
Definition qdtls.cpp:684
QHostAddress peerAddress() const
Returns the peer's address, set by setPeer(), or QHostAddress::Null.
Definition qdtls.cpp:608
QSslCipher sessionCipher() const
Returns the cryptographic \l {QSslCipher} {cipher} used by this connection, or a null cipher if the c...
Definition qdtls.cpp:1033
bool abortHandshake(QUdpSocket *socket)
Aborts the ongoing handshake.
Definition qdtls.cpp:951
GeneratorParameters cookieGeneratorParameters() const
Returns the current hash algorithm and secret, either default ones or previously set by a call to set...
Definition qdtls.cpp:725
QSsl::SslProtocol sessionProtocol() const
Returns the DTLS protocol version used by this connection, or UnknownProtocol if the connection isn't...
Definition qdtls.cpp:1053
bool setPeerVerificationName(const QString &name)
Sets the host name that will be used for the certificate validation and returns true if successful.
Definition qdtls.cpp:583
The QHostAddress class provides an IP address.
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
The QSslCipher class represents an SSL cryptographic cipher.
Definition qsslcipher.h:22
The QSslConfiguration class holds the configuration and state of an SSL connection.
static QTlsBackend * tlsBackendInUse()
SslMode
Describes the connection modes available for QSslSocket.
Definition qsslsocket.h:33
@ UnencryptedMode
Definition qsslsocket.h:34
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\reentrant
Definition qudpsocket.h:21
QHash< int, QWidget * > hash
[35multi]
SslProtocol
Describes the protocol of the cipher.
Definition qssl.h:50
@ UnknownProtocol
Definition qssl.h:69
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE QString msgUnsupportedMulticastAddress()
Definition qdtls.cpp:305
QDtlsError
Definition qdtls.h:25
@ TlsInitializationError
@ InvalidInputParameters
EGLOutputPortEXT port
#define qCWarning(category,...)
GLenum mode
GLuint name
void ** params
GLuint GLuint64EXT address
#define QStringLiteral(str)
#define tr(X)
unsigned short quint16
Definition qtypes.h:48
long long qint64
Definition qtypes.h:60
QTcpSocket * socket
[1]
This class defines parameters for DTLS cookie generator.
Definition qdtls.h:53
GeneratorParameters()
Default constructs GeneratorParameters object with QCryptographicHash::Sha1 as its algorithm and an e...
Definition qdtls.cpp:319