QDtls Class

This class provides encryption for UDP sockets. More...

Header: #include <QDtls>
qmake: QT += network
Since: Qt 5.12
Inherits: QObject

This class was introduced in Qt 5.12.

Public Types

(alias) GeneratorParameters
enum HandshakeState { HandshakeNotStarted, HandshakeInProgress, PeerVerificationFailed, HandshakeComplete }
enum class QDtlsError { NoError, InvalidInputParameters, InvalidOperation, UnderlyingSocketError, RemoteClosedConnectionError, …, TlsNonFatalError }

Detailed Description

The QDtls class can be used to establish a secure connection with a network peer using User Datagram Protocol (UDP). DTLS connection over essentially connectionless UDP means that two peers first have to successfully complete a TLS handshake by calling doHandshake(). After the handshake has completed, encrypted datagrams can be sent to the peer using writeDatagramEncrypted(). Encrypted datagrams coming from the peer can be decrypted by decryptDatagram().

QDtls is designed to work with QUdpSocket. Since QUdpSocket can receive datagrams coming from different peers, an application must implement demultiplexing, forwarding datagrams coming from different peers to their corresponding instances of QDtls. An association between a network peer and its QDtls object can be established using the peer's address and port number. Before starting a handshake, the application must set the peer's address and port number using setPeer().

QDtls does not read datagrams from QUdpSocket, this is expected to be done by the application, for example, in a slot attached to the QUdpSocket::readyRead() signal. Then, these datagrams must be processed by QDtls.

Note: QDtls does not take ownership of the QUdpSocket object.

Normally, several datagrams are to be received and sent by both peers during the handshake phase. Upon reading datagrams, server and client must pass these datagrams to doHandshake() until some error is found or handshakeState() returns HandshakeComplete:

 // A client initiates a handshake:
 QUdpSocket clientSocket;
 QDtls clientDtls;
 clientDtls.setPeer(address, port, peerName);
 clientDtls.doHandshake(&clientSocket);

 // A server accepting an incoming connection; address, port, clientHello are
 // read by QUdpSocket::readDatagram():
 QByteArray clientHello(serverSocket.pendingDatagramSize(), Qt::Uninitialized);
 QHostAddress address;
 quin16 port = {};
 serverSocket.readDatagram(clientHello.data(), clientHello.size(), &address, &port);

 QDtls serverDtls;
 serverDtls.setPeer(address, port);
 serverDtls.doHandshake(&serverSocket, clientHello);

 // Handshake completion, both for server and client:
 void DtlsConnection::continueHandshake(const QByteArray &datagram)
 {
     if (dtls.doHandshake(&udpSocket, datagram)) {
         // Check handshake status:
         if (dtls.handshakeStatus() == QDlts::HandshakeComplete) {
             // Secure DTLS connection is now established.
         }
     } else {
         // Error handling.
     }
 }

For a server, the first call to doHandshake() requires a non-empty datagram containing a ClientHello message. If the server also deploys QDtlsClientVerifier, the first ClientHello message is expected to be the one verified by QDtlsClientVerifier.

In case the peer's identity cannot be validated during the handshake, the application must inspect errors returned by peerVerificationErrors() and then either ignore errors by calling ignoreVerificationErrors() or abort the handshake by calling abortHandshake(). If errors were ignored, the handshake can be resumed by calling resumeHandshake().

After the handshake has been completed, datagrams can be sent to and received from the network peer securely:

 // Sending an encrypted datagram:
 dtlsConnection.writeDatagramEncrypted(&clientSocket, "Hello DTLS server!");

 // Decryption:
 QByteArray encryptedMessage(dgramSize);
 socket.readDatagram(encryptedMessage.data(), dgramSize);
 const QByteArray plainText = dtlsConnection.decryptDatagram(&socket, encryptedMessage);

A DTLS connection may be closed using shutdown().

 DtlsClient::~DtlsClient()
 {
     clientDtls.shutdown(&clientSocket);
 }

Warning: It's recommended to call shutdown() before destroying the client's QDtls object if you are planning to re-use the same port number to connect to the server later. Otherwise, the server may drop incoming ClientHello messages, see RFC 6347, section 4.2.8 for more details and implementation hints.

If the server does not use QDtlsClientVerifier, it must configure its QDtls objects to disable the cookie verification procedure:

 auto config = QSslConfiguration::defaultDtlsConfiguration();
 config.setDtlsCookieVerificationEnabled(false);
 // Some other customization ...
 dtlsConnection.setDtlsConfiguration(config);

A server that uses cookie verification with non-default generator parameters must set the same parameters for its QDtls object before starting the handshake.

Note: The DTLS protocol leaves Path Maximum Transmission Unit (PMTU) discovery to the application. The application may provide QDtls with the MTU using setMtuHint(). This hint affects only the handshake phase, since only handshake messages can be fragmented and reassembled by the DTLS. All other messages sent by the application must fit into a single datagram.

Note: DTLS-specific headers add some overhead to application data further reducing the possible message size.

Warning: A server configured to reply with HelloVerifyRequest will drop all fragmented ClientHello messages, never starting a handshake.

The DTLS server and DTLS client examples illustrate how to use QDtls in applications.

See also QUdpSocket, QDtlsClientVerifier, HandshakeState, QDtlsError, and QSslConfiguration.

Member Type Documentation

[alias] QDtls::GeneratorParameters

This is a type alias for QDtlsClientVerifier::GeneratorParameters.

enum QDtls::HandshakeState

Describes the current state of DTLS handshake.

This enum describes the current state of DTLS handshake for a QDtls connection.

ConstantValueDescription
QDtls::HandshakeNotStarted0Nothing done yet.
QDtls::HandshakeInProgress1Handshake was initiated and no errors were found so far.
QDtls::PeerVerificationFailed2The identity of the peer can't be established.
QDtls::HandshakeComplete3Handshake completed successfully and encrypted connection was established.

This enum was introduced or modified in Qt 5.12.

See also QDtls::doHandshake() and QDtls::handshakeState().

Related Non-Members

enum class QDtlsError

Describes errors that can be found by QDtls and QDtlsClientVerifier.

This enum describes general and TLS-specific errors that can be encountered by objects of the classes QDtlsClientVerifier and QDtls.

ConstantValueDescription
QDtls::QDtlsError::NoError0No error occurred, the last operation was successful.
QDtls::QDtlsError::InvalidInputParameters1Input parameters provided by a caller were invalid.
QDtls::QDtlsError::InvalidOperation2An operation was attempted in a state that did not permit it.
QDtls::QDtlsError::UnderlyingSocketError3QUdpSocket::writeDatagram() failed, QUdpSocket::error() and QUdpSocket::errorString() can provide more specific information.
QDtls::QDtlsError::RemoteClosedConnectionError4TLS shutdown alert message was received.
QDtls::QDtlsError::PeerVerificationError5Peer's identity could not be verified during the TLS handshake.
QDtls::QDtlsError::TlsInitializationError6An error occurred while initializing an underlying TLS backend.
QDtls::QDtlsError::TlsFatalError7A fatal error occurred during TLS handshake, other than peer verification error or TLS initialization error.
QDtls::QDtlsError::TlsNonFatalError8A failure to encrypt or decrypt a datagram, non-fatal, meaning QDtls can continue working after this error.

This enum was introduced or modified in Qt 5.12.