diff options
Diffstat (limited to 'tests/auto/network/ssl/qsslsocket')
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/qsslsocket.pro | 16 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 397 |
2 files changed, 342 insertions, 71 deletions
diff --git a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro index de2be8e126..5c92ca833a 100644 --- a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro +++ b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro @@ -1,7 +1,7 @@ CONFIG += testcase SOURCES += tst_qsslsocket.cpp -win32:!wince: LIBS += -lws2_32 +win32:LIBS += -lws2_32 QT = core core-private network-private testlib TARGET = tst_qsslsocket @@ -15,19 +15,11 @@ win32 { } # OpenSSL support -contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { +qtConfig(openssl)|qtConfig(openssl-linked) { # Add optional SSL libs LIBS += $$OPENSSL_LIBS } -wince* { - DEFINES += SRCDIR=\\\"./\\\" +DEFINES += SRCDIR=\\\"$$PWD/\\\" - certFiles.files = certs ssl.tar.gz - certFiles.path = . - DEPLOYMENT += certFiles -} else { - DEFINES += SRCDIR=\\\"$$PWD/\\\" -} - -requires(contains(QT_CONFIG,private_tests)) +requires(qtConfig(private_tests)) diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index f36528f17d..03ddd4d6f8 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -57,7 +57,7 @@ #include "private/qsslconfiguration_p.h" Q_DECLARE_METATYPE(QSslSocket::SslMode) -typedef QList<QSslError::SslError> SslErrorList; +typedef QVector<QSslError::SslError> SslErrorList; Q_DECLARE_METATYPE(SslErrorList) Q_DECLARE_METATYPE(QSslError) Q_DECLARE_METATYPE(QSslKey) @@ -220,6 +220,10 @@ private slots: void qtbug18498_peek(); void qtbug18498_peek2(); void dhServer(); +#ifndef QT_NO_OPENSSL + void dhServerCustomParamsNull(); + void dhServerCustomParams(); +#endif void ecdhServer(); void verifyClientCertificate_data(); void verifyClientCertificate(); @@ -229,6 +233,8 @@ private slots: void simplePskConnect(); void ephemeralServerKey_data(); void ephemeralServerKey(); + void allowedProtocolNegotiation(); + void pskServer(); #endif void setEmptyDefaultConfiguration(); // this test should be last @@ -380,14 +386,14 @@ void tst_QSslSocket::cleanup() #ifndef QT_NO_SSL QSslSocketPtr tst_QSslSocket::newSocket() { - QSslSocket *socket = new QSslSocket; + const auto socket = QSslSocketPtr::create(); proxyAuthCalled = 0; - connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + connect(socket.data(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), Qt::DirectConnection); - return QSslSocketPtr(socket); + return socket; } #endif @@ -627,7 +633,8 @@ void tst_QSslSocket::sslErrors() // check the SSL errors contain HostNameMismatch and an error due to // the certificate being self-signed SslErrorList sslErrors; - foreach (const QSslError &err, socket->sslErrors()) + const auto socketSslErrors = socket->sslErrors(); + for (const QSslError &err : socketSslErrors) sslErrors << err.error(); qSort(sslErrors); QVERIFY(sslErrors.contains(QSslError::HostNameMismatch)); @@ -636,7 +643,8 @@ void tst_QSslSocket::sslErrors() // check the same errors were emitted by sslErrors QVERIFY(!sslErrorsSpy.isEmpty()); SslErrorList emittedErrors; - foreach (const QSslError &err, qvariant_cast<QList<QSslError> >(sslErrorsSpy.first().first())) + const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(qAsConst(sslErrorsSpy).first().first()); + for (const QSslError &err : sslErrorsSpyErrors) emittedErrors << err.error(); qSort(emittedErrors); QCOMPARE(sslErrors, emittedErrors); @@ -645,7 +653,7 @@ void tst_QSslSocket::sslErrors() QVERIFY(!peerVerifyErrorSpy.isEmpty()); SslErrorList peerErrors; const QList<QVariantList> &peerVerifyList = peerVerifyErrorSpy; - foreach (const QVariantList &args, peerVerifyList) + for (const QVariantList &args : peerVerifyList) peerErrors << qvariant_cast<QSslError>(args.first()).error(); qSort(peerErrors); QCOMPARE(sslErrors, peerErrors); @@ -1159,7 +1167,9 @@ void tst_QSslSocket::protocolServerSide_data() #if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("ssl2-ssl2") << QSsl::SslV2 << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2 #endif +#if !defined(OPENSSL_NO_SSL3) QTest::newRow("ssl3-ssl3") << QSsl::SslV3 << QSsl::SslV3 << true; +#endif 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; @@ -1173,23 +1183,27 @@ void tst_QSslSocket::protocolServerSide_data() QTest::newRow("ssl2-any") << QSsl::SslV2 << QSsl::AnyProtocol << false; // no idea why it does not work, but we don't care about SSL 2 #endif -#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) && !defined(OPENSSL_NO_SSL3) QTest::newRow("ssl3-ssl2") << QSsl::SslV3 << QSsl::SslV2 << false; #endif +#if !defined(OPENSSL_NO_SSL3) QTest::newRow("ssl3-tls1.0") << QSsl::SslV3 << QSsl::TlsV1_0 << false; QTest::newRow("ssl3-tls1ssl3") << QSsl::SslV3 << QSsl::TlsV1SslV3 << true; QTest::newRow("ssl3-secure") << QSsl::SslV3 << QSsl::SecureProtocols << false; -#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) +#endif +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) && !defined(OPENSSL_NO_SSL3) QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << false; // we won't set a SNI header here because we connect to a // numerical IP, so OpenSSL will send a SSL 2 handshake -#else +#elif !defined(OPENSSL_NO_SSL3) QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << true; #endif #if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("tls1.0-ssl2") << QSsl::TlsV1_0 << QSsl::SslV2 << false; #endif +#if !defined(OPENSSL_NO_SSL3) QTest::newRow("tls1.0-ssl3") << QSsl::TlsV1_0 << QSsl::SslV3 << false; +#endif QTest::newRow("tls1-tls1ssl3") << QSsl::TlsV1_0 << QSsl::TlsV1SslV3 << true; QTest::newRow("tls1.0-secure") << QSsl::TlsV1_0 << QSsl::SecureProtocols << true; #if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) @@ -1202,7 +1216,9 @@ void tst_QSslSocket::protocolServerSide_data() #if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("tls1ssl3-ssl2") << QSsl::TlsV1SslV3 << QSsl::SslV2 << false; #endif +#if !defined(OPENSSL_NO_SSL3) QTest::newRow("tls1ssl3-ssl3") << QSsl::TlsV1SslV3 << QSsl::SslV3 << true; +#endif 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; @@ -1210,7 +1226,9 @@ void tst_QSslSocket::protocolServerSide_data() #if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("secure-ssl2") << QSsl::SecureProtocols << QSsl::SslV2 << false; #endif +#if !defined(OPENSSL_NO_SSL3) QTest::newRow("secure-ssl3") << QSsl::SecureProtocols << QSsl::SslV3 << false; +#endif 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; @@ -1218,7 +1236,9 @@ void tst_QSslSocket::protocolServerSide_data() #if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("any-ssl2") << QSsl::AnyProtocol << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2 #endif +#if !defined(OPENSSL_NO_SSL3) QTest::newRow("any-ssl3") << QSsl::AnyProtocol << QSsl::SslV3 << true; +#endif 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; @@ -1243,8 +1263,8 @@ void tst_QSslSocket::protocolServerSide() QEventLoop loop; QTimer::singleShot(5000, &loop, SLOT(quit())); - QSslSocketPtr client(new QSslSocket); - socket = client.data(); + QSslSocket client; + socket = &client; QFETCH(QSsl::SslProtocol, clientProtocol); socket->setProtocol(clientProtocol); // upon SSL wrong version error, error will be triggered, not sslErrors @@ -1252,14 +1272,14 @@ void tst_QSslSocket::protocolServerSide() connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit())); - client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); loop.exec(); QFETCH(bool, works); QAbstractSocket::SocketState expectedState = (works) ? QAbstractSocket::ConnectedState : QAbstractSocket::UnconnectedState; - QCOMPARE(int(client->state()), int(expectedState)); - QCOMPARE(client->isEncrypted(), works); + QCOMPARE(int(client.state()), int(expectedState)); + QCOMPARE(client.isEncrypted(), works); } #ifndef QT_NO_OPENSSL @@ -1284,8 +1304,8 @@ void tst_QSslSocket::serverCipherPreferences() QEventLoop loop; QTimer::singleShot(5000, &loop, SLOT(quit())); - QSslSocketPtr client(new QSslSocket); - socket = client.data(); + QSslSocket client; + socket = &client; socket->setCiphers("AES256-SHA:AES128-SHA"); // upon SSL wrong version error, error will be triggered, not sslErrors @@ -1293,12 +1313,12 @@ void tst_QSslSocket::serverCipherPreferences() connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit())); - client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); loop.exec(); - QVERIFY(client->isEncrypted()); - QCOMPARE(client->sessionCipher().name(), QString("AES128-SHA")); + QVERIFY(client.isEncrypted()); + QCOMPARE(client.sessionCipher().name(), QString("AES128-SHA")); } { @@ -1313,8 +1333,8 @@ void tst_QSslSocket::serverCipherPreferences() QEventLoop loop; QTimer::singleShot(5000, &loop, SLOT(quit())); - QSslSocketPtr client(new QSslSocket); - socket = client.data(); + QSslSocket client; + socket = &client; socket->setCiphers("AES256-SHA:AES128-SHA"); // upon SSL wrong version error, error will be triggered, not sslErrors @@ -1322,12 +1342,12 @@ void tst_QSslSocket::serverCipherPreferences() connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit())); - client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); loop.exec(); - QVERIFY(client->isEncrypted()); - QCOMPARE(client->sessionCipher().name(), QString("AES256-SHA")); + QVERIFY(client.isEncrypted()); + QCOMPARE(client.sessionCipher().name(), QString("AES256-SHA")); } } @@ -1418,21 +1438,21 @@ void tst_QSslSocket::setSocketDescriptor() QEventLoop loop; QTimer::singleShot(5000, &loop, SLOT(quit())); - QSslSocketPtr client(new QSslSocket); - socket = client.data();; + QSslSocket client; + socket = &client; connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit())); - client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); loop.exec(); - QCOMPARE(client->state(), QAbstractSocket::ConnectedState); - QVERIFY(client->isEncrypted()); - QVERIFY(!client->peerAddress().isNull()); - QVERIFY(client->peerPort() != 0); - QVERIFY(!client->localAddress().isNull()); - QVERIFY(client->localPort() != 0); + QCOMPARE(client.state(), QAbstractSocket::ConnectedState); + QVERIFY(client.isEncrypted()); + QVERIFY(!client.peerAddress().isNull()); + QVERIFY(client.peerPort() != 0); + QVERIFY(!client.localAddress().isNull()); + QVERIFY(client.localPort() != 0); } void tst_QSslSocket::setSslConfiguration_data() @@ -2845,10 +2865,37 @@ void tst_QSslSocket::qtbug18498_peek2() void tst_QSslSocket::dhServer() { - if (!QSslSocket::supportsSsl()) { - qWarning("SSL not supported, skipping test"); + if (!QSslSocket::supportsSsl()) + QSKIP("No SSL support"); + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) return; - } + + SslServer server; + server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA"); + QVERIFY(server.listen()); + + QEventLoop loop; + QTimer::singleShot(5000, &loop, SLOT(quit())); + + QSslSocket client; + socket = &client; + connect(socket, SIGNAL(error(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()); + + loop.exec(); + QCOMPARE(client.state(), QAbstractSocket::ConnectedState); +} + +#ifndef QT_NO_OPENSSL +void tst_QSslSocket::dhServerCustomParamsNull() +{ + if (!QSslSocket::supportsSsl()) + QSKIP("No SSL support"); QFETCH_GLOBAL(bool, setProxy); if (setProxy) @@ -2856,22 +2903,74 @@ void tst_QSslSocket::dhServer() SslServer server; server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA"); + + QSslConfiguration cfg = server.config; + cfg.setDiffieHellmanParameters(QSslDiffieHellmanParameters()); + server.config = cfg; + QVERIFY(server.listen()); QEventLoop loop; QTimer::singleShot(5000, &loop, SLOT(quit())); - QSslSocketPtr client(new QSslSocket); - socket = client.data(); + QSslSocket client; + socket = &client; connect(socket, SIGNAL(error(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()); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); loop.exec(); - QCOMPARE(client->state(), QAbstractSocket::ConnectedState); + + QVERIFY(client.state() != QAbstractSocket::ConnectedState); } +#endif // QT_NO_OPENSSL + +#ifndef QT_NO_OPENSSL +void tst_QSslSocket::dhServerCustomParams() +{ + if (!QSslSocket::supportsSsl()) + QSKIP("No SSL support"); + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + SslServer server; + server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA"); + + QSslConfiguration cfg = server.config; + + // Custom 2048-bit DH parameters generated with 'openssl dhparam -outform DER -out out.der -check -2 2048' + const auto dh = QSslDiffieHellmanParameters::fromEncoded(QByteArray::fromBase64(QByteArrayLiteral( + "MIIBCAKCAQEAvVA7b8keTfjFutCtTJmP/pnQfw/prKa+GMed/pBWjrC4N1YwnI8h/A861d9WE/VWY7XMTjvjX3/0" + "aaU8wEe0EXNpFdlTH+ZMQctQTSJOyQH0RCTwJfDGPCPT9L+c9GKwEKWORH38Earip986HJc0w3UbnfIwXUdsWHiXi" + "Z6r3cpyBmTKlsXTFiDVAOUXSiO8d/zOb6zHZbDfyB/VbtZRmnA7TXVn9oMzC0g9+FXHdrV4K+XfdvNZdCegvoAZiy" + "R6ZQgNG9aZ36/AQekhg060hp55f9HDPgXqYeNeXBiferjUtU7S9b3s83XhOJAr01/0Tf5dENwCfg2gK36TM8cC4wI" + "BAg==")), QSsl::Der); + cfg.setDiffieHellmanParameters(dh); + + server.config = cfg; + + QVERIFY(server.listen()); + + QEventLoop loop; + QTimer::singleShot(5000, &loop, SLOT(quit())); + + QSslSocket client; + socket = &client; + connect(socket, SIGNAL(error(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()); + + loop.exec(); + + QVERIFY(client.state() == QAbstractSocket::ConnectedState); +} +#endif // QT_NO_OPENSSL void tst_QSslSocket::ecdhServer() { @@ -2891,16 +2990,16 @@ void tst_QSslSocket::ecdhServer() QEventLoop loop; QTimer::singleShot(5000, &loop, SLOT(quit())); - QSslSocketPtr client(new QSslSocket); - socket = client.data(); + QSslSocket client; + socket = &client; connect(socket, SIGNAL(error(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()); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); loop.exec(); - QCOMPARE(client->state(), QAbstractSocket::ConnectedState); + QCOMPARE(client.state(), QAbstractSocket::ConnectedState); } void tst_QSslSocket::verifyClientCertificate_data() @@ -3002,16 +3101,16 @@ void tst_QSslSocket::verifyClientCertificate() QFETCH(QList<QSslCertificate>, clientCerts); QFETCH(QSslKey, clientKey); - QSslSocketPtr client(new QSslSocket); - client->setLocalCertificateChain(clientCerts); - client->setPrivateKey(clientKey); - socket = client.data(); + QSslSocket client; + client.setLocalCertificateChain(clientCerts); + client.setPrivateKey(clientKey); + socket = &client; connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); connect(socket, SIGNAL(disconnected()), &loop, SLOT(quit())); connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit())); - client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); loop.exec(); @@ -3033,8 +3132,8 @@ void tst_QSslSocket::verifyClientCertificate() } // check client socket - QCOMPARE(int(client->state()), int(expectedState)); - QCOMPARE(client->isEncrypted(), works); + QCOMPARE(int(client.state()), int(expectedState)); + QCOMPARE(client.isEncrypted(), works); } void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, as it has some side effects @@ -3063,8 +3162,12 @@ class PskProvider : public QObject Q_OBJECT public: + bool m_server; + QByteArray m_identity; + QByteArray m_psk; + explicit PskProvider(QObject *parent = 0) - : QObject(parent) + : QObject(parent), m_server(false) { } @@ -3083,7 +3186,11 @@ public slots: { QVERIFY(authenticator); QCOMPARE(authenticator->identityHint(), PSK_SERVER_IDENTITY_HINT); - QVERIFY(authenticator->maximumIdentityLength() > 0); + if (m_server) + QCOMPARE(authenticator->maximumIdentityLength(), 0); + else + QVERIFY(authenticator->maximumIdentityLength() > 0); + QVERIFY(authenticator->maximumPreSharedKeyLength() > 0); if (!m_identity.isEmpty()) { @@ -3096,12 +3203,61 @@ public slots: QCOMPARE(authenticator->preSharedKey(), m_psk); } } - -private: - QByteArray m_identity; - QByteArray m_psk; }; +class PskServer : public QTcpServer +{ + Q_OBJECT +public: + PskServer() + : socket(0), + config(QSslConfiguration::defaultConfiguration()), + ignoreSslErrors(true), + peerVerifyMode(QSslSocket::AutoVerifyPeer), + protocol(QSsl::TlsV1_0), + m_pskProvider() + { + m_pskProvider.m_server = true; + } + QSslSocket *socket; + QSslConfiguration config; + bool ignoreSslErrors; + QSslSocket::PeerVerifyMode peerVerifyMode; + QSsl::SslProtocol protocol; + QString ciphers; + PskProvider m_pskProvider; + +protected: + void incomingConnection(qintptr socketDescriptor) + { + socket = new QSslSocket(this); + socket->setSslConfiguration(config); + socket->setPeerVerifyMode(peerVerifyMode); + socket->setProtocol(protocol); + if (ignoreSslErrors) + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); + + if (!ciphers.isEmpty()) { + socket->setCiphers(ciphers); + } + + QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState)); + QVERIFY(!socket->peerAddress().isNull()); + QVERIFY(socket->peerPort() != 0); + QVERIFY(!socket->localAddress().isNull()); + QVERIFY(socket->localPort() != 0); + + connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired, &m_pskProvider, &PskProvider::providePsk); + + socket->startServerEncryption(); + } + +protected slots: + void ignoreErrorSlot() + { + socket->ignoreSslErrors(); + } +}; void tst_QSslSocket::simplePskConnect_data() { QTest::addColumn<PskConnectTestType>("pskTestType"); @@ -3125,7 +3281,7 @@ void tst_QSslSocket::simplePskConnect() bool pskCipherFound = false; const QList<QSslCipher> supportedCiphers = QSslSocket::supportedCiphers(); - foreach (const QSslCipher &cipher, supportedCiphers) { + for (const QSslCipher &cipher : supportedCiphers) { if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) { pskCipherFound = true; break; @@ -3403,6 +3559,129 @@ void tst_QSslSocket::ephemeralServerKey() QCOMPARE(client->sslConfiguration().ephemeralServerKey().isNull(), emptyKey); } +void tst_QSslSocket::allowedProtocolNegotiation() +{ +#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_TLSEXT) + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + const QByteArray expectedNegotiated("cool-protocol"); + QList<QByteArray> serverProtos; + serverProtos << expectedNegotiated << "not-so-cool-protocol"; + QList<QByteArray> clientProtos; + clientProtos << "uber-cool-protocol" << expectedNegotiated << "not-so-cool-protocol"; + + + SslServer server; + server.config.setAllowedNextProtocols(serverProtos); + QVERIFY(server.listen()); + + QSslSocket clientSocket; + auto configuration = clientSocket.sslConfiguration(); + configuration.setAllowedNextProtocols(clientProtos); + clientSocket.setSslConfiguration(configuration); + + clientSocket.connectToHostEncrypted("127.0.0.1", server.serverPort()); + clientSocket.ignoreSslErrors(); + + QEventLoop loop; + QTimer::singleShot(5000, &loop, SLOT(quit())); + connect(&clientSocket, SIGNAL(encrypted()), &loop, SLOT(quit())); + loop.exec(); + + QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() == + clientSocket.sslConfiguration().nextNegotiatedProtocol()); + QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() == expectedNegotiated); + +#endif // OPENSSL_VERSION_NUMBER +} + +void tst_QSslSocket::pskServer() +{ + QFETCH_GLOBAL(bool, setProxy); + if (!QSslSocket::supportsSsl() || setProxy) + return; + + QSslSocket socket; + this->socket = &socket; + + QSignalSpy connectedSpy(&socket, SIGNAL(connected())); + QVERIFY(connectedSpy.isValid()); + + QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); + QVERIFY(disconnectedSpy.isValid()); + + QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted())); + QVERIFY(connectionEncryptedSpy.isValid()); + + QSignalSpy pskAuthenticationRequiredSpy(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*))); + QVERIFY(pskAuthenticationRequiredSpy.isValid()); + + connect(&socket, SIGNAL(connected()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(disconnected()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(encrypted()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(peerVerifyError(QSslError)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(exitLoop())); + + // force a PSK cipher w/o auth + socket.setCiphers(PSK_CIPHER_WITHOUT_AUTH); + + PskProvider provider; + provider.setIdentity(PSK_CLIENT_IDENTITY); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY); + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + socket.setPeerVerifyMode(QSslSocket::VerifyNone); + + PskServer server; + server.m_pskProvider.setIdentity(provider.m_identity); + server.m_pskProvider.setPreSharedKey(provider.m_psk); + server.config.setPreSharedKeyIdentityHint(PSK_SERVER_IDENTITY_HINT); + QVERIFY(server.listen()); + + // Start connecting + socket.connectToHost(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + enterLoop(5); + + // Entered connected state + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode); + QVERIFY(!socket.isEncrypted()); + QCOMPARE(connectedSpy.count(), 1); + QCOMPARE(disconnectedSpy.count(), 0); + + // Enter encrypted mode + socket.startClientEncryption(); + QCOMPARE(socket.mode(), QSslSocket::SslClientMode); + QVERIFY(!socket.isEncrypted()); + QCOMPARE(connectionEncryptedSpy.count(), 0); + + // Start handshake. + enterLoop(10); + + // We must get the PSK signal in all cases + QCOMPARE(pskAuthenticationRequiredSpy.count(), 1); + + QCOMPARE(connectionEncryptedSpy.count(), 1); + QVERIFY(socket.isEncrypted()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + + // check writing + socket.write("Hello from Qt TLS/PSK!"); + QVERIFY(socket.waitForBytesWritten()); + + // disconnect + socket.disconnectFromHost(); + enterLoop(10); + + QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); + QCOMPARE(disconnectedSpy.count(), 1); +} + #endif // QT_NO_OPENSSL #endif // QT_NO_SSL |