summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2021-02-25 11:30:21 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2021-03-04 07:04:45 +0100
commit6c835796c8ea2590008900ffb5f4bf0d902ee73d (patch)
treec47d4ad51483ceff896961f2eb850930af41c34e
parentdcbaf539eafd6e8190cab29744ab6483993f4fd0 (diff)
Convert QDtls classes to the new plugin-based design
Essentially, the same code re-shuffled and placed behind the new interfaces. Pick-to: dev Fixes: QTBUG-91174 Task-number: QTBUG-65922 Change-Id: I8f14697f10713f9738c5c7805aed0150c084850c Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/network/CMakeLists.txt1
-rw-r--r--src/network/ssl/qdtls.cpp418
-rw-r--r--src/network/ssl/qdtls_base.cpp137
-rw-r--r--src/network/ssl/qdtls_base_p.h115
-rw-r--r--src/network/ssl/qdtls_openssl.cpp94
-rw-r--r--src/network/ssl/qdtls_openssl_p.h47
-rw-r--r--src/network/ssl/qdtls_p.h92
-rw-r--r--src/network/ssl/qtlsbackend.cpp8
-rw-r--r--src/network/ssl/qtlsbackend_openssl.cpp26
-rw-r--r--src/network/ssl/qtlsbackend_openssl_p.h4
-rw-r--r--src/network/ssl/qtlsbackend_p.h85
11 files changed, 749 insertions, 278 deletions
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index 1d0e32cc19..636eb2d3da 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -357,6 +357,7 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FE
qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_ssl
SOURCES
ssl/qdtls.cpp ssl/qdtls.h ssl/qdtls_p.h
+ ssl/qdtls_base.cpp ssl/qdtls_base_p.h
)
qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl
diff --git a/src/network/ssl/qdtls.cpp b/src/network/ssl/qdtls.cpp
index af89740898..e62a4b4043 100644
--- a/src/network/ssl/qdtls.cpp
+++ b/src/network/ssl/qdtls.cpp
@@ -38,8 +38,9 @@
****************************************************************************/
#include "qsslconfiguration.h"
-#include "qdtls_openssl_p.h"
+#include "qsslsocket_p.h"
#include "qudpsocket.h"
+#include "qsslcipher.h"
#include "qdtls_p.h"
#include "qssl_p.h"
#include "qdtls.h"
@@ -337,72 +338,6 @@
QT_BEGIN_NAMESPACE
-QSslConfiguration QDtlsBasePrivate::configuration() const
-{
- auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration);
- copyPrivate->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
- QSslConfiguration copy(copyPrivate);
- copyPrivate->sessionCipher = sessionCipher;
- copyPrivate->sessionProtocol = sessionProtocol;
-
- return copy;
-}
-
-void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
-{
- dtlsConfiguration.localCertificateChain = configuration.localCertificateChain();
- dtlsConfiguration.privateKey = configuration.privateKey();
- dtlsConfiguration.ciphers = configuration.ciphers();
- dtlsConfiguration.ellipticCurves = configuration.ellipticCurves();
- dtlsConfiguration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint();
- dtlsConfiguration.dhParams = configuration.diffieHellmanParameters();
- dtlsConfiguration.caCertificates = configuration.caCertificates();
- dtlsConfiguration.peerVerifyDepth = configuration.peerVerifyDepth();
- dtlsConfiguration.peerVerifyMode = configuration.peerVerifyMode();
- dtlsConfiguration.protocol = configuration.protocol();
- dtlsConfiguration.sslOptions = configuration.d->sslOptions;
- dtlsConfiguration.sslSession = configuration.sessionTicket();
- dtlsConfiguration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
- dtlsConfiguration.nextAllowedProtocols = configuration.allowedNextProtocols();
- dtlsConfiguration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol();
- dtlsConfiguration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus();
- dtlsConfiguration.dtlsCookieEnabled = configuration.dtlsCookieVerificationEnabled();
- dtlsConfiguration.allowRootCertOnDemandLoading = configuration.d->allowRootCertOnDemandLoading;
- dtlsConfiguration.backendConfig = configuration.backendConfiguration();
-
- clearDtlsError();
-}
-
-bool QDtlsBasePrivate::setCookieGeneratorParameters(QCryptographicHash::Algorithm alg,
- const QByteArray &key)
-{
- if (!key.size()) {
- setDtlsError(QDtlsError::InvalidInputParameters,
- QDtls::tr("Invalid (empty) secret"));
- return false;
- }
-
- clearDtlsError();
-
- hashAlgorithm = alg;
- secret = key;
-
- return true;
-}
-
-bool QDtlsBasePrivate::isDtlsProtocol(QSsl::SslProtocol protocol)
-{
- switch (protocol) {
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_2OrLater:
- return true;
- default:
- return false;
- }
-}
-
static QString msgUnsupportedMulticastAddress()
{
return QDtls::tr("Multicast and broadcast addresses are not supported");
@@ -434,22 +369,37 @@ QDtlsClientVerifier::GeneratorParameters::GeneratorParameters(QCryptographicHash
{
}
+QDtlsClientVerifierPrivate::QDtlsClientVerifierPrivate()
+{
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available, cannot verify DTLS client");
+ return;
+ }
+ backend.reset(tlsBackend->createDtlsCookieVerifier());
+ if (!backend.get())
+ qCWarning(lcSsl) << "The backend" << tlsBackend->backendName() << "does not support DTLS cookies";
+}
+
+QDtlsClientVerifierPrivate::~QDtlsClientVerifierPrivate() = default;
+
/*!
Constructs a QDtlsClientVerifier object, \a parent is passed to QObject's
constructor.
*/
QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent)
- : QObject(*new QDtlsClientVerifierOpenSSL, parent)
+ : QObject(*new QDtlsClientVerifierPrivate, parent)
{
Q_D(QDtlsClientVerifier);
- d->mode = QSslSocket::SslServerMode;
- // The default configuration suffices: verifier never does a full
- // handshake and upon verifying a cookie in a client hello message,
- // it reports success.
- auto conf = QSslConfiguration::defaultDtlsConfiguration();
- conf.setPeerVerifyMode(QSslSocket::VerifyNone);
- d->setConfiguration(conf);
+ if (auto *backend = d->backend.get()) {
+ // The default configuration suffices: verifier never does a full
+ // handshake and upon verifying a cookie in a client hello message,
+ // it reports success.
+ auto conf = QSslConfiguration::defaultDtlsConfiguration();
+ conf.setPeerVerifyMode(QSslSocket::VerifyNone);
+ backend->setConfiguration(conf);
+ }
}
/*!
@@ -473,8 +423,10 @@ QDtlsClientVerifier::~QDtlsClientVerifier()
bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters &params)
{
Q_D(QDtlsClientVerifier);
+ if (auto *backend = d->backend.get())
+ return backend->setCookieGeneratorParameters(params);
- return d->setCookieGeneratorParameters(params.hash, params.secret);
+ return false;
}
/*!
@@ -491,7 +443,10 @@ QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorPar
{
Q_D(const QDtlsClientVerifier);
- return {d->hashAlgorithm, d->secret};
+ if (const auto *backend = d->backend.get())
+ return backend->cookieGeneratorParameters();
+
+ return {};
}
/*!
@@ -514,19 +469,23 @@ bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgr
{
Q_D(QDtlsClientVerifier);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket || address.isNull() || !dgram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("A valid UDP socket, non-empty datagram, valid address/port were expected"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("A valid UDP socket, non-empty datagram, and valid address/port were expected"));
return false;
}
if (address.isBroadcast() || address.isMulticast()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- msgUnsupportedMulticastAddress());
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ msgUnsupportedMulticastAddress());
return false;
}
- return d->verifyClient(socket, dgram, address, port);
+ return backend->verifyClient(socket, dgram, address, port);
}
/*!
@@ -539,7 +498,10 @@ QByteArray QDtlsClientVerifier::verifiedHello() const
{
Q_D(const QDtlsClientVerifier);
- return d->verifiedClientHello;
+ if (const auto *backend = d->backend.get())
+ return backend->verifiedHello();
+
+ return {};
}
/*!
@@ -551,7 +513,10 @@ QDtlsError QDtlsClientVerifier::dtlsError() const
{
Q_D(const QDtlsClientVerifier);
- return d->errorCode;
+ if (const auto *backend = d->backend.get())
+ return backend->error();
+
+ return QDtlsError::TlsInitializationError;
}
/*!
@@ -561,11 +526,17 @@ QDtlsError QDtlsClientVerifier::dtlsError() const
*/
QString QDtlsClientVerifier::dtlsErrorString() const
{
- Q_D(const QDtlsBase);
+ Q_D(const QDtlsClientVerifier);
- return d->errorDescription;
+ if (const auto *backend = d->backend.get())
+ return backend->errorString();
+
+ return QStringLiteral("No TLS backend is available, no client verification");
}
+QDtlsPrivate::QDtlsPrivate() = default;
+QDtlsPrivate::~QDtlsPrivate() = default;
+
/*!
Creates a QDtls object, \a parent is passed to the QObject constructor.
\a mode is QSslSocket::SslServerMode for a server-side DTLS connection or
@@ -574,11 +545,19 @@ QString QDtlsClientVerifier::dtlsErrorString() const
\sa sslMode(), QSslSocket::SslMode
*/
QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent)
- : QObject(*new QDtlsPrivateOpenSSL, parent)
+ : QObject(*new QDtlsPrivate, parent)
{
Q_D(QDtls);
-
- d->mode = mode;
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend found, QDtls is unsupported");
+ return;
+ }
+ d->backend.reset(tlsBackend->createDtlsCryptograph(this, mode));
+ if (!d->backend.get()) {
+ qCWarning(lcSsl) << "TLS backend" << tlsBackend->backendName()
+ << "does not support the protocol DTLS";
+ }
setDtlsConfiguration(QSslConfiguration::defaultDtlsConfiguration());
}
@@ -601,29 +580,30 @@ bool QDtls::setPeer(const QHostAddress &address, quint16 port,
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot set peer after handshake started"));
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot set peer after handshake started"));
return false;
}
if (address.isNull()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("Invalid address"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("Invalid address"));
return false;
}
if (address.isBroadcast() || address.isMulticast()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- msgUnsupportedMulticastAddress());
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ msgUnsupportedMulticastAddress());
return false;
}
- d->clearDtlsError();
-
- d->remoteAddress = address;
- d->remotePort = port;
- d->peerVerificationName = verificationName;
+ backend->clearDtlsError();
+ backend->setPeer(address, port, verificationName);
return true;
}
@@ -640,14 +620,18 @@ bool QDtls::setPeerVerificationName(const QString &name)
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
tr("Cannot set verification name after handshake started"));
return false;
}
- d->clearDtlsError();
- d->peerVerificationName = name;
+ backend->clearDtlsError();
+ backend->setPeerVerificationName(name);
return true;
}
@@ -661,7 +645,10 @@ QHostAddress QDtls::peerAddress() const
{
Q_D(const QDtls);
- return d->remoteAddress;
+ if (const auto *backend = d->backend.get())
+ return backend->peerAddress();
+
+ return {};
}
/*!
@@ -671,9 +658,12 @@ QHostAddress QDtls::peerAddress() const
*/
quint16 QDtls::peerPort() const
{
- Q_D(const QDtlsBase);
+ Q_D(const QDtls);
+
+ if (const auto *backend = d->backend.get())
+ return backend->peerPort();
- return d->remotePort;
+ return 0;
}
/*!
@@ -686,7 +676,10 @@ QString QDtls::peerVerificationName() const
{
Q_D(const QDtls);
- return d->peerVerificationName;
+ if (const auto *backend = d->backend.get())
+ return backend->peerVerificationName();
+
+ return {};
}
/*!
@@ -699,7 +692,10 @@ QSslSocket::SslMode QDtls::sslMode() const
{
Q_D(const QDtls);
- return d->mode;
+ if (const auto *backend = d->backend.get())
+ return backend->cryptographMode();
+
+ return QSslSocket::UnencryptedMode;
}
/*!
@@ -712,7 +708,8 @@ void QDtls::setMtuHint(quint16 mtuHint)
{
Q_D(QDtls);
- d->mtuHint = mtuHint;
+ if (auto *backend = d->backend.get())
+ backend->setDtlsMtuHint(mtuHint);
}
/*!
@@ -724,7 +721,10 @@ quint16 QDtls::mtuHint() const
{
Q_D(const QDtls);
- return d->mtuHint;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsMtuHint();
+
+ return 0;
}
/*!
@@ -741,7 +741,10 @@ bool QDtls::setCookieGeneratorParameters(const GeneratorParameters &params)
{
Q_D(QDtls);
- return d->setCookieGeneratorParameters(params.hash, params.secret);
+ if (auto *backend = d->backend.get())
+ backend->setCookieGeneratorParameters(params);
+
+ return false;
}
/*!
@@ -759,7 +762,10 @@ QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const
{
Q_D(const QDtls);
- return {d->hashAlgorithm, d->secret};
+ if (const auto *backend = d->backend.get())
+ return backend->cookieGeneratorParameters();
+
+ return {};
}
/*!
@@ -774,13 +780,17 @@ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot set configuration after handshake started"));
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot set configuration after handshake started"));
return false;
}
- d->setConfiguration(configuration);
+ backend->setConfiguration(configuration);
return true;
}
@@ -793,8 +803,10 @@ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
QSslConfiguration QDtls::dtlsConfiguration() const
{
Q_D(const QDtls);
+ if (const auto *backend = d->backend.get())
+ return backend->configuration();
- return d->configuration();
+ return {};
}
/*!
@@ -806,7 +818,10 @@ QDtls::HandshakeState QDtls::handshakeState()const
{
Q_D(const QDtls);
- return d->handshakeState;
+ if (const auto *backend = d->backend.get())
+ return backend->state();
+
+ return QDtls::HandshakeNotStarted;
}
/*!
@@ -832,13 +847,17 @@ bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram)
{
Q_D(QDtls);
- if (d->handshakeState == HandshakeNotStarted)
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() == HandshakeNotStarted)
return startHandshake(socket, dgram);
- else if (d->handshakeState == HandshakeInProgress)
+ else if (backend->state() == HandshakeInProgress)
return continueHandshake(socket, dgram);
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot start/continue handshake, invalid handshake state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot start/continue handshake, invalid handshake state"));
return false;
}
@@ -849,30 +868,34 @@ bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->remoteAddress.isNull()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("To start a handshake you must set peer's address and port first"));
+ if (backend->peerAddress().isNull()) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("To start a handshake you must set peer's address and port first"));
return false;
}
if (sslMode() == QSslSocket::SslServerMode && !datagram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
return false;
}
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot start handshake, already done/in progress"));
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot start handshake, already done/in progress"));
return false;
}
- return d->startHandshake(socket, datagram);
+ return backend->startHandshake(socket, datagram);
}
/*!
@@ -887,12 +910,16 @@ bool QDtls::handleTimeout(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- return d->handleTimeout(socket);
+ return backend->handleTimeout(socket);
}
/*!
@@ -902,19 +929,23 @@ bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket || !datagram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
return false;
}
- if (d->handshakeState != HandshakeInProgress) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot continue handshake, not in InProgress state"));
+ if (backend->state() != HandshakeInProgress) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot continue handshake, not in InProgress state"));
return false;
}
- return d->continueHandshake(socket, datagram);
+ return backend->continueHandshake(socket, datagram);
}
/*!
@@ -929,18 +960,22 @@ bool QDtls::resumeHandshake(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->handshakeState != PeerVerificationFailed) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot resume, not in VerificationError state"));
+ if (backend->state() != PeerVerificationFailed) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot resume, not in VerificationError state"));
return false;
}
- return d->resumeHandshake(socket);
+ return backend->resumeHandshake(socket);
}
/*!
@@ -953,18 +988,22 @@ bool QDtls::abortHandshake(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->handshakeState != PeerVerificationFailed && d->handshakeState != HandshakeInProgress) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("No handshake in progress, nothing to abort"));
+ if (backend->state() != PeerVerificationFailed && backend->state() != HandshakeInProgress) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("No handshake in progress, nothing to abort"));
return false;
}
- d->abortHandshake(socket);
+ backend->abortHandshake(socket);
return true;
}
@@ -979,19 +1018,23 @@ bool QDtls::shutdown(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("Invalid (nullptr) socket"));
return false;
}
- if (!d->connectionEncrypted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot send shutdown alert, not encrypted"));
+ if (!backend->isConnectionEncrypted()) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot send shutdown alert, not encrypted"));
return false;
}
- d->sendShutdownAlert(socket);
+ backend->sendShutdownAlert(socket);
return true;
}
@@ -1004,7 +1047,11 @@ bool QDtls::isConnectionEncrypted() const
{
Q_D(const QDtls);
- return d->connectionEncrypted;
+
+ if (const auto *backend = d->backend.get())
+ return backend->isConnectionEncrypted();
+
+ return false;
}
/*!
@@ -1023,7 +1070,10 @@ QSslCipher QDtls::sessionCipher() const
{
Q_D(const QDtls);
- return d->sessionCipher;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsSessionCipher();
+
+ return {};
}
/*!
@@ -1040,7 +1090,10 @@ QSsl::SslProtocol QDtls::sessionProtocol() const
{
Q_D(const QDtls);
- return d->sessionProtocol;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsSessionProtocol();
+
+ return QSsl::UnknownProtocol;
}
/*!
@@ -1055,18 +1108,22 @@ qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return -1;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return -1;
}
if (!isConnectionEncrypted()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot write a datagram, not in encrypted state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot write a datagram, not in encrypted state"));
return -1;
}
- return d->writeDatagramEncrypted(socket, dgram);
+ return backend->writeDatagramEncrypted(socket, dgram);
}
/*!
@@ -1079,21 +1136,25 @@ QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return {};
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return {};
}
if (!isConnectionEncrypted()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot read a datagram, not in encrypted state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot read a datagram, not in encrypted state"));
return {};
}
if (!dgram.size())
return {};
- return d->decryptDatagram(socket, dgram);
+ return backend->decryptDatagram(socket, dgram);
}
/*!
@@ -1105,7 +1166,10 @@ QDtlsError QDtls::dtlsError() const
{
Q_D(const QDtls);
- return d->errorCode;
+ if (const auto *backend = d->backend.get())
+ return backend->error();
+
+ return QDtlsError::NoError;
}
/*!
@@ -1118,7 +1182,10 @@ QString QDtls::dtlsErrorString() const
{
Q_D(const QDtls);
- return d->errorDescription;
+ if (const auto *backend = d->backend.get())
+ return backend->errorString();
+
+ return {};
}
/*!
@@ -1131,7 +1198,11 @@ QList<QSslError> QDtls::peerVerificationErrors() const
{
Q_D(const QDtls);
- return d->tlsErrors;
+ if (const auto *backend = d->backend.get())
+ return backend->peerVerificationErrors();
+
+ //return d->tlsErrors;
+ return {};
}
/*!
@@ -1156,7 +1227,8 @@ void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
{
Q_D(QDtls);
- d->tlsErrorsToIgnore = errorsToIgnore;
+ if (auto *backend = d->backend.get())
+ backend->ignoreVerificationErrors(errorsToIgnore);
}
QT_END_NAMESPACE
diff --git a/src/network/ssl/qdtls_base.cpp b/src/network/ssl/qdtls_base.cpp
new file mode 100644
index 0000000000..be10aac7db
--- /dev/null
+++ b/src/network/ssl/qdtls_base.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdtls_base_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QDtlsBasePrivate::setDtlsError(QDtlsError code, const QString &description)
+{
+ errorCode = code;
+ errorDescription = description;
+}
+
+QDtlsError QDtlsBasePrivate::error() const
+{
+ return errorCode;
+}
+
+QString QDtlsBasePrivate::errorString() const
+{
+ return errorDescription;
+}
+
+void QDtlsBasePrivate::clearDtlsError()
+{
+ errorCode = QDtlsError::NoError;
+ errorDescription.clear();
+}
+
+QSslConfiguration QDtlsBasePrivate::configuration() const
+{
+ auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration);
+ copyPrivate->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
+ QSslConfiguration copy(copyPrivate);
+ copyPrivate->sessionCipher = sessionCipher;
+ copyPrivate->sessionProtocol = sessionProtocol;
+
+ return copy;
+}
+
+void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
+{
+ dtlsConfiguration.localCertificateChain = configuration.localCertificateChain();
+ dtlsConfiguration.privateKey = configuration.privateKey();
+ dtlsConfiguration.ciphers = configuration.ciphers();
+ dtlsConfiguration.ellipticCurves = configuration.ellipticCurves();
+ dtlsConfiguration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint();
+ dtlsConfiguration.dhParams = configuration.diffieHellmanParameters();
+ dtlsConfiguration.caCertificates = configuration.caCertificates();
+ dtlsConfiguration.peerVerifyDepth = configuration.peerVerifyDepth();
+ dtlsConfiguration.peerVerifyMode = configuration.peerVerifyMode();
+ dtlsConfiguration.protocol = configuration.protocol();
+ dtlsConfiguration.sslOptions = configuration.d->sslOptions;
+ dtlsConfiguration.sslSession = configuration.sessionTicket();
+ dtlsConfiguration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
+ dtlsConfiguration.nextAllowedProtocols = configuration.allowedNextProtocols();
+ dtlsConfiguration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol();
+ dtlsConfiguration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus();
+ dtlsConfiguration.dtlsCookieEnabled = configuration.dtlsCookieVerificationEnabled();
+ dtlsConfiguration.allowRootCertOnDemandLoading = configuration.d->allowRootCertOnDemandLoading;
+ dtlsConfiguration.backendConfig = configuration.backendConfiguration();
+
+ clearDtlsError();
+}
+
+bool QDtlsBasePrivate::setCookieGeneratorParameters(const GenParams &params)
+{
+ if (!params.secret.size()) {
+ setDtlsError(QDtlsError::InvalidInputParameters,
+ QDtls::tr("Invalid (empty) secret"));
+ return false;
+ }
+
+ clearDtlsError();
+
+ hashAlgorithm = params.hash;
+ secret = params.secret;
+
+ return true;
+}
+
+QDtlsClientVerifier::GeneratorParameters
+QDtlsBasePrivate::cookieGeneratorParameters() const
+{
+ return {hashAlgorithm, secret};
+}
+
+bool QDtlsBasePrivate::isDtlsProtocol(QSsl::SslProtocol protocol)
+{
+ switch (protocol) {
+ case QSsl::DtlsV1_0:
+ case QSsl::DtlsV1_0OrLater:
+ case QSsl::DtlsV1_2:
+ case QSsl::DtlsV1_2OrLater:
+ return true;
+ default:
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qdtls_base_p.h b/src/network/ssl/qdtls_base_p.h
new file mode 100644
index 0000000000..260719b5f0
--- /dev/null
+++ b/src/network/ssl/qdtls_base_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDTLS_BASE_P_H
+#define QDTLS_BASE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtnetworkglobal_p.h>
+
+QT_REQUIRE_CONFIG(dtls);
+
+#include "qsslconfiguration_p.h"
+#include "qtlsbackend_p.h"
+#include "qsslcipher.h"
+#include "qsslsocket.h"
+#include "qssl.h"
+
+#include <QtNetwork/qhostaddress.h>
+
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+// This class exists to re-implement the shared error/cookie handling
+// for both QDtls and QDtlsClientVerifier classes. Use it if/when
+// you need it. Backend neutral.
+class QDtlsBasePrivate : virtual public QSsl::DtlsBase
+{
+public:
+ QDtlsBasePrivate(QSslSocket::SslMode m, const QByteArray &s) : mode(m), secret(s) {}
+ void setDtlsError(QDtlsError code, const QString &description) override;
+ QDtlsError error() const override;
+ QString errorString() const override;
+ void clearDtlsError() override;
+
+ void setConfiguration(const QSslConfiguration &configuration) override;
+ QSslConfiguration configuration() const override;
+
+ bool setCookieGeneratorParameters(const GenParams &) override;
+ GenParams cookieGeneratorParameters() const override;
+
+ static bool isDtlsProtocol(QSsl::SslProtocol protocol);
+
+ QHostAddress remoteAddress;
+ quint16 remotePort = 0;
+ quint16 mtuHint = 0;
+
+ QDtlsError errorCode = QDtlsError::NoError;
+ QString errorDescription;
+ QSslConfigurationPrivate dtlsConfiguration;
+ QSslSocket::SslMode mode = QSslSocket::SslClientMode;
+ QSslCipher sessionCipher;
+ QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
+ QString peerVfyName;
+ QByteArray secret;
+
+#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
+#else
+ QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif // QDTLS_BASE_P_H
diff --git a/src/network/ssl/qdtls_openssl.cpp b/src/network/ssl/qdtls_openssl.cpp
index 4fc2f0a4d6..f1c7898a14 100644
--- a/src/network/ssl/qdtls_openssl.cpp
+++ b/src/network/ssl/qdtls_openssl.cpp
@@ -783,8 +783,8 @@ void DtlsState::setLinkMtu(QDtlsBasePrivate *dtlsBase)
} // namespace dtlsopenssl
QDtlsClientVerifierOpenSSL::QDtlsClientVerifierOpenSSL()
+ : QDtlsBasePrivate(QSslSocket::SslServerMode, dtlsutil::fallbackSecret())
{
- secret = dtlsutil::fallbackSecret();
}
bool QDtlsClientVerifierOpenSSL::verifyClient(QUdpSocket *socket, const QByteArray &dgram,
@@ -827,6 +827,11 @@ bool QDtlsClientVerifierOpenSSL::verifyClient(QUdpSocket *socket, const QByteArr
return false;
}
+QByteArray QDtlsClientVerifierOpenSSL::verifiedHello() const
+{
+ return verifiedClientHello;
+}
+
void QDtlsPrivateOpenSSL::TimeoutHandler::start(int hintMs)
{
Q_ASSERT(timerId == -1);
@@ -861,12 +866,66 @@ void QDtlsPrivateOpenSSL::TimeoutHandler::timerEvent(QTimerEvent *event)
dtlsConnection->reportTimeout();
}
-QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL()
+QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode side)
+ : QDtlsBasePrivate(side, dtlsutil::fallbackSecret()), q(qObject)
{
- secret = dtlsutil::fallbackSecret();
+ Q_ASSERT(qObject);
+
dtls.dtlsPrivate = this;
}
+QSslSocket::SslMode QDtlsPrivateOpenSSL::cryptographMode() const
+{
+ return mode;
+}
+
+void QDtlsPrivateOpenSSL::setPeer(const QHostAddress &addr, quint16 port, const QString &name)
+{
+ remoteAddress = addr;
+ remotePort = port;
+ peerVfyName = name;
+}
+
+QHostAddress QDtlsPrivateOpenSSL::peerAddress() const
+{
+ return remoteAddress;
+}
+
+quint16 QDtlsPrivateOpenSSL::peerPort() const
+{
+ return remotePort;
+}
+
+void QDtlsPrivateOpenSSL::setPeerVerificationName(const QString &name)
+{
+ peerVfyName = name;
+}
+
+QString QDtlsPrivateOpenSSL::peerVerificationName() const
+{
+ return peerVfyName;
+}
+
+void QDtlsPrivateOpenSSL::setDtlsMtuHint(quint16 mtu)
+{
+ mtuHint = mtu;
+}
+
+quint16 QDtlsPrivateOpenSSL::dtlsMtuHint() const
+{
+ return mtuHint;
+}
+
+QDtls::HandshakeState QDtlsPrivateOpenSSL::state() const
+{
+ return handshakeState;
+}
+
+bool QDtlsPrivateOpenSSL::isConnectionEncrypted() const
+{
+ return connectionEncrypted;
+}
+
bool QDtlsPrivateOpenSSL::startHandshake(QUdpSocket *socket, const QByteArray &dgram)
{
Q_ASSERT(socket);
@@ -1070,6 +1129,26 @@ void QDtlsPrivateOpenSSL::sendShutdownAlert(QUdpSocket *socket)
resetDtls();
}
+QList<QSslError> QDtlsPrivateOpenSSL::peerVerificationErrors() const
+{
+ return tlsErrors;
+}
+
+void QDtlsPrivateOpenSSL::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
+{
+ tlsErrorsToIgnore = errorsToIgnore;
+}
+
+QSslCipher QDtlsPrivateOpenSSL::dtlsSessionCipher() const
+{
+ return sessionCipher;
+}
+
+QSsl::SslProtocol QDtlsPrivateOpenSSL::dtlsSessionProtocol() const
+{
+ return sessionProtocol;
+}
+
qint64 QDtlsPrivateOpenSSL::writeDatagramEncrypted(QUdpSocket *socket,
const QByteArray &dgram)
{
@@ -1191,9 +1270,6 @@ unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity
{
// The code below is taken (with some modifications) from qsslsocket_openssl
// - alas, we cannot simply re-use it, it's in QSslSocketPrivate.
-
- Q_Q(QDtls);
-
{
QSslPreSharedKeyAuthenticator authenticator;
// Fill in some read-only fields (for client code)
@@ -1235,8 +1311,6 @@ unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity
unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned char *psk,
unsigned max_psk_len)
{
- Q_Q(QDtls);
-
{
QSslPreSharedKeyAuthenticator authenticator;
// Fill in some read-only fields (for the user)
@@ -1287,7 +1361,7 @@ bool QDtlsPrivateOpenSSL::verifyPeer()
// is empty, we call QAbstractSocket::peerName(), which returns
// either peerName (can be set by setPeerName) or host name
// (can be set as a result of connectToHost).
- QString name = peerVerificationName;
+ QString name = peerVfyName;
if (name.isEmpty()) {
Q_ASSERT(dtls.udpSocket);
name = dtls.udpSocket->peerName();
@@ -1366,8 +1440,6 @@ void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
void QDtlsPrivateOpenSSL::reportTimeout()
{
- Q_Q(QDtls);
-
emit q->handshakeTimeout();
}
diff --git a/src/network/ssl/qdtls_openssl_p.h b/src/network/ssl/qdtls_openssl_p.h
index b1fcc99d5a..1e31ef50ac 100644
--- a/src/network/ssl/qdtls_openssl_p.h
+++ b/src/network/ssl/qdtls_openssl_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -46,6 +46,8 @@
#include <openssl/ossl_typ.h>
+#include "qtlsbackend_openssl_p.h"
+#include "qdtls_base_p.h"
#include "qdtls_p.h"
#include <private/qsslcontext_openssl_p.h>
@@ -55,7 +57,6 @@
#include <QtNetwork/qhostaddress.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qcryptographichash.h>
#include <QtCore/qlist.h>
#include <QtCore/qsharedpointer.h>
@@ -76,6 +77,7 @@ QT_REQUIRE_CONFIG(dtls);
QT_BEGIN_NAMESPACE
class QDtlsPrivateOpenSSL;
+class QDtlsBasePrivate;
class QUdpSocket;
namespace dtlsopenssl
@@ -131,23 +133,40 @@ private:
} // namespace dtlsopenssl
-class QDtlsClientVerifierOpenSSL : public QDtlsClientVerifierPrivate
+class QDtlsClientVerifierOpenSSL : public QSsl::DtlsCookieVerifier, public QDtlsBasePrivate
{
public:
-
QDtlsClientVerifierOpenSSL();
bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
const QHostAddress &address, quint16 port) override;
+ QByteArray verifiedHello() const override;
private:
dtlsopenssl::DtlsState dtls;
+ QByteArray verifiedClientHello;
};
-class QDtlsPrivateOpenSSL : public QDtlsPrivate
+class QDtlsPrivateOpenSSL : public QSsl::DtlsCryptograph, public QDtlsBasePrivate
{
public:
- QDtlsPrivateOpenSSL();
+
+ QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode mode);
+
+private:
+
+ QSslSocket::SslMode cryptographMode() const override;
+ void setPeer(const QHostAddress &addr, quint16 port, const QString &name) override;
+ QHostAddress peerAddress() const override;
+ quint16 peerPort() const override;
+ void setPeerVerificationName(const QString &name) override;
+ QString peerVerificationName() const override;
+
+ virtual void setDtlsMtuHint(quint16 mtu) override;
+ virtual quint16 dtlsMtuHint() const override;
+
+ virtual QDtls::HandshakeState state() const override;
+ virtual bool isConnectionEncrypted() const override;
bool startHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
bool continueHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
@@ -156,9 +175,17 @@ public:
bool handleTimeout(QUdpSocket *socket) override;
void sendShutdownAlert(QUdpSocket *socket) override;
+ QList<QSslError> peerVerificationErrors() const override;
+ void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) override;
+
+ QSslCipher dtlsSessionCipher() const override;
+ QSsl::SslProtocol dtlsSessionProtocol() const override;
+
qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override;
QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
+public:
+
unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
unsigned char *psk, unsigned max_psk_len);
unsigned pskServerCallback(const char *identity, unsigned char *psk,
@@ -195,14 +222,18 @@ private:
QDtlsPrivateOpenSSL *dtlsConnection = nullptr;
};
+ QDtls *q = nullptr;
+ QDtls::HandshakeState handshakeState = QDtls::HandshakeNotStarted;
+
+ QList<QSslError> tlsErrors;
+ QList<QSslError> tlsErrorsToIgnore;
+ bool connectionEncrypted = false;
// We will initialize it 'lazily', just in case somebody wants to move
// QDtls to another thread.
QScopedPointer<TimeoutHandler> timeoutHandler;
bool connectionWasShutdown = false;
QSslPreSharedKeyAuthenticator pskAuthenticator;
QByteArray identityHint;
-
- Q_DECLARE_PUBLIC(QDtls)
};
diff --git a/src/network/ssl/qdtls_p.h b/src/network/ssl/qdtls_p.h
index be54c0e06e..70b411b6d5 100644
--- a/src/network/ssl/qdtls_p.h
+++ b/src/network/ssl/qdtls_p.h
@@ -42,21 +42,9 @@
#include <private/qtnetworkglobal_p.h>
-#include "qdtls.h"
-
-#include <private/qsslconfiguration_p.h>
-#include <private/qobject_p.h>
-
-#include <QtNetwork/qabstractsocket.h>
-#include <QtNetwork/qhostaddress.h>
-#include <QtNetwork/qsslsocket.h>
-#include <QtNetwork/qsslcipher.h>
-#include <QtNetwork/qssl.h>
-
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qstring.h>
+#include "qtlsbackend_p.h"
+#include <QtCore/private/qobject_p.h>
//
// W A R N I N G
// -------------
@@ -74,80 +62,20 @@ QT_BEGIN_NAMESPACE
class QHostAddress;
-class QDtlsBasePrivate : public QObjectPrivate
-{
-public:
-
- void setDtlsError(QDtlsError code, const QString &description)
- {
- errorCode = code;
- errorDescription = description;
- }
-
- void clearDtlsError()
- {
- errorCode = QDtlsError::NoError;
- errorDescription.clear();
- }
-
- void setConfiguration(const QSslConfiguration &configuration);
- QSslConfiguration configuration() const;
-
- bool setCookieGeneratorParameters(QCryptographicHash::Algorithm alg,
- const QByteArray &secret);
-
- static bool isDtlsProtocol(QSsl::SslProtocol protocol);
-
- QHostAddress remoteAddress;
- quint16 remotePort = 0;
- quint16 mtuHint = 0;
-
- QDtlsError errorCode = QDtlsError::NoError;
- QString errorDescription;
- QSslConfigurationPrivate dtlsConfiguration;
- QSslSocket::SslMode mode = QSslSocket::SslClientMode;
- QSslCipher sessionCipher;
- QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
- QString peerVerificationName;
- QByteArray secret;
-
-#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
-#else
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
-#endif
-};
-
-class QDtlsClientVerifierPrivate : public QDtlsBasePrivate
+class QDtlsClientVerifierPrivate : public QObjectPrivate
{
public:
-
- QByteArray verifiedClientHello;
-
- virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port) = 0;
+ QDtlsClientVerifierPrivate();
+ ~QDtlsClientVerifierPrivate();
+ std::unique_ptr<QSsl::DtlsCookieVerifier> backend;
};
-class QDtlsPrivate : public QDtlsBasePrivate
+class QDtlsPrivate : public QObjectPrivate
{
public:
-
- virtual bool startHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual bool handleTimeout(QUdpSocket *socket) = 0;
- virtual bool continueHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual bool resumeHandshake(QUdpSocket *socket) = 0;
- virtual void abortHandshake(QUdpSocket *socket) = 0;
- virtual void sendShutdownAlert(QUdpSocket *socket) = 0;
-
- virtual qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) = 0;
-
- QDtls::HandshakeState handshakeState = QDtls::HandshakeNotStarted;
-
- QList<QSslError> tlsErrors;
- QList<QSslError> tlsErrorsToIgnore;
-
- bool connectionEncrypted = false;
+ QDtlsPrivate();
+ ~QDtlsPrivate();
+ std::unique_ptr<QSsl::DtlsCryptograph> backend;
};
QT_END_NAMESPACE
diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp
index c367766801..9e1f387e11 100644
--- a/src/network/ssl/qtlsbackend.cpp
+++ b/src/network/ssl/qtlsbackend.cpp
@@ -199,6 +199,10 @@ TlsKey *X509Certificate::publicKey() const
return nullptr;
}
+#if QT_CONFIG(dtls)
+DtlsBase::~DtlsBase() = default;
+#endif // QT_CONFIG(dtls)
+
} // namespace QSsl
const QString QTlsBackend::builtinBackendNames[] = {
@@ -250,8 +254,10 @@ QSsl::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
return nullptr;
}
-QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph() const
+QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph(QDtls *qObject, int mode) const
{
+ Q_UNUSED(qObject);
+ Q_UNUSED(mode);
REPORT_MISSING_SUPPORT("does not support QDtls");
return nullptr;
}
diff --git a/src/network/ssl/qtlsbackend_openssl.cpp b/src/network/ssl/qtlsbackend_openssl.cpp
index b3686e15fa..5bff90dd37 100644
--- a/src/network/ssl/qtlsbackend_openssl.cpp
+++ b/src/network/ssl/qtlsbackend_openssl.cpp
@@ -41,6 +41,10 @@
#include "qtlskey_openssl_p.h"
#include "qx509_openssl_p.h"
+#if QT_CONFIG(dtls)
+#include "qdtls_openssl_p.h"
+#endif // QT_CONFIG(dtls)
+
// TLSTODO: Later, this code (ensure initialised, etc.)
// must move from the socket to backend.
#include "qsslsocket_p.h"
@@ -163,6 +167,28 @@ QSsl::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
return new QSsl::X509CertificateOpenSSL;
}
+QSsl::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier() const
+{
+#if QT_CONFIG(dtls)
+ return new QDtlsClientVerifierOpenSSL;
+#else
+ qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot verify DTLS cookies");
+ return nullptr;
+#endif // QT_CONFIG(dtls)
+}
+
+QSsl::DtlsCryptograph *QTlsBackendOpenSSL::createDtlsCryptograph(QDtls *q, int mode) const
+{
+#if QT_CONFIG(dtls)
+ return new QDtlsPrivateOpenSSL(q, QSslSocket::SslMode(mode));
+#else
+ Q_UNUSED(q);
+ Q_UNUSED(mode);
+ qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot encrypt UDP datagrams");
+ return nullptr;
+#endif // QT_CONFIG(dtls)
+}
+
QSsl::X509ChainVerifyPtr QTlsBackendOpenSSL::X509Verifier() const
{
return QSsl::X509CertificateOpenSSL::verify;
diff --git a/src/network/ssl/qtlsbackend_openssl_p.h b/src/network/ssl/qtlsbackend_openssl_p.h
index b3c2b733a5..8e2b8bdbde 100644
--- a/src/network/ssl/qtlsbackend_openssl_p.h
+++ b/src/network/ssl/qtlsbackend_openssl_p.h
@@ -80,6 +80,10 @@ private:
// QSslCertificate:
QSsl::X509Certificate *createCertificate() const override;
+
+ QSsl::DtlsCookieVerifier *createDtlsCookieVerifier() const override;
+ QSsl::DtlsCryptograph *createDtlsCryptograph(QDtls *q, int mode) const override;
+
QSsl::X509ChainVerifyPtr X509Verifier() const override;
QSsl::X509PemReaderPtr X509PemReader() const override;
QSsl::X509DerReaderPtr X509DerReader() const override;
diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h
index d91b3da548..5928dee2c7 100644
--- a/src/network/ssl/qtlsbackend_p.h
+++ b/src/network/ssl/qtlsbackend_p.h
@@ -53,8 +53,14 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include "qsslconfiguration.h"
+#include "qsslerror.h"
#include "qssl_p.h"
+#if QT_CONFIG(dtls)
+#include "qdtls.h"
+#endif
+
#include <QtNetwork/qsslcertificate.h>
#include <QtNetwork/qsslerror.h>
#include <QtNetwork/qsslkey.h>
@@ -72,7 +78,10 @@
QT_BEGIN_NAMESPACE
+class QHostAddress;
class QByteArray;
+class QSslCipher;
+class QUdpSocket;
class QIODevice;
class QSslKey;
@@ -183,11 +192,81 @@ using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertif
// TLS over TCP. Handshake, encryption/decryption.
class TlsCryptograph;
-// TLS over UDP. Handshake, encryption/decryption.
-class DtlsCryptograph;
+#if QT_CONFIG(dtls)
+
+class DtlsBase
+{
+public:
+ virtual ~DtlsBase();
+
+ virtual void setDtlsError(QDtlsError code, const QString &description) = 0;
+
+ virtual QDtlsError error() const = 0;
+ virtual QString errorString() const = 0;
+
+ virtual void clearDtlsError() = 0;
+
+ virtual void setConfiguration(const QSslConfiguration &configuration) = 0;
+ virtual QSslConfiguration configuration() const = 0;
+
+ using GenParams = QDtlsClientVerifier::GeneratorParameters;
+ virtual bool setCookieGeneratorParameters(const GenParams &params) = 0;
+ virtual GenParams cookieGeneratorParameters() const = 0;
+};
// DTLS cookie: generation and verification.
+class DtlsCookieVerifier : virtual public DtlsBase
+{
+public:
+ virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
+ const QHostAddress &address, quint16 port) = 0;
+ virtual QByteArray verifiedHello() const = 0;
+};
+
+// TLS over UDP. Handshake, encryption/decryption.
+class DtlsCryptograph : virtual public DtlsBase
+{
+public:
+
+ virtual QSslSocket::SslMode cryptographMode() const = 0;
+ virtual void setPeer(const QHostAddress &addr, quint16 port, const QString &name) = 0;
+ virtual QHostAddress peerAddress() const = 0;
+ virtual quint16 peerPort() const = 0;
+ virtual void setPeerVerificationName(const QString &name) = 0;
+ virtual QString peerVerificationName() const = 0;
+
+ virtual void setDtlsMtuHint(quint16 mtu) = 0;
+ virtual quint16 dtlsMtuHint() const = 0;
+
+ virtual QDtls::HandshakeState state() const = 0;
+ virtual bool isConnectionEncrypted() const = 0;
+
+ virtual bool startHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual bool handleTimeout(QUdpSocket *socket) = 0;
+ virtual bool continueHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual bool resumeHandshake(QUdpSocket *socket) = 0;
+ virtual void abortHandshake(QUdpSocket *socket) = 0;
+ virtual void sendShutdownAlert(QUdpSocket *socket) = 0;
+
+ virtual QList<QSslError> peerVerificationErrors() const = 0;
+ virtual void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) = 0;
+
+ virtual QSslCipher dtlsSessionCipher() const = 0;
+ virtual QSsl::SslProtocol dtlsSessionProtocol() const = 0;
+
+ virtual qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) = 0;
+};
+
+#else
+
class DtlsCookieVerifier;
+class DtlsCryptograph;
+
+#endif // QT_CONFIG(dtls)
+
+
+
} // namespace QSsl
@@ -213,7 +292,7 @@ public:
// TLS and DTLS:
virtual QSsl::TlsCryptograph *createTlsCryptograph() const;
- virtual QSsl::DtlsCryptograph *createDtlsCryptograph() const;
+ virtual QSsl::DtlsCryptograph *createDtlsCryptograph(class QDtls *qObject, int mode) const;
virtual QSsl::DtlsCookieVerifier *createDtlsCookieVerifier() const;
// TLSTODO - get rid of these function pointers, make them virtuals in