From 5b8d5c7493259544f853eb2732cca2829c0f67ca Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Mon, 6 Aug 2018 12:05:26 +0200 Subject: [PATCH] Document DTLS examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-68070 Change-Id: I2b08322049005b02f1ed680bee21992ade16813a Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Paul Wicking Reviewed-by: Edward Welbourne --- .../doc/images/secureudpclient-example.png | Bin 0 -> 23211 bytes .../doc/images/secureudpserver-example.png | Bin 0 -> 38412 bytes examples/network/doc/src/secureudpclient.qdoc | 93 +++++++++++++++- examples/network/doc/src/secureudpserver.qdoc | 101 +++++++++++++++++- .../network/secureudpclient/addressdialog.h | 2 - .../network/secureudpclient/association.cpp | 35 +++++- .../network/secureudpclient/association.h | 6 +- .../network/secureudpclient/mainwindow.cpp | 4 + examples/network/secureudpclient/mainwindow.h | 2 - .../network/secureudpserver/mainwindow.cpp | 2 + examples/network/secureudpserver/mainwindow.h | 3 - examples/network/secureudpserver/server.cpp | 28 ++++- examples/network/secureudpserver/server.h | 6 +- 13 files changed, 255 insertions(+), 27 deletions(-) create mode 100644 examples/network/doc/images/secureudpclient-example.png create mode 100644 examples/network/doc/images/secureudpserver-example.png diff --git a/examples/network/doc/images/secureudpclient-example.png b/examples/network/doc/images/secureudpclient-example.png new file mode 100644 index 0000000000000000000000000000000000000000..a566aa4ce54b2b60796ce752602a7c17a7bc5db6 GIT binary patch literal 23211 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 literal 0 HcmV?d00001 diff --git a/examples/network/doc/images/secureudpserver-example.png b/examples/network/doc/images/secureudpserver-example.png new file mode 100644 index 0000000000000000000000000000000000000000..a117b02834a41422a735c582b55fd1fb80c1083b GIT binary patch literal 38412 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 literal 0 HcmV?d00001 diff --git a/examples/network/doc/src/secureudpclient.qdoc b/examples/network/doc/src/secureudpclient.qdoc index 587689ac47d..dc8538cf850 100644 --- a/examples/network/doc/src/secureudpclient.qdoc +++ b/examples/network/doc/src/secureudpclient.qdoc @@ -29,9 +29,96 @@ \example secureudpclient \title DTLS client \ingroup examples-network - \brief Demonstrates how to implement a simple DTLS client + \brief This example demonstrates how to implement client-side DTLS connections. - This example uses QUdpSocket, QDtlsClientVerifier, and QDtls to securely - communicate over the User Datagram Protocol with DTLS servers. + \image secureudpclient-example.png Screenshot of the DTLS client example. + + \note The DTLS client example is intended to be run alongside the \l{secureudpserver}{DTLS server} example. + + The example DTLS client can establish several DTLS connections to one + or many DTLS servers. A client-side DTLS connection is implemented by the + DtlsAssociation class. This class uses QUdpSocket to read and write datagrams + and QDtls for encryption: + + \snippet secureudpclient/association.h 0 + + The constructor sets the minimal TLS configuration for the new DTLS connection, + and sets the address and the port of the server: + + \dots + \snippet secureudpclient/association.cpp 1 + \dots + + The QDtls::handshakeTimeout() signal is connected to the handleTimeout() slot + to deal with packet loss and retransmission during the handshake phase: + + \dots + \snippet secureudpclient/association.cpp 2 + \dots + + To ensure we receive only the datagrams from the server, we connect our UDP socket to the server: + + \dots + \snippet secureudpclient/association.cpp 3 + \dots + + The QUdpSocket::readyRead() signal is connected to the readyRead() slot: + + \dots + \snippet secureudpclient/association.cpp 13 + \dots + + When a secure connection to a server is established, a DtlsAssociation object + will be sending short ping messages to the server, using a timer: + + \snippet secureudpclient/association.cpp 4 + + startHandshake() starts a handshake with the server: + + \snippet secureudpclient/association.cpp 5 + + The readyRead() slot reads a datagram sent by the server: + + \snippet secureudpclient/association.cpp 6 + + If the handshake was already completed, this datagram is decrypted: + + \snippet secureudpclient/association.cpp 7 + + otherwise, we try to continue the handshake: + + \snippet secureudpclient/association.cpp 8 + + When the handshake has completed, we send our first ping message: + + \snippet secureudpclient/association.cpp 9 + + The pskRequired() slot provides the Pre-Shared Key (PSK) needed during the handshake + phase: + + \snippet secureudpclient/association.cpp 14 + + \note For the sake of brevity, the definition of pskRequired() is oversimplified. + The documentation for the QSslPreSharedKeyAuthenticator class explains in detail + how this slot can be properly implemented. + + pingTimeout() sends an encrypted message to the server: + + \snippet secureudpclient/association.cpp 10 + + During the handshake phase the client must handle possible timeouts, which + can happen due to packet loss. The handshakeTimeout() slot retransmits + the handshake messages: + + \snippet secureudpclient/association.cpp 11 + + Before a client connection is destroyed, its DTLS connection must be shut down: + + \snippet secureudpclient/association.cpp 12 + + Error messages, informational messages, and decrypted responses from servers + are displayed by the UI: + + \snippet secureudpclient/mainwindow.cpp 0 */ diff --git a/examples/network/doc/src/secureudpserver.qdoc b/examples/network/doc/src/secureudpserver.qdoc index a00d65773b7..0857f7065f9 100644 --- a/examples/network/doc/src/secureudpserver.qdoc +++ b/examples/network/doc/src/secureudpserver.qdoc @@ -29,8 +29,103 @@ \example secureudpserver \title DTLS server \ingroup examples-network - \brief Demonstrates how to implement a simple DTLS server + \brief This examples demonstrates how to implement a simple DTLS server. - This example uses QUdpSocket, QDtlsClientVerifier, and QDtls to securely respond - to DTLS client requests over the User Datagram Protocol. + \image secureudpserver-example.png Screenshot of the DTLS server example. + + \note The DTLS server example is intended to be run alongside the \l{secureudpclient}{DTLS client} example. + + The server is implemented by the DtlsServer class. It uses QUdpSocket, + QDtlsClientVerifier, and QDtls to test each client's reachability, complete a handshake, + and read and write encrypted messages. + + \snippet secureudpserver/server.h 0 + + The constructor connects the QUdpSocket::readyRead() signal to its + readyRead() slot and sets the minimal needed TLS configuration: + + \snippet secureudpserver/server.cpp 1 + + \note The server is not using a certificate and is relying on Pre-Shared + Key (PSK) handshake. + + listen() binds QUdpSocket: + + \snippet secureudpserver/server.cpp 2 + + The readyRead() slot processes incoming datagrams: + + \dots + \snippet secureudpserver/server.cpp 3 + \dots + + After extracting an address and a port number, the server first tests + if it's a datagram from an already known peer: + + \dots + \snippet secureudpserver/server.cpp 4 + \dots + + If it is a new, unknown address and port, the datagram is processed as a + potential ClientHello message, sent by a DTLS client: + + \dots + \snippet secureudpserver/server.cpp 5 + \dots + + If it's a known DTLS client, the server either decrypts the datagram: + + \dots + \snippet secureudpserver/server.cpp 6 + \dots + + or continues a handshake with this peer: + + \dots + \snippet secureudpserver/server.cpp 7 + \dots + + handleNewConnection() verifies it's a reachable DTLS client, or sends a + HelloVerifyRequest: + + \snippet secureudpserver/server.cpp 8 + \dots + + If the new client was verified to be a reachable DTLS client, the server creates + and configures a new QDtls object, and starts a server-side handshake: + + \dots + \snippet secureudpserver/server.cpp 9 + \dots + + doHandshake() progresses through the handshake phase: + + \snippet secureudpserver/server.cpp 11 + + During the handshake phase, the QDtls::pskRequired() signal is emitted and + the pskRequired() slot provides the preshared key: + + \snippet secureudpserver/server.cpp 13 + + \note For the sake of brevity, the definition of pskRequired() is oversimplified. + The documentation for the QSslPreSharedKeyAuthenticator class explains in detail + how this slot can be properly implemented. + + After the handshake is completed for the network peer, an encrypted DTLS + connection is considered to be established and the server decrypts subsequent + datagrams, sent by the peer, by calling decryptDatagram(). The server also + sends an encrypted response to the peer: + + \snippet secureudpserver/server.cpp 12 + + The server closes its DTLS connections by calling QDtls::shutdown(): + + \snippet secureudpserver/server.cpp 14 + + During its operation, the server reports errors, informational messages, and + decrypted datagrams, by emitting signals errorMessage(), warningMessage(), + infoMessage(), and datagramReceived(). These messages are logged by the server's + UI: + + \snippet secureudpserver/mainwindow.cpp 0 */ diff --git a/examples/network/secureudpclient/addressdialog.h b/examples/network/secureudpclient/addressdialog.h index 7c5e2e03e82..43792faa4be 100644 --- a/examples/network/secureudpclient/addressdialog.h +++ b/examples/network/secureudpclient/addressdialog.h @@ -69,7 +69,6 @@ class AddressDialog : public QDialog Q_OBJECT public: - explicit AddressDialog(QWidget *parent = nullptr); ~AddressDialog(); @@ -77,7 +76,6 @@ public: quint16 remotePort() const; private: - void setupHostSelector(); void setupPortSelector(); diff --git a/examples/network/secureudpclient/association.cpp b/examples/network/secureudpclient/association.cpp index 6b510909f12..c9502600789 100644 --- a/examples/network/secureudpclient/association.cpp +++ b/examples/network/secureudpclient/association.cpp @@ -57,27 +57,38 @@ DtlsAssociation::DtlsAssociation(const QHostAddress &address, quint16 port, : name(connectionName), crypto(QSslSocket::SslClientMode) { + //! [1] auto configuration = QSslConfiguration::defaultDtlsConfiguration(); configuration.setPeerVerifyMode(QSslSocket::VerifyNone); crypto.setPeer(address, port); crypto.setDtlsConfiguration(configuration); + //! [1] + //! [2] connect(&crypto, &QDtls::handshakeTimeout, this, &DtlsAssociation::handshakeTimeout); + //! [2] connect(&crypto, &QDtls::pskRequired, this, &DtlsAssociation::pskRequired); - + //! [3] socket.connectToHost(address.toString(), port); + //! [3] + //! [13] connect(&socket, &QUdpSocket::readyRead, this, &DtlsAssociation::readyRead); - + //! [13] + //! [4] pingTimer.setInterval(5000); connect(&pingTimer, &QTimer::timeout, this, &DtlsAssociation::pingTimeout); + //! [4] } +//! [12] DtlsAssociation::~DtlsAssociation() { if (crypto.isConnectionEncrypted()) crypto.shutdown(&socket); } +//! [12] +//! [5] void DtlsAssociation::startHandshake() { if (socket.state() != QAbstractSocket::ConnectedState) { @@ -86,11 +97,12 @@ void DtlsAssociation::startHandshake() return; } - if (!crypto.doHandshake(&socket, {})) + if (!crypto.doHandshake(&socket)) emit errorMessage(tr("%1: failed to start a handshake - %2").arg(name, crypto.dtlsErrorString())); else emit infoMessage(tr("%1: starting a handshake").arg(name)); } +//! [5] void DtlsAssociation::udpSocketConnected() { @@ -100,7 +112,8 @@ void DtlsAssociation::udpSocketConnected() void DtlsAssociation::readyRead() { - QByteArray dgram(socket.pendingDatagramSize(), '\0'); + //! [6] + QByteArray dgram(socket.pendingDatagramSize(), Qt::Uninitialized); const qint64 bytesRead = socket.readDatagram(dgram.data(), dgram.size()); if (bytesRead <= 0) { emit warningMessage(tr("%1: spurious read notification?").arg(name)); @@ -108,6 +121,8 @@ void DtlsAssociation::readyRead() } dgram.resize(bytesRead); + //! [6] + //! [7] if (crypto.isConnectionEncrypted()) { const QByteArray plainText = crypto.decryptDatagram(&socket, dgram); if (plainText.size()) { @@ -124,27 +139,36 @@ void DtlsAssociation::readyRead() emit warningMessage(tr("%1: zero-length datagram received?").arg(name)); } else { + //! [7] + //! [8] if (!crypto.doHandshake(&socket, dgram)) { emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString())); return; } + //! [8] + + //! [9] if (crypto.isConnectionEncrypted()) { emit infoMessage(tr("%1: encrypted connection established!").arg(name)); pingTimer.start(); pingTimeout(); } else { + //! [9] emit infoMessage(tr("%1: continuing with handshake ...").arg(name)); } } } +//! [11] void DtlsAssociation::handshakeTimeout() { emit warningMessage(tr("%1: handshake timeout, trying to re-transmit").arg(name)); if (!crypto.handleTimeout(&socket)) emit errorMessage(tr("%1: failed to re-transmit - %2").arg(name, crypto.dtlsErrorString())); } +//! [11] +//! [14] void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth) { Q_ASSERT(auth); @@ -153,7 +177,9 @@ void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth) auth->setIdentity(name.toLatin1()); auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f")); } +//! [14] +//! [10] void DtlsAssociation::pingTimeout() { static const QString message = QStringLiteral("I am %1, please, accept our ping %2"); @@ -166,5 +192,6 @@ void DtlsAssociation::pingTimeout() ++ping; } +//! [10] QT_END_NAMESPACE diff --git a/examples/network/secureudpclient/association.h b/examples/network/secureudpclient/association.h index 157882f23da..be89ce695e0 100644 --- a/examples/network/secureudpclient/association.h +++ b/examples/network/secureudpclient/association.h @@ -55,19 +55,18 @@ QT_BEGIN_NAMESPACE +//! [0] class DtlsAssociation : public QObject { Q_OBJECT public: - DtlsAssociation(const QHostAddress &address, quint16 port, const QString &connectionName); ~DtlsAssociation(); void startHandshake(); signals: - void errorMessage(const QString &message); void warningMessage(const QString &message); void infoMessage(const QString &message); @@ -75,7 +74,6 @@ signals: const QByteArray &plainText); private slots: - void udpSocketConnected(); void readyRead(); void handshakeTimeout(); @@ -83,7 +81,6 @@ private slots: void pingTimeout(); private: - QString name; QUdpSocket socket; QDtls crypto; @@ -93,6 +90,7 @@ private: Q_DISABLE_COPY(DtlsAssociation) }; +//! [0] QT_END_NAMESPACE diff --git a/examples/network/secureudpclient/mainwindow.cpp b/examples/network/secureudpclient/mainwindow.cpp index 07c614cf3af..2fbf757c81c 100644 --- a/examples/network/secureudpclient/mainwindow.cpp +++ b/examples/network/secureudpclient/mainwindow.cpp @@ -72,6 +72,8 @@ MainWindow::~MainWindow() delete ui; } +//! [0] + const QString colorizer(QStringLiteral("%2
")); void MainWindow::addErrorMessage(const QString &message) @@ -102,6 +104,8 @@ void MainWindow::addServerResponse(const QString &clientInfo, const QByteArray & ui->serverMessages->insertHtml(colorizer.arg(messageColor, html)); } +//! [0] + void MainWindow::on_connectButton_clicked() { if (lookupId != -1) { diff --git a/examples/network/secureudpclient/mainwindow.h b/examples/network/secureudpclient/mainwindow.h index b231b44627b..0d443fd376f 100644 --- a/examples/network/secureudpclient/mainwindow.h +++ b/examples/network/secureudpclient/mainwindow.h @@ -76,7 +76,6 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); @@ -94,7 +93,6 @@ private slots: void lookupFinished(const QHostInfo &hostInfo); private: - void updateUi(); void startNewConnection(const QHostAddress &address); diff --git a/examples/network/secureudpserver/mainwindow.cpp b/examples/network/secureudpserver/mainwindow.cpp index d751ec931db..ef1974c311e 100644 --- a/examples/network/secureudpserver/mainwindow.cpp +++ b/examples/network/secureudpserver/mainwindow.cpp @@ -104,6 +104,7 @@ void MainWindow::updateUi() : ui->startButton->setText(tr("Start listening")); } +//! [0] const QString colorizer(QStringLiteral("%2
")); void MainWindow::addErrorMessage(const QString &message) @@ -134,3 +135,4 @@ void MainWindow::addClientMessage(const QString &peerInfo, const QByteArray &dat QString::fromUtf8(plainText)); ui->messages->insertHtml(colorizer.arg(messageColor, html)); } +//! [0] diff --git a/examples/network/secureudpserver/mainwindow.h b/examples/network/secureudpserver/mainwindow.h index 0c914f5021d..b39d984d50d 100644 --- a/examples/network/secureudpserver/mainwindow.h +++ b/examples/network/secureudpserver/mainwindow.h @@ -69,12 +69,10 @@ class MainWindow : public QMainWindow Q_OBJECT public: - MainWindow(); ~MainWindow(); private slots: - void addErrorMessage(const QString &message); void addWarningMessage(const QString &message); void addInfoMessage(const QString &message); @@ -85,7 +83,6 @@ private slots: void on_quitButton_clicked(); private: - void updateUi(); Ui::MainWindow *ui = nullptr; diff --git a/examples/network/secureudpserver/server.cpp b/examples/network/secureudpserver/server.cpp index 763024e4f44..68701231634 100644 --- a/examples/network/secureudpserver/server.cpp +++ b/examples/network/secureudpserver/server.cpp @@ -87,6 +87,7 @@ QString connection_info(QSharedPointer connection) } // unnamed namespace +//! [1] DtlsServer::DtlsServer() { connect(&serverSocket, &QAbstractSocket::readyRead, this, &DtlsServer::readyRead); @@ -94,12 +95,14 @@ DtlsServer::DtlsServer() serverConfiguration.setPreSharedKeyIdentityHint("Qt DTLS example server"); serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); } +//! [1] DtlsServer::~DtlsServer() { shutdown(); } +//! [2] bool DtlsServer::listen(const QHostAddress &address, quint16 port) { if (address != serverSocket.localAddress() || port != serverSocket.localPort()) { @@ -113,6 +116,7 @@ bool DtlsServer::listen(const QHostAddress &address, quint16 port) return listening; } +//! [2] bool DtlsServer::isListening() const { @@ -126,6 +130,7 @@ void DtlsServer::close() void DtlsServer::readyRead() { + //! [3] const qint64 bytesToRead = serverSocket.pendingDatagramSize(); if (bytesToRead <= 0) { emit warningMessage(tr("A spurious read notification")); @@ -143,7 +148,8 @@ void DtlsServer::readyRead() } dgram.resize(bytesRead); - + //! [3] + //! [4] if (peerAddress.isNull() || !peerPort) { emit warningMessage(tr("Failed to extract peer info (address, port)")); return; @@ -154,20 +160,28 @@ void DtlsServer::readyRead() return connection->peerAddress() == peerAddress && connection->peerPort() == peerPort; }); + //! [4] + //! [5] if (client == knownClients.end()) return handleNewConnection(peerAddress, peerPort, dgram); + //! [5] + //! [6] if ((*client)->isConnectionEncrypted()) { decryptDatagram(*client, dgram); if ((*client)->dtlsError() == QDtlsError::RemoteClosedConnectionError) knownClients.erase(client); return; } + //! [6] + //! [7] doHandshake(*client, dgram); + //! [7] } +//! [13] void DtlsServer::pskRequired(QSslPreSharedKeyAuthenticator *auth) { Q_ASSERT(auth); @@ -176,7 +190,9 @@ void DtlsServer::pskRequired(QSslPreSharedKeyAuthenticator *auth) .arg(QString::fromLatin1(auth->identity()))); auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f")); } +//! [13] +//! [8] void DtlsServer::handleNewConnection(const QHostAddress &peerAddress, quint16 peerPort, const QByteArray &clientHello) { @@ -186,7 +202,8 @@ void DtlsServer::handleNewConnection(const QHostAddress &peerAddress, const QString peerInfo = peer_info(peerAddress, peerPort); if (cookieSender.verifyClient(&serverSocket, clientHello, peerAddress, peerPort)) { emit infoMessage(peerInfo + tr(": verified, starting a handshake")); - + //! [8] + //! [9] DtlsConnection newConnection(new QDtls(QSslSocket::SslServerMode)); newConnection->setDtlsConfiguration(serverConfiguration); newConnection->setPeer(peerAddress, peerPort); @@ -194,6 +211,7 @@ void DtlsServer::handleNewConnection(const QHostAddress &peerAddress, this, &DtlsServer::pskRequired); knownClients.push_back(newConnection); doHandshake(newConnection, clientHello); + //! [9] } else if (cookieSender.dtlsError() != QDtlsError::NoError) { emit errorMessage(tr("DTLS error: ") + cookieSender.dtlsErrorString()); } else { @@ -201,6 +219,7 @@ void DtlsServer::handleNewConnection(const QHostAddress &peerAddress, } } +//! [11] void DtlsServer::doHandshake(DtlsConnection newConnection, const QByteArray &clientHello) { const bool result = newConnection->doHandshake(&serverSocket, clientHello); @@ -223,7 +242,9 @@ void DtlsServer::doHandshake(DtlsConnection newConnection, const QByteArray &cli Q_UNREACHABLE(); } } +//! [11] +//! [12] void DtlsServer::decryptDatagram(DtlsConnection connection, const QByteArray &clientMessage) { Q_ASSERT(connection->isConnectionEncrypted()); @@ -239,7 +260,9 @@ void DtlsServer::decryptDatagram(DtlsConnection connection, const QByteArray &cl emit errorMessage(peerInfo + ": " + connection->dtlsErrorString()); } } +//! [12] +//! [14] void DtlsServer::shutdown() { for (DtlsConnection &connection : knownClients) @@ -248,5 +271,6 @@ void DtlsServer::shutdown() knownClients.clear(); serverSocket.close(); } +//! [14] QT_END_NAMESPACE diff --git a/examples/network/secureudpserver/server.h b/examples/network/secureudpserver/server.h index 33444f74072..b720368e7be 100644 --- a/examples/network/secureudpserver/server.h +++ b/examples/network/secureudpserver/server.h @@ -57,12 +57,12 @@ QT_BEGIN_NAMESPACE +//! [0] class DtlsServer : public QObject { Q_OBJECT public: - DtlsServer(); ~DtlsServer(); @@ -71,7 +71,6 @@ public: void close(); signals: - void errorMessage(const QString &message); void warningMessage(const QString &message); void infoMessage(const QString &message); @@ -80,12 +79,10 @@ signals: const QByteArray &plainText); private slots: - void readyRead(); void pskRequired(QSslPreSharedKeyAuthenticator *auth); private: - void handleNewConnection(const QHostAddress &peerAddress, quint16 peerPort, const QByteArray &clientHello); @@ -103,6 +100,7 @@ private: Q_DISABLE_COPY(DtlsServer) }; +//! [0] QT_END_NAMESPACE