diff options
Diffstat (limited to 'tests/auto/network/ssl/qsslsocket')
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 177 |
1 files changed, 138 insertions, 39 deletions
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index a98790843a..bc289101bb 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -73,7 +73,7 @@ typedef QSharedPointer<QSslSocket> QSslSocketPtr; #else #define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted #endif -#endif // QT_NO_SSL +#endif // QT_NO_OPENSSL // Detect ALPN (Application-Layer Protocol Negotiation) support #undef ALPN_SUPPORTED // Undef the variable first to be safe @@ -259,10 +259,14 @@ private slots: void signatureAlgorithm(); #endif - void disabledProtocols_data(); - void disabledProtocols(); + void unsupportedProtocols_data(); + void unsupportedProtocols(); void oldErrorsOnSocketReuse(); +#if QT_CONFIG(openssl) + void alertMissingCertificate(); + void alertInvalidCertificate(); +#endif // openssl void setEmptyDefaultConfiguration(); // this test should be last @@ -337,6 +341,8 @@ tst_QSslSocket::tst_QSslSocket() qRegisterMetaType<QSslError>("QSslError"); qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState"); qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError"); + qRegisterMetaType<QAlertLevel>("QAlertLevel"); + qRegisterMetaType<QAlertType>("QAlertType"); #ifndef QT_NO_OPENSSL qRegisterMetaType<QSslPreSharedKeyAuthenticator *>(); @@ -1179,25 +1185,6 @@ void tst_QSslSocket::protocol() QCOMPARE(socket->protocol(), QSsl::AnyProtocol); socket->abort(); } - { - // qt-test-server allows TlsV1, so it allows TlsV1SslV3 - socket->setProtocol(QSsl::TlsV1SslV3); - QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); - socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); - if (setProxy && !socket->waitForEncrypted()) - QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); - socket->abort(); - QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); - socket->connectToHost(QtNetworkSettings::httpServerName(), 443); - if (setProxy && !socket->waitForConnected()) - QSKIP("Skipping flaky test - See QTBUG-29941"); - socket->startClientEncryption(); - if (setProxy && !socket->waitForEncrypted()) - QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); - socket->abort(); - } } class SslServer : public QTcpServer @@ -1229,6 +1216,8 @@ public: signals: void socketError(QAbstractSocket::SocketError); + void gotAlert(QAlertLevel level, QAlertType type, const QString &message); + void alertSent(QAlertLevel level, QAlertType type, const QString &message); protected: void incomingConnection(qintptr socketDescriptor) @@ -1240,6 +1229,8 @@ protected: if (ignoreSslErrors) connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(socketError(QAbstractSocket::SocketError))); + connect(socket, &QSslSocket::alertReceived, this, &SslServer::gotAlert); + connect(socket, &QSslSocket::alertSent, this, &SslServer::alertSent); QFile file(m_keyFile); QVERIFY(file.open(QIODevice::ReadOnly)); @@ -1303,20 +1294,13 @@ void tst_QSslSocket::protocolServerSide_data() 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; - QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << QSsl::TlsV1_0 << true; - QTest::newRow("secure-tls1ssl3") << QSsl::SecureProtocols << QSsl::TlsV1SslV3 << true; QTest::newRow("secure-any") << QSsl::SecureProtocols << QSsl::AnyProtocol << true; QTest::newRow("tls1.0orlater-tls1.0") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_0 << true; @@ -1348,7 +1332,6 @@ void tst_QSslSocket::protocolServerSide_data() #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; } @@ -4325,27 +4308,30 @@ void tst_QSslSocket::forwardReadChannelFinished() #endif // QT_NO_OPENSSL -void tst_QSslSocket::disabledProtocols_data() +void tst_QSslSocket::unsupportedProtocols_data() { - QTest::addColumn<QSsl::SslProtocol>("disabledProtocol"); - QTest::newRow("SslV2") << QSsl::SslV2; - QTest::newRow("SslV3") << QSsl::SslV3; + QTest::addColumn<QSsl::SslProtocol>("unsupportedProtocol"); + QTest::newRow("DtlsV1_0") << QSsl::DtlsV1_0; + QTest::newRow("DtlsV1_2") << QSsl::DtlsV1_2; + QTest::newRow("DtlsV1_0OrLater") << QSsl::DtlsV1_0OrLater; + QTest::newRow("DtlsV1_2OrLater") << QSsl::DtlsV1_2OrLater; + QTest::newRow("UnknownProtocol") << QSsl::UnknownProtocol; } -void tst_QSslSocket::disabledProtocols() +void tst_QSslSocket::unsupportedProtocols() { QFETCH_GLOBAL(const bool, setProxy); if (setProxy) return; - QFETCH(const QSsl::SslProtocol, disabledProtocol); + QFETCH(const QSsl::SslProtocol, unsupportedProtocol); 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); + socket.setProtocol(unsupportedProtocol); QCOMPARE(socket.socketError(), QAbstractSocket::UnknownSocketError); socket.connectToHostEncrypted(QStringLiteral("doesnotmatter.org"), 1010); QCOMPARE(socket.socketError(), QAbstractSocket::SslInvalidUserDataError); @@ -4363,7 +4349,7 @@ void tst_QSslSocket::disabledProtocols() socket.connectToHost(QHostAddress::LocalHost, server.serverPort()); QVERIFY(socket.waitForConnected(timeoutMS)); - socket.setProtocol(disabledProtocol); + socket.setProtocol(unsupportedProtocol); socket.startClientEncryption(); QCOMPARE(socket.socketError(), QAbstractSocket::SslInvalidUserDataError); } @@ -4377,7 +4363,7 @@ void tst_QSslSocket::disabledProtocols() // and then calls startServerEncryption() (which must fall). { SslServer server; - server.protocol = disabledProtocol; + server.protocol = unsupportedProtocol; QVERIFY(server.listen()); QTestEventLoop loop; @@ -4442,6 +4428,119 @@ void tst_QSslSocket::oldErrorsOnSocketReuse() #endif // QT_NO_SSL +#if QT_CONFIG(openssl) + +void (QSslSocket::*const tlsErrorSignal)(const QList<QSslError> &) = &QSslSocket::sslErrors; +void (QAbstractSocket::*const socketErrorSignal)(QAbstractSocket::SocketError) = &QAbstractSocket::error; + +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. + + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) // Not what we test here, bail out. + return; + + SslServer server; + if (!server.listen(QHostAddress::LocalHost)) + QSKIP("SslServer::listen() returned false"); + + // We want a certificate request to be sent to the client: + server.peerVerifyMode = QSslSocket::VerifyPeer; + // The only way we can force OpenSSL to send an alert - is to use + // a special option (so we fail before handshake is finished): + server.config.setMissingCertificateIsFatal(true); + + QSslSocket clientSocket; + connect(&clientSocket, tlsErrorSignal, [&clientSocket](const QList<QSslError> &errors){ + qDebug() << "ERR"; + clientSocket.ignoreSslErrors(errors); + }); + + QSignalSpy serverSpy(&server, &SslServer::alertSent); + QSignalSpy clientSpy(&clientSocket, &QSslSocket::alertReceived); + + clientSocket.connectToHostEncrypted(server.serverAddress().toString(), server.serverPort()); + + QTestEventLoop runner; + QTimer::singleShot(500, [&runner](){ + runner.exitLoop(); + }); + + int waitFor = 2; + auto earlyQuitter = [&runner, &waitFor](QAbstractSocket::SocketError) { + if (!--waitFor) + runner.exitLoop(); + }; + + // Presumably, RemoteHostClosedError for the client and SslHandshakeError + // for the server: + connect(&clientSocket, socketErrorSignal, earlyQuitter); + connect(&server, &SslServer::socketError, earlyQuitter); + + runner.enterLoopMSecs(1000); + + QVERIFY(serverSpy.count() > 0); + QVERIFY(clientSpy.count() > 0); + QVERIFY(server.socket && !server.socket->isEncrypted()); + QVERIFY(!clientSocket.isEncrypted()); +} + +void tst_QSslSocket::alertInvalidCertificate() +{ + // In this test a client will not ignore verification errors, + // it also will do 'early' checks, meaning the reported and + // not ignored _during_ the hanshake, not after. This ensures + // OpenSSL sends an alert. + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) // Not what we test here, bail out. + return; + + SslServer server; + if (!server.listen(QHostAddress::LocalHost)) + QSKIP("SslServer::listen() returned false"); + + QSslSocket clientSocket; + auto configuration = QSslConfiguration::defaultConfiguration(); + configuration.setHandshakeMustInterruptOnError(true); + QVERIFY(configuration.handshakeMustInterruptOnError()); + clientSocket.setSslConfiguration(configuration); + + QSignalSpy serverSpy(&server, &SslServer::gotAlert); + QSignalSpy clientSpy(&clientSocket, &QSslSocket::alertSent); + QSignalSpy interruptedSpy(&clientSocket, &QSslSocket::handshakeInterruptedOnError); + + clientSocket.connectToHostEncrypted(server.serverAddress().toString(), server.serverPort()); + + QTestEventLoop runner; + QTimer::singleShot(500, [&runner](){ + runner.exitLoop(); + }); + + int waitFor = 2; + auto earlyQuitter = [&runner, &waitFor](QAbstractSocket::SocketError) { + if (!--waitFor) + runner.exitLoop(); + }; + + // Presumably, RemoteHostClosedError for the server and SslHandshakeError + // for the client: + connect(&clientSocket, socketErrorSignal, earlyQuitter); + connect(&server, &SslServer::socketError, earlyQuitter); + + runner.enterLoopMSecs(1000); + + QVERIFY(serverSpy.count() > 0); + QVERIFY(clientSpy.count() > 0); + QVERIFY(interruptedSpy.count() > 0); + QVERIFY(server.socket && !server.socket->isEncrypted()); + QVERIFY(!clientSocket.isEncrypted()); +} + +#endif // openssl + QTEST_MAIN(tst_QSslSocket) #include "tst_qsslsocket.moc" |