Add test case for QSslSocket to show the wrong behavior
Task-number: QTBUG-81661 Change-Id: I4ed2ad3a22bd5439751328d915e9984eb89397d1 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
e74af68654
commit
8d057fea98
@ -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-----
|
@ -271,6 +271,10 @@ private slots:
|
|||||||
#if QT_CONFIG(openssl)
|
#if QT_CONFIG(openssl)
|
||||||
void alertMissingCertificate();
|
void alertMissingCertificate();
|
||||||
void alertInvalidCertificate();
|
void alertInvalidCertificate();
|
||||||
|
void selfSignedCertificates_data();
|
||||||
|
void selfSignedCertificates();
|
||||||
|
void pskHandshake_data();
|
||||||
|
void pskHandshake();
|
||||||
#endif // openssl
|
#endif // openssl
|
||||||
|
|
||||||
void setEmptyDefaultConfiguration(); // this test should be last
|
void setEmptyDefaultConfiguration(); // this test should be last
|
||||||
@ -1232,7 +1236,9 @@ public:
|
|||||||
QList<QSslCipher> ciphers;
|
QList<QSslCipher> ciphers;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void sslErrors(const QList<QSslError> &errors);
|
||||||
void socketError(QAbstractSocket::SocketError);
|
void socketError(QAbstractSocket::SocketError);
|
||||||
|
void handshakeInterruptedOnError(const QSslError& rrror);
|
||||||
void gotAlert(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message);
|
void gotAlert(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message);
|
||||||
void alertSent(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message);
|
void alertSent(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message);
|
||||||
|
|
||||||
@ -1245,9 +1251,13 @@ protected:
|
|||||||
configuration.setProtocol(protocol);
|
configuration.setProtocol(protocol);
|
||||||
if (ignoreSslErrors)
|
if (ignoreSslErrors)
|
||||||
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
|
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
|
||||||
|
else
|
||||||
|
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SIGNAL(sslErrors(QList<QSslError>)));
|
||||||
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SIGNAL(socketError(QAbstractSocket::SocketError)));
|
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SIGNAL(socketError(QAbstractSocket::SocketError)));
|
||||||
|
connect(socket, &QSslSocket::handshakeInterruptedOnError, this, &SslServer::handshakeInterruptedOnError);
|
||||||
connect(socket, &QSslSocket::alertReceived, this, &SslServer::gotAlert);
|
connect(socket, &QSslSocket::alertReceived, this, &SslServer::gotAlert);
|
||||||
connect(socket, &QSslSocket::alertSent, this, &SslServer::alertSent);
|
connect(socket, &QSslSocket::alertSent, this, &SslServer::alertSent);
|
||||||
|
connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired, this, &SslServer::preSharedKeyAuthenticationRequired);
|
||||||
|
|
||||||
QFile file(m_keyFile);
|
QFile file(m_keyFile);
|
||||||
QVERIFY(file.open(QIODevice::ReadOnly));
|
QVERIFY(file.open(QIODevice::ReadOnly));
|
||||||
@ -1295,6 +1305,11 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
|
||||||
|
{
|
||||||
|
authenticator->setPreSharedKey("123456");
|
||||||
|
}
|
||||||
|
|
||||||
void ignoreErrorSlot()
|
void ignoreErrorSlot()
|
||||||
{
|
{
|
||||||
socket->ignoreSslErrors();
|
socket->ignoreSslErrors();
|
||||||
@ -4418,6 +4433,274 @@ void tst_QSslSocket::alertInvalidCertificate()
|
|||||||
QVERIFY(!clientSocket.isEncrypted());
|
QVERIFY(!clientSocket.isEncrypted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::selfSignedCertificates_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<bool>("clientKnown");
|
||||||
|
|
||||||
|
QTest::newRow("Client known") << true;
|
||||||
|
QTest::newRow("Client unknown") << false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::selfSignedCertificates()
|
||||||
|
{
|
||||||
|
// In this test we want to check the behavior of the client/server when
|
||||||
|
// self-signed certificates are used and the client is un/known to the server.
|
||||||
|
QFETCH(bool, clientKnown);
|
||||||
|
|
||||||
|
QFETCH_GLOBAL(const bool, setProxy);
|
||||||
|
if (setProxy) // Not what we test here, bail out.
|
||||||
|
return;
|
||||||
|
|
||||||
|
SslServer server(testDataDir + "certs/selfsigned-server.key",
|
||||||
|
testDataDir + "certs/selfsigned-server.crt");
|
||||||
|
server.protocol = QSsl::TlsV1_2;
|
||||||
|
server.ignoreSslErrors = false;
|
||||||
|
server.peerVerifyMode = QSslSocket::VerifyPeer;
|
||||||
|
|
||||||
|
if (!server.listen(QHostAddress::LocalHost))
|
||||||
|
QSKIP("SslServer::listen() returned false");
|
||||||
|
|
||||||
|
QFile clientFile(testDataDir + "certs/selfsigned-client.key");
|
||||||
|
QVERIFY(clientFile.open(QIODevice::ReadOnly));
|
||||||
|
QSslKey clientKey(clientFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
|
||||||
|
QSslCertificate clientCert
|
||||||
|
= QSslCertificate::fromPath(testDataDir + "certs/selfsigned-client.crt").first();
|
||||||
|
|
||||||
|
server.config.setCiphers({QSslCipher("DHE-RSA-AES256-SHA256")});
|
||||||
|
server.config.setHandshakeMustInterruptOnError(true);
|
||||||
|
server.config.setMissingCertificateIsFatal(true);
|
||||||
|
if (clientKnown)
|
||||||
|
server.config.setCaCertificates({clientCert});
|
||||||
|
|
||||||
|
connect(&server, &SslServer::sslErrors,
|
||||||
|
[&server](const QList<QSslError> &errors) {
|
||||||
|
QCOMPARE(errors.size(), 1);
|
||||||
|
QVERIFY(errors.first().error() == QSslError::SelfSignedCertificate);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&server, &SslServer::socketError,
|
||||||
|
[&server](QAbstractSocket::SocketError socketError) {
|
||||||
|
QVERIFY(socketError == QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&server, &SslServer::handshakeInterruptedOnError,
|
||||||
|
[&server](const QSslError& error) {
|
||||||
|
QVERIFY(error.error() == QSslError::SelfSignedCertificate);
|
||||||
|
server.socket->continueInterruptedHandshake();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
QSslSocket clientSocket;
|
||||||
|
auto configuration = QSslConfiguration::defaultConfiguration();
|
||||||
|
configuration.setProtocol(QSsl::TlsV1_2);
|
||||||
|
configuration.setCiphers({QSslCipher("DHE-RSA-AES256-SHA256")});
|
||||||
|
configuration.setPrivateKey(clientKey);
|
||||||
|
configuration.setLocalCertificate(clientCert);
|
||||||
|
configuration.setPeerVerifyMode(QSslSocket::VerifyPeer);
|
||||||
|
configuration.setHandshakeMustInterruptOnError(true);
|
||||||
|
configuration.setMissingCertificateIsFatal(true);
|
||||||
|
clientSocket.setSslConfiguration(configuration);
|
||||||
|
|
||||||
|
connect(&clientSocket, &QSslSocket::sslErrors,
|
||||||
|
[&clientSocket](const QList<QSslError> &errors) {
|
||||||
|
for (const auto error : errors) {
|
||||||
|
if (error.error() == QSslError::HostNameMismatch) {
|
||||||
|
QVERIFY(errors.size() == 2);
|
||||||
|
clientSocket.ignoreSslErrors(errors);
|
||||||
|
} else {
|
||||||
|
QVERIFY(error.error() == QSslError::SelfSignedCertificate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&clientSocket, &QAbstractSocket::errorOccurred,
|
||||||
|
[&clientSocket](QAbstractSocket::SocketError socketError) {
|
||||||
|
QVERIFY(socketError == QAbstractSocket::RemoteHostClosedError);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&clientSocket, &QSslSocket::handshakeInterruptedOnError,
|
||||||
|
[&clientSocket](const QSslError& error) {
|
||||||
|
QVERIFY(error.error() == QSslError::SelfSignedCertificate);
|
||||||
|
clientSocket.continueInterruptedHandshake();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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, &QAbstractSocket::errorOccurred, earlyQuitter);
|
||||||
|
connect(&server, &SslServer::socketError, earlyQuitter);
|
||||||
|
|
||||||
|
runner.enterLoopMSecs(1000);
|
||||||
|
|
||||||
|
if (clientKnown) {
|
||||||
|
QCOMPARE(serverSpy.count(), 0);
|
||||||
|
QCOMPARE(clientSpy.count(), 0);
|
||||||
|
QVERIFY(server.socket && server.socket->isEncrypted());
|
||||||
|
QVERIFY(clientSocket.isEncrypted());
|
||||||
|
} else {
|
||||||
|
QVERIFY(serverSpy.count() > 0);
|
||||||
|
QEXPECT_FAIL("", "Failing to trigger signal, QTBUG-81661", Continue);
|
||||||
|
QVERIFY(clientSpy.count() > 0);
|
||||||
|
QVERIFY(server.socket && !server.socket->isEncrypted());
|
||||||
|
QVERIFY(!clientSocket.isEncrypted());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::pskHandshake_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<bool>("pskRight");
|
||||||
|
|
||||||
|
QTest::newRow("Psk right") << true;
|
||||||
|
QTest::newRow("Psk wrong") << false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::pskHandshake()
|
||||||
|
{
|
||||||
|
// In this test we want to check the behavior of the
|
||||||
|
// client/server when a preshared key (right/wrong) is used.
|
||||||
|
QFETCH(bool, pskRight);
|
||||||
|
|
||||||
|
QFETCH_GLOBAL(const bool, setProxy);
|
||||||
|
if (setProxy) // Not what we test here, bail out.
|
||||||
|
return;
|
||||||
|
|
||||||
|
SslServer server(testDataDir + "certs/selfsigned-server.key",
|
||||||
|
testDataDir + "certs/selfsigned-server.crt");
|
||||||
|
server.protocol = QSsl::TlsV1_2;
|
||||||
|
server.ignoreSslErrors = false;
|
||||||
|
server.peerVerifyMode = QSslSocket::VerifyPeer;
|
||||||
|
|
||||||
|
if (!server.listen(QHostAddress::LocalHost))
|
||||||
|
QSKIP("SslServer::listen() returned false");
|
||||||
|
|
||||||
|
QFile clientFile(testDataDir + "certs/selfsigned-client.key");
|
||||||
|
QVERIFY(clientFile.open(QIODevice::ReadOnly));
|
||||||
|
QSslKey clientKey(clientFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
|
||||||
|
QSslCertificate clientCert
|
||||||
|
= QSslCertificate::fromPath(testDataDir + "certs/selfsigned-client.crt").first();
|
||||||
|
|
||||||
|
server.config.setCiphers({QSslCipher("RSA-PSK-AES128-CBC-SHA256")});
|
||||||
|
server.config.setHandshakeMustInterruptOnError(true);
|
||||||
|
server.config.setMissingCertificateIsFatal(true);
|
||||||
|
|
||||||
|
connect(&server, &SslServer::sslErrors,
|
||||||
|
[&server](const QList<QSslError> &errors) {
|
||||||
|
QCOMPARE(errors.size(), 1);
|
||||||
|
QVERIFY(errors.first().error() == QSslError::SelfSignedCertificate);
|
||||||
|
server.socket->ignoreSslErrors(errors);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&server, &SslServer::socketError,
|
||||||
|
[&server](QAbstractSocket::SocketError socketError) {
|
||||||
|
QVERIFY(socketError == QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&server, &SslServer::handshakeInterruptedOnError,
|
||||||
|
[&server](const QSslError& error) {
|
||||||
|
QVERIFY(error.error() == QSslError::SelfSignedCertificate);
|
||||||
|
server.socket->continueInterruptedHandshake();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
QSslSocket clientSocket;
|
||||||
|
auto configuration = QSslConfiguration::defaultConfiguration();
|
||||||
|
configuration.setProtocol(QSsl::TlsV1_2);
|
||||||
|
configuration.setCiphers({QSslCipher("RSA-PSK-AES128-CBC-SHA256")});
|
||||||
|
configuration.setPrivateKey(clientKey);
|
||||||
|
configuration.setLocalCertificate(clientCert);
|
||||||
|
configuration.setPeerVerifyMode(QSslSocket::VerifyPeer);
|
||||||
|
configuration.setHandshakeMustInterruptOnError(true);
|
||||||
|
configuration.setMissingCertificateIsFatal(true);
|
||||||
|
clientSocket.setSslConfiguration(configuration);
|
||||||
|
|
||||||
|
connect(&clientSocket, &QSslSocket::preSharedKeyAuthenticationRequired,
|
||||||
|
[&clientSocket, pskRight](QSslPreSharedKeyAuthenticator *authenticator) {
|
||||||
|
authenticator->setPreSharedKey(pskRight ? "123456": "654321");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
connect(&clientSocket, &QSslSocket::sslErrors,
|
||||||
|
[&clientSocket](const QList<QSslError> &errors) {
|
||||||
|
for (const auto error : errors) {
|
||||||
|
if (error.error() == QSslError::HostNameMismatch) {
|
||||||
|
QVERIFY(errors.size() == 2);
|
||||||
|
clientSocket.ignoreSslErrors(errors);
|
||||||
|
} else {
|
||||||
|
QVERIFY(error.error() == QSslError::SelfSignedCertificate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&clientSocket, &QAbstractSocket::errorOccurred,
|
||||||
|
[&clientSocket](QAbstractSocket::SocketError socketError) {
|
||||||
|
QVERIFY(socketError == QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(&clientSocket, &QSslSocket::handshakeInterruptedOnError,
|
||||||
|
[&clientSocket](const QSslError& error) {
|
||||||
|
QVERIFY(error.error() == QSslError::SelfSignedCertificate);
|
||||||
|
clientSocket.continueInterruptedHandshake();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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, &QAbstractSocket::errorOccurred, earlyQuitter);
|
||||||
|
connect(&server, &SslServer::socketError, earlyQuitter);
|
||||||
|
|
||||||
|
runner.enterLoopMSecs(1000);
|
||||||
|
|
||||||
|
if (pskRight) {
|
||||||
|
QCOMPARE(serverSpy.count(), 0);
|
||||||
|
QCOMPARE(clientSpy.count(), 0);
|
||||||
|
QVERIFY(server.socket && server.socket->isEncrypted());
|
||||||
|
QVERIFY(clientSocket.isEncrypted());
|
||||||
|
} else {
|
||||||
|
QVERIFY(serverSpy.count() > 0);
|
||||||
|
QCOMPARE(serverSpy.first().at(0).toInt(), static_cast<int>(QSsl::AlertLevel::Fatal));
|
||||||
|
QCOMPARE(serverSpy.first().at(1).toInt(), static_cast<int>(QSsl::AlertType::BadRecordMac));
|
||||||
|
QVERIFY(clientSpy.count() > 0);
|
||||||
|
QCOMPARE(clientSpy.first().at(0).toInt(), static_cast<int>(QSsl::AlertLevel::Fatal));
|
||||||
|
QCOMPARE(clientSpy.first().at(1).toInt(), static_cast<int>(QSsl::AlertType::BadRecordMac));
|
||||||
|
QVERIFY(server.socket && !server.socket->isEncrypted());
|
||||||
|
QVERIFY(!clientSocket.isEncrypted());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // openssl
|
#endif // openssl
|
||||||
|
|
||||||
QTEST_MAIN(tst_QSslSocket)
|
QTEST_MAIN(tst_QSslSocket)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user