mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-06 09:15:23 +08:00
qt 6.5.1 original
This commit is contained in:
22
tests/auto/network/ssl/qsslserver/CMakeLists.txt
Normal file
22
tests/auto/network/ssl/qsslserver/CMakeLists.txt
Normal 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}
|
||||
)
|
@ -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-----
|
@ -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-----
|
@ -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-----
|
@ -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-----
|
531
tests/auto/network/ssl/qsslserver/tst_qsslserver.cpp
Normal file
531
tests/auto/network/ssl/qsslserver/tst_qsslserver.cpp
Normal 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"
|
Reference in New Issue
Block a user