diff options
Diffstat (limited to 'tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp')
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 261 |
1 files changed, 142 insertions, 119 deletions
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index 5903eb6488..5dd5f66eba 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -31,6 +31,7 @@ #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> @@ -49,12 +50,15 @@ #include "private/qiodevice_p.h" // for QIODEVICE_BUFFERSIZE #include "../../../network-settings.h" +#include "emulationdetector.h" #ifndef QT_NO_SSL + #ifndef QT_NO_OPENSSL #include "private/qsslsocket_openssl_p.h" #include "private/qsslsocket_openssl_symbols_p.h" -#endif +#endif // QT_NO_OPENSSL + #include "private/qsslsocket_p.h" #include "private/qsslconfiguration_p.h" @@ -73,8 +77,9 @@ typedef QSharedPointer<QSslSocket> QSslSocketPtr; #define FLUKE_CERTIFICATE_ERROR QSslError::SelfSignedCertificate #else #define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted -#endif -#endif // QT_NO_SSL +#endif // QT_NO_OPENSSL + +#endif // QT_NO_OPENSSL // Detect ALPN (Application-Layer Protocol Negotiation) support #undef ALPN_SUPPORTED // Undef the variable first to be safe @@ -164,9 +169,6 @@ private slots: // API tests void sslErrors_data(); void sslErrors(); - void addCaCertificate(); - void addCaCertificates(); - void addCaCertificates2(); void ciphers(); void connectToHostEncrypted(); void connectToHostEncryptedWithVerificationPeerName(); @@ -191,7 +193,7 @@ private slots: void setLocalCertificate(); void localCertificateChain(); void setLocalCertificateChain(); - void setPrivateKey(); + void tlsConfiguration(); void setSocketDescriptor(); void setSslConfiguration_data(); void setSslConfiguration(); @@ -218,6 +220,9 @@ private slots: void waitForMinusOne(); void verifyMode(); void verifyDepth(); +#ifndef QT_NO_OPENSSL + void verifyAndDefaultConfiguration(); +#endif // QT_NO_OPENSSL void disconnectFromHostWhenConnecting(); void disconnectFromHostWhenConnected(); #ifndef QT_NO_OPENSSL @@ -233,9 +238,6 @@ private slots: void writeBigChunk(); void blacklistedCertificates(); void versionAccessors(); -#ifndef QT_NO_OPENSSL - void sslOptions(); -#endif void encryptWithoutConnecting(); void resume_data(); void resume(); @@ -770,28 +772,17 @@ void tst_QSslSocket::sslErrors() QCOMPARE(sslErrors, peerErrors); } -void tst_QSslSocket::addCaCertificate() -{ - if (!QSslSocket::supportsSsl()) - return; -} - -void tst_QSslSocket::addCaCertificates() +void tst_QSslSocket::ciphers() { if (!QSslSocket::supportsSsl()) return; -} -void tst_QSslSocket::addCaCertificates2() -{ - 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()); @@ -805,14 +796,16 @@ void tst_QSslSocket::ciphers() socket.setSslConfiguration(sslConfig); QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers()); - sslConfig.setCiphers(QSslConfiguration::defaultConfiguration().ciphers()); - socket.setSslConfiguration(sslConfig); - QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers()); - - // Task 164356 - sslConfig.setCiphers({QSslCipher("ALL"), QSslCipher("!ADH"), QSslCipher("!LOW"), - QSslCipher("!EXP"), QSslCipher("!MD5"), QSslCipher("@STRENGTH")}); - socket.setSslConfiguration(sslConfig); +#ifndef QT_NO_OPENSSL + const auto ciphers = QSslConfiguration::defaultConfiguration().ciphers(); + for (const auto &cipher : ciphers) { + if (cipher.name().size() && cipher.protocol() != QSsl::UnknownProtocol) { + const QSslCipher aCopy(cipher.name(), cipher.protocol()); + QCOMPARE(aCopy, cipher); + break; + } + } +#endif // QT_NO_OPENSSL } void tst_QSslSocket::connectToHostEncrypted() @@ -1206,7 +1199,7 @@ public: config(QSslConfiguration::defaultConfiguration()), ignoreSslErrors(true), peerVerifyMode(QSslSocket::AutoVerifyPeer), - protocol(QSsl::TlsV1_0), + protocol(QSsl::TlsV1_2), m_keyFile(keyFile), m_certFile(certFile), m_interFile(interFile) @@ -1297,32 +1290,25 @@ 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("tls1ssl3-tls1ssl3") << QSsl::TlsV1SslV3 << QSsl::TlsV1SslV3 << true; QTest::newRow("any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true; QTest::newRow("secure-secure") << QSsl::SecureProtocols << QSsl::SecureProtocols << true; - QTest::newRow("tls1-tls1ssl3") << QSsl::TlsV1_0 << QSsl::TlsV1SslV3 << 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("tls1ssl3-tls1.0") << QSsl::TlsV1SslV3 << QSsl::TlsV1_0 << true; - QTest::newRow("tls1ssl3-secure") << QSsl::TlsV1SslV3 << QSsl::SecureProtocols << true; - QTest::newRow("tls1ssl3-any") << QSsl::TlsV1SslV3 << QSsl::AnyProtocol << true; + const bool tls1Works = +#ifndef QT_NO_OPENSSL + QSslSocket::sslLibraryVersionNumber() >> 28 < 3; +#else + true; +#endif // QT_NO_OPENSSL - QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << QSsl::TlsV1_0 << true; - QTest::newRow("secure-tls1ssl3") << QSsl::SecureProtocols << QSsl::TlsV1SslV3 << true; + QTest::newRow("tls1.0-secure") << QSsl::TlsV1_0 << QSsl::SecureProtocols << tls1Works; + QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << QSsl::TlsV1_0 << tls1Works; 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; #ifdef TLS1_3_VERSION QTest::newRow("tls1.0orlater-tls1.3") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_3 << true; #endif - 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; #ifdef TLS1_3_VERSION @@ -1334,16 +1320,12 @@ void tst_QSslSocket::protocolServerSide_data() QTest::newRow("tls1.2orlater-tls1.2") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_2 << true; #ifdef TLS1_3_VERSION QTest::newRow("tls1.2orlater-tls1.3") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_3 << true; -#endif -#ifdef TLS1_3_VERSION 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.2") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_2 << false; QTest::newRow("tls1.3orlater-tls1.3") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_3 << true; #endif // TLS1_3_VERSION - QTest::newRow("any-tls1.0") << QSsl::AnyProtocol << QSsl::TlsV1_0 << true; - QTest::newRow("any-tls1ssl3") << QSsl::AnyProtocol << QSsl::TlsV1SslV3 << true; QTest::newRow("any-secure") << QSsl::AnyProtocol << QSsl::SecureProtocols << true; } @@ -1416,10 +1398,28 @@ void tst_QSslSocket::serverCipherPreferences() 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; @@ -1429,7 +1429,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 @@ -1442,16 +1443,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 (EmulationDetector::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; @@ -1461,7 +1465,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 @@ -1474,7 +1479,7 @@ void tst_QSslSocket::serverCipherPreferences() loop.exec(); QVERIFY(client.isEncrypted()); - QCOMPARE(client.sessionCipher().name(), QString("AES256-SHA")); + QCOMPARE(client.sessionCipher().name(), testedCiphers[1].name()); } } @@ -1558,12 +1563,39 @@ void tst_QSslSocket::setLocalCertificateChain() Abort); #endif 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()); +#ifndef QT_NO_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() @@ -1603,6 +1635,9 @@ void tst_QSslSocket::setSocketDescriptor() void tst_QSslSocket::setSslConfiguration_data() { +#if QT_CONFIG(securetransport) + QSKIP("Skipping the cases with certificate, SecureTransport does not like old certificate on the test server"); +#endif // securetransport QTest::addColumn<QSslConfiguration>("configuration"); QTest::addColumn<bool>("works"); @@ -2387,6 +2422,43 @@ void tst_QSslSocket::verifyDepth() QCOMPARE(socket.peerVerifyDepth(), 1); } +#ifndef QT_NO_OPENSSL +void tst_QSslSocket::verifyAndDefaultConfiguration() +{ + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) + return; + 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<QSslCertificate>() << caCert); +#endif +} +#endif // QT_NO_OPENSSL + void tst_QSslSocket::disconnectFromHostWhenConnecting() { QSslSocketPtr socket = newSocket(); @@ -2762,60 +2834,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()) @@ -3405,6 +3423,7 @@ void tst_QSslSocket::verifyClientCertificate() #endif SslServer server; + server.protocol = QSsl::TlsV1_2; server.addCaCertificates = testDataDir + "certs/bogus-ca.crt"; server.ignoreSslErrors = false; server.peerVerifyMode = peerVerifyMode; @@ -4313,13 +4332,17 @@ void tst_QSslSocket::oldErrorsOnSocketReuse() if (setProxy) return; // not relevant SslServer server; +#ifdef QT_NO_OPENSSL server.protocol = QSsl::TlsV1_1; +#endif server.m_certFile = testDataDir + "certs/fluke.cert"; server.m_keyFile = testDataDir + "certs/fluke.key"; QVERIFY(server.listen(QHostAddress::SpecialAddress::LocalHost)); QSslSocket socket; +#ifdef QT_NO_OPENSSL socket.setProtocol(QSsl::TlsV1_1); +#endif QList<QSslError> errorList; auto connection = connect(&socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), [&socket, &errorList](const QList<QSslError> &errors) { |