summaryrefslogtreecommitdiffstats
path: root/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp')
-rw-r--r--tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp1309
1 files changed, 845 insertions, 464 deletions
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
index d5035c5266..b45d6b5d8f 100644
--- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
@@ -1,36 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
#include <QtCore/qglobal.h>
#include <QtCore/qthread.h>
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qrandom.h>
+#include <QtCore/qscopeguard.h>
#include <QtNetwork/qhostaddress.h>
#include <QtNetwork/qhostinfo.h>
#include <QtNetwork/qnetworkproxy.h>
@@ -40,24 +18,48 @@
#include <QtNetwork/qsslsocket.h>
#include <QtNetwork/qtcpserver.h>
#include <QtNetwork/qsslpresharedkeyauthenticator.h>
-#include <QtTest/QtTest>
+#include <QtTest/private/qemulationdetector_p.h>
+
+#include <QTest>
#include <QNetworkProxy>
#include <QAuthenticator>
+#include <QTestEventLoop>
+#include <QSignalSpy>
+#include <QSemaphore>
#include "private/qhostinfo_p.h"
#include "private/qiodevice_p.h" // for QIODEVICE_BUFFERSIZE
#include "../../../network-settings.h"
+#include "../shared/tlshelpers.h"
-#ifndef QT_NO_SSL
-#ifndef QT_NO_OPENSSL
-#include "private/qsslsocket_openssl_p.h"
-#include "private/qsslsocket_openssl_symbols_p.h"
+#if QT_CONFIG(openssl)
+#include "../shared/qopenssl_symbols.h"
#endif
+
+#include "private/qtlsbackend_p.h"
+
#include "private/qsslsocket_p.h"
#include "private/qsslconfiguration_p.h"
+using namespace std::chrono_literals;
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+// make these enum values available without causing deprecation warnings:
+namespace Test {
+#define COPY(tag, v) \
+ constexpr auto tag ## V ## v = QSsl:: tag ## V ## v ; \
+ constexpr auto tag ## V ## v ## OrLater = QSsl:: tag ## V ## v ## OrLater ; \
+ /* end */
+COPY(Tls, 1_0)
+COPY(Dtls, 1_0)
+COPY(Tls, 1_1)
+#undef COPY
+} // namespace Test
+QT_WARNING_POP
+
Q_DECLARE_METATYPE(QSslSocket::SslMode)
typedef QList<QSslError::SslError> SslErrorList;
Q_DECLARE_METATYPE(SslErrorList)
@@ -67,25 +69,6 @@ Q_DECLARE_METATYPE(QSsl::SslProtocol)
Q_DECLARE_METATYPE(QSslSocket::PeerVerifyMode);
typedef QSharedPointer<QSslSocket> QSslSocketPtr;
-// Non-OpenSSL backends are not able to report a specific error code
-// for self-signed certificates.
-#ifndef QT_NO_OPENSSL
-#define FLUKE_CERTIFICATE_ERROR QSslError::SelfSignedCertificate
-#else
-#define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted
-#endif
-#endif // QT_NO_OPENSSL
-
-// Detect ALPN (Application-Layer Protocol Negotiation) support
-#undef ALPN_SUPPORTED // Undef the variable first to be safe
-#if defined(OPENSSL_VERSION_NUMBER) && !defined(OPENSSL_NO_TLSEXT)
-#define ALPN_SUPPORTED 1
-#endif
-
-#if QT_CONFIG(schannel) && !defined(Q_CC_MINGW)
-#define ALPN_SUPPORTED 1
-#endif
-
#if defined Q_OS_HPUX && defined Q_CC_GNU
// This error is delivered every time we try to use the fluke CA
// certificate. For now we work around this bug. Task 202317.
@@ -95,19 +78,18 @@ typedef QSharedPointer<QSslSocket> QSslSocketPtr;
// Use this cipher to force PSK key sharing.
// Also, it's a cipher w/o auth, to check that we emit the signals warning
// about the identity of the peer.
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
static const QString PSK_CIPHER_WITHOUT_AUTH = QStringLiteral("PSK-AES256-CBC-SHA");
static const quint16 PSK_SERVER_PORT = 4433;
static const QByteArray PSK_CLIENT_PRESHAREDKEY = QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f");
static const QByteArray PSK_SERVER_IDENTITY_HINT = QByteArrayLiteral("QtTestServerHint");
static const QByteArray PSK_CLIENT_IDENTITY = QByteArrayLiteral("Client_identity");
+#endif // QT_CONFIG(openssl)
QT_BEGIN_NAMESPACE
void qt_ForceTlsSecurityLevel();
QT_END_NAMESPACE
-#endif // !QT_NO_OPENSSL
-
class tst_QSslSocket : public QObject
{
Q_OBJECT
@@ -128,10 +110,10 @@ public:
return QTestEventLoop::instance().timeout();
}
-#ifndef QT_NO_SSL
+#if QT_CONFIG(ssl)
QSslSocketPtr newSocket();
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
enum PskConnectTestType {
PskConnectDoNotHandlePsk,
PskConnectEmptyCredentials,
@@ -142,20 +124,22 @@ public:
PskConnectRightCredentialsVerifyPeer,
PskConnectRightCredentialsDoNotVerifyPeer,
};
-#endif
-#endif
+#endif // QT_CONFIG(openssl)
+#endif // QT_CONFIG(ssl)
public slots:
void initTestCase_data();
void initTestCase();
void init();
void cleanup();
-#ifndef QT_NO_NETWORKPROXY
+#if QT_CONFIG(networkproxy)
void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth);
#endif
-#ifndef QT_NO_SSL
+#if QT_CONFIG(ssl)
private slots:
+ void activeBackend();
+ void backends();
void constructing();
void configNoOnDemandLoad();
void simpleConnect();
@@ -164,34 +148,30 @@ private slots:
// API tests
void sslErrors_data();
void sslErrors();
- void addCaCertificate();
- void addCaCertificates();
- void addCaCertificates2();
void ciphers();
+#if QT_CONFIG(securetransport)
+ void tls13Ciphers();
+#endif // QT_CONFIG(securetransport)
void connectToHostEncrypted();
void connectToHostEncryptedWithVerificationPeerName();
void sessionCipher();
- void flush();
- void isEncrypted();
void localCertificate();
void mode();
void peerCertificate();
void peerCertificateChain();
void privateKey();
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
void privateKeyOpaque();
#endif
void protocol();
void protocolServerSide_data();
void protocolServerSide();
-#ifndef QT_NO_OPENSSL
void serverCipherPreferences();
-#endif // QT_NO_OPENSSL
void setCaCertificates();
void setLocalCertificate();
void localCertificateChain();
void setLocalCertificateChain();
- void setPrivateKey();
+ void tlsConfiguration();
void setSocketDescriptor();
void setSslConfiguration_data();
void setSslConfiguration();
@@ -218,9 +198,10 @@ private slots:
void waitForMinusOne();
void verifyMode();
void verifyDepth();
+ void verifyAndDefaultConfiguration();
void disconnectFromHostWhenConnecting();
void disconnectFromHostWhenConnected();
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
void closeWhileEmittingSocketError();
#endif
void resetProxy();
@@ -233,19 +214,16 @@ private slots:
void writeBigChunk();
void blacklistedCertificates();
void versionAccessors();
-#ifndef QT_NO_OPENSSL
- void sslOptions();
-#endif
void encryptWithoutConnecting();
void resume_data();
void resume();
void qtbug18498_peek();
void qtbug18498_peek2();
void dhServer();
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
void dhServerCustomParamsNull();
void dhServerCustomParams();
-#endif
+#endif // QT_CONFIG(openssl)
void ecdhServer();
void verifyClientCertificate_data();
void verifyClientCertificate();
@@ -253,7 +231,7 @@ private slots:
void allowedProtocolNegotiation();
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
void simplePskConnect_data();
void simplePskConnect();
void ephemeralServerKey_data();
@@ -262,7 +240,7 @@ private slots:
void forwardReadChannelFinished();
void signatureAlgorithm_data();
void signatureAlgorithm();
-#endif
+#endif // QT_CONFIG(openssl)
void unsupportedProtocols_data();
void unsupportedProtocols();
@@ -312,19 +290,48 @@ protected slots:
private:
QSslSocket *socket;
QList<QSslError> storedExpectedSslErrors;
-#endif // QT_NO_SSL
+ bool isTestingOpenSsl = false;
+ bool isSecurityLevel0Required = false;
+ bool opensslResolved = false;
+ bool isTestingSecureTransport = false;
+ bool isTestingSchannel = false;
+ QSslError::SslError flukeCertificateError = QSslError::CertificateUntrusted;
+ bool hasServerAlpn = false;
+#endif // QT_CONFIG(ssl)
private:
static int loopLevel;
public:
static QString testDataDir;
+
+ bool supportsTls13() const
+ {
+ if (isTestingOpenSsl) {
+#ifdef TLS1_3_VERSION
+ return true;
+#endif
+ }
+ if (isTestingSchannel) {
+ // Copied from qtls_schannel.cpp #supportsTls13()
+ static bool supported = []() {
+ const auto current = QOperatingSystemVersion::current();
+ const auto minimum =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221);
+ return current >= minimum;
+ }();
+ return supported;
+ }
+
+ return false;
+ }
+
};
QString tst_QSslSocket::testDataDir;
-#ifndef QT_NO_SSL
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(ssl)
+#if QT_CONFIG(openssl)
Q_DECLARE_METATYPE(tst_QSslSocket::PskConnectTestType)
-#endif
-#endif
+#endif // QT_CONFIG(openssl)
+#endif // QT_CONFIG(ssl)
int tst_QSslSocket::loopLevel = 0;
@@ -341,39 +348,22 @@ QString httpServerCertChainPath()
#endif // QT_TEST_SERVER
}
-bool supportsTls13()
-{
-#ifdef TLS1_3_VERSION
- return true;
-#elif QT_CONFIG(schannel)
- // Copied from qsslsocket_schannel.cpp #supportsTls13()
- static bool supported = []() {
- const auto current = QOperatingSystemVersion::current();
- const auto minimum =
- QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221);
- return current >= minimum;
- }();
- return supported;
-#else
- return false;
-#endif
-}
-
} // unnamed namespace
tst_QSslSocket::tst_QSslSocket()
{
-#ifndef QT_NO_SSL
+#if QT_CONFIG(ssl)
qRegisterMetaType<QList<QSslError> >("QList<QSslError>");
qRegisterMetaType<QSslError>("QSslError");
qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
qRegisterMetaType<QSslPreSharedKeyAuthenticator *>();
qRegisterMetaType<tst_QSslSocket::PskConnectTestType>();
-#endif
-#endif
+#endif // QT_CONFIG(openssl)
+
+#endif // QT_CONFIG(ssl)
}
enum ProxyTests {
@@ -410,7 +400,31 @@ void tst_QSslSocket::initTestCase()
testDataDir = QCoreApplication::applicationDirPath();
if (!testDataDir.endsWith(QLatin1String("/")))
testDataDir += QLatin1String("/");
-#ifndef QT_NO_SSL
+
+ hasServerAlpn = QSslSocket::supportedFeatures().contains(QSsl::SupportedFeature::ServerSideAlpn);
+ // Several plugins (TLS-backends) can co-exist. QSslSocket would implicitly
+ // select 'openssl' if available, and if not: 'securetransport' (Darwin) or
+ // 'schannel' (Windows). Check what we actually have:
+ const auto &tlsBackends = QSslSocket::availableBackends();
+ if (tlsBackends.contains(QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexOpenSSL])) {
+ isTestingOpenSsl = true;
+ flukeCertificateError = QSslError::SelfSignedCertificate;
+#if QT_CONFIG(openssl)
+ opensslResolved = qt_auto_test_resolve_OpenSSL_symbols();
+ // This is where OpenSSL moved several protocols under
+ // non-default (0) security level (the default is 1).
+ isSecurityLevel0Required = OPENSSL_VERSION_NUMBER >= 0x30100010;
+#else
+ opensslResolved = false; // Not 'unused variable' anymore.
+#endif
+ } else if (tlsBackends.contains(QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSchannel])) {
+ isTestingSchannel = true;
+ } else {
+ QVERIFY(tlsBackends.contains(QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSecureTransport]));
+ isTestingSecureTransport = true;
+ }
+
+#if QT_CONFIG(ssl)
qDebug("Using SSL library %s (%ld)",
qPrintable(QSslSocket::sslLibraryVersionString()),
QSslSocket::sslLibraryVersionNumber());
@@ -427,14 +441,14 @@ void tst_QSslSocket::initTestCase()
if (!QtNetworkSettings::verifyTestNetworkSettings())
QSKIP("No network test server available");
#endif // QT_TEST_SERVER
-#endif // QT_NO_SSL
+#endif // QT_CONFIG(ssl)
}
void tst_QSslSocket::init()
{
QFETCH_GLOBAL(bool, setProxy);
if (setProxy) {
-#ifndef QT_NO_NETWORKPROXY
+#if QT_CONFIG(networkproxy)
QFETCH_GLOBAL(int, proxyType);
const QString socksProxyAddr = QtNetworkSettings::socksProxyServerIp().toString();
const QString httpProxyAddr = QtNetworkSettings::httpProxyServerIp().toString();
@@ -462,26 +476,24 @@ void tst_QSslSocket::init()
break;
}
QNetworkProxy::setApplicationProxy(proxy);
-#else // !QT_NO_NETWORKPROXY
+#else
QSKIP("No proxy support");
-#endif // QT_NO_NETWORKPROXY
+#endif // QT_CONFIG(networkproxy)
}
-#ifndef QT_NO_OPENSSL
QT_PREPEND_NAMESPACE(qt_ForceTlsSecurityLevel)();
-#endif // QT_NO_OPENSSL
qt_qhostinfo_clear_cache();
}
void tst_QSslSocket::cleanup()
{
-#ifndef QT_NO_NETWORKPROXY
+#if QT_CONFIG(networkproxy)
QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
#endif
}
-#ifndef QT_NO_SSL
+#if QT_CONFIG(ssl)
QSslSocketPtr tst_QSslSocket::newSocket()
{
const auto socket = QSslSocketPtr::create();
@@ -493,18 +505,184 @@ QSslSocketPtr tst_QSslSocket::newSocket()
return socket;
}
-#endif
+#endif // QT_CONFIG(ssl)
-#ifndef QT_NO_NETWORKPROXY
+#if QT_CONFIG(networkproxy)
void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
{
++proxyAuthCalled;
auth->setUser("qsockstest");
auth->setPassword("password");
}
-#endif // !QT_NO_NETWORKPROXY
+#endif // QT_CONFIG(networkproxy)
+
+#if QT_CONFIG(ssl)
-#ifndef QT_NO_SSL
+void tst_QSslSocket::activeBackend()
+{
+ QFETCH_GLOBAL(const bool, setProxy);
+ if (setProxy) // Not interesting for backend test.
+ return;
+
+ // We cannot set non-existing as active:
+ const QString nonExistingBackend = QStringLiteral("TheQtTLS");
+ QCOMPARE(QSslSocket::setActiveBackend(nonExistingBackend), false);
+ QCOMPARE(QSslSocket::supportedProtocols(nonExistingBackend).size(), 0);
+ QCOMPARE(QSslSocket::supportedFeatures(nonExistingBackend), QList<QSsl::SupportedFeature>());
+ QCOMPARE(QSslSocket::implementedClasses(nonExistingBackend), QList<QSsl::ImplementedClass>());
+
+ const QString backendName = QSslSocket::activeBackend();
+ // Implemented by all our existing backends:
+ const auto implemented = QSsl::ImplementedClass::Socket;
+ const auto supportedFt = QSsl::SupportedFeature::ClientSideAlpn;
+
+ QVERIFY(QSslSocket::availableBackends().contains(backendName));
+ QCOMPARE(QSslSocket::setActiveBackend(backendName), true);
+ QCOMPARE(QSslSocket::activeBackend(), backendName);
+ QCOMPARE(QSslSocket::setActiveBackend(backendName), true); // We can do it again.
+ QCOMPARE(QSslSocket::activeBackend(), backendName);
+
+ const auto protocols = QSslSocket::supportedProtocols();
+ QVERIFY(protocols.size() > 0);
+ // 'Any' and 'Secure', since they are always present:
+ QVERIFY(protocols.contains(QSsl::AnyProtocol));
+ QVERIFY(protocols.contains(QSsl::SecureProtocols));
+
+ const auto protocolsForNamed = QSslSocket::supportedProtocols(backendName);
+ QCOMPARE(protocols, protocolsForNamed);
+ // Any and secure, new versions are coming, old
+ // go away, nothing more specific.
+ QVERIFY(protocolsForNamed.contains(QSsl::AnyProtocol));
+ QVERIFY(protocolsForNamed.contains(QSsl::SecureProtocols));
+ QCOMPARE(QSslSocket::isProtocolSupported(QSsl::SecureProtocols), true);
+ QCOMPARE(QSslSocket::isProtocolSupported(QSsl::SecureProtocols, backendName), true);
+
+ const auto classes = QSslSocket::implementedClasses();
+ QVERIFY(classes.contains(implemented));
+ QVERIFY(QSslSocket::isClassImplemented(implemented));
+ QVERIFY(QSslSocket::isClassImplemented(implemented, backendName));
+
+ const auto features = QSslSocket::supportedFeatures();
+ QVERIFY(features.contains(QSsl::SupportedFeature(supportedFt)));
+ QVERIFY(QSslSocket::isFeatureSupported(QSsl::SupportedFeature(supportedFt)));
+ QVERIFY(QSslSocket::isFeatureSupported(QSsl::SupportedFeature(supportedFt), backendName));
+}
+
+namespace {
+struct MockTlsBackend : QTlsBackend
+{
+ MockTlsBackend(const QString &mockName) : name(mockName)
+ {
+ }
+ QString backendName() const override
+ {
+ return name;
+ }
+
+ QList<QSsl::SupportedFeature> supportedFeatures() const override
+ {
+ return features;
+ }
+ QList<QSsl::SslProtocol> supportedProtocols() const override
+ {
+ return protocols;
+ }
+ QList<QSsl::ImplementedClass> implementedClasses() const override
+ {
+ return classes;
+ }
+
+ QString name;
+ QList<QSsl::ImplementedClass> classes;
+ QList<QSsl::SupportedFeature> features;
+ QList<QSsl::SslProtocol> protocols;
+};
+
+} // Unnamed backend.
+
+void tst_QSslSocket::backends()
+{
+ QFETCH_GLOBAL(const bool, setProxy);
+ if (setProxy) // Not interesting for backend test.
+ return;
+
+ // We are here, protected by QT_CONFIG(ssl). Some backend must be pre-existing.
+ // Let's test the 'real' backend:
+ auto backendNames = QTlsBackend::availableBackendNames();
+ const auto sizeBefore = backendNames.size();
+ QVERIFY(sizeBefore > 0);
+
+ const QString tlsBackend = QSslSocket::activeBackend();
+ QVERIFY(tlsBackend == QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexOpenSSL]
+ || tlsBackend == QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSchannel]
+ || tlsBackend == QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSecureTransport]);
+
+ const auto builtinProtocols = QSslSocket::supportedProtocols(tlsBackend);
+ QVERIFY(builtinProtocols.contains(QSsl::SecureProtocols));
+ // Socket and ALPN are supported by all our backends:
+ const auto builtinClasses = QSslSocket::implementedClasses(tlsBackend);
+ QVERIFY(builtinClasses.contains(QSsl::ImplementedClass::Socket));
+ const auto builtinFeatures = QSslSocket::supportedFeatures(tlsBackend);
+ QVERIFY(builtinFeatures.contains(QSsl::SupportedFeature::ClientSideAlpn));
+
+ // Verify that non-dummy backend can be found:
+ auto *systemBackend = QTlsBackend::findBackend(tlsBackend);
+ QVERIFY(systemBackend);
+
+ const auto protocols = QList<QSsl::SslProtocol>{QSsl::SecureProtocols};
+ const auto classes = QList<QSsl::ImplementedClass>{QSsl::ImplementedClass::Socket};
+ const auto features = QList<QSsl::SupportedFeature>{QSsl::SupportedFeature::CertificateVerification};
+
+ const QString nameA = QStringLiteral("backend A");
+ const QString nameB = QStringLiteral("backend B");
+ const QString nonExisting = QStringLiteral("non-existing backend");
+
+ QVERIFY(!backendNames.contains(nameA));
+ QVERIFY(!backendNames.contains(nameB));
+ QVERIFY(!backendNames.contains(nonExisting));
+ {
+ MockTlsBackend factoryA(nameA);
+ backendNames = QTlsBackend::availableBackendNames();
+ QVERIFY(backendNames.contains(nameA));
+ QVERIFY(!backendNames.contains(nameB));
+ QVERIFY(!backendNames.contains(nonExisting));
+
+ const auto *backendA = QTlsBackend::findBackend(nameA);
+ QVERIFY(backendA);
+ QCOMPARE(backendA->backendName(), nameA);
+
+ QCOMPARE(factoryA.supportedFeatures().size(), 0);
+ QCOMPARE(factoryA.supportedProtocols().size(), 0);
+ QCOMPARE(factoryA.implementedClasses().size(), 0);
+
+ factoryA.protocols = protocols;
+ factoryA.classes = classes;
+ factoryA.features = features;
+
+ // It's an overrider in some re-implemented factory:
+ QCOMPARE(factoryA.supportedProtocols(), protocols);
+ QCOMPARE(factoryA.supportedFeatures(), features);
+ QCOMPARE(factoryA.implementedClasses(), classes);
+
+ // That's a helper function (static member function):
+ QCOMPARE(QTlsBackend::supportedProtocols(nameA), protocols);
+ QCOMPARE(QTlsBackend::supportedFeatures(nameA), features);
+ QCOMPARE(QTlsBackend::implementedClasses(nameA), classes);
+
+ MockTlsBackend factoryB(nameB);
+ QVERIFY(QTlsBackend::availableBackendNames().contains(nameA));
+ QVERIFY(QTlsBackend::availableBackendNames().contains(nameB));
+ QVERIFY(!QTlsBackend::availableBackendNames().contains(nonExisting));
+
+ const auto *nullBackend = QTlsBackend::findBackend(nonExisting);
+ QCOMPARE(nullBackend, nullptr);
+ }
+ backendNames = QTlsBackend::availableBackendNames();
+ QCOMPARE(backendNames.size(), sizeBefore);
+ // Check we cleaned up our factories:
+ QVERIFY(!backendNames.contains(nameA));
+ QVERIFY(!backendNames.contains(nameB));
+}
void tst_QSslSocket::constructing()
{
@@ -536,7 +714,7 @@ void tst_QSslSocket::constructing()
QVERIFY(!socket.isTextModeEnabled());
QVERIFY(!socket.isWritable());
QCOMPARE(socket.openMode(), QIODevice::NotOpen);
- QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage);
+ QTest::ignoreMessage(QtWarningMsg, "QIODevice::peek (QSslSocket): device not open");
QVERIFY(socket.peek(2).isEmpty());
QCOMPARE(socket.pos(), qint64(0));
QTest::ignoreMessage(QtWarningMsg, writeNotOpenMessage);
@@ -547,8 +725,7 @@ void tst_QSslSocket::constructing()
QCOMPARE(socket.read(0, 0), qint64(-1));
QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage);
QVERIFY(socket.readAll().isEmpty());
- QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine (QSslSocket): Called with maxSize < 2");
- QCOMPARE(socket.readLine(0, 0), qint64(-1));
+ QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine (QSslSocket): device not open");
char buf[10];
QCOMPARE(socket.readLine(buf, sizeof(buf)), qint64(-1));
QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device");
@@ -570,7 +747,7 @@ void tst_QSslSocket::constructing()
QCOMPARE(socket.peerAddress(), QHostAddress());
QVERIFY(socket.peerName().isEmpty());
QCOMPARE(socket.peerPort(), quint16(0));
-#ifndef QT_NO_NETWORKPROXY
+#if QT_CONFIG(networkproxy)
QCOMPARE(socket.proxy().type(), QNetworkProxy::DefaultProxy);
#endif
QCOMPARE(socket.readBufferSize(), qint64(0));
@@ -621,16 +798,32 @@ void tst_QSslSocket::configNoOnDemandLoad()
QCOMPARE(customConfig, socket.sslConfiguration());
}
+static void downgrade_TLS_QTQAINFRA_4499(QSslSocket &socket)
+{
+ // Set TLS 1.0 or above because the server doesn't support TLS 1.2 or above
+ // QTQAINFRA-4499
+ QSslConfiguration config = socket.sslConfiguration();
+ config.setProtocol(Test::TlsV1_0OrLater);
+ socket.setSslConfiguration(config);
+}
+
void tst_QSslSocket::simpleConnect()
{
if (!QSslSocket::supportsSsl())
return;
+ // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use when connecting) are not available by default.
+ if (isSecurityLevel0Required)
+ QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier");
+
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
QSslSocket socket;
+
+ downgrade_TLS_QTQAINFRA_4499(socket);
+
QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
QSignalSpy hostFoundSpy(&socket, SIGNAL(hostFound()));
QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected()));
@@ -651,30 +844,30 @@ void tst_QSslSocket::simpleConnect()
// Entered connecting state
QCOMPARE(socket.state(), QAbstractSocket::ConnectingState);
- QCOMPARE(connectedSpy.count(), 0);
- QCOMPARE(hostFoundSpy.count(), 1);
- QCOMPARE(disconnectedSpy.count(), 0);
+ QCOMPARE(connectedSpy.size(), 0);
+ QCOMPARE(hostFoundSpy.size(), 1);
+ QCOMPARE(disconnectedSpy.size(), 0);
enterLoop(10);
// Entered connected state
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
QVERIFY(!socket.isEncrypted());
- QCOMPARE(connectedSpy.count(), 1);
- QCOMPARE(hostFoundSpy.count(), 1);
- QCOMPARE(disconnectedSpy.count(), 0);
+ QCOMPARE(connectedSpy.size(), 1);
+ QCOMPARE(hostFoundSpy.size(), 1);
+ QCOMPARE(disconnectedSpy.size(), 0);
// Enter encrypted mode
socket.startClientEncryption();
QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
QVERIFY(!socket.isEncrypted());
- QCOMPARE(connectionEncryptedSpy.count(), 0);
- QCOMPARE(sslErrorsSpy.count(), 0);
+ QCOMPARE(connectionEncryptedSpy.size(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 0);
// Starting handshake
enterLoop(10);
- QCOMPARE(sslErrorsSpy.count(), 1);
- QCOMPARE(connectionEncryptedSpy.count(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 1);
+ QCOMPARE(connectionEncryptedSpy.size(), 0);
QVERIFY(!socket.isEncrypted());
QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
}
@@ -684,6 +877,10 @@ void tst_QSslSocket::simpleConnectWithIgnore()
if (!QSslSocket::supportsSsl())
return;
+ // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use when connecting) are not available by default.
+ if (isSecurityLevel0Required)
+ QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier");
+
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
@@ -693,6 +890,8 @@ void tst_QSslSocket::simpleConnectWithIgnore()
QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted()));
QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(QList<QSslError>)));
+ downgrade_TLS_QTQAINFRA_4499(socket);
+
connect(&socket, SIGNAL(readyRead()), this, SLOT(exitLoop()));
connect(&socket, SIGNAL(encrypted()), this, SLOT(exitLoop()));
connect(&socket, SIGNAL(connected()), this, SLOT(exitLoop()));
@@ -710,10 +909,10 @@ void tst_QSslSocket::simpleConnectWithIgnore()
enterLoop(10);
// Done; encryption should be enabled.
- QCOMPARE(sslErrorsSpy.count(), 1);
+ QCOMPARE(sslErrorsSpy.size(), 1);
QVERIFY(socket.isEncrypted());
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
- QCOMPARE(encryptedSpy.count(), 1);
+ QCOMPARE(encryptedSpy.size(), 1);
// Wait for incoming data
if (!socket.canReadLine())
@@ -726,6 +925,10 @@ void tst_QSslSocket::simpleConnectWithIgnore()
void tst_QSslSocket::sslErrors_data()
{
+ // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use in 'sslErrors' test) are not available by default.
+ if (isSecurityLevel0Required)
+ QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier");
+
QTest::addColumn<QString>("host");
QTest::addColumn<int>("port");
@@ -742,10 +945,10 @@ void tst_QSslSocket::sslErrors()
QFETCH(int, port);
QSslSocketPtr socket = newSocket();
-#if QT_CONFIG(schannel)
- // Needs to be < 1.2 because of the old certificate and <= 1.0 because of the mail server
- socket->setProtocol(QSsl::SslProtocol::TlsV1_0);
-#endif
+
+ QVERIFY(socket);
+ downgrade_TLS_QTQAINFRA_4499(*socket);
+
QSignalSpy sslErrorsSpy(socket.data(), SIGNAL(sslErrors(QList<QSslError>)));
QSignalSpy peerVerifyErrorSpy(socket.data(), SIGNAL(peerVerifyError(QSslError)));
@@ -775,12 +978,15 @@ void tst_QSslSocket::sslErrors()
sslErrors << err.error();
std::sort(sslErrors.begin(), sslErrors.end());
QVERIFY(sslErrors.contains(QSslError::HostNameMismatch));
- QVERIFY(sslErrors.contains(FLUKE_CERTIFICATE_ERROR));
+
+ // Non-OpenSSL backends are not able to report a specific error code
+ // for self-signed certificates.
+ QVERIFY(sslErrors.contains(flukeCertificateError));
// check the same errors were emitted by sslErrors
QVERIFY(!sslErrorsSpy.isEmpty());
SslErrorList emittedErrors;
- const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(qAsConst(sslErrorsSpy).first().first());
+ const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(std::as_const(sslErrorsSpy).first().first());
for (const QSslError &err : sslErrorsSpyErrors)
emittedErrors << err.error();
std::sort(emittedErrors.begin(), emittedErrors.end());
@@ -796,28 +1002,17 @@ void tst_QSslSocket::sslErrors()
QCOMPARE(sslErrors, peerErrors);
}
-void tst_QSslSocket::addCaCertificate()
-{
- if (!QSslSocket::supportsSsl())
- return;
-}
-
-void tst_QSslSocket::addCaCertificates()
-{
- if (!QSslSocket::supportsSsl())
- return;
-}
-
-void tst_QSslSocket::addCaCertificates2()
+void tst_QSslSocket::ciphers()
{
if (!QSslSocket::supportsSsl())
return;
-}
-void tst_QSslSocket::ciphers()
-{
- if (!QSslSocket::supportsSsl())
+ QFETCH_GLOBAL(const bool, setProxy);
+ if (setProxy) {
+ // KISS(mart), we don't connect, no need to test the same thing
+ // many times!
return;
+ }
QSslSocket socket;
QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers());
@@ -840,7 +1035,7 @@ void tst_QSslSocket::ciphers()
QString ciphersAsString;
const auto &supported = sslConfig.supportedCiphers();
for (const auto &cipher : supported) {
- if (cipher.isNull() || !cipher.name().length())
+ if (cipher.isNull() || !cipher.name().size())
continue;
if (ciphers.size() > 0)
ciphersAsString += QStringLiteral(":");
@@ -853,17 +1048,65 @@ void tst_QSslSocket::ciphers()
if (!ciphers.size())
QSKIP("No proper ciphersuite was found to test 'setCiphers'");
-#if QT_CONFIG(schannel)
- qWarning("Schannel doesn't support setting ciphers from a cipher-string.");
-#else
- sslConfig.setCiphers(ciphersAsString);
- socket.setSslConfiguration(sslConfig);
- QCOMPARE(ciphers, socket.sslConfiguration().ciphers());
-#endif
+
+ if (isTestingSchannel) {
+ qWarning("Schannel doesn't support setting ciphers from a cipher-string.");
+ } else {
+ sslConfig.setCiphers(ciphersAsString);
+ socket.setSslConfiguration(sslConfig);
+ QCOMPARE(ciphers, socket.sslConfiguration().ciphers());
+ }
+
sslConfig.setCiphers(ciphers);
socket.setSslConfiguration(sslConfig);
QCOMPARE(ciphers, socket.sslConfiguration().ciphers());
+
+ if (isTestingOpenSsl) {
+ for (const auto &cipher : ciphers) {
+ if (cipher.name().size() && cipher.protocol() != QSsl::UnknownProtocol) {
+ const QSslCipher aCopy(cipher.name(), cipher.protocol());
+ QCOMPARE(aCopy, cipher);
+ break;
+ }
+ }
+ }
+}
+
+#if QT_CONFIG(securetransport)
+void tst_QSslSocket::tls13Ciphers()
+{
+ // SecureTransport introduced several new ciphers under
+ // "TLS 1.3 ciphersuites" section. Since Qt 6 we respect
+ // the ciphers from QSslConfiguration. In case of default
+ // configuration, these are the same we report and we
+ // were failing (for historical reasons) to report those
+ // TLS 1.3 suites when creating default QSslConfiguration.
+ // Check we now have them.
+ if (!isTestingSecureTransport)
+ QSKIP("The feature 'securetransport' was enabled, but active backend is not \"securetransport\"");
+
+ QFETCH_GLOBAL(const bool, setProxy);
+ if (setProxy)
+ return;
+
+ const auto suites = QSslConfiguration::defaultConfiguration().ciphers();
+ QSslCipher ciph;
+ // Check the one of reported and previously missed:
+ for (const auto &suite : suites) {
+ if (suite.encryptionMethod() == QStringLiteral("CHACHA20")) {
+ // There are several ciphesuites using CHACHA20, the first one
+ // is sufficient for the purpose of this test:
+ ciph = suite;
+ break;
+ }
+ }
+
+ QVERIFY(!ciph.isNull());
+ QCOMPARE(ciph.encryptionMethod(), QStringLiteral("CHACHA20"));
+ QCOMPARE(ciph.supportedBits(), 256);
+ QCOMPARE(ciph.usedBits(), 256);
}
+#endif // QT_CONFIG(securetransport)
void tst_QSslSocket::connectToHostEncrypted()
{
@@ -871,9 +1114,7 @@ void tst_QSslSocket::connectToHostEncrypted()
return;
QSslSocketPtr socket = newSocket();
-#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
- socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
-#endif
+
this->socket = socket.data();
auto config = socket->sslConfiguration();
QVERIFY(config.addCaCertificates(httpServerCertChainPath()));
@@ -893,6 +1134,7 @@ void tst_QSslSocket::connectToHostEncrypted()
socket->disconnectFromHost();
QVERIFY(socket->waitForDisconnected());
+ QVERIFY(!socket->isEncrypted());
QCOMPARE(socket->mode(), QSslSocket::SslClientMode);
@@ -909,9 +1151,7 @@ void tst_QSslSocket::connectToHostEncryptedWithVerificationPeerName()
return;
QSslSocketPtr socket = newSocket();
-#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
- socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
-#endif
+
this->socket = socket.data();
auto config = socket->sslConfiguration();
@@ -966,14 +1206,6 @@ void tst_QSslSocket::sessionCipher()
QVERIFY(socket->waitForDisconnected());
}
-void tst_QSslSocket::flush()
-{
-}
-
-void tst_QSslSocket::isEncrypted()
-{
-}
-
void tst_QSslSocket::localCertificate()
{
if (!QSslSocket::supportsSsl())
@@ -1017,7 +1249,7 @@ void tst_QSslSocket::peerCertificateChain()
QSslSocketPtr socket = newSocket();
this->socket = socket.data();
QList<QSslCertificate> caCertificates = QSslCertificate::fromPath(httpServerCertChainPath());
- QCOMPARE(caCertificates.count(), 1);
+ QCOMPARE(caCertificates.size(), 1);
auto config = socket->sslConfiguration();
config.addCaCertificates(caCertificates);
socket->setSslConfiguration(config);
@@ -1034,7 +1266,7 @@ void tst_QSslSocket::peerCertificateChain()
QSKIP("Skipping flaky test - See QTBUG-29941");
QList<QSslCertificate> certChain = socket->peerCertificateChain();
- QVERIFY(certChain.count() > 0);
+ QVERIFY(certChain.size() > 0);
QCOMPARE(certChain.first(), socket->peerCertificate());
socket->disconnectFromHost();
@@ -1075,11 +1307,15 @@ void tst_QSslSocket::privateKey()
{
}
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
void tst_QSslSocket::privateKeyOpaque()
{
- if (!QSslSocket::supportsSsl())
- return;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS backend does not support private opaque keys");
+
+ if (!opensslResolved)
+ QSKIP("Failed to resolve OpenSSL symbols, required by this test");
QFile file(testDataDir + "certs/fluke.key");
QVERIFY(file.open(QIODevice::ReadOnly));
@@ -1108,8 +1344,9 @@ void tst_QSslSocket::privateKeyOpaque()
QFETCH_GLOBAL(bool, setProxy);
if (setProxy && !socket->waitForEncrypted(10000))
QSKIP("Skipping flaky test - See QTBUG-29941");
+#endif // OPENSSL_NO_DEPRECATED_3_0
}
-#endif
+#endif // Feature 'openssl'.
void tst_QSslSocket::protocol()
{
@@ -1133,38 +1370,38 @@ void tst_QSslSocket::protocol()
QFETCH_GLOBAL(bool, setProxy);
{
// qt-test-server allows TLSV1.
- socket->setProtocol(QSsl::TlsV1_0);
- QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
+ socket->setProtocol(Test::TlsV1_0);
+ QCOMPARE(socket->protocol(), Test::TlsV1_0);
socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443);
if (setProxy && !socket->waitForEncrypted())
QSKIP("Skipping flaky test - See QTBUG-29941");
- QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
+ QCOMPARE(socket->protocol(), Test::TlsV1_0);
socket->abort();
- QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
+ QCOMPARE(socket->protocol(), Test::TlsV1_0);
socket->connectToHost(QtNetworkSettings::httpServerName(), 443);
QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
socket->startClientEncryption();
if (setProxy && !socket->waitForEncrypted())
QSKIP("Skipping flaky test - See QTBUG-29941");
- QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
+ QCOMPARE(socket->protocol(), Test::TlsV1_0);
socket->abort();
}
{
// qt-test-server probably doesn't allow TLSV1.1
- socket->setProtocol(QSsl::TlsV1_1);
- QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+ socket->setProtocol(Test::TlsV1_1);
+ QCOMPARE(socket->protocol(), Test::TlsV1_1);
socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443);
if (setProxy && !socket->waitForEncrypted())
QSKIP("Skipping flaky test - See QTBUG-29941");
- QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+ QCOMPARE(socket->protocol(), Test::TlsV1_1);
socket->abort();
- QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+ QCOMPARE(socket->protocol(), Test::TlsV1_1);
socket->connectToHost(QtNetworkSettings::httpServerName(), 443);
QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
socket->startClientEncryption();
if (setProxy && !socket->waitForEncrypted())
QSKIP("Skipping flaky test - See QTBUG-29941");
- QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+ QCOMPARE(socket->protocol(), Test::TlsV1_1);
socket->abort();
}
{
@@ -1235,7 +1472,7 @@ public:
config(QSslConfiguration::defaultConfiguration()),
ignoreSslErrors(true),
peerVerifyMode(QSslSocket::AutoVerifyPeer),
- protocol(QSsl::TlsV1_0),
+ protocol(QSsl::SecureProtocols),
m_keyFile(keyFile),
m_certFile(certFile),
m_interFile(interFile)
@@ -1257,6 +1494,7 @@ signals:
void handshakeInterruptedOnError(const QSslError& rrror);
void gotAlert(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message);
void alertSent(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message);
+ void socketEncrypted(QSslSocket *);
protected:
void incomingConnection(qintptr socketDescriptor) override
@@ -1274,6 +1512,7 @@ protected:
connect(socket, &QSslSocket::alertReceived, this, &SslServer::gotAlert);
connect(socket, &QSslSocket::alertSent, this, &SslServer::alertSent);
connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired, this, &SslServer::preSharedKeyAuthenticationRequired);
+ connect(socket, &QSslSocket::encrypted, this, [this](){ emit socketEncrypted(socket); });
QFile file(m_keyFile);
QVERIFY(file.open(QIODevice::ReadOnly));
@@ -1338,41 +1577,34 @@ void tst_QSslSocket::protocolServerSide_data()
QTest::addColumn<QSsl::SslProtocol>("clientProtocol");
QTest::addColumn<bool>("works");
- QTest::newRow("tls1.0-tls1.0") << QSsl::TlsV1_0 << QSsl::TlsV1_0 << true;
QTest::newRow("any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true;
QTest::newRow("secure-secure") << QSsl::SecureProtocols << QSsl::SecureProtocols << true;
- QTest::newRow("tls1.0-secure") << QSsl::TlsV1_0 << QSsl::SecureProtocols << true;
- QTest::newRow("tls1.0-any") << QSsl::TlsV1_0 << QSsl::AnyProtocol << true;
-
- QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << QSsl::TlsV1_0 << true;
+ QTest::newRow("tls1.0-secure") << Test::TlsV1_0 << QSsl::SecureProtocols << false;
+ QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << Test::TlsV1_0 << false;
QTest::newRow("secure-any") << QSsl::SecureProtocols << QSsl::AnyProtocol << true;
- QTest::newRow("tls1.0orlater-tls1.0") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_0 << true;
- QTest::newRow("tls1.0orlater-tls1.1") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_1 << true;
- QTest::newRow("tls1.0orlater-tls1.2") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_2 << true;
+ QTest::newRow("tls1.0orlater-tls1.2") << Test::TlsV1_0OrLater << QSsl::TlsV1_2 << true;
if (supportsTls13())
- QTest::newRow("tls1.0orlater-tls1.3") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_3 << true;
+ QTest::newRow("tls1.0orlater-tls1.3") << Test::TlsV1_0OrLater << QSsl::TlsV1_3 << true;
- QTest::newRow("tls1.1orlater-tls1.0") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_0 << false;
- QTest::newRow("tls1.1orlater-tls1.1") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_1 << true;
- QTest::newRow("tls1.1orlater-tls1.2") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_2 << true;
+ QTest::newRow("tls1.1orlater-tls1.0") << Test::TlsV1_1OrLater << Test::TlsV1_0 << false;
+ QTest::newRow("tls1.1orlater-tls1.2") << Test::TlsV1_1OrLater << QSsl::TlsV1_2 << true;
if (supportsTls13())
- QTest::newRow("tls1.1orlater-tls1.3") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_3 << true;
+ QTest::newRow("tls1.1orlater-tls1.3") << Test::TlsV1_1OrLater << QSsl::TlsV1_3 << true;
- QTest::newRow("tls1.2orlater-tls1.0") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_0 << false;
- QTest::newRow("tls1.2orlater-tls1.1") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_1 << false;
+ QTest::newRow("tls1.2orlater-tls1.0") << QSsl::TlsV1_2OrLater << Test::TlsV1_0 << false;
+ QTest::newRow("tls1.2orlater-tls1.1") << QSsl::TlsV1_2OrLater << Test::TlsV1_1 << false;
QTest::newRow("tls1.2orlater-tls1.2") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_2 << true;
if (supportsTls13()) {
QTest::newRow("tls1.2orlater-tls1.3") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_3 << true;
- QTest::newRow("tls1.3orlater-tls1.0") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_0 << false;
- QTest::newRow("tls1.3orlater-tls1.1") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_1 << false;
+ QTest::newRow("tls1.3orlater-tls1.0") << QSsl::TlsV1_3OrLater << Test::TlsV1_0 << false;
+ QTest::newRow("tls1.3orlater-tls1.1") << QSsl::TlsV1_3OrLater << Test::TlsV1_1 << false;
QTest::newRow("tls1.3orlater-tls1.2") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_2 << false;
QTest::newRow("tls1.3orlater-tls1.3") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_3 << true;
}
- QTest::newRow("any-tls1.0") << QSsl::AnyProtocol << QSsl::TlsV1_0 << true;
QTest::newRow("any-secure") << QSsl::AnyProtocol << QSsl::SecureProtocols << true;
}
@@ -1429,23 +1661,37 @@ void tst_QSslSocket::protocolServerSide()
QCOMPARE(client.isEncrypted(), works);
}
-#ifndef QT_NO_OPENSSL
-
void tst_QSslSocket::serverCipherPreferences()
{
- if (!QSslSocket::supportsSsl()) {
- qWarning("SSL not supported, skipping test");
- return;
- }
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS backend does not support server-side cipher preferences");
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
- // First using the default (server preference)
+ QSslCipher testedCiphers[2];
{
+ // First using the default (server preference)
+ const auto supportedCiphers = QSslConfiguration::supportedCiphers();
+ int nSet = 0;
+ for (const auto &cipher : supportedCiphers) {
+ // Ciphersuites from TLS 1.2 and 1.3 are set separately,
+ // let's select 1.3 or above explicitly.
+ if (cipher.protocol() < QSsl::TlsV1_3)
+ continue;
+
+ testedCiphers[nSet++] = cipher;
+ if (nSet == 2)
+ break;
+ }
+
+ if (nSet != 2)
+ QSKIP("Failed to find two proper ciphersuites to test, bailing out.");
+
SslServer server;
- server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")};
+ server.protocol = QSsl::TlsV1_2OrLater;
+ server.ciphers = {testedCiphers[0], testedCiphers[1]};
QVERIFY(server.listen());
QEventLoop loop;
@@ -1455,7 +1701,8 @@ void tst_QSslSocket::serverCipherPreferences()
socket = &client;
auto sslConfig = socket->sslConfiguration();
- sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")});
+ sslConfig.setProtocol(QSsl::TlsV1_2OrLater);
+ sslConfig.setCiphers({testedCiphers[1], testedCiphers[0]});
socket->setSslConfiguration(sslConfig);
// upon SSL wrong version error, errorOccurred will be triggered, not sslErrors
@@ -1468,16 +1715,19 @@ void tst_QSslSocket::serverCipherPreferences()
loop.exec();
QVERIFY(client.isEncrypted());
- QCOMPARE(client.sessionCipher().name(), QString("AES128-SHA"));
+ QCOMPARE(client.sessionCipher().name(), testedCiphers[0].name());
}
{
+ if (QTestPrivate::isRunningArmOnX86())
+ QSKIP("This test is known to crash on QEMU emulation for no good reason.");
// Now using the client preferences
SslServer server;
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setSslOption(QSsl::SslOptionDisableServerCipherPreference, true);
server.config = config;
- server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")};
+ server.protocol = QSsl::TlsV1_2OrLater;
+ server.ciphers = {testedCiphers[0], testedCiphers[1]};
QVERIFY(server.listen());
QEventLoop loop;
@@ -1487,7 +1737,8 @@ void tst_QSslSocket::serverCipherPreferences()
socket = &client;
auto sslConfig = socket->sslConfiguration();
- sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")});
+ sslConfig.setProtocol(QSsl::TlsV1_2OrLater);
+ sslConfig.setCiphers({testedCiphers[1], testedCiphers[0]});
socket->setSslConfiguration(sslConfig);
// upon SSL wrong version error, errorOccurred will be triggered, not sslErrors
@@ -1500,12 +1751,10 @@ void tst_QSslSocket::serverCipherPreferences()
loop.exec();
QVERIFY(client.isEncrypted());
- QCOMPARE(client.sessionCipher().name(), QString("AES256-SHA"));
+ QCOMPARE(client.sessionCipher().name(), testedCiphers[1].name());
}
}
-#endif // QT_NO_OPENSSL
-
void tst_QSslSocket::setCaCertificates()
{
@@ -1575,18 +1824,46 @@ void tst_QSslSocket::setLocalCertificateChain()
loop.exec();
QList<QSslCertificate> chain = socket->peerCertificateChain();
-#if QT_CONFIG(schannel)
- QEXPECT_FAIL("", "Schannel cannot send intermediate certificates not "
- "located in a system certificate store",
- Abort);
-#endif
+ if (isTestingSchannel) {
+ QEXPECT_FAIL("", "Schannel cannot send intermediate certificates not "
+ "located in a system certificate store",
+ Abort);
+ }
+
QCOMPARE(chain.size(), 2);
- QCOMPARE(chain[0].serialNumber(), QByteArray("10:a0:ad:77:58:f6:6e:ae:46:93:a3:43:f9:59:8a:9e"));
- QCOMPARE(chain[1].serialNumber(), QByteArray("3b:eb:99:c5:ea:d8:0b:5d:0b:97:5d:4f:06:75:4b:e1"));
+ QCOMPARE(chain[0].serialNumber(),
+ QByteArray("58:df:33:c1:9b:bc:c5:51:7a:00:86:64:43:94:41:e2:26:ef:3f:89"));
+ QCOMPARE(chain[1].serialNumber(),
+ QByteArray("11:72:34:bc:21:e6:ca:04:24:13:f8:35:48:84:a6:e9:de:96:22:15"));
}
-void tst_QSslSocket::setPrivateKey()
+void tst_QSslSocket::tlsConfiguration()
{
+ QFETCH_GLOBAL(const bool, setProxy);
+ if (setProxy)
+ return;
+ // Test some things not covered by any other auto-test.
+ QSslSocket socket;
+ auto tlsConfig = socket.sslConfiguration();
+ QVERIFY(tlsConfig.sessionCipher().isNull());
+ QCOMPARE(tlsConfig.addCaCertificates(QStringLiteral("nonexisting/chain.crt")), false);
+ QCOMPARE(tlsConfig.sessionProtocol(), QSsl::UnknownProtocol);
+ QSslConfiguration nullConfig;
+ QVERIFY(nullConfig.isNull());
+#if QT_CONFIG(openssl)
+ nullConfig.setEllipticCurves(tlsConfig.ellipticCurves());
+ QCOMPARE(nullConfig.ellipticCurves(), tlsConfig.ellipticCurves());
+#endif
+ QMap<QByteArray, QVariant> backendConfig;
+ backendConfig["DTLSMTU"] = QVariant::fromValue(1024);
+ backendConfig["DTLSTIMEOUTMS"] = QVariant::fromValue(1000);
+ nullConfig.setBackendConfiguration(backendConfig);
+ QCOMPARE(nullConfig.backendConfiguration(), backendConfig);
+ QTest::ignoreMessage(QtWarningMsg, "QSslConfiguration::setPeerVerifyDepth: cannot set negative depth of -1000");
+ nullConfig.setPeerVerifyDepth(-1000);
+ QVERIFY(nullConfig.peerVerifyDepth() != -1000);
+ nullConfig.setPeerVerifyDepth(100);
+ QCOMPARE(nullConfig.peerVerifyDepth(), 100);
}
void tst_QSslSocket::setSocketDescriptor()
@@ -1629,11 +1906,16 @@ void tst_QSslSocket::setSslConfiguration_data()
QTest::newRow("empty") << QSslConfiguration() << false;
QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
QTest::newRow("default") << conf << false; // does not contain test server cert
- QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(httpServerCertChainPath());
- conf.setCaCertificates(testServerCert);
- QTest::newRow("set-root-cert") << conf << true;
- conf.setProtocol(QSsl::SecureProtocols);
- QTest::newRow("secure") << conf << true;
+
+ if (!isTestingSecureTransport) {
+ QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(httpServerCertChainPath());
+ conf.setCaCertificates(testServerCert);
+ QTest::newRow("set-root-cert") << conf << true;
+ conf.setProtocol(QSsl::SecureProtocols);
+ QTest::newRow("secure") << conf << true;
+ } else {
+ qWarning("Skipping the cases with certificate, SecureTransport does not like old certificate on the test server");
+ }
}
void tst_QSslSocket::setSslConfiguration()
@@ -1644,9 +1926,7 @@ void tst_QSslSocket::setSslConfiguration()
QSslSocketPtr socket = newSocket();
QFETCH(QSslConfiguration, configuration);
socket->setSslConfiguration(configuration);
-#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
- socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
-#endif
+
this->socket = socket.data();
socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443);
QFETCH(bool, works);
@@ -1699,9 +1979,19 @@ void tst_QSslSocket::waitForConnectedEncryptedReadyRead()
if (!QSslSocket::supportsSsl())
return;
+ // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use here) are not available by default.
+ if (isSecurityLevel0Required)
+ QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier");
+
QSslSocketPtr socket = newSocket();
this->socket = socket.data();
+ // Set TLS 1.0 or above because the server doesn't support TLS 1.2 or above
+ // QTQAINFRA-4499
+ QSslConfiguration config = socket->sslConfiguration();
+ config.setProtocol(Test::TlsV1_0OrLater);
+ socket->setSslConfiguration(config);
+
connect(this->socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
socket->connectToHostEncrypted(QtNetworkSettings::imapServerName(), 993);
@@ -1980,8 +2270,17 @@ void tst_QSslSocket::spontaneousWrite()
receiver->startClientEncryption();
// SSL handshake:
- connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop()));
+ // Need to wait for both sides to emit encrypted as the ordering of which
+ // ones emits encrypted() changes depending on whether we use TLS 1.2 or 1.3
+ int waitFor = 2;
+ auto earlyQuitter = [&waitFor]() {
+ if (!--waitFor)
+ exitLoop();
+ };
+ connect(receiver, &QSslSocket::encrypted, this, earlyQuitter);
+ connect(sender, &QSslSocket::encrypted, this, earlyQuitter);
enterLoop(1);
+
QVERIFY(!timeout());
QVERIFY(sender->isEncrypted());
QVERIFY(receiver->isEncrypted());
@@ -2024,9 +2323,21 @@ void tst_QSslSocket::setReadBufferSize()
receiver->ignoreSslErrors();
receiver->startClientEncryption();
- // SSL handshake:
- connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop()));
+ // Need to wait for both sides to emit encrypted as the ordering of which
+ // ones emits encrypted() changes depending on whether we use TLS 1.2 or 1.3
+ int waitFor = 2;
+ auto earlyQuitter = [&waitFor]() {
+ if (!--waitFor)
+ exitLoop();
+ };
+ connect(receiver, &QSslSocket::encrypted, this, earlyQuitter);
+ connect(sender, &QSslSocket::encrypted, this, earlyQuitter);
+
enterLoop(1);
+ if (!sender->isEncrypted()) {
+ connect(sender, &QSslSocket::encrypted, this, &tst_QSslSocket::exitLoop);
+ enterLoop(1);
+ }
QVERIFY(!timeout());
QVERIFY(sender->isEncrypted());
QVERIFY(receiver->isEncrypted());
@@ -2346,9 +2657,7 @@ void tst_QSslSocket::verifyMode()
return;
QSslSocket socket;
-#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
- socket.setProtocol(QSsl::SslProtocol::TlsV1_1);
-#endif
+
QCOMPARE(socket.peerVerifyMode(), QSslSocket::AutoVerifyPeer);
socket.setPeerVerifyMode(QSslSocket::VerifyNone);
QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyNone);
@@ -2361,7 +2670,7 @@ void tst_QSslSocket::verifyMode()
QSKIP("Skipping flaky test - See QTBUG-29941");
QList<QSslError> expectedErrors = QList<QSslError>()
- << QSslError(FLUKE_CERTIFICATE_ERROR, socket.peerCertificate());
+ << QSslError(flukeCertificateError, socket.peerCertificate());
QCOMPARE(socket.sslHandshakeErrors(), expectedErrors);
socket.abort();
@@ -2392,6 +2701,43 @@ void tst_QSslSocket::verifyDepth()
QCOMPARE(socket.peerVerifyDepth(), 1);
}
+void tst_QSslSocket::verifyAndDefaultConfiguration()
+{
+ QFETCH_GLOBAL(const bool, setProxy);
+ if (setProxy)
+ return;
+ if (!QSslSocket::supportedFeatures().contains(QSsl::SupportedFeature::CertificateVerification))
+ QSKIP("This backend doesn't support manual certificate verification");
+ const auto defaultCACertificates = QSslConfiguration::defaultConfiguration().caCertificates();
+ const auto chainGuard = qScopeGuard([&defaultCACertificates]{
+ auto conf = QSslConfiguration::defaultConfiguration();
+ conf.setCaCertificates(defaultCACertificates);
+ QSslConfiguration::setDefaultConfiguration(conf);
+ });
+
+ auto chain = QSslCertificate::fromPath(testDataDir + QStringLiteral("certs/qtiochain.crt"), QSsl::Pem);
+ QCOMPARE(chain.size(), 2);
+ QVERIFY(!chain.at(0).isNull());
+ QVERIFY(!chain.at(1).isNull());
+ auto errors = QSslCertificate::verify(chain);
+ // At least, test that 'verify' did not alter the default configuration:
+ QCOMPARE(defaultCACertificates, QSslConfiguration::defaultConfiguration().caCertificates());
+ if (!errors.isEmpty())
+ QSKIP("The certificate for qt.io could not be trusted, skipping the rest of the test");
+#ifdef Q_OS_WINDOWS
+ const auto fakeCaChain = QSslCertificate::fromPath(testDataDir + QStringLiteral("certs/fluke.cert"));
+ QCOMPARE(fakeCaChain.size(), 1);
+ const auto caCert = fakeCaChain.at(0);
+ QVERIFY(!caCert.isNull());
+ auto conf = QSslConfiguration::defaultConfiguration();
+ conf.setCaCertificates({caCert});
+ QSslConfiguration::setDefaultConfiguration(conf);
+ errors = QSslCertificate::verify(chain);
+ QVERIFY(errors.size() > 0);
+ QCOMPARE(QSslConfiguration::defaultConfiguration().caCertificates(), QList{caCert});
+#endif
+}
+
void tst_QSslSocket::disconnectFromHostWhenConnecting()
{
QSslSocketPtr socket = newSocket();
@@ -2436,7 +2782,7 @@ void tst_QSslSocket::disconnectFromHostWhenConnected()
QCOMPARE(socket->bytesToWrite(), qint64(0));
}
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
class BrokenPskHandshake : public QTcpServer
{
@@ -2467,6 +2813,9 @@ private:
void tst_QSslSocket::closeWhileEmittingSocketError()
{
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS backend does not support this test");
+
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
@@ -2487,17 +2836,17 @@ void tst_QSslSocket::closeWhileEmittingSocketError()
// Make sure we have some data buffered so that close will try to flush:
clientSocket.write(QByteArray(1000000, Qt::Uninitialized));
- QTestEventLoop::instance().enterLoopMSecs(1000);
+ QTestEventLoop::instance().enterLoop(1s);
QVERIFY(!QTestEventLoop::instance().timeout());
- QCOMPARE(socketErrorSpy.count(), 1);
+ QCOMPARE(socketErrorSpy.size(), 1);
}
-#endif // QT_NO_OPENSSL
+#endif // Feature 'openssl'.
void tst_QSslSocket::resetProxy()
{
-#ifndef QT_NO_NETWORKPROXY
+#if QT_CONFIG(networkproxy)
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
@@ -2541,7 +2890,7 @@ void tst_QSslSocket::resetProxy()
socket2.setProxy(goodProxy);
socket2.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443);
QVERIFY2(socket2.waitForConnected(10000), qPrintable(socket.errorString()));
-#endif // QT_NO_NETWORKPROXY
+#endif // QT_CONFIG(networkproxy)
}
void tst_QSslSocket::ignoreSslErrorsList_data()
@@ -2553,8 +2902,8 @@ void tst_QSslSocket::ignoreSslErrorsList_data()
QList<QSslError> expectedSslErrors;
// fromPath gives us a list of certs, but it actually only contains one
QList<QSslCertificate> certs = QSslCertificate::fromPath(httpServerCertChainPath());
- QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0));
- QSslError wrongError(FLUKE_CERTIFICATE_ERROR);
+ QSslError rightError(flukeCertificateError, certs.at(0));
+ QSslError wrongError(flukeCertificateError);
QTest::newRow("SSL-failure-empty-list") << expectedSslErrors << 1;
@@ -2587,7 +2936,7 @@ void tst_QSslSocket::ignoreSslErrorsList()
bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0);
if (socket.waitForEncrypted(10000) != expectEncryptionSuccess)
QSKIP("Skipping flaky test - See QTBUG-29941");
- QCOMPARE(sslErrorsSpy.count(), expectedSslErrorSignalCount);
+ QCOMPARE(sslErrorsSpy.size(), expectedSslErrorSignalCount);
}
void tst_QSslSocket::ignoreSslErrorsListWithSlot_data()
@@ -2648,9 +2997,7 @@ void tst_QSslSocket::abortOnSslErrors()
void tst_QSslSocket::readFromClosedSocket()
{
QSslSocketPtr socket = newSocket();
-#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
- socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
-#endif
+
socket->ignoreSslErrors();
socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443);
socket->ignoreSslErrors();
@@ -2747,9 +3094,16 @@ void tst_QSslSocket::blacklistedCertificates()
connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop()));
enterLoop(1);
QList<QSslError> sslErrors = receiver->sslHandshakeErrors();
- QVERIFY(sslErrors.count() > 0);
+ QVERIFY(sslErrors.size() > 0);
// there are more errors (self signed cert and hostname mismatch), but we only care about the blacklist error
- QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted);
+ std::optional<QSslError> blacklistedError;
+ for (const QSslError &error : sslErrors) {
+ if (error.error() == QSslError::CertificateBlacklisted) {
+ blacklistedError = error;
+ break;
+ }
+ }
+ QVERIFY2(blacklistedError, "CertificateBlacklisted error not found!");
}
void tst_QSslSocket::versionAccessors()
@@ -2761,60 +3115,6 @@ void tst_QSslSocket::versionAccessors()
qDebug() << QString::number(QSslSocket::sslLibraryVersionNumber(), 16);
}
-#ifndef QT_NO_OPENSSL
-void tst_QSslSocket::sslOptions()
-{
- if (!QSslSocket::supportsSsl())
- return;
-
-#ifdef SSL_OP_NO_COMPRESSION
- QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
- QSslConfigurationPrivate::defaultSslOptions),
- long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE));
-#else
- QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
- QSslConfigurationPrivate::defaultSslOptions),
- long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
-#endif
-
- QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
- QSsl::SslOptionDisableEmptyFragments
- |QSsl::SslOptionDisableLegacyRenegotiation),
- long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
-
-#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
- QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
- QSsl::SslOptionDisableEmptyFragments),
- long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
-#endif
-
-#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
- QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
- QSsl::SslOptionDisableLegacyRenegotiation),
- long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS));
-#endif
-
-#ifdef SSL_OP_NO_TICKET
- QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
- QSsl::SslOptionDisableEmptyFragments
- |QSsl::SslOptionDisableLegacyRenegotiation
- |QSsl::SslOptionDisableSessionTickets),
- long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_CIPHER_SERVER_PREFERENCE)));
-#endif
-
-#ifdef SSL_OP_NO_TICKET
-#ifdef SSL_OP_NO_COMPRESSION
- QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
- QSsl::SslOptionDisableEmptyFragments
- |QSsl::SslOptionDisableLegacyRenegotiation
- |QSsl::SslOptionDisableSessionTickets
- |QSsl::SslOptionDisableCompression),
- long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
-#endif
-#endif
-}
-#endif
-
void tst_QSslSocket::encryptWithoutConnecting()
{
if (!QSslSocket::supportsSsl())
@@ -2829,6 +3129,10 @@ void tst_QSslSocket::encryptWithoutConnecting()
void tst_QSslSocket::resume_data()
{
+ // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use in 'resume' test) are not available by default.
+ if (isSecurityLevel0Required)
+ QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier");
+
QTest::addColumn<bool>("ignoreErrorsAfterPause");
QTest::addColumn<QList<QSslError> >("errorsToIgnore");
QTest::addColumn<bool>("expectSuccess");
@@ -2840,8 +3144,8 @@ void tst_QSslSocket::resume_data()
// Note, httpServerCertChainPath() it's ... because we use the same certificate on
// different services. We'll be actually connecting to IMAP server.
QList<QSslCertificate> certs = QSslCertificate::fromPath(httpServerCertChainPath());
- QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0));
- QSslError wrongError(FLUKE_CERTIFICATE_ERROR);
+ QSslError rightError(flukeCertificateError, certs.at(0));
+ QSslError wrongError(flukeCertificateError);
errorsList.append(wrongError);
QTest::newRow("ignoreSpecificErrors-Wrong") << true << errorsList << false;
errorsList.clear();
@@ -2864,6 +3168,12 @@ void tst_QSslSocket::resume()
QSslSocket socket;
socket.setPauseMode(QAbstractSocket::PauseOnSslErrors);
+ // Set TLS 1.0 or above because the server doesn't support TLS 1.2 or above
+ // QTQAINFRA-4499
+ QSslConfiguration config = socket.sslConfiguration();
+ config.setProtocol(Test::TlsV1_0OrLater);
+ socket.setSslConfiguration(config);
+
QSignalSpy sslErrorSpy(&socket, SIGNAL(sslErrors(QList<QSslError>)));
QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted()));
QSignalSpy errorSpy(&socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
@@ -2879,9 +3189,9 @@ void tst_QSslSocket::resume()
QFETCH_GLOBAL(bool, setProxy);
if (setProxy && QTestEventLoop::instance().timeout())
QSKIP("Skipping flaky test - See QTBUG-29941");
- QCOMPARE(sslErrorSpy.count(), 1);
- QCOMPARE(errorSpy.count(), 0);
- QCOMPARE(encryptedSpy.count(), 0);
+ QCOMPARE(sslErrorSpy.size(), 1);
+ QCOMPARE(errorSpy.size(), 0);
+ QCOMPARE(encryptedSpy.size(), 0);
QVERIFY(!socket.isEncrypted());
if (ignoreErrorsAfterPause) {
if (errorsToIgnore.empty())
@@ -2893,15 +3203,15 @@ void tst_QSslSocket::resume()
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout()); // quit by encrypted() or error() signal
if (expectSuccess) {
- QCOMPARE(encryptedSpy.count(), 1);
+ QCOMPARE(encryptedSpy.size(), 1);
QVERIFY(socket.isEncrypted());
- QCOMPARE(errorSpy.count(), 0);
+ QCOMPARE(errorSpy.size(), 0);
socket.disconnectFromHost();
QVERIFY(socket.waitForDisconnected(10000));
} else {
- QCOMPARE(encryptedSpy.count(), 0);
+ QCOMPARE(encryptedSpy.size(), 0);
QVERIFY(!socket.isEncrypted());
- QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(errorSpy.size(), 1);
QCOMPARE(socket.error(), QAbstractSocket::SslHandshakeFailedError);
}
}
@@ -3088,17 +3398,17 @@ void tst_QSslSocket::qtbug18498_peek2()
bigblock.fill('#', QIODEVICE_BUFFERSIZE + 1024);
QVERIFY(client->write(QByteArray("head")));
QVERIFY(client->write(bigblock));
- QTRY_COMPARE(server->bytesAvailable(), bigblock.length() + 4);
+ QTRY_COMPARE(server->bytesAvailable(), bigblock.size() + 4);
QCOMPARE(server->read(4), QByteArray("head"));
- QCOMPARE(server->peek(bigblock.length()), bigblock);
- b.reserve(bigblock.length());
- b.resize(server->peek(b.data(), bigblock.length()));
+ QCOMPARE(server->peek(bigblock.size()), bigblock);
+ b.reserve(bigblock.size());
+ b.resize(server->peek(b.data(), bigblock.size()));
QCOMPARE(b, bigblock);
//check oversized peek
- QCOMPARE(server->peek(bigblock.length() * 3), bigblock);
- b.reserve(bigblock.length() * 3);
- b.resize(server->peek(b.data(), bigblock.length() * 3));
+ QCOMPARE(server->peek(bigblock.size() * 3), bigblock);
+ b.reserve(bigblock.size() * 3);
+ b.resize(server->peek(b.data(), bigblock.size() * 3));
QCOMPARE(b, bigblock);
QCOMPARE(server->readAll(), bigblock);
@@ -3166,7 +3476,13 @@ void tst_QSslSocket::dhServer()
return;
SslServer server;
- server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")};
+ QSslCipher rsaCipher("DHE-RSA-AES256-SHA");
+ QSslCipher dssCipher("DHE-DSS-AES256-SHA");
+ if (rsaCipher.isNull())
+ QSKIP("The current backend doesn't support DHE-RSA-AES256-SHA");
+ if (dssCipher.isNull())
+ QSKIP("The current backend doesn't support DHE-DSS-AES256-SHA");
+ server.ciphers = { rsaCipher, dssCipher };
QVERIFY(server.listen());
QEventLoop loop;
@@ -3184,18 +3500,20 @@ void tst_QSslSocket::dhServer()
QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
}
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
void tst_QSslSocket::dhServerCustomParamsNull()
{
- if (!QSslSocket::supportsSsl())
- QSKIP("No SSL support");
+ if (!isTestingOpenSsl)
+ QSKIP("This test requires OpenSSL as the active TLS backend");
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
+ const QSslCipher cipherWithDH("DHE-RSA-AES256-SHA256");
SslServer server;
- server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")};
+ server.ciphers = {cipherWithDH};
+ server.protocol = QSsl::TlsV1_2;
QSslConfiguration cfg = server.config;
cfg.setDiffieHellmanParameters(QSslDiffieHellmanParameters());
@@ -3207,6 +3525,8 @@ void tst_QSslSocket::dhServerCustomParamsNull()
QTimer::singleShot(5000, &loop, SLOT(quit()));
QSslSocket client;
+ QSslConfiguration config = client.sslConfiguration();
+ client.setSslConfiguration(config);
socket = &client;
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
@@ -3216,22 +3536,25 @@ void tst_QSslSocket::dhServerCustomParamsNull()
loop.exec();
- QVERIFY(client.state() != QAbstractSocket::ConnectedState);
+ QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(client.sessionCipher(), cipherWithDH);
}
-#endif // QT_NO_OPENSSL
-#ifndef QT_NO_OPENSSL
void tst_QSslSocket::dhServerCustomParams()
{
if (!QSslSocket::supportsSsl())
QSKIP("No SSL support");
+ if (!QSslSocket::isClassImplemented(QSsl::ImplementedClass::DiffieHellman))
+ QSKIP("The current backend doesn't support diffie hellman parameters");
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
SslServer server;
- server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")};
+ const QSslCipher cipherWithDH("DHE-RSA-AES256-SHA256");
+ server.ciphers = {cipherWithDH};
+ server.protocol = QSsl::TlsV1_2;
QSslConfiguration cfg = server.config;
@@ -3261,9 +3584,10 @@ void tst_QSslSocket::dhServerCustomParams()
loop.exec();
- QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+ QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(client.sessionCipher(), cipherWithDH);
}
-#endif // QT_NO_OPENSSL
+#endif // QT_CONFIG(openssl)
void tst_QSslSocket::ecdhServer()
{
@@ -3277,7 +3601,10 @@ void tst_QSslSocket::ecdhServer()
return;
SslServer server;
- server.ciphers = {QSslCipher("ECDHE-RSA-AES128-SHA")};
+ QSslCipher cipher("ECDHE-RSA-AES128-SHA");
+ if (cipher.isNull())
+ QSKIP("The current backend doesn't support ECDHE-RSA-AES128-SHA");
+ server.ciphers = {cipher};
QVERIFY(server.listen());
QEventLoop loop;
@@ -3365,14 +3692,15 @@ void tst_QSslSocket::verifyClientCertificate_data()
void tst_QSslSocket::verifyClientCertificate()
{
-#if QT_CONFIG(securetransport)
- // We run both client and server on the same machine,
- // this means, client can update keychain with client's certificates,
- // and server later will use the same certificates from the same
- // keychain thus making tests fail (wrong number of certificates,
- // success instead of failure etc.).
- QSKIP("This test can not work with Secure Transport");
-#endif // QT_CONFIG(securetransport)
+ if (isTestingSecureTransport) {
+ // We run both client and server on the same machine,
+ // this means, client can update keychain with client's certificates,
+ // and server later will use the same certificates from the same
+ // keychain thus making tests fail (wrong number of certificates,
+ // success instead of failure etc.).
+ QSKIP("This test can not work with Secure Transport");
+ }
+
if (!QSslSocket::supportsSsl()) {
qWarning("SSL not supported, skipping test");
return;
@@ -3383,12 +3711,13 @@ void tst_QSslSocket::verifyClientCertificate()
return;
QFETCH(QSslSocket::PeerVerifyMode, peerVerifyMode);
-#if QT_CONFIG(schannel)
- if (peerVerifyMode == QSslSocket::QueryPeer || peerVerifyMode == QSslSocket::AutoVerifyPeer)
- QSKIP("Schannel doesn't tackle requesting a certificate and not receiving one.");
-#endif
+ if (isTestingSchannel) {
+ if (peerVerifyMode == QSslSocket::QueryPeer || peerVerifyMode == QSslSocket::AutoVerifyPeer)
+ QSKIP("Schannel doesn't tackle requesting a certificate and not receiving one.");
+ }
SslServer server;
+ server.protocol = QSsl::TlsV1_2;
server.addCaCertificates = testDataDir + "certs/bogus-ca.crt";
server.ignoreSslErrors = false;
server.peerVerifyMode = peerVerifyMode;
@@ -3402,6 +3731,9 @@ void tst_QSslSocket::verifyClientCertificate()
QSslSocket client;
client.setLocalCertificateChain(clientCerts);
client.setPrivateKey(clientKey);
+ QSslConfiguration config = client.sslConfiguration();
+ config.setProtocol(Test::TlsV1_0OrLater);
+ client.setSslConfiguration(config);
socket = &client;
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
@@ -3426,13 +3758,13 @@ void tst_QSslSocket::verifyClientCertificate()
QVERIFY(server.socket->peerCertificateChain().isEmpty());
} else {
QCOMPARE(server.socket->peerCertificate(), clientCerts.first());
-#if QT_CONFIG(schannel)
- if (clientCerts.count() == 1 && server.socket->peerCertificateChain().count() == 2) {
- QEXPECT_FAIL("",
- "Schannel includes the entire chain, not just the leaf and intermediates",
- Continue);
+ if (isTestingSchannel) {
+ if (clientCerts.size() == 1 && server.socket->peerCertificateChain().size() == 2) {
+ QEXPECT_FAIL("",
+ "Schannel includes the entire chain, not just the leaf and intermediates",
+ Continue);
+ }
}
-#endif
QCOMPARE(server.socket->peerCertificateChain(), clientCerts);
}
@@ -3443,7 +3775,18 @@ void tst_QSslSocket::verifyClientCertificate()
void tst_QSslSocket::readBufferMaxSize()
{
-#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
+ // QTBUG-94186: originally, only SecureTransport was
+ // running this test (since it was a bug in that backend,
+ // see comment below), after TLS plugins were introduced,
+ // we enabled this test on all backends, as a part of
+ // the clean up. This revealed the fact that this test
+ // is flaky, and it started to fail on Windows.
+ // TODO: this is a temporary solution, to be removed
+ // as soon as 94186 fixed for good.
+ if (!isTestingSecureTransport)
+ QSKIP("This test is flaky with TLS backend other than SecureTransport");
+
+
// QTBUG-55170:
// SecureTransport back-end was ignoring read-buffer
// size limit, resulting (potentially) in a constantly
@@ -3468,11 +3811,19 @@ void tst_QSslSocket::readBufferMaxSize()
socket = client.data();
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
- connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
server.serverPort());
+ int waitFor = 2;
+ auto earlyQuitter = [&loop, &waitFor]() {
+ if (!--waitFor)
+ loop.exit();
+ };
+
+ connect(socket, &QSslSocket::encrypted, &loop, earlyQuitter);
+ connect(&server, &SslServer::socketEncrypted, &loop, earlyQuitter);
+
// Wait for 'encrypted' first:
QTimer::singleShot(5000, &loop, SLOT(quit()));
loop.exec();
@@ -3498,9 +3849,6 @@ void tst_QSslSocket::readBufferMaxSize()
loop.exec();
QCOMPARE(client->bytesAvailable() + readSoFar, message.size());
-#else
- // Not needed, QSslSocket works correctly with other back-ends.
-#endif // QT_CONFIG(securetransport) || QT_CONFIG(schannel)
}
void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, as it has some side effects
@@ -3525,20 +3873,13 @@ void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last,
void tst_QSslSocket::allowedProtocolNegotiation()
{
-#ifndef ALPN_SUPPORTED
- QSKIP("ALPN is unsupported, skipping test");
-#endif
-
-#if QT_CONFIG(schannel)
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
- QSKIP("ALPN is not supported on this version of Windows using Schannel.");
-#endif
+ if (!hasServerAlpn)
+ QSKIP("Server-side ALPN is unsupported, skipping test");
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
-
const QByteArray expectedNegotiated("cool-protocol");
QList<QByteArray> serverProtos;
serverProtos << expectedNegotiated << "not-so-cool-protocol";
@@ -3560,15 +3901,25 @@ void tst_QSslSocket::allowedProtocolNegotiation()
QEventLoop loop;
QTimer::singleShot(5000, &loop, SLOT(quit()));
- connect(&clientSocket, SIGNAL(encrypted()), &loop, SLOT(quit()));
+
+ // Need to wait for both sides to emit encrypted as the ordering of which
+ // ones emits encrypted() changes depending on whether we use TLS 1.2 or 1.3
+ int waitFor = 2;
+ auto earlyQuitter = [&loop, &waitFor]() {
+ if (!--waitFor)
+ loop.exit();
+ };
+ connect(&clientSocket, &QSslSocket::encrypted, &loop, earlyQuitter);
+ connect(&server, &SslServer::socketEncrypted, &loop, earlyQuitter);
+
loop.exec();
- QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() ==
- clientSocket.sslConfiguration().nextNegotiatedProtocol());
- QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() == expectedNegotiated);
+ QCOMPARE(server.socket->sslConfiguration().nextNegotiatedProtocol(),
+ clientSocket.sslConfiguration().nextNegotiatedProtocol());
+ QCOMPARE(server.socket->sslConfiguration().nextNegotiatedProtocol(), expectedNegotiated);
}
-#ifndef QT_NO_OPENSSL
+#if QT_CONFIG(openssl)
class PskProvider : public QObject
{
Q_OBJECT
@@ -3626,7 +3977,7 @@ public:
config(QSslConfiguration::defaultConfiguration()),
ignoreSslErrors(true),
peerVerifyMode(QSslSocket::AutoVerifyPeer),
- protocol(QSsl::TlsV1_0),
+ protocol(QSsl::TlsV1_2),
m_pskProvider()
{
m_pskProvider.m_server = true;
@@ -3672,8 +4023,12 @@ protected slots:
socket->ignoreSslErrors();
}
};
+
void tst_QSslSocket::simplePskConnect_data()
{
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS backend does support PSK");
+
QTest::addColumn<PskConnectTestType>("pskTestType");
QTest::newRow("PskConnectDoNotHandlePsk") << PskConnectDoNotHandlePsk;
QTest::newRow("PskConnectEmptyCredentials") << PskConnectEmptyCredentials;
@@ -3764,14 +4119,14 @@ void tst_QSslSocket::simplePskConnect()
case PskConnectWrongCredentials:
// provide totally wrong credentials
- provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.length() - 1));
- provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.length() - 1));
+ provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.size() - 1));
+ provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.size() - 1));
connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
break;
case PskConnectWrongIdentity:
// right PSK, wrong identity
- provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.length() - 1));
+ provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.size() - 1));
provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
break;
@@ -3779,7 +4134,7 @@ void tst_QSslSocket::simplePskConnect()
case PskConnectWrongPreSharedKey:
// right identity, wrong PSK
provider.setIdentity(PSK_CLIENT_IDENTITY);
- provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.length() - 1));
+ provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.size() - 1));
connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
break;
@@ -3831,32 +4186,32 @@ void tst_QSslSocket::simplePskConnect()
// Entered connecting state
QCOMPARE(socket.state(), QAbstractSocket::ConnectingState);
- QCOMPARE(connectedSpy.count(), 0);
- QCOMPARE(hostFoundSpy.count(), 1);
- QCOMPARE(disconnectedSpy.count(), 0);
+ QCOMPARE(connectedSpy.size(), 0);
+ QCOMPARE(hostFoundSpy.size(), 1);
+ QCOMPARE(disconnectedSpy.size(), 0);
enterLoop(10);
// Entered connected state
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
QVERIFY(!socket.isEncrypted());
- QCOMPARE(connectedSpy.count(), 1);
- QCOMPARE(hostFoundSpy.count(), 1);
- QCOMPARE(disconnectedSpy.count(), 0);
+ QCOMPARE(connectedSpy.size(), 1);
+ QCOMPARE(hostFoundSpy.size(), 1);
+ QCOMPARE(disconnectedSpy.size(), 0);
// Enter encrypted mode
socket.startClientEncryption();
QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
QVERIFY(!socket.isEncrypted());
- QCOMPARE(connectionEncryptedSpy.count(), 0);
- QCOMPARE(sslErrorsSpy.count(), 0);
- QCOMPARE(peerVerifyErrorSpy.count(), 0);
+ QCOMPARE(connectionEncryptedSpy.size(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 0);
+ QCOMPARE(peerVerifyErrorSpy.size(), 0);
// Start handshake.
enterLoop(10);
// We must get the PSK signal in all cases
- QCOMPARE(pskAuthenticationRequiredSpy.count(), 1);
+ QCOMPARE(pskAuthenticationRequiredSpy.size(), 1);
switch (pskTestType) {
case PskConnectDoNotHandlePsk:
@@ -3865,40 +4220,40 @@ void tst_QSslSocket::simplePskConnect()
case PskConnectWrongIdentity:
case PskConnectWrongPreSharedKey:
// Handshake failure
- QCOMPARE(socketErrorsSpy.count(), 1);
+ QCOMPARE(socketErrorsSpy.size(), 1);
QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError);
- QCOMPARE(sslErrorsSpy.count(), 0);
- QCOMPARE(peerVerifyErrorSpy.count(), 0);
- QCOMPARE(connectionEncryptedSpy.count(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 0);
+ QCOMPARE(peerVerifyErrorSpy.size(), 0);
+ QCOMPARE(connectionEncryptedSpy.size(), 0);
QVERIFY(!socket.isEncrypted());
break;
case PskConnectRightCredentialsPeerVerifyFailure:
// Peer verification failure
- QCOMPARE(socketErrorsSpy.count(), 1);
+ QCOMPARE(socketErrorsSpy.size(), 1);
QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError);
- QCOMPARE(sslErrorsSpy.count(), 1);
- QCOMPARE(peerVerifyErrorSpy.count(), 1);
- QCOMPARE(connectionEncryptedSpy.count(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 1);
+ QCOMPARE(peerVerifyErrorSpy.size(), 1);
+ QCOMPARE(connectionEncryptedSpy.size(), 0);
QVERIFY(!socket.isEncrypted());
break;
case PskConnectRightCredentialsVerifyPeer:
// Peer verification failure, but ignore it and keep connecting
- QCOMPARE(socketErrorsSpy.count(), 0);
- QCOMPARE(sslErrorsSpy.count(), 1);
- QCOMPARE(peerVerifyErrorSpy.count(), 1);
- QCOMPARE(connectionEncryptedSpy.count(), 1);
+ QCOMPARE(socketErrorsSpy.size(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 1);
+ QCOMPARE(peerVerifyErrorSpy.size(), 1);
+ QCOMPARE(connectionEncryptedSpy.size(), 1);
QVERIFY(socket.isEncrypted());
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
break;
case PskConnectRightCredentialsDoNotVerifyPeer:
// No peer verification => no failure
- QCOMPARE(socketErrorsSpy.count(), 0);
- QCOMPARE(sslErrorsSpy.count(), 0);
- QCOMPARE(peerVerifyErrorSpy.count(), 0);
- QCOMPARE(connectionEncryptedSpy.count(), 1);
+ QCOMPARE(socketErrorsSpy.size(), 0);
+ QCOMPARE(sslErrorsSpy.size(), 0);
+ QCOMPARE(peerVerifyErrorSpy.size(), 0);
+ QCOMPARE(connectionEncryptedSpy.size(), 1);
QVERIFY(socket.isEncrypted());
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
break;
@@ -3939,11 +4294,14 @@ void tst_QSslSocket::simplePskConnect()
}
QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
- QCOMPARE(disconnectedSpy.count(), 1);
+ QCOMPARE(disconnectedSpy.size(), 1);
}
void tst_QSslSocket::ephemeralServerKey_data()
{
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS backend does not support ephemeral keys");
+
QTest::addColumn<QString>("cipher");
QTest::addColumn<bool>("emptyKey");
@@ -3969,16 +4327,16 @@ void tst_QSslSocket::ephemeralServerKey()
client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
spy.wait();
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QVERIFY(server.config.ephemeralServerKey().isNull());
QCOMPARE(client->sslConfiguration().ephemeralServerKey().isNull(), emptyKey);
}
void tst_QSslSocket::pskServer()
{
-#if QT_CONFIG(schannel)
- QSKIP("Schannel does not have PSK support implemented.");
-#endif
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS-backend does not have PSK support implemented.");
+
QFETCH_GLOBAL(bool, setProxy);
if (!QSslSocket::supportsSsl() || setProxy)
return;
@@ -4032,22 +4390,22 @@ void tst_QSslSocket::pskServer()
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
QVERIFY(!socket.isEncrypted());
- QCOMPARE(connectedSpy.count(), 1);
- QCOMPARE(disconnectedSpy.count(), 0);
+ QCOMPARE(connectedSpy.size(), 1);
+ QCOMPARE(disconnectedSpy.size(), 0);
// Enter encrypted mode
socket.startClientEncryption();
QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
QVERIFY(!socket.isEncrypted());
- QCOMPARE(connectionEncryptedSpy.count(), 0);
+ QCOMPARE(connectionEncryptedSpy.size(), 0);
// Start handshake.
enterLoop(10);
// We must get the PSK signal in all cases
- QCOMPARE(pskAuthenticationRequiredSpy.count(), 1);
+ QCOMPARE(pskAuthenticationRequiredSpy.size(), 1);
- QCOMPARE(connectionEncryptedSpy.count(), 1);
+ QCOMPARE(connectionEncryptedSpy.size(), 1);
QVERIFY(socket.isEncrypted());
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
@@ -4060,13 +4418,13 @@ void tst_QSslSocket::pskServer()
enterLoop(10);
QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
- QCOMPARE(disconnectedSpy.count(), 1);
+ QCOMPARE(disconnectedSpy.size(), 1);
}
void tst_QSslSocket::signatureAlgorithm_data()
{
- if (!QSslSocket::supportsSsl())
- QSKIP("Signature algorithms cannot be tested without SSL support");
+ if (!isTestingOpenSsl)
+ QSKIP("Signature algorithms cannot be tested with a non-OpenSSL TLS backend");
if (QSslSocket::sslLibraryVersionNumber() >= 0x10101000L) {
// FIXME: investigate if this test makes any sense with TLS 1.3.
@@ -4132,7 +4490,7 @@ void tst_QSslSocket::signatureAlgorithm_data()
// signature algorithms do not match, but are ignored because the tls version is not v1.2
QTest::newRow("client_ignore_TlsV1_1")
<< QByteArrayList({rsaSha256})
- << QSsl::TlsV1_1
+ << Test::TlsV1_1
<< QByteArrayList({rsaSha512})
<< QSsl::AnyProtocol
<< QAbstractSocket::ConnectedState;
@@ -4140,11 +4498,11 @@ void tst_QSslSocket::signatureAlgorithm_data()
<< QByteArrayList({rsaSha256})
<< QSsl::AnyProtocol
<< QByteArrayList({rsaSha512})
- << QSsl::TlsV1_1
+ << Test::TlsV1_1
<< QAbstractSocket::ConnectedState;
QTest::newRow("client_ignore_TlsV1_0")
<< QByteArrayList({rsaSha256})
- << QSsl::TlsV1_0
+ << Test::TlsV1_0
<< QByteArrayList({rsaSha512})
<< QSsl::AnyProtocol
<< QAbstractSocket::ConnectedState;
@@ -4152,7 +4510,7 @@ void tst_QSslSocket::signatureAlgorithm_data()
<< QByteArrayList({rsaSha256})
<< QSsl::AnyProtocol
<< QByteArrayList({rsaSha512})
- << QSsl::TlsV1_0
+ << Test::TlsV1_0
<< QAbstractSocket::ConnectedState;
}
@@ -4195,8 +4553,9 @@ void tst_QSslSocket::signatureAlgorithm()
void tst_QSslSocket::forwardReadChannelFinished()
{
- if (!QSslSocket::supportsSsl())
- QSKIP("Needs SSL");
+ if (!isTestingOpenSsl)
+ QSKIP("This test requires the OpenSSL backend");
+
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
QSKIP("This test doesn't work via a proxy");
@@ -4212,17 +4571,17 @@ void tst_QSslSocket::forwardReadChannelFinished()
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443);
enterLoop(10);
- QVERIFY(readChannelFinishedSpy.count());
+ QVERIFY(readChannelFinishedSpy.size());
}
-#endif // QT_NO_OPENSSL
+#endif // QT_CONFIG(openssl)
void tst_QSslSocket::unsupportedProtocols_data()
{
QTest::addColumn<QSsl::SslProtocol>("unsupportedProtocol");
- QTest::newRow("DtlsV1_0") << QSsl::DtlsV1_0;
+ QTest::newRow("DtlsV1_0") << Test::DtlsV1_0;
QTest::newRow("DtlsV1_2") << QSsl::DtlsV1_2;
- QTest::newRow("DtlsV1_0OrLater") << QSsl::DtlsV1_0OrLater;
+ QTest::newRow("DtlsV1_0OrLater") << Test::DtlsV1_0OrLater;
QTest::newRow("DtlsV1_2OrLater") << QSsl::DtlsV1_2OrLater;
QTest::newRow("UnknownProtocol") << QSsl::UnknownProtocol;
}
@@ -4234,7 +4593,7 @@ void tst_QSslSocket::unsupportedProtocols()
return;
QFETCH(const QSsl::SslProtocol, unsupportedProtocol);
- const int timeoutMS = 500;
+ constexpr auto timeout = 500ms;
// Test a client socket.
{
// 0. connectToHostEncrypted: client-side, non-blocking API, error is discovered
@@ -4256,7 +4615,7 @@ void tst_QSslSocket::unsupportedProtocols()
QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
- QVERIFY(socket.waitForConnected(timeoutMS));
+ QVERIFY(socket.waitForConnected(int(timeout.count())));
socket.setProtocol(unsupportedProtocol);
socket.startClientEncryption();
@@ -4281,7 +4640,7 @@ void tst_QSslSocket::unsupportedProtocols()
QTcpSocket client;
client.connectToHost(QHostAddress::LocalHost, server.serverPort());
- loop.enterLoopMSecs(timeoutMS);
+ loop.enterLoop(timeout);
QVERIFY(!loop.timeout());
QVERIFY(server.socket);
QCOMPARE(server.socket->error(), QAbstractSocket::SslInvalidUserDataError);
@@ -4294,13 +4653,15 @@ void tst_QSslSocket::oldErrorsOnSocketReuse()
if (setProxy)
return; // not relevant
SslServer server;
- server.protocol = QSsl::TlsV1_1;
+ if (!isTestingOpenSsl)
+ server.protocol = Test::TlsV1_1;
server.m_certFile = testDataDir + "certs/fluke.cert";
server.m_keyFile = testDataDir + "certs/fluke.key";
QVERIFY(server.listen(QHostAddress::SpecialAddress::LocalHost));
QSslSocket socket;
- socket.setProtocol(QSsl::TlsV1_1);
+ if (!isTestingOpenSsl)
+ socket.setProtocol(Test::TlsV1_1);
QList<QSslError> errorList;
auto connection = connect(&socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors),
[&socket, &errorList](const QList<QSslError> &errors) {
@@ -4335,8 +4696,6 @@ void tst_QSslSocket::oldErrorsOnSocketReuse()
}
}
-#endif // QT_NO_SSL
-
#if QT_CONFIG(openssl)
void tst_QSslSocket::alertMissingCertificate()
@@ -4344,6 +4703,8 @@ void tst_QSslSocket::alertMissingCertificate()
// In this test we want a server to abort the connection due to the failing
// client authentication. The server expected to send an alert before closing
// the connection, and the client expected to receive this alert and report it.
+ if (!isTestingOpenSsl)
+ QSKIP("This test requires the OpenSSL backend");
QFETCH_GLOBAL(const bool, setProxy);
if (setProxy) // Not what we test here, bail out.
@@ -4386,10 +4747,19 @@ void tst_QSslSocket::alertMissingCertificate()
connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter);
connect(&server, &SslServer::socketError, earlyQuitter);
- runner.enterLoopMSecs(1000);
+ runner.enterLoop(1s);
- QVERIFY(serverSpy.count() > 0);
- QVERIFY(clientSpy.count() > 0);
+ if (clientSocket.isEncrypted()) {
+ // When using TLS 1.3 the client side thinks it is connected very
+ // quickly, before the server has finished processing. So wait for the
+ // inevitable disconnect.
+ QCOMPARE(clientSocket.sessionProtocol(), QSsl::TlsV1_3);
+ connect(&clientSocket, &QSslSocket::disconnected, &runner, &QTestEventLoop::exitLoop);
+ runner.enterLoop(10s);
+ }
+
+ QVERIFY(serverSpy.size() > 0);
+ QVERIFY(clientSpy.size() > 0);
QVERIFY(server.socket && !server.socket->isEncrypted());
QVERIFY(!clientSocket.isEncrypted());
}
@@ -4400,6 +4770,9 @@ void tst_QSslSocket::alertInvalidCertificate()
// it also will do 'early' checks, meaning the reported and
// not ignored _during_ the hanshake, not after. This ensures
// OpenSSL sends an alert.
+ if (!isTestingOpenSsl)
+ QSKIP("This test requires the OpenSSL backend");
+
QFETCH_GLOBAL(const bool, setProxy);
if (setProxy) // Not what we test here, bail out.
return;
@@ -4437,17 +4810,20 @@ void tst_QSslSocket::alertInvalidCertificate()
connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter);
connect(&server, &SslServer::socketError, earlyQuitter);
- runner.enterLoopMSecs(1000);
+ runner.enterLoop(1s);
- QVERIFY(serverSpy.count() > 0);
- QVERIFY(clientSpy.count() > 0);
- QVERIFY(interruptedSpy.count() > 0);
+ QVERIFY(serverSpy.size() > 0);
+ QVERIFY(clientSpy.size() > 0);
+ QVERIFY(interruptedSpy.size() > 0);
QVERIFY(server.socket && !server.socket->isEncrypted());
QVERIFY(!clientSocket.isEncrypted());
}
void tst_QSslSocket::selfSignedCertificates_data()
{
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS backend does not detect the required error");
+
QTest::addColumn<bool>("clientKnown");
QTest::newRow("Client known") << true;
@@ -4562,17 +4938,17 @@ void tst_QSslSocket::selfSignedCertificates()
connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter);
connect(&server, &SslServer::socketError, earlyQuitter);
- runner.enterLoopMSecs(1000);
+ runner.enterLoop(1s);
if (clientKnown) {
- QCOMPARE(serverSpy.count(), 0);
- QCOMPARE(clientSpy.count(), 0);
+ QCOMPARE(serverSpy.size(), 0);
+ QCOMPARE(clientSpy.size(), 0);
QVERIFY(server.socket && server.socket->isEncrypted());
QVERIFY(clientSocket.isEncrypted());
} else {
- QVERIFY(serverSpy.count() > 0);
+ QVERIFY(serverSpy.size() > 0);
QEXPECT_FAIL("", "Failing to trigger signal, QTBUG-81661", Continue);
- QVERIFY(clientSpy.count() > 0);
+ QVERIFY(clientSpy.size() > 0);
QVERIFY(server.socket && !server.socket->isEncrypted());
QVERIFY(!clientSocket.isEncrypted());
}
@@ -4580,6 +4956,9 @@ void tst_QSslSocket::selfSignedCertificates()
void tst_QSslSocket::pskHandshake_data()
{
+ if (!isTestingOpenSsl)
+ QSKIP("The active TLS backend does not support PSK");
+
QTest::addColumn<bool>("pskRight");
QTest::newRow("Psk right") << true;
@@ -4697,18 +5076,18 @@ void tst_QSslSocket::pskHandshake()
connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter);
connect(&server, &SslServer::socketError, earlyQuitter);
- runner.enterLoopMSecs(1000);
+ runner.enterLoop(1s);
if (pskRight) {
- QCOMPARE(serverSpy.count(), 0);
- QCOMPARE(clientSpy.count(), 0);
+ QCOMPARE(serverSpy.size(), 0);
+ QCOMPARE(clientSpy.size(), 0);
QVERIFY(server.socket && server.socket->isEncrypted());
QVERIFY(clientSocket.isEncrypted());
} else {
- QVERIFY(serverSpy.count() > 0);
+ QVERIFY(serverSpy.size() > 0);
QCOMPARE(serverSpy.first().at(0).toInt(), static_cast<int>(QSsl::AlertLevel::Fatal));
QCOMPARE(serverSpy.first().at(1).toInt(), static_cast<int>(QSsl::AlertType::BadRecordMac));
- QVERIFY(clientSpy.count() > 0);
+ QVERIFY(clientSpy.size() > 0);
QCOMPARE(clientSpy.first().at(0).toInt(), static_cast<int>(QSsl::AlertLevel::Fatal));
QCOMPARE(clientSpy.first().at(1).toInt(), static_cast<int>(QSsl::AlertType::BadRecordMac));
QVERIFY(server.socket && !server.socket->isEncrypted());
@@ -4716,7 +5095,9 @@ void tst_QSslSocket::pskHandshake()
}
}
-#endif // openssl
+#endif // QT_CONFIG(openssl)
+#endif // QT_CONFIG(ssl)
+
QTEST_MAIN(tst_QSslSocket)