From 7c1aa0c48c995778cc52b98ce323db5cdb7898a9 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 25 Feb 2021 11:30:21 +0100 Subject: Convert QDtls classes to the new plugin-based design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Essentially, the same code re-shuffled and placed behind the new interfaces. Fixes: QTBUG-91174 Task-number: QTBUG-65922 Change-Id: I8f14697f10713f9738c5c7805aed0150c084850c Reviewed-by: Edward Welbourne Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit 6c835796c8ea2590008900ffb5f4bf0d902ee73d) Reviewed-by: Qt Cherry-pick Bot --- src/network/CMakeLists.txt | 1 + src/network/ssl/qdtls.cpp | 418 +++++++++++++++++++------------- src/network/ssl/qdtls_base.cpp | 137 +++++++++++ src/network/ssl/qdtls_base_p.h | 115 +++++++++ src/network/ssl/qdtls_openssl.cpp | 94 ++++++- src/network/ssl/qdtls_openssl_p.h | 47 +++- src/network/ssl/qdtls_p.h | 92 +------ src/network/ssl/qtlsbackend.cpp | 8 +- src/network/ssl/qtlsbackend_openssl.cpp | 26 ++ src/network/ssl/qtlsbackend_openssl_p.h | 4 + src/network/ssl/qtlsbackend_p.h | 85 ++++++- 11 files changed, 749 insertions(+), 278 deletions(-) create mode 100644 src/network/ssl/qdtls_base.cpp create mode 100644 src/network/ssl/qdtls_base_p.h (limited to 'src/network') diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index a260218a13..15e4c0763e 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 ¶ms) { 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 ¶ms) { 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 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 &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 ¶ms) +{ + 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 + +QT_REQUIRE_CONFIG(dtls); + +#include "qsslconfiguration_p.h" +#include "qtlsbackend_p.h" +#include "qsslcipher.h" +#include "qsslsocket.h" +#include "qssl.h" + +#include + +#include +#include +#include +#include + +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 QDtlsPrivateOpenSSL::peerVerificationErrors() const +{ + return tlsErrors; +} + +void QDtlsPrivateOpenSSL::ignoreVerificationErrors(const QList &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 +#include "qtlsbackend_openssl_p.h" +#include "qdtls_base_p.h" #include "qdtls_p.h" #include @@ -55,7 +57,6 @@ #include #include -#include #include #include @@ -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 peerVerificationErrors() const override; + void ignoreVerificationErrors(const QList &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 tlsErrors; + QList tlsErrorsToIgnore; + bool connectionEncrypted = false; // We will initialize it 'lazily', just in case somebody wants to move // QDtls to another thread. QScopedPointer 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 -#include "qdtls.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include +#include "qtlsbackend_p.h" +#include // // 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 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 tlsErrors; - QList tlsErrorsToIgnore; - - bool connectionEncrypted = false; + QDtlsPrivate(); + ~QDtlsPrivate(); + std::unique_ptr 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 +#include "qsslconfiguration.h" +#include "qsslerror.h" #include "qssl_p.h" +#if QT_CONFIG(dtls) +#include "qdtls.h" +#endif + #include #include #include @@ -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 ¶ms) = 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 peerVerificationErrors() const = 0; + virtual void ignoreVerificationErrors(const QList &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 -- cgit v1.2.3