From 4c089601d7982bb45080d57b3399ed0653f69dd1 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Mon, 4 Jun 2018 16:42:13 +0200 Subject: Document the DTLS API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-68070 Change-Id: Ifd08ecb7c2c1a6dc352952a10ad56259bd1ecf10 Reviewed-by: Paul Wicking Reviewed-by: MÃ¥rten Nordheim --- .../doc/snippets/code/src_network_ssl_qdtls.cpp | 138 +++++++++++++++++++++ .../snippets/code/src_network_ssl_qdtlscookie.cpp | 125 +++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 src/network/doc/snippets/code/src_network_ssl_qdtls.cpp create mode 100644 src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp (limited to 'src/network/doc/snippets/code') diff --git a/src/network/doc/snippets/code/src_network_ssl_qdtls.cpp b/src/network/doc/snippets/code/src_network_ssl_qdtls.cpp new file mode 100644 index 0000000000..2132b48338 --- /dev/null +++ b/src/network/doc/snippets/code/src_network_ssl_qdtls.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +// 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. + } +} + +//! [0] + +//! [1] +DtlsClient::DtlsClient() +{ + // Some initialization code here ... + connect(&clientDtls, &QDtls::handshakeTimeout, this, &DtlsClient::handleTimeout); +} + +void DtlsClient::handleTimeout() +{ + clientDtls.handleTimeout(&clientSocket); +} +//! [1] + +//! [2] +// 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); +//! [2] + +//! [3] +DtlsClient::~DtlsClient() +{ + clientDtls.shutdown(&clientSocket); +} +//! [3] + +//! [4] +auto config = QSslConfiguration::defaultDtlsConfiguration(); +config.setDtlsCookieVerificationEnabled(false); +// Some other customization ... +dtlsConnection.setDtlsConfiguration(config); +//! [4] + +//! [5] +if (!dtls.doHandshake(&socket, dgram)) { + if (dtls.dtlsError() == QDtlsError::PeerVerificationError) + dtls.abortAfterError(&socket); +} +//! [5] + +//! [6] +QList cert = QSslCertificate::fromPath(QLatin1String("server-certificate.pem")); +QSslError error(QSslError::SelfSignedCertificate, cert.at(0)); +QList expectedSslErrors; +expectedSslErrors.append(error); + +QDtls dtls; +dtls.ignoreVerificationErrors(expectedSslErrors); +dtls.doHandshake(udpSocket); +//! [6] + diff --git a/src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp b/src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp new file mode 100644 index 0000000000..a9e596eca5 --- /dev/null +++ b/src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +class DtlsServer : public QObject +{ +public: + bool listen(const QHostAddress &address, quint16 port); + // ... + +private: + void readyRead(); + // ... + + QUdpSocket serverSocket; + QDtlsClientVerifier verifier; + // ... +}; + +bool DtlsServer::listen(const QHostAddress &serverAddress, quint16 serverPort) +{ + if (serverSocket.bind(serverAddress, serverPort)) + connect(&serverSocket, &QUdpSocket::readyRead, this, &DtlsServer::readyRead); + return serverSocket.state() == QAbstractSocket::BoundState; +} + +void DtlsServer::readyRead() +{ + QByteArray dgram(serverSocket.pendingDatagramSize(), Qt::Uninitialized); + QHostAddress address; + quint16 port = {}; + serverSocket.readDatagram(dgram.data(), dgram.size(), &address, &port); + if (verifiedClients.contains({address, port}) { + // This client was verified previously, we either continue the + // handshake or decrypt the incoming message. + } else if (verifier.verifyClient(&serverSocket, dgram, address, port)) { + // Apparently we have a real DTLS client who wants to send us + // encrypted datagrams. Remember this client as verified + // and proceed with a handshake. + } else { + // No matching cookie was found in the incoming datagram, + // verifyClient() has sent a ClientVerify message. + // We'll hear from the client again soon, if they're real. + } +} +//! [0] + +//! [1] +void DtlsServer::updateServerSecret() +{ + const QByteArray newSecret(generateCryptoStrongSecret()); + if (newSecret.size()) { + usedCookies.append(newSecret); + verifier.setCookieGeneratorParameters({QCryptographicHash::Sha1, newSecret}); + } +} +//! [1] + +//! [2] +if (!verifier.verifyClient(&socket, message, address, port)) { + switch (verifyClient.dtlsError()) { + case QDtlsError::NoError: + // Not verified yet, but no errors found and we have to wait for the next + // message from this client. + return; + case QDtlsError::TlsInitializationError: + // This error is fatal, nothing we can do about it. + // Probably, quit the server after reporting the error. + return; + case QDtlsError::UnderlyingSocketError: + // There is some problem in QUdpSocket, handle it (see QUdpSocket::error()) + return; + case QDtlsError::InvalidInputParameters: + default: + Q_UNREACHABLE(); + } +} +//! [2] -- cgit v1.2.3