qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,22 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT QT_FEATURE_private_tests)
return()
endif()
#####################################################################
## tst_qsslserver Test:
#####################################################################
# Collect test data
list(APPEND test_data "certs")
qt_internal_add_test(tst_qsslserver
SOURCES
tst_qsslserver.cpp
LIBRARIES
Qt::CorePrivate
Qt::NetworkPrivate
TESTDATA ${test_data}
)

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC6TCCAdECCC/r9KvmbWTKMA0GCSqGSIb3DQEBCwUAMDUxFDASBgNVBAMMC0F1
c3dlaXNBcHAyMR0wGwYDVQQFExQxODIzNTE0MTY0NzI5NDg5NDM3MTAiGA8xOTcw
MDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjA1MRQwEgYDVQQDDAtBdXN3ZWlz
QXBwMjEdMBsGA1UEBRMUMTgyMzUxNDE2NDcyOTQ4OTQzNzEwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCahBpcZyr+PJBCpolzQeFVvDKABwlpdRKGZ8qq
jD4sq2L7VlBJslgJGv5vsB5oJbnX1FFEu4Uw2kYb/LhnFCEXEFtGKRpWOEZOOqWb
4l4q2MCa82ZCoIDt8yoAt0sSShbtR6pjW+l0lwAOEpfGvMaMVo5JUyspRxhl1dSu
sS2Wf65zliqF5VSM2r4xMfJ6LVytxDZsGfTe/HFT2OYYrF+UQZg0mNL39rYWOK4R
xoOz8eLl3K5hKuHNfn5zPt5QtMhaIvebijBg23xJpl+BeoS37WzaK1f+NyWZKPFb
rttvSnFxpkyRHqJJ5piNGH6pkQ1+zhd7uh7eOIwxktjYBOFzAgMBAAEwDQYJKoZI
hvcNAQELBQADggEBADw3MYPft+X78OK/2HAltzsKjfxv/D5qVizm9hcyG1GYe5pS
qgFn0trCyJopYdbRr+hP7CuHwMmv62CZiHSog3CBPoUh19JENUDGbHXxTEFleB0i
Fd8I2+WvRjbQ+ehaeTJPx88v5kkJnB2tZUNZuhEws8emCwr1G0TQv1tRYCR1Lp9i
8/I3FSFpL1zyk47WfM/THa279MPw9WtrFGA6oi36gH9mYxek7n/zQTVi54xDx9GT
KigBYqavjFdNXryjLTCCtJpMTDePgP66NAUnxn0D/amI2vSbIN++PSTsBm+n4Ti5
QW/ShFQDNb4bDiwjtTKCeKwvAp2/6GSHVkYy28M=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAmoQaXGcq/jyQQqaJc0HhVbwygAcJaXUShmfKqow+LKti+1ZQ
SbJYCRr+b7AeaCW519RRRLuFMNpGG/y4ZxQhFxBbRikaVjhGTjqlm+JeKtjAmvNm
QqCA7fMqALdLEkoW7UeqY1vpdJcADhKXxrzGjFaOSVMrKUcYZdXUrrEtln+uc5Yq
heVUjNq+MTHyei1crcQ2bBn03vxxU9jmGKxflEGYNJjS9/a2FjiuEcaDs/Hi5dyu
YSrhzX5+cz7eULTIWiL3m4owYNt8SaZfgXqEt+1s2itX/jclmSjxW67bb0pxcaZM
kR6iSeaYjRh+qZENfs4Xe7oe3jiMMZLY2AThcwIDAQABAoIBAFjgvc0C5t8AdTZx
VsS+U2Aedang4lAPsE0xbIj3TFgjaTcLKfmKJUtvhIU39/WOJbz4+pofhvhXxVYZ
4vQfxvzeQrIzuFt52S7sWxA0gFgC/57hfKO8cQzt/u4UgJEPnupze5XVa47NwJFX
rof5U/erXgLdXQlMRMNm4QRvE7rp58E2MkSYNur0Xgy9L7cRcUQJ8iuMaxBpOzhS
fbNFi5zT7RCGcQSIDcb1JFlgs5tMUs6jzLoDSVD2+vvsN4i4LAAPkJSGTGed5vY1
xn4G8KPR4HHrnBYEb0SGu4ZTznOnQ+JSKhQrbnvEzXM4RTfjqn0YvF8x70+pWSMi
Fb4mlBECgYEAzW82O79HAlMm8LD7J4byPfVc/1M5/JOnE9H+RR5Vt4jZQGyjCmJu
cj4UeZyVim0xg30sSYrJ2Urd27CtHp+sMgHkvJt3/ZgcfMZJbMKNGq/OUtV8s/cA
nkU++/LgeW8r7wpaDjT7bfnOdcf16mYoXrmk0rTJvRqGXCBvCxtt5bsCgYEAwIxu
vZjPV4Vu/VX6sH2d31D9EFZuZKjGhqukFVtRqLbeosqT9mA+LhQ/wP5qoR2gLQbe
EwxJLJwGFjUhyhbHNlo6oHv3fWkzmHIMPwDRRI3Ktwi/50SwNSnyERUQcLaiwqKx
BqaxPYNnspUt0nKE0LFZsSlrfEyxajqAlUEgm6kCgYAV+uQumFScpxDvh8AXhpS8
lFgS6XC22YVy1XEDLC+3p2i3P+hh4A45IvNF378QRIabrvTiGXtnSF9cdhbPw/3E
i/dRRsEb3P6PSxfoDxjR1iWZL0Zcav0h8f6/LkleNMralJz2EC0moye36mEhZzTC
jdJYyQccuI3PpZi7839aqQKBgGezOnEiO4kHdB88jyc+gCglliWWZx4PR9x/1H8s
D26uDnneYJHwg4yNm0h1vTfInNujNzdLBp3f6edL9kbAvcmoDqsgGMqSPhd8VNwZ
tJsXQnYRYElN1RjM3nIUxiXuNvpcZLsQS6S1gMPNVEBjLOS4n3WquRjYtTRhDZ9U
1BsBAoGAUFrIatOLFhcgaqENHyUbMx5uSx0lIfF6Xd5KIAgi+btdmugHe+NK8Cd2
Rc2bQLQ9K1SvKFX6nFuEsGxnXkKuyhL/j0Kgm8nZin4uAcrtFnNdFumvCL6YgYSc
IvvM+uVfGEdbqm4pTuiLBfzOXIIy3kVlLGo402QG1pBzOtmsRMs=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC5TCCAc0CCAO22gNi0v20MA0GCSqGSIb3DQEBCwUAMDMxFDASBgNVBAMMC0F1
c3dlaXNBcHAyMRswGQYDVQQFExIyNTIxMTE1NjY3NjM2MjExODgwIhgPMTk3MDAx
MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowMzEUMBIGA1UEAwwLQXVzd2Vpc0Fw
cDIxGzAZBgNVBAUTEjI1MjExMTU2Njc2MzYyMTE4ODCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAL+Fl6v5dcU7qk7vbINclWOhvCe/uklKnXV2QU382x7g
qpbYxJiJvz24C6tgDMmE0pwEz6PiCbh1dkc8+9cdp37eBcFLCOXYQb27gqVVyVtu
xO0LLVXPCv48bGSwljOz0FRC3FolzWxzrZogM/i2b/lmehHJ3D4ejmINmIgtFJ9P
JNNCH4Oh5YEbaFFlNf2m7lCoSuQkOlLZcGeLoipK2XvhZJff6c1uxValh/Mx5dNB
5Mgd5cOZSSEhwf7mcE8C3SHVfjeNfZGIqlkwdY8lvAOjirAtj6Yl88sJOUID/Q/N
hU9D8IZy6+Bk2cJQwI/Gzr590VYvlSTI+6lXr//oBBECAwEAATANBgkqhkiG9w0B
AQsFAAOCAQEArSMO88AYT+9tPCl5lXtSRa0OycqKNlW58GujxIDuR8WX1eFmGSHQ
uijo5KPYUnqydZzAewGC8NvC9WcLwFltNZ9igXikUHiAHc1JLfW7+7SgKpwOUb02
rJkUkpPA/SmwkLSKYiR1prt5wgSulU1HPBESep05DfR8MCU5+KHkLyXDqtrbudJ4
lQd9dSKJFn+cSjUC5JNxCPHoIISe7hfGFMLkd0/tVfSIXLVOAZG4K6zExUdjyPi8
qEuPq6QCRyIJbYQc5HfnARgwK6GXHqkyLWlqK946Yz8VOba7Nan5uQ6xCjUMHw8Z
z/673o/3DCaQ9N6dWahNQ09a9ZH8U1X4iA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAv4WXq/l1xTuqTu9sg1yVY6G8J7+6SUqddXZBTfzbHuCqltjE
mIm/PbgLq2AMyYTSnATPo+IJuHV2Rzz71x2nft4FwUsI5dhBvbuCpVXJW27E7Qst
Vc8K/jxsZLCWM7PQVELcWiXNbHOtmiAz+LZv+WZ6EcncPh6OYg2YiC0Un08k00If
g6HlgRtoUWU1/abuUKhK5CQ6UtlwZ4uiKkrZe+Fkl9/pzW7FVqWH8zHl00HkyB3l
w5lJISHB/uZwTwLdIdV+N419kYiqWTB1jyW8A6OKsC2PpiXzywk5QgP9D82FT0Pw
hnLr4GTZwlDAj8bOvn3RVi+VJMj7qVev/+gEEQIDAQABAoIBADdoXsjSEtBMwqiz
e6FFV7LLR7P4M9ygSY2B+MKnNH1qYe/iJn4626jvZfDeiNSEKKoaejffXRCQaveR
HQrO+XYqpV+WZayZM+vAI7vRZb+d/DrX0PXSQEvtDy7SJ6Itk0fNUBKEfTmy/bZp
Op/pp9tvWkFrNNyD2o1jgY1j/WNY8g605m0oURJ9WQsMUu/Kzu+NMoaKTIoQGb3d
dP71F4KaTXHYxj3B0c+y0NedKbrvnBsP6XbEpgJBaXjtD9z+z/aMF6dmuvpkx7uY
qzwPMRw05QPyJ9x+1V/v4TytY5f596NgW2niVj77BunkZasTYIEX7bjByrlTeLdx
xvPRpAECgYEA5KkM/ORbhN1oaw9+tQxA48oG2DFqChBr+vc4NU4j5SNFn9ks5nHI
xdJNZ9k+bjVUkBP4m88Wd07SW9zXCL8Q5lczb+p5SWl/Pp7ltqaxpH17uzamsaIv
KIBkeJTOU5TuWdXiV5FY+ofK9ojyEaqX1tmylWnoVe4bIMRWXE5bMSkCgYEA1mvJ
snkNzPFG0RK7ikjsNxrhzE07+7RSnoM9WeW8y2lvQ9MjdR6eOgqnnlcdk2A7OVbf
culNgLc0qx/PxZ4BV+8yLLb1EBBGvuVG+x4a6H2mLHdFCJekByZHaQNs9ogVLvdv
3z8D59KknBUjtj9dCw90Z41yMM4kpWMG9yfSEKkCgYEAvuCvytwF2d/JrrV8nD3i
XUTkecymLEiRGysMbNMR+9F56XotlSEe7KQloa8kAnPaZ3uEaOxyYJ4X1D+B8fct
cFsSwTYGkVXTtr6GG/cDC8EEbL+uX1J382Nae54croEAh1WYYGkg0eJRd4PSLxUt
M1j/TuLd4/2j/7JmNR/j2CECgYBdB3MBHghgzKXe+/OmMbFazyz8SN4nfLsDzwkF
QenBj0MY+DhADkK0B/9lcYKBeJT5cbmMz7AykkolnK22nbETh9ILGG4GxCkNlchQ
F2WxTSKV1EF9Ut11xKPi6fuSksQuFmjRQTPelsOYfIt7/M3PiKsGapYKmsXHg8l3
3i0D0QKBgQCi+HNOaYqduxwjrj8h4eUbiwjID8DCNJ+jXsuGVa6jcsfFpdpivx2c
ytYSXuTXLRq0I3c1ChUOGQQeztJ5GtCPnXjLHHMf3f6yr7Pk56AUmUsaIlR1Q2Zo
gqpFD8zYD5UFc2KM7Y38YTh4j82uDzDvHBBFpli7dEmSn2WpcmzFag==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,531 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QDebug>
#include <QSignalSpy>
#include <QTimer>
#include <QtNetwork/QSslServer>
#include <QtNetwork/QSslKey>
#include "private/qtlsbackend_p.h"
class tst_QSslServer : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void testOneSuccessfulConnection();
void testSelfSignedCertificateRejectedByServer();
void testSelfSignedCertificateRejectedByClient();
#if QT_CONFIG(openssl)
void testHandshakeInterruptedOnError();
void testPreSharedKeyAuthenticationRequired();
#endif
void plaintextClient();
void quietClient();
void twoGoodAndManyBadClients();
private:
QString testDataDir;
bool isTestingOpenSsl = false;
QSslConfiguration selfSignedClientQSslConfiguration();
QSslConfiguration selfSignedServerQSslConfiguration();
QSslConfiguration createQSslConfiguration(QString keyFileName, QString certificateFileName);
};
class SslServerSpy : public QObject
{
Q_OBJECT
public:
SslServerSpy(QSslConfiguration &configuration);
QSslServer server;
QSignalSpy sslErrorsSpy;
QSignalSpy peerVerifyErrorSpy;
QSignalSpy errorOccurredSpy;
QSignalSpy pendingConnectionAvailableSpy;
QSignalSpy preSharedKeyAuthenticationRequiredSpy;
QSignalSpy alertSentSpy;
QSignalSpy alertReceivedSpy;
QSignalSpy handshakeInterruptedOnErrorSpy;
QSignalSpy startedEncryptionHandshakeSpy;
};
SslServerSpy::SslServerSpy(QSslConfiguration &configuration)
: server(),
sslErrorsSpy(&server, &QSslServer::sslErrors),
peerVerifyErrorSpy(&server, &QSslServer::peerVerifyError),
errorOccurredSpy(&server, &QSslServer::errorOccurred),
pendingConnectionAvailableSpy(&server, &QSslServer::pendingConnectionAvailable),
preSharedKeyAuthenticationRequiredSpy(&server,
&QSslServer::preSharedKeyAuthenticationRequired),
alertSentSpy(&server, &QSslServer::alertSent),
alertReceivedSpy(&server, &QSslServer::alertReceived),
handshakeInterruptedOnErrorSpy(&server, &QSslServer::handshakeInterruptedOnError),
startedEncryptionHandshakeSpy(&server, &QSslServer::startedEncryptionHandshake)
{
server.setSslConfiguration(configuration);
}
void tst_QSslServer::initTestCase()
{
testDataDir = QFileInfo(QFINDTESTDATA("certs")).absolutePath();
if (testDataDir.isEmpty())
testDataDir = QCoreApplication::applicationDirPath();
if (!testDataDir.endsWith(QLatin1String("/")))
testDataDir += QLatin1String("/");
const QString openSslBackend = QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexOpenSSL];
const auto &tlsBackends = QSslSocket::availableBackends();
if (tlsBackends.contains(openSslBackend)) {
isTestingOpenSsl = true;
}
}
QSslConfiguration tst_QSslServer::selfSignedClientQSslConfiguration()
{
return createQSslConfiguration(testDataDir + "certs/selfsigned-client.key",
testDataDir + "certs/selfsigned-client.crt");
}
QSslConfiguration tst_QSslServer::selfSignedServerQSslConfiguration()
{
return createQSslConfiguration(testDataDir + "certs/selfsigned-server.key",
testDataDir + "certs/selfsigned-server.crt");
}
QSslConfiguration tst_QSslServer::createQSslConfiguration(QString keyFileName,
QString certificateFileName)
{
QSslConfiguration configuration(QSslConfiguration::defaultConfiguration());
QFile keyFile(keyFileName);
if (keyFile.open(QIODevice::ReadOnly)) {
QSslKey key(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
if (!key.isNull()) {
configuration.setPrivateKey(key);
} else {
qCritical() << "Could not parse key: " << keyFileName;
}
} else {
qCritical() << "Could not find key: " << keyFileName;
}
QList<QSslCertificate> localCert = QSslCertificate::fromPath(certificateFileName);
if (!localCert.isEmpty() && !localCert.first().isNull()) {
configuration.setLocalCertificate(localCert.first());
} else {
qCritical() << "Could not find certificate: " << certificateFileName;
}
return configuration;
}
void tst_QSslServer::testOneSuccessfulConnection()
{
// Setup server
QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration();
SslServerSpy server(serverConfiguration);
QVERIFY(server.server.listen());
// Check that all signal spys are valid
QVERIFY(server.sslErrorsSpy.isValid());
QVERIFY(server.peerVerifyErrorSpy.isValid());
QVERIFY(server.errorOccurredSpy.isValid());
QVERIFY(server.pendingConnectionAvailableSpy.isValid());
QVERIFY(server.preSharedKeyAuthenticationRequiredSpy.isValid());
QVERIFY(server.alertSentSpy.isValid());
QVERIFY(server.alertReceivedSpy.isValid());
QVERIFY(server.handshakeInterruptedOnErrorSpy.isValid());
QVERIFY(server.startedEncryptionHandshakeSpy.isValid());
// Check that no connections has occurred
QCOMPARE(server.sslErrorsSpy.size(), 0);
QCOMPARE(server.peerVerifyErrorSpy.size(), 0);
QCOMPARE(server.errorOccurredSpy.size(), 0);
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0);
QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0);
QCOMPARE(server.alertSentSpy.size(), 0);
QCOMPARE(server.alertReceivedSpy.size(), 0);
QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0);
QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 0);
// Connect client
QSslSocket client;
QSslConfiguration clientConfiguration = QSslConfiguration::defaultConfiguration();
client.setSslConfiguration(clientConfiguration);
client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
server.server.serverPort());
// Type of certificate error to expect
const auto certificateError =
isTestingOpenSsl ? QSslError::SelfSignedCertificate : QSslError::CertificateUntrusted;
// Expected errors
connect(&client, &QSslSocket::sslErrors,
[&certificateError, &client](const QList<QSslError> &errors) {
QCOMPARE(errors.size(), 2);
for (auto error : errors) {
QVERIFY(error.error() == certificateError
|| error.error() == QSslError::HostNameMismatch);
}
client.ignoreSslErrors();
});
QEventLoop loop;
int waitFor = 2;
connect(&client, &QSslSocket::encrypted, [&loop, &waitFor]() {
if (!--waitFor)
loop.quit();
});
connect(&server.server, &QTcpServer::pendingConnectionAvailable, [&loop, &waitFor]() {
if (!--waitFor)
loop.quit();
});
QTimer::singleShot(5000, &loop, SLOT(quit()));
loop.exec();
// Check that one encrypted connection has occurred without error
QCOMPARE(server.sslErrorsSpy.size(), 0);
QCOMPARE(server.peerVerifyErrorSpy.size(), 0);
QCOMPARE(server.errorOccurredSpy.size(), 0);
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1);
QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0);
QCOMPARE(server.alertSentSpy.size(), 0);
QCOMPARE(server.alertReceivedSpy.size(), 0);
QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0);
QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1);
// Check client socket
QVERIFY(client.isEncrypted());
QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
}
void tst_QSslServer::testSelfSignedCertificateRejectedByServer()
{
// Set up server that verifies client
QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration();
serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer);
SslServerSpy server(serverConfiguration);
QVERIFY(server.server.listen());
// Connect client
QSslSocket client;
QSslConfiguration clientConfiguration = selfSignedClientQSslConfiguration();
clientConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
client.setSslConfiguration(clientConfiguration);
client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
server.server.serverPort());
QEventLoop loop;
QObject::connect(&client, SIGNAL(disconnected()), &loop, SLOT(quit()));
QTimer::singleShot(5000, &loop, SLOT(quit()));
loop.exec();
// Check that one encrypted connection has failed
QCOMPARE(server.sslErrorsSpy.size(), 1);
QCOMPARE(server.peerVerifyErrorSpy.size(), 1);
QCOMPARE(server.errorOccurredSpy.size(), 1);
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0);
QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0);
QCOMPARE(server.alertSentSpy.size(),
isTestingOpenSsl ? 1 : 0); // OpenSSL only signal
QCOMPARE(server.alertReceivedSpy.size(), 0);
QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0);
QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1);
// Type of certificate error to expect
const auto certificateError =
isTestingOpenSsl ? QSslError::SelfSignedCertificate : QSslError::CertificateUntrusted;
// Check the sslErrorsSpy
const auto sslErrorsSpyErrors =
qvariant_cast<QList<QSslError>>(std::as_const(server.sslErrorsSpy).first()[1]);
QCOMPARE(sslErrorsSpyErrors.size(), 1);
QCOMPARE(sslErrorsSpyErrors.first().error(), certificateError);
// Check the peerVerifyErrorSpy
const auto peerVerifyErrorSpyError =
qvariant_cast<QSslError>(std::as_const(server.peerVerifyErrorSpy).first()[1]);
QCOMPARE(peerVerifyErrorSpyError.error(), certificateError);
// Check client socket
QVERIFY(!client.isEncrypted());
QCOMPARE(client.state(), QAbstractSocket::UnconnectedState);
}
void tst_QSslServer::testSelfSignedCertificateRejectedByClient()
{
// Set up server without verification of client
QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration();
SslServerSpy server(serverConfiguration);
QVERIFY(server.server.listen());
// Connect client that authenticates server
QSslSocket client;
QSslConfiguration clientConfiguration = selfSignedClientQSslConfiguration();
if (isTestingOpenSsl) {
clientConfiguration.setHandshakeMustInterruptOnError(true);
QVERIFY(clientConfiguration.handshakeMustInterruptOnError());
}
client.setSslConfiguration(clientConfiguration);
QSignalSpy clientConnectedSpy(&client, SIGNAL(connected()));
QSignalSpy clientHostFoundSpy(&client, SIGNAL(hostFound()));
QSignalSpy clientDisconnectedSpy(&client, SIGNAL(disconnected()));
QSignalSpy clientConnectionEncryptedSpy(&client, SIGNAL(encrypted()));
QSignalSpy clientSslErrorsSpy(&client, SIGNAL(sslErrors(QList<QSslError>)));
QSignalSpy clientErrorOccurredSpy(&client, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
server.server.serverPort());
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
// Type of socket error to expect
const auto socketError = isTestingOpenSsl
? QAbstractSocket::SocketError::SslHandshakeFailedError
: QAbstractSocket::SocketError::RemoteHostClosedError;
QTcpSocket *connection = server.server.nextPendingConnection();
if (connection == nullptr) {
// Client disconnected before connection accepted by server
QCOMPARE(server.sslErrorsSpy.size(), 0);
QCOMPARE(server.peerVerifyErrorSpy.size(), 0);
QCOMPARE(server.errorOccurredSpy.size(), 1); // Client rejected first
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0);
QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0);
QCOMPARE(server.alertSentSpy.size(), 0);
QCOMPARE(server.alertReceivedSpy.size(),
isTestingOpenSsl ? 1 : 0); // OpenSSL only signal
QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0);
QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1);
const auto errrOccuredSpyError = qvariant_cast<QAbstractSocket::SocketError>(
std::as_const(server.errorOccurredSpy).first()[1]);
QCOMPARE(errrOccuredSpyError, socketError);
} else {
// Client disconnected after connection accepted by server
QCOMPARE(server.sslErrorsSpy.size(), 0);
QCOMPARE(server.peerVerifyErrorSpy.size(), 0);
QCOMPARE(server.errorOccurredSpy.size(), 0); // Server accepted first
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1);
QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0);
QCOMPARE(server.alertSentSpy.size(), 0);
QCOMPARE(server.alertReceivedSpy.size(),
isTestingOpenSsl ? 1 : 0); // OpenSSL only signal
QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0);
QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1);
QCOMPARE(connection->state(), QAbstractSocket::UnconnectedState);
QCOMPARE(connection->error(), socketError);
auto sslConnection = qobject_cast<QSslSocket *>(connection);
QVERIFY(sslConnection);
QVERIFY(!sslConnection->isEncrypted());
}
// Check that client has rejected server
QCOMPARE(clientConnectedSpy.size(), 1);
QCOMPARE(clientHostFoundSpy.size(), 1);
QCOMPARE(clientDisconnectedSpy.size(), 1);
QCOMPARE(clientConnectionEncryptedSpy.size(), 0);
QCOMPARE(clientSslErrorsSpy.size(), isTestingOpenSsl ? 0 : 1);
QCOMPARE(clientErrorOccurredSpy.size(), 1);
// Check client socket
QVERIFY(!client.isEncrypted());
QCOMPARE(client.state(), QAbstractSocket::UnconnectedState);
}
#if QT_CONFIG(openssl)
void tst_QSslServer::testHandshakeInterruptedOnError()
{
if (!isTestingOpenSsl)
QSKIP("This test requires OpenSSL as the active TLS backend");
auto serverConfiguration = selfSignedServerQSslConfiguration();
serverConfiguration.setHandshakeMustInterruptOnError(true);
QVERIFY(serverConfiguration.handshakeMustInterruptOnError());
serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer);
SslServerSpy server(serverConfiguration);
server.server.listen();
QSslSocket client;
auto clientConfiguration = selfSignedClientQSslConfiguration();
clientConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
client.setSslConfiguration(clientConfiguration);
client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
server.server.serverPort());
QEventLoop loop;
QObject::connect(&client, SIGNAL(disconnected()), &loop, SLOT(quit()));
QTimer::singleShot(5000, &loop, SLOT(quit()));
loop.exec();
// Check that client certificate causes handshake interrupted signal to be emitted
QCOMPARE(server.sslErrorsSpy.size(), 0);
QCOMPARE(server.peerVerifyErrorSpy.size(), 0);
QCOMPARE(server.errorOccurredSpy.size(), 1);
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0);
QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0);
QCOMPARE(server.alertSentSpy.size(), 1);
QCOMPARE(server.alertReceivedSpy.size(), 0);
QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 1);
QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1);
}
void tst_QSslServer::testPreSharedKeyAuthenticationRequired()
{
if (!isTestingOpenSsl)
QSKIP("This test requires OpenSSL as the active TLS backend");
auto serverConfiguration = QSslConfiguration::defaultConfiguration();
serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer);
serverConfiguration.setProtocol(QSsl::TlsV1_2);
serverConfiguration.setCiphers({ QSslCipher("PSK-AES256-CBC-SHA") });
serverConfiguration.setPreSharedKeyIdentityHint("Server Y");
SslServerSpy server(serverConfiguration);
connect(&server.server, &QSslServer::preSharedKeyAuthenticationRequired,
[](QSslSocket *, QSslPreSharedKeyAuthenticator *authenticator) {
QCOMPARE(authenticator->identity(), QByteArray("Client X"));
authenticator->setPreSharedKey("123456");
});
server.server.listen();
QSslSocket client;
auto clientConfiguration = QSslConfiguration::defaultConfiguration();
clientConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
clientConfiguration.setProtocol(QSsl::TlsV1_2);
clientConfiguration.setCiphers({ QSslCipher("PSK-AES256-CBC-SHA") });
client.setSslConfiguration(clientConfiguration);
connect(&client, &QSslSocket::preSharedKeyAuthenticationRequired,
[](QSslPreSharedKeyAuthenticator *authenticator) {
QCOMPARE(authenticator->identityHint(), QByteArray("Server Y"));
authenticator->setPreSharedKey("123456");
authenticator->setIdentity("Client X");
});
client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
server.server.serverPort());
connect(&server.server, &QSslServer::sslErrors,
[](QSslSocket *socket, const QList<QSslError> &errors) {
for (auto error : errors) {
QCOMPARE(error.error(), QSslError::NoPeerCertificate);
}
socket->ignoreSslErrors();
});
QEventLoop loop;
QObject::connect(&client, SIGNAL(encrypted()), &loop, SLOT(quit()));
QTimer::singleShot(5000, &loop, SLOT(quit()));
loop.exec();
// Check that server is connected
QCOMPARE(server.sslErrorsSpy.size(), 1);
QCOMPARE(server.peerVerifyErrorSpy.size(), 1);
QCOMPARE(server.errorOccurredSpy.size(), 0);
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1);
QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 1);
QCOMPARE(server.alertSentSpy.size(), 0);
QCOMPARE(server.alertReceivedSpy.size(), 0);
QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0);
QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1);
// Check client socket
QVERIFY(client.isEncrypted());
QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
}
#endif
void tst_QSslServer::plaintextClient()
{
QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration();
SslServerSpy server(serverConfiguration);
QVERIFY(server.server.listen());
QTcpSocket socket;
QSignalSpy socketDisconnectedSpy(&socket, &QTcpSocket::disconnected);
socket.connectToHost(QHostAddress::LocalHost, server.server.serverPort());
QVERIFY(socket.waitForConnected());
QTest::qWait(100);
// No disconnect from short break...:
QCOMPARE(socket.state(), QAbstractSocket::SocketState::ConnectedState);
// ... but we write some plaintext data...:
socket.write("Hello World!");
socket.waitForBytesWritten();
// ... and quickly get disconnected:
QTRY_COMPARE_GT(socketDisconnectedSpy.size(), 0);
QCOMPARE(socket.state(), QAbstractSocket::SocketState::UnconnectedState);
}
void tst_QSslServer::quietClient()
{
QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration();
SslServerSpy server(serverConfiguration);
server.server.setHandshakeTimeout(1'000);
QVERIFY(server.server.listen());
quint16 serverPeerPort = 0;
auto grabServerPeerPort = [&serverPeerPort](QSslSocket *socket) {
serverPeerPort = socket->peerPort();
};
QObject::connect(&server.server, &QSslServer::errorOccurred, &server.server,
grabServerPeerPort);
QTcpSocket socket;
QSignalSpy socketDisconnectedSpy(&socket, &QTcpSocket::disconnected);
socket.connectToHost(QHostAddress::LocalHost, server.server.serverPort());
quint16 clientLocalPort = socket.localPort();
QVERIFY(socket.waitForConnected());
// Disconnects after overlong break:
QVERIFY(socketDisconnectedSpy.wait(5'000));
QCOMPARE(socket.state(), QAbstractSocket::SocketState::UnconnectedState);
QCOMPARE_GT(server.errorOccurredSpy.size(), 0);
QCOMPARE(serverPeerPort, clientLocalPort);
}
void tst_QSslServer::twoGoodAndManyBadClients()
{
QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration();
SslServerSpy server(serverConfiguration);
server.server.setHandshakeTimeout(750);
constexpr qsizetype ExpectedConnections = 5;
server.server.setMaxPendingConnections(ExpectedConnections);
QVERIFY(server.server.listen());
auto connectGoodClient = [&server](QSslSocket *socket) {
QObject::connect(socket, &QSslSocket::sslErrors, socket,
qOverload<const QList<QSslError> &>(&QSslSocket::ignoreSslErrors));
socket->connectToHostEncrypted("127.0.0.1", server.server.serverPort());
};
// Connect one socket encrypted so we have a socket in the regular queue
QSslSocket tlsSocket;
connectGoodClient(&tlsSocket);
// Then we connect a bunch of TCP sockets who will not send any data at all
std::array<QTcpSocket, size_t(ExpectedConnections) * 2> sockets;
for (QTcpSocket &socket : sockets)
socket.connectToHost(QHostAddress::LocalHost, server.server.serverPort());
QTest::qWait(500); // some leeway to let connections try to connect...
// I happen to know the sockets are all children of the server, so let's see
// how many are created:
qsizetype connectedCount = server.server.findChildren<QSslSocket *>().size();
QCOMPARE(connectedCount, ExpectedConnections);
// 1 socket is ready and pending
QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1);
// Connect another client to make sure that the server is accepting connections again even after
// all the bad actors tried to connect:
QSslSocket goodClient;
connectGoodClient(&goodClient);
QTRY_COMPARE(server.pendingConnectionAvailableSpy.size(), 2);
}
QTEST_MAIN(tst_QSslServer)
#include "tst_qsslserver.moc"