diff options
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 26 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_p.h | 1 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 99 |
3 files changed, 82 insertions, 44 deletions
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 068dfb9f2d..a6c86837ea 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -460,6 +460,9 @@ void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, O return; } + if (!d->verifyProtocolSupported("QSslSocket::connectToHostEncrypted:")) + return; + d->init(); d->autoStartHandshake = true; d->initialized = true; @@ -1607,6 +1610,8 @@ bool QSslSocket::waitForEncrypted(int msecs) return false; if (d->mode == UnencryptedMode && !d->autoStartHandshake) return false; + if (!d->verifyProtocolSupported("QSslSocket::waitForEncrypted:")) + return false; QElapsedTimer stopWatch; stopWatch.start(); @@ -1856,6 +1861,10 @@ void QSslSocket::startClientEncryption() d->setErrorAndEmit(QAbstractSocket::SslInternalError, tr("TLS initialization failed")); return; } + + if (!d->verifyProtocolSupported("QSslSocket::startClientEncryption:")) + return; + #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << "QSslSocket::startClientEncryption()"; #endif @@ -1899,6 +1908,9 @@ void QSslSocket::startServerEncryption() d->setErrorAndEmit(QAbstractSocket::SslInternalError, tr("TLS initialization failed")); return; } + if (!d->verifyProtocolSupported("QSslSocket::startServerEncryption")) + return; + d->mode = SslServerMode; emit modeChanged(d->mode); d->startServerEncryption(); @@ -2133,6 +2145,20 @@ void QSslSocketPrivate::init() /*! \internal */ +bool QSslSocketPrivate::verifyProtocolSupported(const char *where) +{ + if (configuration.protocol == QSsl::SslV2 || configuration.protocol == QSsl::SslV3) { + qCWarning(lcSsl) << where << "Attempted to use an unsupported protocol."; + setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, + QSslSocket::tr("Attempted to use an unsupported protocol.")); + return false; + } + return true; +} + +/*! + \internal +*/ QList<QSslCipher> QSslSocketPrivate::defaultCiphers() { QSslSocketPrivate::ensureInitialized(); diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 2f394f013b..5115613695 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -97,6 +97,7 @@ public: virtual ~QSslSocketPrivate(); void init(); + bool verifyProtocolSupported(const char *where); bool initialized; QSslSocket::SslMode mode; diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index 0523f2591f..184f07a48e 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -245,8 +245,8 @@ private slots: void signatureAlgorithm(); #endif - void deprecatedProtocols_data(); - void deprecatedProtocols(); + void disabledProtocols_data(); + void disabledProtocols(); void setEmptyDefaultConfiguration(); // this test should be last @@ -4051,60 +4051,71 @@ void tst_QSslSocket::forwardReadChannelFinished() #endif // QT_NO_OPENSSL -void tst_QSslSocket::deprecatedProtocols_data() +void tst_QSslSocket::disabledProtocols_data() { - QTest::addColumn<QSsl::SslProtocol>("protocol"); - QTest::addColumn<bool>("succeeds"); - QTest::newRow("SecureProtocols") << QSsl::SecureProtocols << true; - QTest::newRow("SslV2") << QSsl::SslV2 << false; - QTest::newRow("SslV3") << QSsl::SslV3 << false; + QTest::addColumn<QSsl::SslProtocol>("disabledProtocol"); + QTest::newRow("SslV2") << QSsl::SslV2; + QTest::newRow("SslV3") << QSsl::SslV3; } -void tst_QSslSocket::deprecatedProtocols() +void tst_QSslSocket::disabledProtocols() { - QFETCH_GLOBAL(bool, setProxy); + QFETCH_GLOBAL(const bool, setProxy); if (setProxy) - QSKIP("This test does not work under a proxy"); - - QFETCH(QSsl::SslProtocol, protocol); - QFETCH(bool, succeeds); - - QSslSocket socket; - socket.setProtocol(protocol); - - QSignalSpy connectedSpy(&socket, &QSslSocket::connected); - QVERIFY(connectedSpy.isValid()); - - QSignalSpy encryptedSpy(&socket, &QSslSocket::encrypted); - QVERIFY(encryptedSpy.isValid()); + return; - QSignalSpy errorSpy(&socket, QOverload<QAbstractSocket::SocketError>::of(&QSslSocket::error)); - QVERIFY(errorSpy.isValid()); + QFETCH(const QSsl::SslProtocol, disabledProtocol); + const int timeoutMS = 500; + // Test a client socket. + { + // 0. connectToHostEncrypted: client-side, non-blocking API, error is discovered + // early, preventing any real connection from ever starting. + QSslSocket socket; + socket.setProtocol(disabledProtocol); + QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); + socket.connectToHostEncrypted(QStringLiteral("doesnotmatter.org"), 1010); + QCOMPARE(socket.error(), QAbstractSocket::SslInvalidUserDataError); + QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); + } + { + // 1. startClientEncryption: client-side, non blocking API, but wants a socket in + // the 'connected' state (otherwise just returns false not setting any error code). + SslServer server; + QVERIFY(server.listen()); - connect(&socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), - &socket, QOverload<>::of(&QSslSocket::ignoreSslErrors)); + QSslSocket socket; + QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); - SslServer server; - QVERIFY(server.listen()); + socket.connectToHost(server.serverAddress(), server.serverPort()); + QVERIFY(socket.waitForConnected(timeoutMS)); - socket.connectToHost(server.serverAddress(), server.serverPort()); + socket.setProtocol(disabledProtocol); + socket.startClientEncryption(); + QCOMPARE(socket.error(), QAbstractSocket::SslInvalidUserDataError); + } + { + // 2. waitForEncrypted: client-side, blocking API plus requires from us + // to call ... connectToHostEncrypted(), which will notice an error and + // will prevent any connect at all. Nothing to test. + } - // Can't use waitForConnected / waitForEncrypted as they wait forever, - // so do this asynchronously via QTRY_ macros (QTBUG-72179) - QTRY_COMPARE(connectedSpy.size(), 1); - QCOMPARE(encryptedSpy.size(), 0); - QCOMPARE(errorSpy.size(), 0); + // Test a server side, relatively simple: server does not connect, it listens/accepts + // and then calls startServerEncryption() (which must fall). + { + SslServer server; + server.protocol = disabledProtocol; + QVERIFY(server.listen()); - socket.startClientEncryption(); + QTestEventLoop loop; + connect(&server, &SslServer::socketError, [&loop](QAbstractSocket::SocketError) + {loop.exitLoop();}); - if (succeeds) { - QTRY_COMPARE(encryptedSpy.size(), 1); - QCOMPARE(errorSpy.size(), 0); - } else { - // The various backends differ in the errors fired here (QTBUG-72196), - // so just check that we did get an error (and we're not encrypted) - QTRY_VERIFY(errorSpy.size() > 0); - QCOMPARE(encryptedSpy.size(), 0); + QTcpSocket client; + client.connectToHost(server.serverAddress(), server.serverPort()); + loop.enterLoopMSecs(timeoutMS); + QVERIFY(!loop.timeout()); + QVERIFY(server.socket); + QCOMPARE(server.socket->error(), QAbstractSocket::SslInvalidUserDataError); } } |