1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2014 Governikus GmbH & Co. KG.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <QtCore/qglobal.h>
31#include <QtCore/qthread.h>
32#include <QtCore/qelapsedtimer.h>
33#include <QtCore/qrandom.h>
34#include <QtCore/qscopeguard.h>
35#include <QtNetwork/qhostaddress.h>
36#include <QtNetwork/qhostinfo.h>
37#include <QtNetwork/qnetworkproxy.h>
38#include <QtNetwork/qsslcipher.h>
39#include <QtNetwork/qsslconfiguration.h>
40#include <QtNetwork/qsslkey.h>
41#include <QtNetwork/qsslsocket.h>
42#include <QtNetwork/qtcpserver.h>
43#include <QtNetwork/qsslpresharedkeyauthenticator.h>
44#include <QtTest/QtTest>
45
46#include <QNetworkProxy>
47#include <QAuthenticator>
48
49#include "private/qhostinfo_p.h"
50#include "private/qiodevice_p.h" // for QIODEVICE_BUFFERSIZE
51
52#include "../../../network-settings.h"
53
54#ifndef QT_NO_SSL
55
56#ifndef QT_NO_OPENSSL
57#include "private/qsslsocket_openssl_p.h"
58#include "private/qsslsocket_openssl_symbols_p.h"
59#endif // QT_NO_OPENSSL
60
61#include "private/qsslsocket_p.h"
62#include "private/qsslconfiguration_p.h"
63
64Q_DECLARE_METATYPE(QSslSocket::SslMode)
65typedef QVector<QSslError::SslError> SslErrorList;
66Q_DECLARE_METATYPE(SslErrorList)
67Q_DECLARE_METATYPE(QSslError)
68Q_DECLARE_METATYPE(QSslKey)
69Q_DECLARE_METATYPE(QSsl::SslProtocol)
70Q_DECLARE_METATYPE(QSslSocket::PeerVerifyMode);
71typedef QSharedPointer<QSslSocket> QSslSocketPtr;
72
73// Non-OpenSSL backends are not able to report a specific error code
74// for self-signed certificates.
75#ifndef QT_NO_OPENSSL
76#define FLUKE_CERTIFICATE_ERROR QSslError::SelfSignedCertificate
77#else
78#define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted
79#endif // QT_NO_OPENSSL
80
81#endif // QT_NO_OPENSSL
82
83// Detect ALPN (Application-Layer Protocol Negotiation) support
84#undef ALPN_SUPPORTED // Undef the variable first to be safe
85#if defined(OPENSSL_VERSION_NUMBER) && !defined(OPENSSL_NO_TLSEXT)
86#define ALPN_SUPPORTED 1
87#endif
88
89#if QT_CONFIG(schannel) && !defined(Q_CC_MINGW)
90#define ALPN_SUPPORTED 1
91#endif
92
93#if defined Q_OS_HPUX && defined Q_CC_GNU
94// This error is delivered every time we try to use the fluke CA
95// certificate. For now we work around this bug. Task 202317.
96#define QSSLSOCKET_CERTUNTRUSTED_WORKAROUND
97#endif
98
99// Use this cipher to force PSK key sharing.
100// Also, it's a cipher w/o auth, to check that we emit the signals warning
101// about the identity of the peer.
102#ifndef QT_NO_OPENSSL
103static const QString PSK_CIPHER_WITHOUT_AUTH = QStringLiteral("PSK-AES256-CBC-SHA");
104static const quint16 PSK_SERVER_PORT = 4433;
105static const QByteArray PSK_CLIENT_PRESHAREDKEY = QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f");
106static const QByteArray PSK_SERVER_IDENTITY_HINT = QByteArrayLiteral("QtTestServerHint");
107static const QByteArray PSK_CLIENT_IDENTITY = QByteArrayLiteral("Client_identity");
108
109QT_BEGIN_NAMESPACE
110void qt_ForceTlsSecurityLevel();
111QT_END_NAMESPACE
112
113#endif // !QT_NO_OPENSSL
114
115class tst_QSslSocket : public QObject
116{
117 Q_OBJECT
118
119 int proxyAuthCalled;
120
121public:
122 tst_QSslSocket();
123
124 static void enterLoop(int secs)
125 {
126 ++loopLevel;
127 QTestEventLoop::instance().enterLoop(secs);
128 }
129
130 static bool timeout()
131 {
132 return QTestEventLoop::instance().timeout();
133 }
134
135#ifndef QT_NO_SSL
136 QSslSocketPtr newSocket();
137
138#ifndef QT_NO_OPENSSL
139 enum PskConnectTestType {
140 PskConnectDoNotHandlePsk,
141 PskConnectEmptyCredentials,
142 PskConnectWrongCredentials,
143 PskConnectWrongIdentity,
144 PskConnectWrongPreSharedKey,
145 PskConnectRightCredentialsPeerVerifyFailure,
146 PskConnectRightCredentialsVerifyPeer,
147 PskConnectRightCredentialsDoNotVerifyPeer,
148 };
149#endif
150#endif
151
152public slots:
153 void initTestCase_data();
154 void initTestCase();
155 void init();
156 void cleanup();
157#ifndef QT_NO_NETWORKPROXY
158 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth);
159#endif
160
161#ifndef QT_NO_SSL
162private slots:
163 void constructing();
164 void configNoOnDemandLoad();
165 void simpleConnect();
166 void simpleConnectWithIgnore();
167
168 // API tests
169 void sslErrors_data();
170 void sslErrors();
171 void ciphers();
172 void connectToHostEncrypted();
173 void connectToHostEncryptedWithVerificationPeerName();
174 void sessionCipher();
175 void flush();
176 void isEncrypted();
177 void localCertificate();
178 void mode();
179 void peerCertificate();
180 void peerCertificateChain();
181 void privateKey();
182#ifndef QT_NO_OPENSSL
183 void privateKeyOpaque();
184#endif
185 void protocol();
186 void protocolServerSide_data();
187 void protocolServerSide();
188#ifndef QT_NO_OPENSSL
189 void serverCipherPreferences();
190#endif // QT_NO_OPENSSL
191 void setCaCertificates();
192 void setLocalCertificate();
193 void localCertificateChain();
194 void setLocalCertificateChain();
195 void tlsConfiguration();
196 void setSocketDescriptor();
197 void setSslConfiguration_data();
198 void setSslConfiguration();
199 void waitForEncrypted();
200 void waitForEncryptedMinusOne();
201 void waitForConnectedEncryptedReadyRead();
202 void startClientEncryption();
203 void startServerEncryption();
204 void addDefaultCaCertificate();
205 void defaultCaCertificates();
206 void defaultCiphers();
207 void resetDefaultCiphers();
208 void setDefaultCaCertificates();
209 void setDefaultCiphers();
210 void supportedCiphers();
211 void systemCaCertificates();
212 void wildcardCertificateNames();
213 void isMatchingHostname();
214 void wildcard();
215 void setEmptyKey();
216 void spontaneousWrite();
217 void setReadBufferSize();
218 void setReadBufferSize_task_250027();
219 void waitForMinusOne();
220 void verifyMode();
221 void verifyDepth();
222#ifndef QT_NO_OPENSSL
223 void verifyAndDefaultConfiguration();
224#endif // QT_NO_OPENSSL
225 void disconnectFromHostWhenConnecting();
226 void disconnectFromHostWhenConnected();
227#ifndef QT_NO_OPENSSL
228 void closeWhileEmittingSocketError();
229#endif
230 void resetProxy();
231 void ignoreSslErrorsList_data();
232 void ignoreSslErrorsList();
233 void ignoreSslErrorsListWithSlot_data();
234 void ignoreSslErrorsListWithSlot();
235 void abortOnSslErrors();
236 void readFromClosedSocket();
237 void writeBigChunk();
238 void blacklistedCertificates();
239 void versionAccessors();
240#ifndef QT_NO_OPENSSL
241 void sslOptions();
242#endif
243 void encryptWithoutConnecting();
244 void resume_data();
245 void resume();
246 void qtbug18498_peek();
247 void qtbug18498_peek2();
248 void dhServer();
249#ifndef QT_NO_OPENSSL
250 void dhServerCustomParamsNull();
251 void dhServerCustomParams();
252#endif
253 void ecdhServer();
254 void verifyClientCertificate_data();
255 void verifyClientCertificate();
256 void readBufferMaxSize();
257
258 void allowedProtocolNegotiation();
259
260#ifndef QT_NO_OPENSSL
261 void simplePskConnect_data();
262 void simplePskConnect();
263 void ephemeralServerKey_data();
264 void ephemeralServerKey();
265 void pskServer();
266 void forwardReadChannelFinished();
267 void signatureAlgorithm_data();
268 void signatureAlgorithm();
269#endif
270
271 void disabledProtocols_data();
272 void disabledProtocols();
273
274 void oldErrorsOnSocketReuse();
275
276 void setEmptyDefaultConfiguration(); // this test should be last
277
278protected slots:
279
280 static void exitLoop()
281 {
282 // Safe exit - if we aren't in an event loop, don't
283 // exit one.
284 if (loopLevel > 0) {
285 --loopLevel;
286 QTestEventLoop::instance().exitLoop();
287 }
288 }
289
290 void ignoreErrorSlot()
291 {
292 socket->ignoreSslErrors();
293 }
294 void abortOnErrorSlot()
295 {
296 QSslSocket *sock = static_cast<QSslSocket *>(sender());
297 sock->abort();
298 }
299 void untrustedWorkaroundSlot(const QList<QSslError> &errors)
300 {
301 if (errors.size() == 1 &&
302 (errors.first().error() == QSslError::CertificateUntrusted ||
303 errors.first().error() == QSslError::SelfSignedCertificate))
304 socket->ignoreSslErrors();
305 }
306 void ignoreErrorListSlot(const QList<QSslError> &errors);
307
308private:
309 QSslSocket *socket;
310 QList<QSslError> storedExpectedSslErrors;
311#endif // QT_NO_SSL
312private:
313 static int loopLevel;
314public:
315 static QString testDataDir;
316};
317QString tst_QSslSocket::testDataDir;
318
319#ifndef QT_NO_SSL
320#ifndef QT_NO_OPENSSL
321Q_DECLARE_METATYPE(tst_QSslSocket::PskConnectTestType)
322#endif
323#endif
324
325int tst_QSslSocket::loopLevel = 0;
326
327namespace {
328
329QString httpServerCertChainPath()
330{
331 // DOCKERTODO: note how we use CA certificate on the real server. The docker container
332 // is using a different cert with a "special" CN. Check if it's important!
333#ifdef QT_TEST_SERVER
334 return tst_QSslSocket::testDataDir + QStringLiteral("certs/qt-test-server-cert.pem");
335#else
336 return tst_QSslSocket::testDataDir + QStringLiteral("certs/qt-test-server-cacert.pem");
337#endif // QT_TEST_SERVER
338}
339
340} // unnamed namespace
341
342tst_QSslSocket::tst_QSslSocket()
343{
344#ifndef QT_NO_SSL
345 qRegisterMetaType<QList<QSslError> >(typeName: "QList<QSslError>");
346 qRegisterMetaType<QSslError>(typeName: "QSslError");
347 qRegisterMetaType<QAbstractSocket::SocketState>(typeName: "QAbstractSocket::SocketState");
348 qRegisterMetaType<QAbstractSocket::SocketError>(typeName: "QAbstractSocket::SocketError");
349
350#ifndef QT_NO_OPENSSL
351 qRegisterMetaType<QSslPreSharedKeyAuthenticator *>();
352 qRegisterMetaType<tst_QSslSocket::PskConnectTestType>();
353#endif
354#endif
355}
356
357enum ProxyTests {
358 NoProxy = 0x00,
359 Socks5Proxy = 0x01,
360 HttpProxy = 0x02,
361 TypeMask = 0x0f,
362
363 NoAuth = 0x00,
364 AuthBasic = 0x10,
365 AuthNtlm = 0x20,
366 AuthMask = 0xf0
367};
368
369void tst_QSslSocket::initTestCase_data()
370{
371 QTest::addColumn<bool>(name: "setProxy");
372 QTest::addColumn<int>(name: "proxyType");
373
374 QTest::newRow(dataTag: "WithoutProxy") << false << 0;
375 QTest::newRow(dataTag: "WithSocks5Proxy") << true << int(Socks5Proxy);
376 QTest::newRow(dataTag: "WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic);
377
378 QTest::newRow(dataTag: "WithHttpProxy") << true << int(HttpProxy);
379 QTest::newRow(dataTag: "WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic);
380 // uncomment the line below when NTLM works
381// QTest::newRow("WithHttpProxyNtlmAuth") << true << int(HttpProxy | AuthNtlm);
382}
383
384void tst_QSslSocket::initTestCase()
385{
386 testDataDir = QFileInfo(QFINDTESTDATA("certs")).absolutePath();
387 if (testDataDir.isEmpty())
388 testDataDir = QCoreApplication::applicationDirPath();
389 if (!testDataDir.endsWith(s: QLatin1String("/")))
390 testDataDir += QLatin1String("/");
391#ifndef QT_NO_SSL
392 qDebug(msg: "Using SSL library %s (%ld)",
393 qPrintable(QSslSocket::sslLibraryVersionString()),
394 QSslSocket::sslLibraryVersionNumber());
395#ifdef QT_TEST_SERVER
396 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
397 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1081));
398 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128));
399 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3129));
400 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3130));
401 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 443));
402 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 993));
403 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::echoServerName(), 13));
404#else
405 if (!QtNetworkSettings::verifyTestNetworkSettings())
406 QSKIP("No network test server available");
407#endif // QT_TEST_SERVER
408#endif // QT_NO_SSL
409}
410
411void tst_QSslSocket::init()
412{
413 QFETCH_GLOBAL(bool, setProxy);
414 if (setProxy) {
415#ifndef QT_NO_NETWORKPROXY
416 QFETCH_GLOBAL(int, proxyType);
417 const QString socksProxyAddr = QtNetworkSettings::socksProxyServerIp().toString();
418 const QString httpProxyAddr = QtNetworkSettings::httpProxyServerIp().toString();
419 QNetworkProxy proxy;
420
421 switch (proxyType) {
422 case Socks5Proxy:
423 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksProxyAddr, 1080);
424 break;
425
426 case Socks5Proxy | AuthBasic:
427 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socksProxyAddr, 1081);
428 break;
429
430 case HttpProxy | NoAuth:
431 proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddr, 3128);
432 break;
433
434 case HttpProxy | AuthBasic:
435 proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddr, 3129);
436 break;
437
438 case HttpProxy | AuthNtlm:
439 proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddr, 3130);
440 break;
441 }
442 QNetworkProxy::setApplicationProxy(proxy);
443#else // !QT_NO_NETWORKPROXY
444 QSKIP("No proxy support");
445#endif // QT_NO_NETWORKPROXY
446 }
447
448#ifndef QT_NO_OPENSSL
449 QT_PREPEND_NAMESPACE(qt_ForceTlsSecurityLevel)();
450#endif // QT_NO_OPENSSL
451
452 qt_qhostinfo_clear_cache();
453}
454
455void tst_QSslSocket::cleanup()
456{
457#ifndef QT_NO_NETWORKPROXY
458 QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
459#endif
460}
461
462#ifndef QT_NO_SSL
463QSslSocketPtr tst_QSslSocket::newSocket()
464{
465 const auto socket = QSslSocketPtr::create();
466
467 proxyAuthCalled = 0;
468 connect(asender: socket.data(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
469 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
470 atype: Qt::DirectConnection);
471
472 return socket;
473}
474#endif
475
476#ifndef QT_NO_NETWORKPROXY
477void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
478{
479 ++proxyAuthCalled;
480 auth->setUser("qsockstest");
481 auth->setPassword("password");
482}
483#endif // !QT_NO_NETWORKPROXY
484
485#ifndef QT_NO_SSL
486
487void tst_QSslSocket::constructing()
488{
489 const char readNotOpenMessage[] = "QIODevice::read (QSslSocket): device not open";
490 const char writeNotOpenMessage[] = "QIODevice::write (QSslSocket): device not open";
491
492 if (!QSslSocket::supportsSsl())
493 return;
494
495 QSslSocket socket;
496
497 QCOMPARE(socket.state(), QSslSocket::UnconnectedState);
498 QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
499 QVERIFY(!socket.isEncrypted());
500 QCOMPARE(socket.bytesAvailable(), qint64(0));
501 QCOMPARE(socket.bytesToWrite(), qint64(0));
502 QVERIFY(!socket.canReadLine());
503 QVERIFY(socket.atEnd());
504 QCOMPARE(socket.localCertificate(), QSslCertificate());
505 QCOMPARE(socket.sslConfiguration(), QSslConfiguration::defaultConfiguration());
506 QCOMPARE(socket.errorString(), QString("Unknown error"));
507 char c = '\0';
508 QTest::ignoreMessage(type: QtWarningMsg, message: readNotOpenMessage);
509 QVERIFY(!socket.getChar(&c));
510 QCOMPARE(c, '\0');
511 QVERIFY(!socket.isOpen());
512 QVERIFY(!socket.isReadable());
513 QVERIFY(socket.isSequential());
514 QVERIFY(!socket.isTextModeEnabled());
515 QVERIFY(!socket.isWritable());
516 QCOMPARE(socket.openMode(), QIODevice::NotOpen);
517 QTest::ignoreMessage(type: QtWarningMsg, message: readNotOpenMessage);
518 QVERIFY(socket.peek(2).isEmpty());
519 QCOMPARE(socket.pos(), qint64(0));
520 QTest::ignoreMessage(type: QtWarningMsg, message: writeNotOpenMessage);
521 QVERIFY(!socket.putChar('c'));
522 QTest::ignoreMessage(type: QtWarningMsg, message: readNotOpenMessage);
523 QVERIFY(socket.read(2).isEmpty());
524 QTest::ignoreMessage(type: QtWarningMsg, message: readNotOpenMessage);
525 QCOMPARE(socket.read(0, 0), qint64(-1));
526 QTest::ignoreMessage(type: QtWarningMsg, message: readNotOpenMessage);
527 QVERIFY(socket.readAll().isEmpty());
528 QTest::ignoreMessage(type: QtWarningMsg, message: "QIODevice::readLine (QSslSocket): Called with maxSize < 2");
529 QCOMPARE(socket.readLine(0, 0), qint64(-1));
530 char buf[10];
531 QCOMPARE(socket.readLine(buf, sizeof(buf)), qint64(-1));
532 QTest::ignoreMessage(type: QtWarningMsg, message: "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device");
533 QVERIFY(!socket.reset());
534 QTest::ignoreMessage(type: QtWarningMsg, message: "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device");
535 QVERIFY(!socket.seek(2));
536 QCOMPARE(socket.size(), qint64(0));
537 QVERIFY(!socket.waitForBytesWritten(10));
538 QVERIFY(!socket.waitForReadyRead(10));
539 QTest::ignoreMessage(type: QtWarningMsg, message: writeNotOpenMessage);
540 QCOMPARE(socket.write(0, 0), qint64(-1));
541 QTest::ignoreMessage(type: QtWarningMsg, message: writeNotOpenMessage);
542 QCOMPARE(socket.write(QByteArray()), qint64(-1));
543 QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
544 QVERIFY(!socket.flush());
545 QVERIFY(!socket.isValid());
546 QCOMPARE(socket.localAddress(), QHostAddress());
547 QCOMPARE(socket.localPort(), quint16(0));
548 QCOMPARE(socket.peerAddress(), QHostAddress());
549 QVERIFY(socket.peerName().isEmpty());
550 QCOMPARE(socket.peerPort(), quint16(0));
551#ifndef QT_NO_NETWORKPROXY
552 QCOMPARE(socket.proxy().type(), QNetworkProxy::DefaultProxy);
553#endif
554 QCOMPARE(socket.readBufferSize(), qint64(0));
555 QCOMPARE(socket.socketDescriptor(), qintptr(-1));
556 QCOMPARE(socket.socketType(), QAbstractSocket::TcpSocket);
557 QVERIFY(!socket.waitForConnected(10));
558 QTest::ignoreMessage(type: QtWarningMsg, message: "QSslSocket::waitForDisconnected() is not allowed in UnconnectedState");
559 QVERIFY(!socket.waitForDisconnected(10));
560 QCOMPARE(socket.protocol(), QSsl::SecureProtocols);
561
562 QSslConfiguration savedDefault = QSslConfiguration::defaultConfiguration();
563
564 auto sslConfig = socket.sslConfiguration();
565 sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates());
566 socket.setSslConfiguration(sslConfig);
567
568 auto defaultConfig = QSslConfiguration::defaultConfiguration();
569 defaultConfig.setCaCertificates(QList<QSslCertificate>());
570 defaultConfig.setCiphers(QList<QSslCipher>());
571 QSslConfiguration::setDefaultConfiguration(defaultConfig);
572
573 QVERIFY(!socket.sslConfiguration().caCertificates().isEmpty());
574 QVERIFY(!socket.sslConfiguration().ciphers().isEmpty());
575
576 // verify the default as well:
577 QVERIFY(QSslConfiguration::defaultConfiguration().caCertificates().isEmpty());
578 QVERIFY(QSslConfiguration::defaultConfiguration().ciphers().isEmpty());
579
580 QSslConfiguration::setDefaultConfiguration(savedDefault);
581}
582
583void tst_QSslSocket::configNoOnDemandLoad()
584{
585 QFETCH_GLOBAL(bool, setProxy);
586 if (setProxy)
587 return; // NoProxy is enough.
588
589 // We noticed a peculiar situation, where a configuration
590 // set on a socket is not equal to the configuration we
591 // get back from the socket afterwards.
592 auto customConfig = QSslConfiguration::defaultConfiguration();
593 // Setting CA certificates disables loading root certificates
594 // during verification:
595 customConfig.setCaCertificates(customConfig.caCertificates());
596
597 QSslSocket socket;
598 socket.setSslConfiguration(customConfig);
599 QCOMPARE(customConfig, socket.sslConfiguration());
600}
601
602void tst_QSslSocket::simpleConnect()
603{
604 if (!QSslSocket::supportsSsl())
605 return;
606
607 QFETCH_GLOBAL(bool, setProxy);
608 if (setProxy)
609 return;
610
611 QSslSocket socket;
612 QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
613 QSignalSpy hostFoundSpy(&socket, SIGNAL(hostFound()));
614 QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected()));
615 QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted()));
616 QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(QList<QSslError>)));
617
618 connect(sender: &socket, SIGNAL(connected()), receiver: this, SLOT(exitLoop()));
619 connect(sender: &socket, SIGNAL(disconnected()), receiver: this, SLOT(exitLoop()));
620 connect(sender: &socket, SIGNAL(modeChanged(QSslSocket::SslMode)), receiver: this, SLOT(exitLoop()));
621 connect(sender: &socket, SIGNAL(encrypted()), receiver: this, SLOT(exitLoop()));
622 connect(sender: &socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), receiver: this, SLOT(exitLoop()));
623 connect(sender: &socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(exitLoop()));
624
625 // Start connecting
626 socket.connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 993);
627 QCOMPARE(socket.state(), QAbstractSocket::HostLookupState);
628 enterLoop(secs: 10);
629
630 // Entered connecting state
631 QCOMPARE(socket.state(), QAbstractSocket::ConnectingState);
632 QCOMPARE(connectedSpy.count(), 0);
633 QCOMPARE(hostFoundSpy.count(), 1);
634 QCOMPARE(disconnectedSpy.count(), 0);
635 enterLoop(secs: 10);
636
637 // Entered connected state
638 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
639 QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
640 QVERIFY(!socket.isEncrypted());
641 QCOMPARE(connectedSpy.count(), 1);
642 QCOMPARE(hostFoundSpy.count(), 1);
643 QCOMPARE(disconnectedSpy.count(), 0);
644
645 // Enter encrypted mode
646 socket.startClientEncryption();
647 QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
648 QVERIFY(!socket.isEncrypted());
649 QCOMPARE(connectionEncryptedSpy.count(), 0);
650 QCOMPARE(sslErrorsSpy.count(), 0);
651
652 // Starting handshake
653 enterLoop(secs: 10);
654 QCOMPARE(sslErrorsSpy.count(), 1);
655 QCOMPARE(connectionEncryptedSpy.count(), 0);
656 QVERIFY(!socket.isEncrypted());
657 QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
658}
659
660void tst_QSslSocket::simpleConnectWithIgnore()
661{
662 if (!QSslSocket::supportsSsl())
663 return;
664
665 QFETCH_GLOBAL(bool, setProxy);
666 if (setProxy)
667 return;
668
669 QSslSocket socket;
670 this->socket = &socket;
671 QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted()));
672 QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(QList<QSslError>)));
673
674 connect(sender: &socket, SIGNAL(readyRead()), receiver: this, SLOT(exitLoop()));
675 connect(sender: &socket, SIGNAL(encrypted()), receiver: this, SLOT(exitLoop()));
676 connect(sender: &socket, SIGNAL(connected()), receiver: this, SLOT(exitLoop()));
677 connect(sender: &socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
678 connect(sender: &socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(exitLoop()));
679
680 // Start connecting
681 socket.connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 993);
682 QVERIFY(socket.state() != QAbstractSocket::UnconnectedState); // something must be in progress
683 enterLoop(secs: 10);
684
685 // Start handshake
686 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
687 socket.startClientEncryption();
688 enterLoop(secs: 10);
689
690 // Done; encryption should be enabled.
691 QCOMPARE(sslErrorsSpy.count(), 1);
692 QVERIFY(socket.isEncrypted());
693 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
694 QCOMPARE(encryptedSpy.count(), 1);
695
696 // Wait for incoming data
697 if (!socket.canReadLine())
698 enterLoop(secs: 10);
699
700 QByteArray data = socket.readAll();
701 socket.disconnectFromHost();
702 QVERIFY2(QtNetworkSettings::compareReplyIMAPSSL(data), data.constData());
703}
704
705void tst_QSslSocket::sslErrors_data()
706{
707 QTest::addColumn<QString>(name: "host");
708 QTest::addColumn<int>(name: "port");
709
710 QString name = QtNetworkSettings::serverLocalName();
711 QTest::newRow(qPrintable(name)) << name << 993;
712
713 name = QtNetworkSettings::httpServerIp().toString();
714 QTest::newRow(qPrintable(name)) << name << 443;
715}
716
717void tst_QSslSocket::sslErrors()
718{
719 QFETCH(QString, host);
720 QFETCH(int, port);
721
722 QSslSocketPtr socket = newSocket();
723#if QT_CONFIG(schannel)
724 // Needs to be < 1.2 because of the old certificate and <= 1.0 because of the mail server
725 socket->setProtocol(QSsl::SslProtocol::TlsV1_0);
726#endif
727 QSignalSpy sslErrorsSpy(socket.data(), SIGNAL(sslErrors(QList<QSslError>)));
728 QSignalSpy peerVerifyErrorSpy(socket.data(), SIGNAL(peerVerifyError(QSslError)));
729
730#ifdef QT_TEST_SERVER
731 // On the old test server we had the same certificate on different services.
732 // The idea of this test is to fail with 'HostNameMismatch', when we're using
733 // either serverLocalName() or IP address directly. With Docker we connect
734 // to IMAP server, and we have to connect using imapServerName() and passing
735 // 'host' as peerVerificationName to the overload of connectToHostEncrypted().
736 if (port == 993) {
737 socket->connectToHostEncrypted(QtNetworkSettings::imapServerName(), port, host);
738 } else
739#endif // QT_TEST_SERVER
740 {
741 socket->connectToHostEncrypted(hostName: host, port);
742 }
743
744 if (!socket->waitForConnected())
745 QSKIP("Skipping flaky test - See QTBUG-29941");
746 socket->waitForEncrypted(msecs: 10000);
747
748 // check the SSL errors contain HostNameMismatch and an error due to
749 // the certificate being self-signed
750 SslErrorList sslErrors;
751 const auto socketSslErrors = socket->sslHandshakeErrors();
752 for (const QSslError &err : socketSslErrors)
753 sslErrors << err.error();
754 std::sort(first: sslErrors.begin(), last: sslErrors.end());
755 QVERIFY(sslErrors.contains(QSslError::HostNameMismatch));
756 QVERIFY(sslErrors.contains(FLUKE_CERTIFICATE_ERROR));
757
758 // check the same errors were emitted by sslErrors
759 QVERIFY(!sslErrorsSpy.isEmpty());
760 SslErrorList emittedErrors;
761 const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(v: qAsConst(t&: sslErrorsSpy).first().first());
762 for (const QSslError &err : sslErrorsSpyErrors)
763 emittedErrors << err.error();
764 std::sort(first: emittedErrors.begin(), last: emittedErrors.end());
765 QCOMPARE(sslErrors, emittedErrors);
766
767 // check the same errors were emitted by peerVerifyError
768 QVERIFY(!peerVerifyErrorSpy.isEmpty());
769 SslErrorList peerErrors;
770 const QList<QVariantList> &peerVerifyList = peerVerifyErrorSpy;
771 for (const QVariantList &args : peerVerifyList)
772 peerErrors << qvariant_cast<QSslError>(v: args.first()).error();
773 std::sort(first: peerErrors.begin(), last: peerErrors.end());
774 QCOMPARE(sslErrors, peerErrors);
775}
776
777void tst_QSslSocket::ciphers()
778{
779 if (!QSslSocket::supportsSsl())
780 return;
781
782 QFETCH_GLOBAL(const bool, setProxy);
783 if (setProxy) {
784 // KISS(mart), we don't connect, no need to test the same thing
785 // many times!
786 return;
787 }
788
789 QSslSocket socket;
790 QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers());
791
792 auto sslConfig = socket.sslConfiguration();
793 sslConfig.setCiphers(QList<QSslCipher>());
794 socket.setSslConfiguration(sslConfig);
795 QVERIFY(socket.sslConfiguration().ciphers().isEmpty());
796
797 sslConfig.setCiphers(QSslConfiguration::defaultConfiguration().ciphers());
798 socket.setSslConfiguration(sslConfig);
799 QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers());
800
801#ifndef QT_NO_OPENSSL
802 const auto ciphers = QSslConfiguration::defaultConfiguration().ciphers();
803 for (const auto &cipher : ciphers) {
804 if (cipher.name().size() && cipher.protocol() != QSsl::UnknownProtocol) {
805 const QSslCipher aCopy(cipher.name(), cipher.protocol());
806 QCOMPARE(aCopy, cipher);
807 break;
808 }
809 }
810#endif // QT_NO_OPENSSL
811}
812
813void tst_QSslSocket::connectToHostEncrypted()
814{
815 if (!QSslSocket::supportsSsl())
816 return;
817
818 QSslSocketPtr socket = newSocket();
819#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
820 socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
821#endif
822 this->socket = socket.data();
823 auto config = socket->sslConfiguration();
824 QVERIFY(config.addCaCertificates(httpServerCertChainPath()));
825 socket->setSslConfiguration(config);
826#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND
827 connect(socket.data(), SIGNAL(sslErrors(QList<QSslError>)),
828 this, SLOT(untrustedWorkaroundSlot(QList<QSslError>)));
829#endif
830
831 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
832
833 // This should pass unconditionally when using fluke's CA certificate.
834 // or use untrusted certificate workaround
835 QFETCH_GLOBAL(bool, setProxy);
836 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
837 QSKIP("Skipping flaky test - See QTBUG-29941");
838
839 socket->disconnectFromHost();
840 QVERIFY(socket->waitForDisconnected());
841
842 QCOMPARE(socket->mode(), QSslSocket::SslClientMode);
843
844 socket->connectToHost(hostName: QtNetworkSettings::echoServerName(), port: 13);
845
846 QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode);
847
848 QVERIFY(socket->waitForDisconnected());
849}
850
851void tst_QSslSocket::connectToHostEncryptedWithVerificationPeerName()
852{
853 if (!QSslSocket::supportsSsl())
854 return;
855
856 QSslSocketPtr socket = newSocket();
857#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
858 socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
859#endif
860 this->socket = socket.data();
861
862 auto config = socket->sslConfiguration();
863 config.addCaCertificates(path: httpServerCertChainPath());
864 socket->setSslConfiguration(config);
865#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND
866 connect(socket.data(), SIGNAL(sslErrors(QList<QSslError>)),
867 this, SLOT(untrustedWorkaroundSlot(QList<QSslError>)));
868#endif
869
870#ifdef QT_TEST_SERVER
871 socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443, QtNetworkSettings::httpServerName());
872#else
873 // Connect to the server with its local name, but use the full name for verification.
874 socket->connectToHostEncrypted(hostName: QtNetworkSettings::serverLocalName(), port: 443, sslPeerName: QtNetworkSettings::httpServerName());
875#endif
876
877 // This should pass unconditionally when using fluke's CA certificate.
878 QFETCH_GLOBAL(bool, setProxy);
879 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
880 QSKIP("Skipping flaky test - See QTBUG-29941");
881
882 socket->disconnectFromHost();
883 QVERIFY(socket->waitForDisconnected());
884
885 QCOMPARE(socket->mode(), QSslSocket::SslClientMode);
886}
887
888void tst_QSslSocket::sessionCipher()
889{
890 if (!QSslSocket::supportsSsl())
891 return;
892
893 QSslSocketPtr socket = newSocket();
894 this->socket = socket.data();
895 connect(sender: socket.data(), SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
896 QVERIFY(socket->sessionCipher().isNull());
897 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443 /* https */);
898 QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString()));
899 QVERIFY(socket->sessionCipher().isNull());
900 socket->startClientEncryption();
901 if (!socket->waitForEncrypted(msecs: 5000))
902 QSKIP("Skipping flaky test - See QTBUG-29941");
903 QVERIFY(!socket->sessionCipher().isNull());
904
905 qDebug() << "Supported Ciphers:" << QSslConfiguration::supportedCiphers();
906 qDebug() << "Default Ciphers:" << QSslConfiguration::defaultConfiguration().ciphers();
907 qDebug() << "Session Cipher:" << socket->sessionCipher();
908
909 QVERIFY(QSslConfiguration::supportedCiphers().contains(socket->sessionCipher()));
910 socket->disconnectFromHost();
911 QVERIFY(socket->waitForDisconnected());
912}
913
914void tst_QSslSocket::flush()
915{
916}
917
918void tst_QSslSocket::isEncrypted()
919{
920}
921
922void tst_QSslSocket::localCertificate()
923{
924 if (!QSslSocket::supportsSsl())
925 return;
926
927 // This test does not make 100% sense yet. We just set some local CA/cert/key and use it
928 // to authenticate ourselves against the server. The server does not actually check this
929 // values. This test should just run the codepath inside qsslsocket_openssl.cpp
930
931 QSslSocketPtr socket = newSocket();
932 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: httpServerCertChainPath());
933
934 auto sslConfig = socket->sslConfiguration();
935 sslConfig.setCaCertificates(localCert);
936 socket->setSslConfiguration(sslConfig);
937
938 socket->setLocalCertificate(fileName: testDataDir + "certs/fluke.cert");
939 socket->setPrivateKey(fileName: testDataDir + "certs/fluke.key");
940
941 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
942 QFETCH_GLOBAL(bool, setProxy);
943 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
944 QSKIP("Skipping flaky test - See QTBUG-29941");
945}
946
947void tst_QSslSocket::mode()
948{
949}
950
951void tst_QSslSocket::peerCertificate()
952{
953}
954
955void tst_QSslSocket::peerCertificateChain()
956{
957 if (!QSslSocket::supportsSsl())
958 return;
959
960 QSKIP("QTBUG-29941 - Unstable auto-test due to intermittently unreachable host");
961
962 QSslSocketPtr socket = newSocket();
963 this->socket = socket.data();
964 QList<QSslCertificate> caCertificates = QSslCertificate::fromPath(path: httpServerCertChainPath());
965 QCOMPARE(caCertificates.count(), 1);
966 auto config = socket->sslConfiguration();
967 config.addCaCertificates(certificates: caCertificates);
968 socket->setSslConfiguration(config);
969#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND
970 connect(socket.data(), SIGNAL(sslErrors(QList<QSslError>)),
971 this, SLOT(untrustedWorkaroundSlot(QList<QSslError>)));
972#endif
973
974 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
975 QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode);
976 QVERIFY(socket->peerCertificateChain().isEmpty());
977 QFETCH_GLOBAL(bool, setProxy);
978 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
979 QSKIP("Skipping flaky test - See QTBUG-29941");
980
981 QList<QSslCertificate> certChain = socket->peerCertificateChain();
982 QVERIFY(certChain.count() > 0);
983 QCOMPARE(certChain.first(), socket->peerCertificate());
984
985 socket->disconnectFromHost();
986 QVERIFY(socket->waitForDisconnected());
987
988 // connect again to a different server
989 socket->connectToHostEncrypted(hostName: "www.qt.io", port: 443);
990 socket->ignoreSslErrors();
991 QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode);
992 QVERIFY(socket->peerCertificateChain().isEmpty());
993 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
994 QSKIP("Skipping flaky test - See QTBUG-29941");
995
996 QCOMPARE(socket->peerCertificateChain().first(), socket->peerCertificate());
997 QVERIFY(socket->peerCertificateChain() != certChain);
998
999 socket->disconnectFromHost();
1000 QVERIFY(socket->waitForDisconnected());
1001
1002 // now do it again back to the original server
1003 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
1004 QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode);
1005 QVERIFY(socket->peerCertificateChain().isEmpty());
1006 QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString()));
1007
1008 socket->startClientEncryption();
1009 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
1010 QSKIP("Skipping flaky test - See QTBUG-29941");
1011
1012 QCOMPARE(socket->peerCertificateChain().first(), socket->peerCertificate());
1013 QCOMPARE(socket->peerCertificateChain(), certChain);
1014
1015 socket->disconnectFromHost();
1016 QVERIFY(socket->waitForDisconnected());
1017}
1018
1019void tst_QSslSocket::privateKey()
1020{
1021}
1022
1023#ifndef QT_NO_OPENSSL
1024void tst_QSslSocket::privateKeyOpaque()
1025{
1026 if (!QSslSocket::supportsSsl())
1027 return;
1028
1029 QFile file(testDataDir + "certs/fluke.key");
1030 QVERIFY(file.open(QIODevice::ReadOnly));
1031 QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
1032 QVERIFY(!key.isNull());
1033
1034 EVP_PKEY *pkey = q_EVP_PKEY_new();
1035 q_EVP_PKEY_set1_RSA(a: pkey, b: reinterpret_cast<RSA *>(key.handle()));
1036
1037 // This test does not make 100% sense yet. We just set some local CA/cert/key and use it
1038 // to authenticate ourselves against the server. The server does not actually check this
1039 // values. This test should just run the codepath inside qsslsocket_openssl.cpp
1040
1041 QSslSocketPtr socket = newSocket();
1042 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: httpServerCertChainPath());
1043
1044 auto sslConfig = socket->sslConfiguration();
1045 sslConfig.setCaCertificates(localCert);
1046 socket->setSslConfiguration(sslConfig);
1047
1048 socket->setLocalCertificate(fileName: testDataDir + "certs/fluke.cert");
1049 socket->setPrivateKey(QSslKey(reinterpret_cast<Qt::HANDLE>(pkey)));
1050
1051 socket->setPeerVerifyMode(QSslSocket::QueryPeer);
1052 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1053 QFETCH_GLOBAL(bool, setProxy);
1054 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
1055 QSKIP("Skipping flaky test - See QTBUG-29941");
1056}
1057#endif
1058
1059void tst_QSslSocket::protocol()
1060{
1061 if (!QSslSocket::supportsSsl())
1062 return;
1063
1064 QSslSocketPtr socket = newSocket();
1065 this->socket = socket.data();
1066 QList<QSslCertificate> certs = QSslCertificate::fromPath(path: httpServerCertChainPath());
1067
1068 auto sslConfig = socket->sslConfiguration();
1069 sslConfig.setCaCertificates(certs);
1070 socket->setSslConfiguration(sslConfig);
1071
1072#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND
1073 connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
1074 this, SLOT(untrustedWorkaroundSlot(QList<QSslError>)));
1075#endif
1076
1077 QCOMPARE(socket->protocol(), QSsl::SecureProtocols);
1078 QFETCH_GLOBAL(bool, setProxy);
1079 {
1080 // qt-test-server allows TLSV1.
1081 socket->setProtocol(QSsl::TlsV1_0);
1082 QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
1083 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1084 if (setProxy && !socket->waitForEncrypted())
1085 QSKIP("Skipping flaky test - See QTBUG-29941");
1086 QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
1087 socket->abort();
1088 QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
1089 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
1090 QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
1091 socket->startClientEncryption();
1092 if (setProxy && !socket->waitForEncrypted())
1093 QSKIP("Skipping flaky test - See QTBUG-29941");
1094 QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
1095 socket->abort();
1096 }
1097 {
1098 // qt-test-server probably doesn't allow TLSV1.1
1099 socket->setProtocol(QSsl::TlsV1_1);
1100 QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
1101 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1102 if (setProxy && !socket->waitForEncrypted())
1103 QSKIP("Skipping flaky test - See QTBUG-29941");
1104 QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
1105 socket->abort();
1106 QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
1107 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
1108 QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
1109 socket->startClientEncryption();
1110 if (setProxy && !socket->waitForEncrypted())
1111 QSKIP("Skipping flaky test - See QTBUG-29941");
1112 QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
1113 socket->abort();
1114 }
1115 {
1116 // qt-test-server probably doesn't allows TLSV1.2
1117 socket->setProtocol(QSsl::TlsV1_2);
1118 QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
1119 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1120 if (setProxy && !socket->waitForEncrypted())
1121 QSKIP("Skipping flaky test - See QTBUG-29941");
1122 QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
1123 socket->abort();
1124 QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
1125 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
1126 QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
1127 socket->startClientEncryption();
1128 if (setProxy && !socket->waitForEncrypted())
1129 QSKIP("Skipping flaky test - See QTBUG-29941");
1130 QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
1131 socket->abort();
1132 }
1133
1134#ifdef TLS1_3_VERSION
1135 {
1136 // qt-test-server probably doesn't allow TLSV1.3
1137 socket->setProtocol(QSsl::TlsV1_3);
1138 QCOMPARE(socket->protocol(), QSsl::TlsV1_3);
1139 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1140 if (setProxy && !socket->waitForEncrypted())
1141 QSKIP("TLS 1.3 is not supported by the test server or the test is flaky - see QTBUG-29941");
1142 QCOMPARE(socket->protocol(), QSsl::TlsV1_3);
1143 socket->abort();
1144 QCOMPARE(socket->protocol(), QSsl::TlsV1_3);
1145 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
1146 QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
1147 socket->startClientEncryption();
1148 if (setProxy && !socket->waitForEncrypted())
1149 QSKIP("TLS 1.3 is not supported by the test server or the test is flaky - see QTBUG-29941");
1150 QCOMPARE(socket->sessionProtocol(), QSsl::TlsV1_3);
1151 socket->abort();
1152 }
1153#endif // TLS1_3_VERSION
1154 {
1155 // qt-test-server allows SSLV3, so it allows AnyProtocol.
1156 socket->setProtocol(QSsl::AnyProtocol);
1157 QCOMPARE(socket->protocol(), QSsl::AnyProtocol);
1158 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1159 if (setProxy && !socket->waitForEncrypted())
1160 QSKIP("Skipping flaky test - See QTBUG-29941");
1161 QCOMPARE(socket->protocol(), QSsl::AnyProtocol);
1162 socket->abort();
1163 QCOMPARE(socket->protocol(), QSsl::AnyProtocol);
1164 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
1165 QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
1166 socket->startClientEncryption();
1167 if (setProxy && !socket->waitForEncrypted())
1168 QSKIP("Skipping flaky test - See QTBUG-29941");
1169 QCOMPARE(socket->protocol(), QSsl::AnyProtocol);
1170 socket->abort();
1171 }
1172 {
1173 // qt-test-server allows TlsV1, so it allows TlsV1SslV3
1174 socket->setProtocol(QSsl::TlsV1SslV3);
1175 QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
1176 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1177 if (setProxy && !socket->waitForEncrypted())
1178 QSKIP("Skipping flaky test - See QTBUG-29941");
1179 QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
1180 socket->abort();
1181 QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
1182 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
1183 if (setProxy && !socket->waitForConnected())
1184 QSKIP("Skipping flaky test - See QTBUG-29941");
1185 socket->startClientEncryption();
1186 if (setProxy && !socket->waitForEncrypted())
1187 QSKIP("Skipping flaky test - See QTBUG-29941");
1188 QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
1189 socket->abort();
1190 }
1191}
1192
1193class SslServer : public QTcpServer
1194{
1195 Q_OBJECT
1196public:
1197 SslServer(const QString &keyFile = tst_QSslSocket::testDataDir + "certs/fluke.key",
1198 const QString &certFile = tst_QSslSocket::testDataDir + "certs/fluke.cert",
1199 const QString &interFile = QString())
1200 : socket(0),
1201 config(QSslConfiguration::defaultConfiguration()),
1202 ignoreSslErrors(true),
1203 peerVerifyMode(QSslSocket::AutoVerifyPeer),
1204 protocol(QSsl::TlsV1_0),
1205 m_keyFile(keyFile),
1206 m_certFile(certFile),
1207 m_interFile(interFile)
1208 { }
1209 QSslSocket *socket;
1210 QSslConfiguration config;
1211 QString addCaCertificates;
1212 bool ignoreSslErrors;
1213 QSslSocket::PeerVerifyMode peerVerifyMode;
1214 QSsl::SslProtocol protocol;
1215 QString m_keyFile;
1216 QString m_certFile;
1217 QString m_interFile;
1218 QList<QSslCipher> ciphers;
1219
1220signals:
1221 void socketError(QAbstractSocket::SocketError);
1222
1223protected:
1224 void incomingConnection(qintptr socketDescriptor)
1225 {
1226 QSslConfiguration configuration = config;
1227 socket = new QSslSocket(this);
1228 configuration.setPeerVerifyMode(peerVerifyMode);
1229 configuration.setProtocol(protocol);
1230 if (ignoreSslErrors)
1231 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1232 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: this, SIGNAL(socketError(QAbstractSocket::SocketError)));
1233
1234 QFile file(m_keyFile);
1235 QVERIFY(file.open(QIODevice::ReadOnly));
1236 QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
1237 QVERIFY(!key.isNull());
1238 configuration.setPrivateKey(key);
1239
1240 // Add CA certificates to verify client certificate
1241 if (!addCaCertificates.isEmpty()) {
1242 QList<QSslCertificate> caCert = QSslCertificate::fromPath(path: addCaCertificates);
1243 QVERIFY(!caCert.isEmpty());
1244 QVERIFY(!caCert.first().isNull());
1245 configuration.addCaCertificates(certificates: caCert);
1246 }
1247
1248 // If we have a cert issued directly from the CA
1249 if (m_interFile.isEmpty()) {
1250 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: m_certFile);
1251 QVERIFY(!localCert.isEmpty());
1252 QVERIFY(!localCert.first().isNull());
1253 configuration.setLocalCertificate(localCert.first());
1254 } else {
1255 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: m_certFile);
1256 QVERIFY(!localCert.isEmpty());
1257 QVERIFY(!localCert.first().isNull());
1258
1259 QList<QSslCertificate> interCert = QSslCertificate::fromPath(path: m_interFile);
1260 QVERIFY(!interCert.isEmpty());
1261 QVERIFY(!interCert.first().isNull());
1262
1263 configuration.setLocalCertificateChain(localCert + interCert);
1264 }
1265
1266 if (!ciphers.isEmpty())
1267 configuration.setCiphers(ciphers);
1268 socket->setSslConfiguration(configuration);
1269
1270 QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState));
1271 QVERIFY(!socket->peerAddress().isNull());
1272 QVERIFY(socket->peerPort() != 0);
1273 QVERIFY(!socket->localAddress().isNull());
1274 QVERIFY(socket->localPort() != 0);
1275
1276 socket->startServerEncryption();
1277 }
1278
1279protected slots:
1280 void ignoreErrorSlot()
1281 {
1282 socket->ignoreSslErrors();
1283 }
1284};
1285
1286void tst_QSslSocket::protocolServerSide_data()
1287{
1288#ifdef Q_OS_WINRT
1289 QSKIP("Server-side encryption is not implemented on WinRT.");
1290#endif
1291 QTest::addColumn<QSsl::SslProtocol>(name: "serverProtocol");
1292 QTest::addColumn<QSsl::SslProtocol>(name: "clientProtocol");
1293 QTest::addColumn<bool>(name: "works");
1294
1295 QTest::newRow(dataTag: "tls1.0-tls1.0") << QSsl::TlsV1_0 << QSsl::TlsV1_0 << true;
1296 QTest::newRow(dataTag: "tls1ssl3-tls1ssl3") << QSsl::TlsV1SslV3 << QSsl::TlsV1SslV3 << true;
1297 QTest::newRow(dataTag: "any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true;
1298 QTest::newRow(dataTag: "secure-secure") << QSsl::SecureProtocols << QSsl::SecureProtocols << true;
1299
1300 QTest::newRow(dataTag: "tls1-tls1ssl3") << QSsl::TlsV1_0 << QSsl::TlsV1SslV3 << true;
1301 QTest::newRow(dataTag: "tls1.0-secure") << QSsl::TlsV1_0 << QSsl::SecureProtocols << true;
1302 QTest::newRow(dataTag: "tls1.0-any") << QSsl::TlsV1_0 << QSsl::AnyProtocol << true;
1303
1304 QTest::newRow(dataTag: "tls1ssl3-tls1.0") << QSsl::TlsV1SslV3 << QSsl::TlsV1_0 << true;
1305 QTest::newRow(dataTag: "tls1ssl3-secure") << QSsl::TlsV1SslV3 << QSsl::SecureProtocols << true;
1306 QTest::newRow(dataTag: "tls1ssl3-any") << QSsl::TlsV1SslV3 << QSsl::AnyProtocol << true;
1307
1308 QTest::newRow(dataTag: "secure-tls1.0") << QSsl::SecureProtocols << QSsl::TlsV1_0 << true;
1309 QTest::newRow(dataTag: "secure-tls1ssl3") << QSsl::SecureProtocols << QSsl::TlsV1SslV3 << true;
1310 QTest::newRow(dataTag: "secure-any") << QSsl::SecureProtocols << QSsl::AnyProtocol << true;
1311
1312 QTest::newRow(dataTag: "tls1.0orlater-tls1.0") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_0 << true;
1313 QTest::newRow(dataTag: "tls1.0orlater-tls1.1") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_1 << true;
1314 QTest::newRow(dataTag: "tls1.0orlater-tls1.2") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_2 << true;
1315#ifdef TLS1_3_VERSION
1316 QTest::newRow(dataTag: "tls1.0orlater-tls1.3") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_3 << true;
1317#endif
1318
1319 QTest::newRow(dataTag: "tls1.1orlater-tls1.0") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_0 << false;
1320 QTest::newRow(dataTag: "tls1.1orlater-tls1.1") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_1 << true;
1321 QTest::newRow(dataTag: "tls1.1orlater-tls1.2") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_2 << true;
1322
1323#ifdef TLS1_3_VERSION
1324 QTest::newRow(dataTag: "tls1.1orlater-tls1.3") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_3 << true;
1325#endif
1326
1327 QTest::newRow(dataTag: "tls1.2orlater-tls1.0") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_0 << false;
1328 QTest::newRow(dataTag: "tls1.2orlater-tls1.1") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_1 << false;
1329 QTest::newRow(dataTag: "tls1.2orlater-tls1.2") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_2 << true;
1330#ifdef TLS1_3_VERSION
1331 QTest::newRow(dataTag: "tls1.2orlater-tls1.3") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_3 << true;
1332#endif
1333#ifdef TLS1_3_VERSION
1334 QTest::newRow(dataTag: "tls1.3orlater-tls1.0") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_0 << false;
1335 QTest::newRow(dataTag: "tls1.3orlater-tls1.1") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_1 << false;
1336 QTest::newRow(dataTag: "tls1.3orlater-tls1.2") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_2 << false;
1337 QTest::newRow(dataTag: "tls1.3orlater-tls1.3") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_3 << true;
1338#endif // TLS1_3_VERSION
1339
1340 QTest::newRow(dataTag: "any-tls1.0") << QSsl::AnyProtocol << QSsl::TlsV1_0 << true;
1341 QTest::newRow(dataTag: "any-tls1ssl3") << QSsl::AnyProtocol << QSsl::TlsV1SslV3 << true;
1342 QTest::newRow(dataTag: "any-secure") << QSsl::AnyProtocol << QSsl::SecureProtocols << true;
1343}
1344
1345void tst_QSslSocket::protocolServerSide()
1346{
1347 if (!QSslSocket::supportsSsl()) {
1348 qWarning(msg: "SSL not supported, skipping test");
1349 return;
1350 }
1351
1352 QFETCH_GLOBAL(bool, setProxy);
1353 if (setProxy)
1354 return;
1355
1356 QFETCH(QSsl::SslProtocol, serverProtocol);
1357 SslServer server;
1358 server.protocol = serverProtocol;
1359 QVERIFY(server.listen());
1360
1361 QEventLoop loop;
1362 connect(sender: &server, SIGNAL(socketError(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
1363 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
1364
1365 QSslSocket client;
1366 socket = &client;
1367 QFETCH(QSsl::SslProtocol, clientProtocol);
1368 socket->setProtocol(clientProtocol);
1369 // upon SSL wrong version error, errorOccurred will be triggered, not sslErrors
1370 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
1371 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1372 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
1373
1374 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
1375
1376 loop.exec();
1377
1378 QFETCH(bool, works);
1379 QAbstractSocket::SocketState expectedState = (works) ? QAbstractSocket::ConnectedState : QAbstractSocket::UnconnectedState;
1380 // Determine whether the client or the server caused the event loop
1381 // to quit due to a socket error, and investigate the culprit.
1382 if (client.error() != QAbstractSocket::UnknownSocketError) {
1383 // It can happen that the client, after TCP connection established, before
1384 // incomingConnection() slot fired, hits TLS initialization error and stops
1385 // the loop, so the server socket is not created yet.
1386 if (server.socket)
1387 QVERIFY(server.socket->error() == QAbstractSocket::UnknownSocketError);
1388
1389 QCOMPARE(client.state(), expectedState);
1390 } else if (server.socket->error() != QAbstractSocket::UnknownSocketError) {
1391 QVERIFY(client.error() == QAbstractSocket::UnknownSocketError);
1392 QCOMPARE(server.socket->state(), expectedState);
1393 }
1394
1395 QCOMPARE(client.isEncrypted(), works);
1396}
1397
1398#ifndef QT_NO_OPENSSL
1399
1400void tst_QSslSocket::serverCipherPreferences()
1401{
1402#ifdef Q_OS_WINRT
1403 QSKIP("Server-side encryption is not implemented on WinRT.");
1404#endif
1405 if (!QSslSocket::supportsSsl()) {
1406 qWarning(msg: "SSL not supported, skipping test");
1407 return;
1408 }
1409
1410 QFETCH_GLOBAL(bool, setProxy);
1411 if (setProxy)
1412 return;
1413
1414 // First using the default (server preference)
1415 {
1416 SslServer server;
1417 server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")};
1418 QVERIFY(server.listen());
1419
1420 QEventLoop loop;
1421 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
1422
1423 QSslSocket client;
1424 socket = &client;
1425
1426 auto sslConfig = socket->sslConfiguration();
1427 sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")});
1428 socket->setSslConfiguration(sslConfig);
1429
1430 // upon SSL wrong version error, errorOccurred will be triggered, not sslErrors
1431 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
1432 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1433 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
1434
1435 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
1436
1437 loop.exec();
1438
1439 QVERIFY(client.isEncrypted());
1440 QCOMPARE(client.sessionCipher().name(), QString("AES128-SHA"));
1441 }
1442
1443 {
1444 // Now using the client preferences
1445 SslServer server;
1446 QSslConfiguration config = QSslConfiguration::defaultConfiguration();
1447 config.setSslOption(option: QSsl::SslOptionDisableServerCipherPreference, on: true);
1448 server.config = config;
1449 server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")};
1450 QVERIFY(server.listen());
1451
1452 QEventLoop loop;
1453 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
1454
1455 QSslSocket client;
1456 socket = &client;
1457
1458 auto sslConfig = socket->sslConfiguration();
1459 sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")});
1460 socket->setSslConfiguration(sslConfig);
1461
1462 // upon SSL wrong version error, errorOccurred will be triggered, not sslErrors
1463 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
1464 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1465 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
1466
1467 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
1468
1469 loop.exec();
1470
1471 QVERIFY(client.isEncrypted());
1472 QCOMPARE(client.sessionCipher().name(), QString("AES256-SHA"));
1473 }
1474}
1475
1476#endif // QT_NO_OPENSSL
1477
1478
1479void tst_QSslSocket::setCaCertificates()
1480{
1481 if (!QSslSocket::supportsSsl())
1482 return;
1483
1484 QSslSocket socket;
1485 QCOMPARE(socket.sslConfiguration().caCertificates(),
1486 QSslConfiguration::defaultConfiguration().caCertificates());
1487
1488 auto sslConfig = socket.sslConfiguration();
1489 sslConfig.setCaCertificates(
1490 QSslCertificate::fromPath(path: testDataDir + "certs/qt-test-server-cacert.pem"));
1491 socket.setSslConfiguration(sslConfig);
1492 QCOMPARE(socket.sslConfiguration().caCertificates().size(), 1);
1493
1494 sslConfig.setCaCertificates(QSslConfiguration::defaultConfiguration().caCertificates());
1495 socket.setSslConfiguration(sslConfig);
1496 QCOMPARE(socket.sslConfiguration().caCertificates(),
1497 QSslConfiguration::defaultConfiguration().caCertificates());
1498}
1499
1500void tst_QSslSocket::setLocalCertificate()
1501{
1502}
1503
1504void tst_QSslSocket::localCertificateChain()
1505{
1506 if (!QSslSocket::supportsSsl())
1507 return;
1508
1509 QSslSocket socket;
1510 socket.setLocalCertificate(fileName: testDataDir + "certs/fluke.cert");
1511
1512 QSslConfiguration conf = socket.sslConfiguration();
1513 QList<QSslCertificate> chain = conf.localCertificateChain();
1514 QCOMPARE(chain.size(), 1);
1515 QCOMPARE(chain[0], conf.localCertificate());
1516 QCOMPARE(chain[0], socket.localCertificate());
1517}
1518
1519void tst_QSslSocket::setLocalCertificateChain()
1520{
1521#ifdef Q_OS_WINRT
1522 QSKIP("Server-side encryption is not implemented on WinRT.");
1523#endif
1524 if (!QSslSocket::supportsSsl())
1525 return;
1526
1527 QFETCH_GLOBAL(bool, setProxy);
1528 if (setProxy)
1529 return;
1530
1531 SslServer server(testDataDir + "certs/leaf.key",
1532 testDataDir + "certs/leaf.crt",
1533 testDataDir + "certs/inter.crt");
1534
1535 QVERIFY(server.listen());
1536
1537 QEventLoop loop;
1538 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
1539
1540 const QScopedPointer<QSslSocket, QScopedPointerDeleteLater> client(new QSslSocket);
1541 socket = client.data();
1542 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
1543 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
1544 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1545
1546 socket->connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
1547 loop.exec();
1548
1549 QList<QSslCertificate> chain = socket->peerCertificateChain();
1550#if QT_CONFIG(schannel)
1551 QEXPECT_FAIL("", "Schannel cannot send intermediate certificates not "
1552 "located in a system certificate store",
1553 Abort);
1554#endif
1555 QCOMPARE(chain.size(), 2);
1556 QCOMPARE(chain[0].serialNumber(), QByteArray("10:a0:ad:77:58:f6:6e:ae:46:93:a3:43:f9:59:8a:9e"));
1557 QCOMPARE(chain[1].serialNumber(), QByteArray("3b:eb:99:c5:ea:d8:0b:5d:0b:97:5d:4f:06:75:4b:e1"));
1558}
1559
1560void tst_QSslSocket::tlsConfiguration()
1561{
1562 QFETCH_GLOBAL(const bool, setProxy);
1563 if (setProxy)
1564 return;
1565 // Test some things not covered by any other auto-test.
1566 QSslSocket socket;
1567 auto tlsConfig = socket.sslConfiguration();
1568 QVERIFY(tlsConfig.sessionCipher().isNull());
1569 QCOMPARE(tlsConfig.addCaCertificates(QStringLiteral("nonexisting/chain.crt")), false);
1570 QCOMPARE(tlsConfig.sessionProtocol(), QSsl::UnknownProtocol);
1571 QSslConfiguration nullConfig;
1572 QVERIFY(nullConfig.isNull());
1573#ifndef QT_NO_OPENSSL
1574 nullConfig.setEllipticCurves(tlsConfig.ellipticCurves());
1575 QCOMPARE(nullConfig.ellipticCurves(), tlsConfig.ellipticCurves());
1576#endif
1577 QMap<QByteArray, QVariant> backendConfig;
1578 backendConfig["DTLSMTU"] = QVariant::fromValue(value: 1024);
1579 backendConfig["DTLSTIMEOUTMS"] = QVariant::fromValue(value: 1000);
1580 nullConfig.setBackendConfiguration(backendConfig);
1581 QCOMPARE(nullConfig.backendConfiguration(), backendConfig);
1582 QTest::ignoreMessage(type: QtWarningMsg, message: "QSslConfiguration::setPeerVerifyDepth: cannot set negative depth of -1000");
1583 nullConfig.setPeerVerifyDepth(-1000);
1584 QVERIFY(nullConfig.peerVerifyDepth() != -1000);
1585 nullConfig.setPeerVerifyDepth(100);
1586 QCOMPARE(nullConfig.peerVerifyDepth(), 100);
1587}
1588
1589void tst_QSslSocket::setSocketDescriptor()
1590{
1591#ifdef Q_OS_WINRT
1592 QSKIP("Server-side encryption is not implemented on WinRT.");
1593#endif
1594 if (!QSslSocket::supportsSsl())
1595 return;
1596
1597 QFETCH_GLOBAL(bool, setProxy);
1598 if (setProxy)
1599 return;
1600
1601 SslServer server;
1602 QVERIFY(server.listen());
1603
1604 QEventLoop loop;
1605 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
1606
1607 QSslSocket client;
1608 socket = &client;
1609 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1610 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
1611
1612 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
1613
1614 loop.exec();
1615
1616 QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
1617 QVERIFY(client.isEncrypted());
1618 QVERIFY(!client.peerAddress().isNull());
1619 QVERIFY(client.peerPort() != 0);
1620 QVERIFY(!client.localAddress().isNull());
1621 QVERIFY(client.localPort() != 0);
1622}
1623
1624void tst_QSslSocket::setSslConfiguration_data()
1625{
1626#if QT_CONFIG(securetransport)
1627 QSKIP("Skipping the cases with certificate, SecureTransport does not like old certificate on the test server");
1628#endif // securetransport
1629 QTest::addColumn<QSslConfiguration>(name: "configuration");
1630 QTest::addColumn<bool>(name: "works");
1631
1632 QTest::newRow(dataTag: "empty") << QSslConfiguration() << false;
1633 QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
1634 QTest::newRow(dataTag: "default") << conf << false; // does not contain test server cert
1635 QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(path: httpServerCertChainPath());
1636 conf.setCaCertificates(testServerCert);
1637 QTest::newRow(dataTag: "set-root-cert") << conf << true;
1638 conf.setProtocol(QSsl::SecureProtocols);
1639 QTest::newRow(dataTag: "secure") << conf << true;
1640}
1641
1642void tst_QSslSocket::setSslConfiguration()
1643{
1644 if (!QSslSocket::supportsSsl())
1645 return;
1646
1647 QSslSocketPtr socket = newSocket();
1648 QFETCH(QSslConfiguration, configuration);
1649 socket->setSslConfiguration(configuration);
1650#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
1651 socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
1652#endif
1653 this->socket = socket.data();
1654 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1655 QFETCH(bool, works);
1656 QFETCH_GLOBAL(bool, setProxy);
1657 if (setProxy && (socket->waitForEncrypted(msecs: 10000) != works))
1658 QSKIP("Skipping flaky test - See QTBUG-29941");
1659 if (works) {
1660 socket->disconnectFromHost();
1661 QVERIFY2(socket->waitForDisconnected(), qPrintable(socket->errorString()));
1662 }
1663}
1664
1665void tst_QSslSocket::waitForEncrypted()
1666{
1667 if (!QSslSocket::supportsSsl())
1668 return;
1669
1670 QSslSocketPtr socket = newSocket();
1671 this->socket = socket.data();
1672
1673 connect(sender: this->socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1674 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1675
1676 QFETCH_GLOBAL(bool, setProxy);
1677 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
1678 QSKIP("Skipping flaky test - See QTBUG-29941");
1679}
1680
1681void tst_QSslSocket::waitForEncryptedMinusOne()
1682{
1683#ifdef Q_OS_WIN
1684 QSKIP("QTBUG-24451 - indefinite wait may hang");
1685#endif
1686 if (!QSslSocket::supportsSsl())
1687 return;
1688
1689 QSslSocketPtr socket = newSocket();
1690 this->socket = socket.data();
1691
1692 connect(sender: this->socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1693 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
1694
1695 QFETCH_GLOBAL(bool, setProxy);
1696 if (setProxy && !socket->waitForEncrypted(msecs: -1))
1697 QSKIP("Skipping flaky test - See QTBUG-29941");
1698}
1699
1700void tst_QSslSocket::waitForConnectedEncryptedReadyRead()
1701{
1702 if (!QSslSocket::supportsSsl())
1703 return;
1704
1705 QSslSocketPtr socket = newSocket();
1706 this->socket = socket.data();
1707
1708 connect(sender: this->socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
1709 socket->connectToHostEncrypted(hostName: QtNetworkSettings::imapServerName(), port: 993);
1710
1711 QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString()));
1712 QFETCH_GLOBAL(bool, setProxy);
1713 if (setProxy && !socket->waitForEncrypted(msecs: 10000))
1714 QSKIP("Skipping flaky test - See QTBUG-29941");
1715
1716 // We only do this if we have no bytes available to read already because readyRead will
1717 // not be emitted again.
1718 if (socket->bytesAvailable() == 0)
1719 QVERIFY(socket->waitForReadyRead(10000));
1720
1721 QVERIFY(!socket->peerCertificate().isNull());
1722 QVERIFY(!socket->peerCertificateChain().isEmpty());
1723}
1724
1725void tst_QSslSocket::startClientEncryption()
1726{
1727}
1728
1729void tst_QSslSocket::startServerEncryption()
1730{
1731}
1732
1733void tst_QSslSocket::addDefaultCaCertificate()
1734{
1735 if (!QSslSocket::supportsSsl())
1736 return;
1737
1738 // Reset the global CA chain
1739 auto sslConfig = QSslConfiguration::defaultConfiguration();
1740 sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates());
1741 QSslConfiguration::setDefaultConfiguration(sslConfig);
1742
1743 QList<QSslCertificate> flukeCerts = QSslCertificate::fromPath(path: httpServerCertChainPath());
1744 QCOMPARE(flukeCerts.size(), 1);
1745 QList<QSslCertificate> globalCerts = QSslConfiguration::defaultConfiguration().caCertificates();
1746 QVERIFY(!globalCerts.contains(flukeCerts.first()));
1747 sslConfig.addCaCertificate(certificate: flukeCerts.first());
1748 QSslConfiguration::setDefaultConfiguration(sslConfig);
1749 QCOMPARE(QSslConfiguration::defaultConfiguration().caCertificates().size(),
1750 globalCerts.size() + 1);
1751 QVERIFY(QSslConfiguration::defaultConfiguration().caCertificates()
1752 .contains(flukeCerts.first()));
1753
1754 // Restore the global CA chain
1755 sslConfig = QSslConfiguration::defaultConfiguration();
1756 sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates());
1757 QSslConfiguration::setDefaultConfiguration(sslConfig);
1758}
1759
1760void tst_QSslSocket::defaultCaCertificates()
1761{
1762 if (!QSslSocket::supportsSsl())
1763 return;
1764
1765 QList<QSslCertificate> certs = QSslConfiguration::defaultConfiguration().caCertificates();
1766 QVERIFY(certs.size() > 1);
1767 QCOMPARE(certs, QSslConfiguration::systemCaCertificates());
1768}
1769
1770void tst_QSslSocket::defaultCiphers()
1771{
1772 if (!QSslSocket::supportsSsl())
1773 return;
1774
1775 QList<QSslCipher> ciphers = QSslConfiguration::defaultConfiguration().ciphers();
1776 QVERIFY(ciphers.size() > 1);
1777
1778 QSslSocket socket;
1779 QCOMPARE(socket.sslConfiguration().defaultConfiguration().ciphers(), ciphers);
1780 QCOMPARE(socket.sslConfiguration().ciphers(), ciphers);
1781}
1782
1783void tst_QSslSocket::resetDefaultCiphers()
1784{
1785}
1786
1787void tst_QSslSocket::setDefaultCaCertificates()
1788{
1789}
1790
1791void tst_QSslSocket::setDefaultCiphers()
1792{
1793}
1794
1795void tst_QSslSocket::supportedCiphers()
1796{
1797 if (!QSslSocket::supportsSsl())
1798 return;
1799
1800 QList<QSslCipher> ciphers = QSslConfiguration::supportedCiphers();
1801 QVERIFY(ciphers.size() > 1);
1802
1803 QSslSocket socket;
1804 QCOMPARE(socket.sslConfiguration().supportedCiphers(), ciphers);
1805}
1806
1807void tst_QSslSocket::systemCaCertificates()
1808{
1809 if (!QSslSocket::supportsSsl())
1810 return;
1811
1812 QList<QSslCertificate> certs = QSslConfiguration::systemCaCertificates();
1813 QVERIFY(certs.size() > 1);
1814 QCOMPARE(certs, QSslConfiguration::defaultConfiguration().systemCaCertificates());
1815}
1816
1817void tst_QSslSocket::wildcardCertificateNames()
1818{
1819 // Passing CN matches
1820 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("www.example.com"), QString("www.example.com")), true );
1821 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("WWW.EXAMPLE.COM"), QString("www.example.com")), true );
1822 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.example.com"), QString("www.example.com")), true );
1823 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("xxx*.example.com"), QString("xxxwww.example.com")), true );
1824 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("f*.example.com"), QString("foo.example.com")), true );
1825 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("192.168.0.0"), QString("192.168.0.0")), true );
1826 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("foo.éxample.com"), QString("foo.xn--xample-9ua.com")), true );
1827 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.éxample.com"), QString("foo.xn--xample-9ua.com")), true );
1828 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("xn--kcry6tjko.example.org"), QString("xn--kcry6tjko.example.org")), true);
1829 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.xn--kcry6tjko.example.org"), QString("xn--kcr.xn--kcry6tjko.example.org")), true);
1830
1831 // Failing CN matches
1832 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("xxx.example.com"), QString("www.example.com")), false );
1833 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*"), QString("www.example.com")), false );
1834 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.*.com"), QString("www.example.com")), false );
1835 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.example.com"), QString("baa.foo.example.com")), false );
1836 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("f*.example.com"), QString("baa.example.com")), false );
1837 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.com"), QString("example.com")), false );
1838 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*fail.com"), QString("example.com")), false );
1839 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.example."), QString("www.example.")), false );
1840 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.example."), QString("www.example")), false );
1841 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString(""), QString("www")), false );
1842 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*"), QString("www")), false );
1843 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("*.168.0.0"), QString("192.168.0.0")), false );
1844 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("xn--kcry6tjko*.example.org"), QString("xn--kcry6tjkoanc.example.org")), false ); // RFC 6125 §7.2
1845 QCOMPARE( QSslSocketPrivate::isMatchingHostname(QString("Ã¥*.example.org"), QString("xn--la-xia.example.org")), false );
1846}
1847
1848void tst_QSslSocket::isMatchingHostname()
1849{
1850 // with normalization: (the certificate has *.SCHÄUFELE.DE as a CN)
1851 // openssl req -x509 -nodes -subj "/CN=*.SCHÄUFELE.DE" -newkey rsa:512 -keyout /dev/null -out xn--schufele-2za.crt
1852 QList<QSslCertificate> certs = QSslCertificate::fromPath(path: testDataDir + "certs/xn--schufele-2za.crt");
1853 QVERIFY(!certs.isEmpty());
1854 QSslCertificate cert = certs.first();
1855
1856 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("WWW.SCHÄUFELE.DE")), true);
1857 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("www.xn--schufele-2za.de")), true);
1858 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("www.schäufele.de")), true);
1859 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("föo.schäufele.de")), true);
1860
1861 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("foo.foo.xn--schufele-2za.de")), false);
1862 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("www.schaufele.de")), false);
1863 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("www.schufele.de")), false);
1864
1865 /* Generated with the following command (only valid with openssl >= 1.1.1 due to "-addext"):
1866 openssl req -x509 -nodes -subj "/CN=example.org" \
1867 -addext "subjectAltName = IP:192.5.8.16, IP:fe80::3c29:2fa1:dd44:765" \
1868 -newkey rsa:2048 -keyout /dev/null -out subjectAltNameIP.crt
1869 */
1870 certs = QSslCertificate::fromPath(path: testDataDir + "certs/subjectAltNameIP.crt");
1871 QVERIFY(!certs.isEmpty());
1872 cert = certs.first();
1873 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("192.5.8.16")), true);
1874 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("fe80::3c29:2fa1:dd44:765")), true);
1875
1876 /* openssl req -x509 -nodes -new -newkey rsa -keyout /dev/null -out 127-0-0-1-as-CN.crt \
1877 -subj "/CN=127.0.0.1"
1878 */
1879 certs = QSslCertificate::fromPath(path: testDataDir + "certs/127-0-0-1-as-CN.crt");
1880 QVERIFY(!certs.isEmpty());
1881 cert = certs.first();
1882 QCOMPARE(QSslSocketPrivate::isMatchingHostname(cert, QString::fromUtf8("127.0.0.1")), true);
1883}
1884
1885void tst_QSslSocket::wildcard()
1886{
1887 QSKIP("TODO: solve wildcard problem");
1888
1889 if (!QSslSocket::supportsSsl())
1890 return;
1891
1892 // Fluke runs an apache server listening on port 4443, serving the
1893 // wildcard fluke.*.troll.no. The DNS entry for
1894 // fluke.wildcard.dev.troll.no, served by ares (root for dev.troll.no),
1895 // returns the CNAME fluke.troll.no for this domain. The web server
1896 // responds with the wildcard, and QSslSocket should accept that as a
1897 // valid connection. This was broken in 4.3.0.
1898 QSslSocketPtr socket = newSocket();
1899 auto config = socket->sslConfiguration();
1900 config.addCaCertificates(path: QLatin1String("certs/aspiriniks.ca.crt"));
1901 socket->setSslConfiguration(config);
1902 this->socket = socket.data();
1903#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND
1904 connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
1905 this, SLOT(untrustedWorkaroundSlot(QList<QSslError>)));
1906#endif
1907 socket->connectToHostEncrypted(hostName: QtNetworkSettings::wildcardServerName(), port: 4443);
1908
1909 QFETCH_GLOBAL(bool, setProxy);
1910 if (setProxy && !socket->waitForEncrypted(msecs: 3000))
1911 QSKIP("Skipping flaky test - See QTBUG-29941");
1912
1913 QSslCertificate certificate = socket->peerCertificate();
1914 QVERIFY(certificate.subjectInfo(QSslCertificate::CommonName).contains(QString(QtNetworkSettings::serverLocalName() + ".*." + QtNetworkSettings::serverDomainName())));
1915 QVERIFY(certificate.issuerInfo(QSslCertificate::CommonName).contains(QtNetworkSettings::serverName()));
1916
1917 socket->close();
1918}
1919
1920class SslServer2 : public QTcpServer
1921{
1922protected:
1923 void incomingConnection(qintptr socketDescriptor)
1924 {
1925 QSslSocket *socket = new QSslSocket(this);
1926 socket->ignoreSslErrors();
1927
1928 // Only set the certificate
1929 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: tst_QSslSocket::testDataDir + "certs/fluke.cert");
1930 QVERIFY(!localCert.isEmpty());
1931 QVERIFY(!localCert.first().isNull());
1932 socket->setLocalCertificate(localCert.first());
1933
1934 QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState));
1935
1936 socket->startServerEncryption();
1937 }
1938};
1939
1940void tst_QSslSocket::setEmptyKey()
1941{
1942#ifdef Q_OS_WINRT
1943 QSKIP("Server-side encryption is not implemented on WinRT.");
1944#endif
1945 if (!QSslSocket::supportsSsl())
1946 return;
1947
1948 QFETCH_GLOBAL(bool, setProxy);
1949 if (setProxy)
1950 return;
1951
1952 SslServer2 server;
1953 server.listen();
1954
1955 QSslSocket socket;
1956 socket.connectToHostEncrypted(hostName: "127.0.0.1", port: server.serverPort());
1957
1958 QTestEventLoop::instance().enterLoop(secs: 2);
1959
1960 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
1961 QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
1962}
1963
1964void tst_QSslSocket::spontaneousWrite()
1965{
1966#ifdef Q_OS_WINRT
1967 QSKIP("Server-side encryption is not implemented on WinRT.");
1968#endif
1969 QFETCH_GLOBAL(bool, setProxy);
1970 if (setProxy)
1971 return;
1972
1973 SslServer server;
1974 QSslSocket *receiver = new QSslSocket(this);
1975 connect(asender: receiver, SIGNAL(readyRead()), SLOT(exitLoop()));
1976
1977 // connect two sockets to each other:
1978 QVERIFY(server.listen(QHostAddress::LocalHost));
1979 receiver->connectToHost(hostName: "127.0.0.1", port: server.serverPort());
1980 QVERIFY(receiver->waitForConnected(5000));
1981 QVERIFY(server.waitForNewConnection(0));
1982
1983 QSslSocket *sender = server.socket;
1984 QVERIFY(sender);
1985 QCOMPARE(sender->state(), QAbstractSocket::ConnectedState);
1986 receiver->setObjectName("receiver");
1987 sender->setObjectName("sender");
1988 receiver->ignoreSslErrors();
1989 receiver->startClientEncryption();
1990
1991 // SSL handshake:
1992 connect(asender: receiver, SIGNAL(encrypted()), SLOT(exitLoop()));
1993 enterLoop(secs: 1);
1994 QVERIFY(!timeout());
1995 QVERIFY(sender->isEncrypted());
1996 QVERIFY(receiver->isEncrypted());
1997
1998 // make sure there's nothing to be received on the sender:
1999 while (sender->waitForReadyRead(msecs: 10) || receiver->waitForBytesWritten(msecs: 10)) {}
2000
2001 // spontaneously write something:
2002 QByteArray data("Hello World");
2003 sender->write(data);
2004
2005 // check if the other side receives it:
2006 enterLoop(secs: 1);
2007 QVERIFY(!timeout());
2008 QCOMPARE(receiver->bytesAvailable(), qint64(data.size()));
2009 QCOMPARE(receiver->readAll(), data);
2010}
2011
2012void tst_QSslSocket::setReadBufferSize()
2013{
2014#ifdef Q_OS_WINRT
2015 QSKIP("Server-side encryption is not implemented on WinRT.");
2016#endif
2017 QFETCH_GLOBAL(bool, setProxy);
2018 if (setProxy)
2019 return;
2020
2021 SslServer server;
2022 QSslSocket *receiver = new QSslSocket(this);
2023 connect(asender: receiver, SIGNAL(readyRead()), SLOT(exitLoop()));
2024
2025 // connect two sockets to each other:
2026 QVERIFY(server.listen(QHostAddress::LocalHost));
2027 receiver->connectToHost(hostName: "127.0.0.1", port: server.serverPort());
2028 QVERIFY(receiver->waitForConnected(5000));
2029 QVERIFY(server.waitForNewConnection(0));
2030
2031 QSslSocket *sender = server.socket;
2032 QVERIFY(sender);
2033 QCOMPARE(sender->state(), QAbstractSocket::ConnectedState);
2034 receiver->setObjectName("receiver");
2035 sender->setObjectName("sender");
2036 receiver->ignoreSslErrors();
2037 receiver->startClientEncryption();
2038
2039 // SSL handshake:
2040 connect(asender: receiver, SIGNAL(encrypted()), SLOT(exitLoop()));
2041 enterLoop(secs: 1);
2042 QVERIFY(!timeout());
2043 QVERIFY(sender->isEncrypted());
2044 QVERIFY(receiver->isEncrypted());
2045
2046 QByteArray data(2048, 'b');
2047 receiver->setReadBufferSize(39 * 1024); // make it a non-multiple of the data.size()
2048
2049 // saturate the incoming buffer
2050 while (sender->state() == QAbstractSocket::ConnectedState &&
2051 receiver->state() == QAbstractSocket::ConnectedState &&
2052 receiver->bytesAvailable() < receiver->readBufferSize()) {
2053 sender->write(data);
2054 //qDebug() << receiver->bytesAvailable() << "<" << receiver->readBufferSize() << (receiver->bytesAvailable() < receiver->readBufferSize());
2055
2056 while (sender->bytesToWrite())
2057 QVERIFY(sender->waitForBytesWritten(10));
2058
2059 // drain it:
2060 while (receiver->bytesAvailable() < receiver->readBufferSize() &&
2061 receiver->waitForReadyRead(msecs: 10)) {}
2062 }
2063
2064 //qDebug() << sender->bytesToWrite() << "bytes to write";
2065 //qDebug() << receiver->bytesAvailable() << "bytes available";
2066
2067 // send a bit more
2068 sender->write(data);
2069 sender->write(data);
2070 sender->write(data);
2071 sender->write(data);
2072 QVERIFY(sender->waitForBytesWritten(10));
2073
2074 qint64 oldBytesAvailable = receiver->bytesAvailable();
2075
2076 // now unset the read buffer limit and iterate
2077 receiver->setReadBufferSize(0);
2078 enterLoop(secs: 1);
2079 QVERIFY(!timeout());
2080
2081 QVERIFY(receiver->bytesAvailable() > oldBytesAvailable);
2082}
2083
2084class SetReadBufferSize_task_250027_handler : public QObject {
2085 Q_OBJECT
2086public slots:
2087 void readyReadSlot() {
2088 QTestEventLoop::instance().exitLoop();
2089 }
2090 void waitSomeMore(QSslSocket *socket) {
2091 QElapsedTimer t;
2092 t.start();
2093 while (!socket->encryptedBytesAvailable()) {
2094 QCoreApplication::processEvents(flags: QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents, maxtime: 250);
2095 if (t.elapsed() > 1000 || socket->state() != QAbstractSocket::ConnectedState)
2096 return;
2097 }
2098 }
2099};
2100
2101void tst_QSslSocket::setReadBufferSize_task_250027()
2102{
2103 QSKIP("QTBUG-29730 - flakey test blocking integration");
2104
2105 // do not execute this when a proxy is set.
2106 QFETCH_GLOBAL(bool, setProxy);
2107 if (setProxy)
2108 return;
2109
2110 QSslSocketPtr socket = newSocket();
2111 socket->setReadBufferSize(1000); // limit to 1 kb/sec
2112 socket->ignoreSslErrors();
2113 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2114 socket->ignoreSslErrors();
2115 QVERIFY2(socket->waitForConnected(10*1000), qPrintable(socket->errorString()));
2116 if (setProxy && !socket->waitForEncrypted(msecs: 10*1000))
2117 QSKIP("Skipping flaky test - See QTBUG-29941");
2118
2119 // exit the event loop as soon as we receive a readyRead()
2120 SetReadBufferSize_task_250027_handler setReadBufferSize_task_250027_handler;
2121 connect(sender: socket.data(), SIGNAL(readyRead()), receiver: &setReadBufferSize_task_250027_handler, SLOT(readyReadSlot()));
2122
2123 // provoke a response by sending a request
2124 socket->write(data: "GET /qtest/fluke.gif HTTP/1.0\n"); // this file is 27 KB
2125 socket->write(data: "Host: ");
2126 socket->write(data: QtNetworkSettings::httpServerName().toLocal8Bit().constData());
2127 socket->write(data: "\n");
2128 socket->write(data: "Connection: close\n");
2129 socket->write(data: "\n");
2130 socket->flush();
2131
2132 QTestEventLoop::instance().enterLoop(secs: 10);
2133 setReadBufferSize_task_250027_handler.waitSomeMore(socket: socket.data());
2134 QByteArray firstRead = socket->readAll();
2135 // First read should be some data, but not the whole file
2136 QVERIFY(firstRead.size() > 0 && firstRead.size() < 20*1024);
2137
2138 QTestEventLoop::instance().enterLoop(secs: 10);
2139 setReadBufferSize_task_250027_handler.waitSomeMore(socket: socket.data());
2140 QByteArray secondRead = socket->readAll();
2141 // second read should be some more data
2142
2143 int secondReadSize = secondRead.size();
2144
2145 if (secondReadSize <= 0) {
2146 QEXPECT_FAIL("", "QTBUG-29730", Continue);
2147 }
2148
2149 QVERIFY(secondReadSize > 0);
2150
2151 socket->close();
2152}
2153
2154class SslServer3 : public QTcpServer
2155{
2156 Q_OBJECT
2157public:
2158 SslServer3() : socket(0) { }
2159 QSslSocket *socket;
2160
2161protected:
2162 void incomingConnection(qintptr socketDescriptor)
2163 {
2164 socket = new QSslSocket(this);
2165 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
2166
2167 QFile file(tst_QSslSocket::testDataDir + "certs/fluke.key");
2168 QVERIFY(file.open(QIODevice::ReadOnly));
2169 QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
2170 QVERIFY(!key.isNull());
2171 socket->setPrivateKey(key);
2172
2173 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: tst_QSslSocket::testDataDir
2174 + "certs/fluke.cert");
2175 QVERIFY(!localCert.isEmpty());
2176 QVERIFY(!localCert.first().isNull());
2177 socket->setLocalCertificate(localCert.first());
2178
2179 QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState));
2180 QVERIFY(!socket->peerAddress().isNull());
2181 QVERIFY(socket->peerPort() != 0);
2182 QVERIFY(!socket->localAddress().isNull());
2183 QVERIFY(socket->localPort() != 0);
2184 }
2185
2186protected slots:
2187 void ignoreErrorSlot()
2188 {
2189 socket->ignoreSslErrors();
2190 }
2191};
2192
2193class ThreadedSslServer: public QThread
2194{
2195 Q_OBJECT
2196public:
2197 QSemaphore dataReadSemaphore;
2198 int serverPort;
2199 bool ok;
2200
2201 ThreadedSslServer() : serverPort(-1), ok(false)
2202 { }
2203
2204 ~ThreadedSslServer()
2205 {
2206 if (isRunning()) wait(time: 2000);
2207 QVERIFY(ok);
2208 }
2209
2210signals:
2211 void listening();
2212
2213protected:
2214 void run()
2215 {
2216 // if all goes well (no timeouts), this thread will sleep for a total of 500 ms
2217 // (i.e., 5 times 100 ms, one sleep for each operation)
2218
2219 SslServer3 server;
2220 server.listen(address: QHostAddress::LocalHost);
2221 serverPort = server.serverPort();
2222 emit listening();
2223
2224 // delayed acceptance:
2225 QTest::qSleep(ms: 100);
2226 bool ret = server.waitForNewConnection(msec: 2000);
2227 Q_UNUSED(ret);
2228
2229 // delayed start of encryption
2230 QTest::qSleep(ms: 100);
2231 QSslSocket *socket = server.socket;
2232 if (!socket || !socket->isValid())
2233 return; // error
2234 socket->ignoreSslErrors();
2235 socket->startServerEncryption();
2236 if (!socket->waitForEncrypted(msecs: 2000))
2237 return; // error
2238
2239 // delayed reading data
2240 QTest::qSleep(ms: 100);
2241 if (!socket->waitForReadyRead(msecs: 2000) && socket->bytesAvailable() == 0)
2242 return; // error
2243 socket->readAll();
2244 dataReadSemaphore.release();
2245
2246 // delayed sending data
2247 QTest::qSleep(ms: 100);
2248 socket->write(data: "Hello, World");
2249 while (socket->bytesToWrite())
2250 if (!socket->waitForBytesWritten(msecs: 2000))
2251 return; // error
2252
2253 // delayed replying (reading then sending)
2254 QTest::qSleep(ms: 100);
2255 if (!socket->waitForReadyRead(msecs: 2000))
2256 return; // error
2257 socket->write(data: "Hello, World");
2258 while (socket->bytesToWrite())
2259 if (!socket->waitForBytesWritten(msecs: 2000))
2260 return; // error
2261
2262 // delayed disconnection:
2263 QTest::qSleep(ms: 100);
2264 socket->disconnectFromHost();
2265 if (!socket->waitForDisconnected(msecs: 2000))
2266 return; // error
2267
2268 delete socket;
2269 ok = true;
2270 }
2271};
2272
2273void tst_QSslSocket::waitForMinusOne()
2274{
2275#ifdef Q_OS_WIN
2276 QSKIP("QTBUG-24451 - indefinite wait may hang");
2277#endif
2278#ifdef Q_OS_WINRT // This can stay in case the one above goes away
2279 QSKIP("Server-side encryption is not implemented on WinRT.");
2280#endif
2281 QFETCH_GLOBAL(bool, setProxy);
2282 if (setProxy)
2283 return;
2284
2285 ThreadedSslServer server;
2286 connect(asender: &server, SIGNAL(listening()), SLOT(exitLoop()));
2287
2288 // start the thread and wait for it to be ready
2289 server.start();
2290 enterLoop(secs: 1);
2291 QVERIFY(!timeout());
2292
2293 // connect to the server
2294 QSslSocket socket;
2295 QTest::qSleep(ms: 100);
2296 socket.connectToHost(hostName: "127.0.0.1", port: server.serverPort);
2297 QVERIFY(socket.waitForConnected(-1));
2298 socket.ignoreSslErrors();
2299 socket.startClientEncryption();
2300
2301 // first verification: this waiting should take 200 ms
2302 if (!socket.waitForEncrypted(msecs: -1))
2303 QSKIP("Skipping flaky test - See QTBUG-29941");
2304 QVERIFY(socket.isEncrypted());
2305 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
2306 QCOMPARE(socket.bytesAvailable(), Q_INT64_C(0));
2307
2308 // second verification: write and make sure the other side got it (100 ms)
2309 socket.write(data: "How are you doing?");
2310 QVERIFY(socket.bytesToWrite() != 0);
2311 QVERIFY(socket.waitForBytesWritten(-1));
2312 QVERIFY(server.dataReadSemaphore.tryAcquire(1, 2500));
2313
2314 // third verification: it should wait for 100 ms:
2315 QVERIFY(socket.waitForReadyRead(-1));
2316 QVERIFY(socket.isEncrypted());
2317 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
2318 QVERIFY(socket.bytesAvailable() != 0);
2319
2320 // fourth verification: deadlock prevention:
2321 // we write and then wait for reading; the other side needs to receive before
2322 // replying (100 ms delay)
2323 socket.write(data: "I'm doing just fine!");
2324 QVERIFY(socket.bytesToWrite() != 0);
2325 QVERIFY(socket.waitForReadyRead(-1));
2326
2327 // fifth verification: it should wait for 200 ms more
2328 QVERIFY(socket.waitForDisconnected(-1));
2329
2330 // sixth verification: reading from a disconnected socket returns -1
2331 // once we deplete the read buffer
2332 QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
2333 socket.readAll();
2334 char aux;
2335 QCOMPARE(socket.read(&aux, 1), -1);
2336}
2337
2338class VerifyServer : public QTcpServer
2339{
2340 Q_OBJECT
2341public:
2342 VerifyServer() : socket(0) { }
2343 QSslSocket *socket;
2344
2345protected:
2346 void incomingConnection(qintptr socketDescriptor)
2347 {
2348 socket = new QSslSocket(this);
2349
2350 socket->setPrivateKey(fileName: tst_QSslSocket::testDataDir + "certs/fluke.key");
2351 socket->setLocalCertificate(fileName: tst_QSslSocket::testDataDir + "certs/fluke.cert");
2352 socket->setSocketDescriptor(socketDescriptor);
2353 socket->startServerEncryption();
2354 }
2355};
2356
2357void tst_QSslSocket::verifyMode()
2358{
2359#ifdef Q_OS_WINRT
2360 QSKIP("Server-side encryption is not implemented on WinRT.");
2361#endif
2362 QFETCH_GLOBAL(bool, setProxy);
2363 if (setProxy)
2364 return;
2365
2366 QSslSocket socket;
2367#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
2368 socket.setProtocol(QSsl::SslProtocol::TlsV1_1);
2369#endif
2370 QCOMPARE(socket.peerVerifyMode(), QSslSocket::AutoVerifyPeer);
2371 socket.setPeerVerifyMode(QSslSocket::VerifyNone);
2372 QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyNone);
2373 socket.setPeerVerifyMode(QSslSocket::VerifyNone);
2374 socket.setPeerVerifyMode(QSslSocket::VerifyPeer);
2375 QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyPeer);
2376
2377 socket.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2378 if (socket.waitForEncrypted())
2379 QSKIP("Skipping flaky test - See QTBUG-29941");
2380
2381 QList<QSslError> expectedErrors = QList<QSslError>()
2382 << QSslError(FLUKE_CERTIFICATE_ERROR, socket.peerCertificate());
2383 QCOMPARE(socket.sslHandshakeErrors(), expectedErrors);
2384 socket.abort();
2385
2386 VerifyServer server;
2387 server.listen();
2388
2389 QSslSocket clientSocket;
2390 clientSocket.connectToHostEncrypted(hostName: "127.0.0.1", port: server.serverPort());
2391 clientSocket.ignoreSslErrors();
2392
2393 QEventLoop loop;
2394 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
2395 connect(sender: &clientSocket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
2396 loop.exec();
2397
2398 QVERIFY(clientSocket.isEncrypted());
2399 QVERIFY(server.socket->sslHandshakeErrors().isEmpty());
2400}
2401
2402void tst_QSslSocket::verifyDepth()
2403{
2404 QSslSocket socket;
2405 QCOMPARE(socket.peerVerifyDepth(), 0);
2406 socket.setPeerVerifyDepth(1);
2407 QCOMPARE(socket.peerVerifyDepth(), 1);
2408 QTest::ignoreMessage(type: QtWarningMsg, message: "QSslSocket::setPeerVerifyDepth: cannot set negative depth of -1");
2409 socket.setPeerVerifyDepth(-1);
2410 QCOMPARE(socket.peerVerifyDepth(), 1);
2411}
2412
2413#ifndef QT_NO_OPENSSL
2414void tst_QSslSocket::verifyAndDefaultConfiguration()
2415{
2416 QFETCH_GLOBAL(const bool, setProxy);
2417 if (setProxy)
2418 return;
2419 const auto defaultCACertificates = QSslConfiguration::defaultConfiguration().caCertificates();
2420 const auto chainGuard = qScopeGuard(f: [&defaultCACertificates]{
2421 auto conf = QSslConfiguration::defaultConfiguration();
2422 conf.setCaCertificates(defaultCACertificates);
2423 QSslConfiguration::setDefaultConfiguration(conf);
2424 });
2425
2426 auto chain = QSslCertificate::fromPath(path: testDataDir + QStringLiteral("certs/qtiochain.crt"), format: QSsl::Pem);
2427 QCOMPARE(chain.size(), 2);
2428 QVERIFY(!chain.at(0).isNull());
2429 QVERIFY(!chain.at(1).isNull());
2430 auto errors = QSslCertificate::verify(certificateChain: chain);
2431 // At least, test that 'verify' did not alter the default configuration:
2432 QCOMPARE(defaultCACertificates, QSslConfiguration::defaultConfiguration().caCertificates());
2433 if (!errors.isEmpty())
2434 QSKIP("The certificate for qt.io could not be trusted, skipping the rest of the test");
2435#ifdef Q_OS_WINDOWS
2436 const auto fakeCaChain = QSslCertificate::fromPath(testDataDir + QStringLiteral("certs/fluke.cert"));
2437 QCOMPARE(fakeCaChain.size(), 1);
2438 const auto caCert = fakeCaChain.at(0);
2439 QVERIFY(!caCert.isNull());
2440 auto conf = QSslConfiguration::defaultConfiguration();
2441 conf.setCaCertificates({caCert});
2442 QSslConfiguration::setDefaultConfiguration(conf);
2443 errors = QSslCertificate::verify(chain);
2444 QVERIFY(errors.size() > 0);
2445 QCOMPARE(QSslConfiguration::defaultConfiguration().caCertificates(), QList<QSslCertificate>() << caCert);
2446#endif
2447}
2448#endif // QT_NO_OPENSSL
2449
2450void tst_QSslSocket::disconnectFromHostWhenConnecting()
2451{
2452 QSslSocketPtr socket = newSocket();
2453 socket->connectToHostEncrypted(hostName: QtNetworkSettings::imapServerName(), port: 993);
2454 socket->ignoreSslErrors();
2455 socket->write(data: "XXXX LOGOUT\r\n");
2456 QAbstractSocket::SocketState state = socket->state();
2457 // without proxy, the state will be HostLookupState;
2458 // with proxy, the state will be ConnectingState.
2459 QVERIFY(socket->state() == QAbstractSocket::HostLookupState ||
2460 socket->state() == QAbstractSocket::ConnectingState);
2461 socket->disconnectFromHost();
2462 // the state of the socket must be the same before and after calling
2463 // disconnectFromHost()
2464 QCOMPARE(state, socket->state());
2465 QVERIFY(socket->state() == QAbstractSocket::HostLookupState ||
2466 socket->state() == QAbstractSocket::ConnectingState);
2467 if (!socket->waitForDisconnected(msecs: 10000))
2468 QSKIP("Skipping flaky test - See QTBUG-29941");
2469 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2470 // we did not call close, so the socket must be still open
2471 QVERIFY(socket->isOpen());
2472 QCOMPARE(socket->bytesToWrite(), qint64(0));
2473
2474 // don't forget to login
2475 QCOMPARE((int) socket->write("USER ftptest\r\n"), 14);
2476
2477}
2478
2479void tst_QSslSocket::disconnectFromHostWhenConnected()
2480{
2481 QSslSocketPtr socket = newSocket();
2482 socket->connectToHostEncrypted(hostName: QtNetworkSettings::imapServerName(), port: 993);
2483 socket->ignoreSslErrors();
2484 if (!socket->waitForEncrypted(msecs: 5000))
2485 QSKIP("Skipping flaky test - See QTBUG-29941");
2486 socket->write(data: "XXXX LOGOUT\r\n");
2487 QCOMPARE(socket->state(), QAbstractSocket::ConnectedState);
2488 socket->disconnectFromHost();
2489 QCOMPARE(socket->state(), QAbstractSocket::ClosingState);
2490 QVERIFY(socket->waitForDisconnected(5000));
2491 QCOMPARE(socket->bytesToWrite(), qint64(0));
2492}
2493
2494#ifndef QT_NO_OPENSSL
2495
2496class BrokenPskHandshake : public QTcpServer
2497{
2498public:
2499 void socketError(QAbstractSocket::SocketError error)
2500 {
2501 Q_UNUSED(error);
2502 QSslSocket *clientSocket = qobject_cast<QSslSocket *>(object: sender());
2503 Q_ASSERT(clientSocket);
2504 clientSocket->close();
2505 QTestEventLoop::instance().exitLoop();
2506 }
2507private:
2508
2509 void incomingConnection(qintptr handle) override
2510 {
2511 if (!socket.setSocketDescriptor(socketDescriptor: handle))
2512 return;
2513
2514 QSslConfiguration serverConfig(QSslConfiguration::defaultConfiguration());
2515 serverConfig.setPreSharedKeyIdentityHint("abcdefghijklmnop");
2516 socket.setSslConfiguration(serverConfig);
2517 socket.startServerEncryption();
2518 }
2519
2520 QSslSocket socket;
2521};
2522
2523void tst_QSslSocket::closeWhileEmittingSocketError()
2524{
2525 QFETCH_GLOBAL(bool, setProxy);
2526 if (setProxy)
2527 return;
2528
2529 BrokenPskHandshake handshake;
2530 if (!handshake.listen())
2531 QSKIP("failed to start TLS server");
2532
2533 QSslSocket clientSocket;
2534 QSslConfiguration clientConfig(QSslConfiguration::defaultConfiguration());
2535 clientConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
2536 clientSocket.setSslConfiguration(clientConfig);
2537
2538 QSignalSpy socketErrorSpy(&clientSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
2539 connect(sender: &clientSocket, signal: &QSslSocket::errorOccurred, receiver: &handshake, slot: &BrokenPskHandshake::socketError);
2540
2541 clientSocket.connectToHostEncrypted(QStringLiteral("127.0.0.1"), port: handshake.serverPort());
2542 // Make sure we have some data buffered so that close will try to flush:
2543 clientSocket.write(data: QByteArray(1000000, Qt::Uninitialized));
2544
2545 QTestEventLoop::instance().enterLoopMSecs(ms: 1000);
2546 QVERIFY(!QTestEventLoop::instance().timeout());
2547
2548 QCOMPARE(socketErrorSpy.count(), 1);
2549}
2550
2551#endif // QT_NO_OPENSSL
2552
2553void tst_QSslSocket::resetProxy()
2554{
2555#ifndef QT_NO_NETWORKPROXY
2556 QFETCH_GLOBAL(bool, setProxy);
2557 if (setProxy)
2558 return;
2559
2560 // check fix for bug 199941
2561
2562 QNetworkProxy goodProxy(QNetworkProxy::NoProxy);
2563 QNetworkProxy badProxy(QNetworkProxy::HttpProxy, "thisCannotWorkAbsolutelyNotForSure", 333);
2564
2565 // make sure the connection works, and then set a nonsense proxy, and then
2566 // make sure it does not work anymore
2567 QSslSocket socket;
2568 auto config = socket.sslConfiguration();
2569 config.addCaCertificates(path: httpServerCertChainPath());
2570 socket.setSslConfiguration(config);
2571 socket.setProxy(goodProxy);
2572 socket.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2573 QVERIFY2(socket.waitForConnected(10000), qPrintable(socket.errorString()));
2574 socket.abort();
2575 socket.setProxy(badProxy);
2576 socket.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2577 QVERIFY(! socket.waitForConnected(10000));
2578
2579 // don't forget to login
2580 QCOMPARE((int) socket.write("USER ftptest\r\n"), 14);
2581 QCOMPARE((int) socket.write("PASS password\r\n"), 15);
2582
2583 enterLoop(secs: 10);
2584
2585 // now the other way round:
2586 // set the nonsense proxy and make sure the connection does not work,
2587 // and then set the right proxy and make sure it works
2588 QSslSocket socket2;
2589 auto config2 = socket.sslConfiguration();
2590 config2.addCaCertificates(path: httpServerCertChainPath());
2591 socket2.setSslConfiguration(config2);
2592 socket2.setProxy(badProxy);
2593 socket2.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2594 QVERIFY(! socket2.waitForConnected(10000));
2595 socket2.abort();
2596 socket2.setProxy(goodProxy);
2597 socket2.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2598 QVERIFY2(socket2.waitForConnected(10000), qPrintable(socket.errorString()));
2599#endif // QT_NO_NETWORKPROXY
2600}
2601
2602void tst_QSslSocket::ignoreSslErrorsList_data()
2603{
2604 QTest::addColumn<QList<QSslError> >(name: "expectedSslErrors");
2605 QTest::addColumn<int>(name: "expectedSslErrorSignalCount");
2606
2607 // construct the list of errors that we will get with the SSL handshake and that we will ignore
2608 QList<QSslError> expectedSslErrors;
2609 // fromPath gives us a list of certs, but it actually only contains one
2610 QList<QSslCertificate> certs = QSslCertificate::fromPath(path: httpServerCertChainPath());
2611 QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(i: 0));
2612 QSslError wrongError(FLUKE_CERTIFICATE_ERROR);
2613
2614
2615 QTest::newRow(dataTag: "SSL-failure-empty-list") << expectedSslErrors << 1;
2616 expectedSslErrors.append(t: wrongError);
2617 QTest::newRow(dataTag: "SSL-failure-wrong-error") << expectedSslErrors << 1;
2618 expectedSslErrors.append(t: rightError);
2619 QTest::newRow(dataTag: "allErrorsInExpectedList1") << expectedSslErrors << 0;
2620 expectedSslErrors.removeAll(t: wrongError);
2621 QTest::newRow(dataTag: "allErrorsInExpectedList2") << expectedSslErrors << 0;
2622 expectedSslErrors.removeAll(t: rightError);
2623 QTest::newRow(dataTag: "SSL-failure-empty-list-again") << expectedSslErrors << 1;
2624}
2625
2626void tst_QSslSocket::ignoreSslErrorsList()
2627{
2628 QSslSocket socket;
2629 connect(sender: &socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
2630 receiver: this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
2631
2632 QSslCertificate cert;
2633
2634 QFETCH(QList<QSslError>, expectedSslErrors);
2635 socket.ignoreSslErrors(errors: expectedSslErrors);
2636
2637 QFETCH(int, expectedSslErrorSignalCount);
2638 QSignalSpy sslErrorsSpy(&socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
2639
2640 socket.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2641
2642 bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0);
2643 if (socket.waitForEncrypted(msecs: 10000) != expectEncryptionSuccess)
2644 QSKIP("Skipping flaky test - See QTBUG-29941");
2645 QCOMPARE(sslErrorsSpy.count(), expectedSslErrorSignalCount);
2646}
2647
2648void tst_QSslSocket::ignoreSslErrorsListWithSlot_data()
2649{
2650 ignoreSslErrorsList_data();
2651}
2652
2653// this is not a test, just a slot called in the test below
2654void tst_QSslSocket::ignoreErrorListSlot(const QList<QSslError> &)
2655{
2656 socket->ignoreSslErrors(errors: storedExpectedSslErrors);
2657}
2658
2659void tst_QSslSocket::ignoreSslErrorsListWithSlot()
2660{
2661 QSslSocket socket;
2662 this->socket = &socket;
2663
2664 QFETCH(QList<QSslError>, expectedSslErrors);
2665 // store the errors to ignore them later in the slot connected below
2666 storedExpectedSslErrors = expectedSslErrors;
2667 connect(sender: &socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
2668 receiver: this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
2669 connect(sender: &socket, SIGNAL(sslErrors(QList<QSslError>)),
2670 receiver: this, SLOT(ignoreErrorListSlot(QList<QSslError>)));
2671 socket.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2672
2673 QFETCH(int, expectedSslErrorSignalCount);
2674 bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0);
2675 QFETCH_GLOBAL(bool, setProxy);
2676 if (setProxy && (socket.waitForEncrypted(msecs: 10000) != expectEncryptionSuccess))
2677 QSKIP("Skipping flaky test - See QTBUG-29941");
2678}
2679
2680void tst_QSslSocket::abortOnSslErrors()
2681{
2682#ifdef Q_OS_WINRT
2683 QSKIP("Server-side encryption is not implemented on WinRT.");
2684#endif
2685 QFETCH_GLOBAL(bool, setProxy);
2686 if (setProxy)
2687 return;
2688
2689 SslServer server;
2690 QVERIFY(server.listen());
2691
2692 QSslSocket clientSocket;
2693 connect(sender: &clientSocket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(abortOnErrorSlot()));
2694 clientSocket.connectToHostEncrypted(hostName: "127.0.0.1", port: server.serverPort());
2695 clientSocket.ignoreSslErrors();
2696
2697 QEventLoop loop;
2698 QTimer::singleShot(msec: 1000, receiver: &loop, SLOT(quit()));
2699 loop.exec();
2700
2701 QCOMPARE(clientSocket.state(), QAbstractSocket::UnconnectedState);
2702}
2703
2704// make sure a closed socket has no bytesAvailable()
2705// related to https://bugs.webkit.org/show_bug.cgi?id=28016
2706void tst_QSslSocket::readFromClosedSocket()
2707{
2708 QSslSocketPtr socket = newSocket();
2709#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2
2710 socket->setProtocol(QSsl::SslProtocol::TlsV1_1);
2711#endif
2712 socket->ignoreSslErrors();
2713 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2714 socket->ignoreSslErrors();
2715 socket->waitForConnected();
2716 socket->waitForEncrypted();
2717 // provoke a response by sending a request
2718 socket->write(data: "GET /qtest/fluke.gif HTTP/1.1\n");
2719 socket->write(data: "Host: ");
2720 socket->write(data: QtNetworkSettings::httpServerName().toLocal8Bit().constData());
2721 socket->write(data: "\n");
2722 socket->write(data: "\n");
2723 socket->waitForBytesWritten();
2724 socket->waitForReadyRead();
2725 QFETCH_GLOBAL(bool, setProxy);
2726 if (setProxy && (socket->state() != QAbstractSocket::ConnectedState))
2727 QSKIP("Skipping flaky test - See QTBUG-29941");
2728 QVERIFY(socket->bytesAvailable());
2729 socket->close();
2730 QVERIFY(!socket->bytesAvailable());
2731 QVERIFY(!socket->bytesToWrite());
2732 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2733}
2734
2735void tst_QSslSocket::writeBigChunk()
2736{
2737 if (!QSslSocket::supportsSsl())
2738 return;
2739
2740 QSslSocketPtr socket = newSocket();
2741 this->socket = socket.data();
2742
2743 connect(sender: this->socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
2744 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
2745
2746 QByteArray data;
2747 // Originally, the test had this: '1024*1024*10; // 10 MB'
2748 data.resize(size: 1024 * 1024 * 10);
2749 // Init with garbage. Needed so TLS cannot compress it in an efficient way.
2750 QRandomGenerator::global()->fillRange(buffer: reinterpret_cast<quint32 *>(data.data()),
2751 count: data.size() / int(sizeof(quint32)));
2752
2753 if (!socket->waitForEncrypted(msecs: 10000))
2754 QSKIP("Skipping flaky test - See QTBUG-29941");
2755 QString errorBefore = socket->errorString();
2756
2757 int ret = socket->write(data: data.constData(), len: data.size());
2758 QCOMPARE(data.size(), ret);
2759
2760 // spin the event loop once so QSslSocket::transmit() gets called
2761 QCoreApplication::processEvents();
2762 QString errorAfter = socket->errorString();
2763
2764 // no better way to do this right now since the error is the same as the default error.
2765 if (socket->errorString().startsWith(s: QLatin1String("Unable to write data")))
2766 {
2767 qWarning() << socket->error() << socket->errorString();
2768 QFAIL("Error while writing! Check if the OpenSSL BIO size is limited?!");
2769 }
2770 // also check the error string. If another error (than UnknownError) occurred, it should be different than before
2771 QVERIFY2(errorBefore == errorAfter || socket->error() == QAbstractSocket::RemoteHostClosedError,
2772 QByteArray("unexpected error: ").append(qPrintable(errorAfter)));
2773
2774 // check that everything has been written to OpenSSL
2775 QCOMPARE(socket->bytesToWrite(), 0);
2776
2777 socket->close();
2778}
2779
2780void tst_QSslSocket::blacklistedCertificates()
2781{
2782#ifdef Q_OS_WINRT
2783 QSKIP("Server-side encryption is not implemented on WinRT.");
2784#endif
2785 QFETCH_GLOBAL(bool, setProxy);
2786 if (setProxy)
2787 return;
2788
2789 SslServer server(testDataDir + "certs/fake-login.live.com.key", testDataDir + "certs/fake-login.live.com.pem");
2790 QSslSocket *receiver = new QSslSocket(this);
2791 connect(asender: receiver, SIGNAL(readyRead()), SLOT(exitLoop()));
2792
2793 // connect two sockets to each other:
2794 QVERIFY(server.listen(QHostAddress::LocalHost));
2795 receiver->connectToHost(hostName: "127.0.0.1", port: server.serverPort());
2796 QVERIFY(receiver->waitForConnected(5000));
2797 if (!server.waitForNewConnection(msec: 0))
2798 QSKIP("Skipping flaky test - See QTBUG-29941");
2799
2800 QSslSocket *sender = server.socket;
2801 QVERIFY(sender);
2802 QCOMPARE(sender->state(), QAbstractSocket::ConnectedState);
2803 receiver->setObjectName("receiver");
2804 sender->setObjectName("sender");
2805 receiver->startClientEncryption();
2806
2807 connect(asender: receiver, SIGNAL(sslErrors(QList<QSslError>)), SLOT(exitLoop()));
2808 connect(asender: receiver, SIGNAL(encrypted()), SLOT(exitLoop()));
2809 enterLoop(secs: 1);
2810 QList<QSslError> sslErrors = receiver->sslHandshakeErrors();
2811 QVERIFY(sslErrors.count() > 0);
2812 // there are more errors (self signed cert and hostname mismatch), but we only care about the blacklist error
2813 QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted);
2814}
2815
2816void tst_QSslSocket::versionAccessors()
2817{
2818 if (!QSslSocket::supportsSsl())
2819 return;
2820
2821 qDebug() << QSslSocket::sslLibraryVersionString();
2822 qDebug() << QString::number(QSslSocket::sslLibraryVersionNumber(), base: 16);
2823}
2824
2825#ifndef QT_NO_OPENSSL
2826void tst_QSslSocket::sslOptions()
2827{
2828 if (!QSslSocket::supportsSsl())
2829 return;
2830
2831#ifdef SSL_OP_NO_COMPRESSION
2832 QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
2833 QSslConfigurationPrivate::defaultSslOptions),
2834 long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE));
2835#else
2836 QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
2837 QSslConfigurationPrivate::defaultSslOptions),
2838 long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
2839#endif
2840
2841 QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
2842 QSsl::SslOptionDisableEmptyFragments
2843 |QSsl::SslOptionDisableLegacyRenegotiation),
2844 long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
2845
2846#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
2847 QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
2848 QSsl::SslOptionDisableEmptyFragments),
2849 long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
2850#endif
2851
2852#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
2853 QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
2854 QSsl::SslOptionDisableLegacyRenegotiation),
2855 long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS));
2856#endif
2857
2858#ifdef SSL_OP_NO_TICKET
2859 QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
2860 QSsl::SslOptionDisableEmptyFragments
2861 |QSsl::SslOptionDisableLegacyRenegotiation
2862 |QSsl::SslOptionDisableSessionTickets),
2863 long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_CIPHER_SERVER_PREFERENCE)));
2864#endif
2865
2866#ifdef SSL_OP_NO_TICKET
2867#ifdef SSL_OP_NO_COMPRESSION
2868 QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
2869 QSsl::SslOptionDisableEmptyFragments
2870 |QSsl::SslOptionDisableLegacyRenegotiation
2871 |QSsl::SslOptionDisableSessionTickets
2872 |QSsl::SslOptionDisableCompression),
2873 long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
2874#endif
2875#endif
2876}
2877#endif
2878
2879void tst_QSslSocket::encryptWithoutConnecting()
2880{
2881 if (!QSslSocket::supportsSsl())
2882 return;
2883
2884 QTest::ignoreMessage(type: QtWarningMsg,
2885 message: "QSslSocket::startClientEncryption: cannot start handshake when not connected");
2886
2887 QSslSocket sock;
2888 sock.startClientEncryption();
2889}
2890
2891void tst_QSslSocket::resume_data()
2892{
2893 QTest::addColumn<bool>(name: "ignoreErrorsAfterPause");
2894 QTest::addColumn<QList<QSslError> >(name: "errorsToIgnore");
2895 QTest::addColumn<bool>(name: "expectSuccess");
2896
2897 QList<QSslError> errorsList;
2898 QTest::newRow(dataTag: "DoNotIgnoreErrors") << false << QList<QSslError>() << false;
2899 QTest::newRow(dataTag: "ignoreAllErrors") << true << QList<QSslError>() << true;
2900
2901 // Note, httpServerCertChainPath() it's ... because we use the same certificate on
2902 // different services. We'll be actually connecting to IMAP server.
2903 QList<QSslCertificate> certs = QSslCertificate::fromPath(path: httpServerCertChainPath());
2904 QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(i: 0));
2905 QSslError wrongError(FLUKE_CERTIFICATE_ERROR);
2906 errorsList.append(t: wrongError);
2907 QTest::newRow(dataTag: "ignoreSpecificErrors-Wrong") << true << errorsList << false;
2908 errorsList.clear();
2909 errorsList.append(t: rightError);
2910 QTest::newRow(dataTag: "ignoreSpecificErrors-Right") << true << errorsList << true;
2911}
2912
2913void tst_QSslSocket::resume()
2914{
2915 // make sure the server certificate is not in the list of accepted certificates,
2916 // we want to trigger the sslErrors signal
2917 auto sslConfig = QSslConfiguration::defaultConfiguration();
2918 sslConfig.setCaCertificates(QSslConfiguration::systemCaCertificates());
2919 QSslConfiguration::setDefaultConfiguration(sslConfig);
2920
2921 QFETCH(bool, ignoreErrorsAfterPause);
2922 QFETCH(QList<QSslError>, errorsToIgnore);
2923 QFETCH(bool, expectSuccess);
2924
2925 QSslSocket socket;
2926 socket.setPauseMode(QAbstractSocket::PauseOnSslErrors);
2927
2928 QSignalSpy sslErrorSpy(&socket, SIGNAL(sslErrors(QList<QSslError>)));
2929 QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted()));
2930 QSignalSpy errorSpy(&socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
2931
2932 connect(sender: &socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
2933 connect(sender: &socket, SIGNAL(encrypted()), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
2934 connect(sender: &socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
2935 receiver: this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
2936 connect(sender: &socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
2937
2938 socket.connectToHostEncrypted(hostName: QtNetworkSettings::imapServerName(), port: 993);
2939 QTestEventLoop::instance().enterLoop(secs: 10);
2940 QFETCH_GLOBAL(bool, setProxy);
2941 if (setProxy && QTestEventLoop::instance().timeout())
2942 QSKIP("Skipping flaky test - See QTBUG-29941");
2943 QCOMPARE(sslErrorSpy.count(), 1);
2944 QCOMPARE(errorSpy.count(), 0);
2945 QCOMPARE(encryptedSpy.count(), 0);
2946 QVERIFY(!socket.isEncrypted());
2947 if (ignoreErrorsAfterPause) {
2948 if (errorsToIgnore.empty())
2949 socket.ignoreSslErrors();
2950 else
2951 socket.ignoreSslErrors(errors: errorsToIgnore);
2952 }
2953 socket.resume();
2954 QTestEventLoop::instance().enterLoop(secs: 10);
2955 QVERIFY(!QTestEventLoop::instance().timeout()); // quit by encrypted() or error() signal
2956 if (expectSuccess) {
2957 QCOMPARE(encryptedSpy.count(), 1);
2958 QVERIFY(socket.isEncrypted());
2959 QCOMPARE(errorSpy.count(), 0);
2960 socket.disconnectFromHost();
2961 QVERIFY(socket.waitForDisconnected(10000));
2962 } else {
2963 QCOMPARE(encryptedSpy.count(), 0);
2964 QVERIFY(!socket.isEncrypted());
2965 QCOMPARE(errorSpy.count(), 1);
2966 QCOMPARE(socket.error(), QAbstractSocket::SslHandshakeFailedError);
2967 }
2968}
2969
2970class WebSocket : public QSslSocket
2971{
2972 Q_OBJECT
2973public:
2974 explicit WebSocket(qintptr socketDescriptor,
2975 const QString &keyFile = tst_QSslSocket::testDataDir + "certs/fluke.key",
2976 const QString &certFile = tst_QSslSocket::testDataDir + "certs/fluke.cert");
2977
2978protected slots:
2979 void onReadyReadFirstBytes(void);
2980
2981private:
2982 void _startServerEncryption(void);
2983
2984 QString m_keyFile;
2985 QString m_certFile;
2986
2987private:
2988 Q_DISABLE_COPY(WebSocket)
2989};
2990
2991WebSocket::WebSocket (qintptr socketDescriptor, const QString &keyFile, const QString &certFile)
2992 : m_keyFile(keyFile),
2993 m_certFile(certFile)
2994{
2995 QVERIFY(setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState, QIODevice::ReadWrite | QIODevice::Unbuffered));
2996 connect (sender: this, SIGNAL(readyRead()), receiver: this, SLOT(onReadyReadFirstBytes()));
2997}
2998
2999void WebSocket::_startServerEncryption (void)
3000{
3001 QFile file(m_keyFile);
3002 QVERIFY(file.open(QIODevice::ReadOnly));
3003 QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
3004 QVERIFY(!key.isNull());
3005 setPrivateKey(key);
3006
3007 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: m_certFile);
3008 QVERIFY(!localCert.isEmpty());
3009 QVERIFY(!localCert.first().isNull());
3010 setLocalCertificate(localCert.first());
3011
3012 QVERIFY(!peerAddress().isNull());
3013 QVERIFY(peerPort() != 0);
3014 QVERIFY(!localAddress().isNull());
3015 QVERIFY(localPort() != 0);
3016
3017 setProtocol(QSsl::AnyProtocol);
3018 setPeerVerifyMode(QSslSocket::VerifyNone);
3019 ignoreSslErrors();
3020 startServerEncryption();
3021}
3022
3023void WebSocket::onReadyReadFirstBytes (void)
3024{
3025 peek(maxlen: 1);
3026 disconnect(sender: this,SIGNAL(readyRead()), receiver: this, SLOT(onReadyReadFirstBytes()));
3027 _startServerEncryption();
3028}
3029
3030class SslServer4 : public QTcpServer
3031{
3032 Q_OBJECT
3033public:
3034
3035 QScopedPointer<WebSocket> socket;
3036
3037protected:
3038 void incomingConnection(qintptr socketDescriptor) override
3039 {
3040 socket.reset(other: new WebSocket(socketDescriptor));
3041 }
3042};
3043
3044void tst_QSslSocket::qtbug18498_peek()
3045{
3046#ifdef Q_OS_WINRT
3047 QSKIP("Server-side encryption is not implemented on WinRT.");
3048#endif
3049 QFETCH_GLOBAL(bool, setProxy);
3050 if (setProxy)
3051 return;
3052
3053 SslServer4 server;
3054 QVERIFY(server.listen(QHostAddress::LocalHost));
3055
3056 QSslSocket client;
3057 client.connectToHost(hostName: "127.0.0.1", port: server.serverPort());
3058 QVERIFY(client.waitForConnected(5000));
3059 QVERIFY(server.waitForNewConnection(1000));
3060 client.ignoreSslErrors();
3061
3062 int encryptedCounter = 2;
3063 connect(sender: &client, signal: &QSslSocket::encrypted, context: this, slot: [&encryptedCounter](){
3064 if (!--encryptedCounter)
3065 exitLoop();
3066 });
3067 WebSocket *serversocket = server.socket.data();
3068 connect(sender: serversocket, signal: &QSslSocket::encrypted, context: this, slot: [&encryptedCounter](){
3069 if (!--encryptedCounter)
3070 exitLoop();
3071 });
3072 connect(sender: &client, SIGNAL(disconnected()), receiver: this, SLOT(exitLoop()));
3073
3074 client.startClientEncryption();
3075 QVERIFY(serversocket);
3076
3077 enterLoop(secs: 1);
3078 QVERIFY(!timeout());
3079 QVERIFY(serversocket->isEncrypted());
3080 QVERIFY(client.isEncrypted());
3081
3082 QByteArray data("abc123");
3083 client.write(data: data.data());
3084
3085 connect(sender: serversocket, SIGNAL(readyRead()), receiver: this, SLOT(exitLoop()));
3086 enterLoop(secs: 1);
3087 QVERIFY(!timeout());
3088
3089 QByteArray peek1_data;
3090 peek1_data.reserve(asize: data.size());
3091 QByteArray peek2_data;
3092 QByteArray read_data;
3093
3094 int lngth = serversocket->peek(data: peek1_data.data(), maxlen: 10);
3095 peek1_data.resize(size: lngth);
3096
3097 peek2_data = serversocket->peek(maxlen: 10);
3098 read_data = serversocket->readAll();
3099
3100 QCOMPARE(peek1_data, data);
3101 QCOMPARE(peek2_data, data);
3102 QCOMPARE(read_data, data);
3103}
3104
3105class SslServer5 : public QTcpServer
3106{
3107 Q_OBJECT
3108public:
3109 SslServer5() : socket(0) {}
3110 QSslSocket *socket;
3111
3112protected:
3113 void incomingConnection(qintptr socketDescriptor)
3114 {
3115 socket = new QSslSocket;
3116 socket->setSocketDescriptor(socketDescriptor);
3117 }
3118};
3119
3120void tst_QSslSocket::qtbug18498_peek2()
3121{
3122#ifdef Q_OS_WINRT
3123 QSKIP("Server-side encryption is not implemented on WinRT.");
3124#endif
3125 QFETCH_GLOBAL(bool, setProxy);
3126 if (setProxy)
3127 return;
3128
3129 SslServer5 listener;
3130 QVERIFY(listener.listen(QHostAddress::Any));
3131 QScopedPointer<QSslSocket> client(new QSslSocket);
3132 client->connectToHost(address: QHostAddress::LocalHost, port: listener.serverPort());
3133 QVERIFY(client->waitForConnected(5000));
3134 QVERIFY(listener.waitForNewConnection(1000));
3135
3136 QScopedPointer<QSslSocket> server(listener.socket);
3137
3138 QVERIFY(server->write("HELLO\r\n", 7));
3139 QTRY_COMPARE(client->bytesAvailable(), 7);
3140 char c;
3141 QCOMPARE(client->peek(&c,1), 1);
3142 QCOMPARE(c, 'H');
3143 QCOMPARE(client->read(&c,1), 1);
3144 QCOMPARE(c, 'H');
3145 QByteArray b = client->peek(maxlen: 2);
3146 QCOMPARE(b, QByteArray("EL"));
3147 char a[3];
3148 QVERIFY(client->peek(a, 2) == 2);
3149 QCOMPARE(a[0], 'E');
3150 QCOMPARE(a[1], 'L');
3151 QCOMPARE(client->readAll(), QByteArray("ELLO\r\n"));
3152
3153 //check data split between QIODevice and plain socket buffers.
3154 QByteArray bigblock;
3155 bigblock.fill(c: '#', QIODEVICE_BUFFERSIZE + 1024);
3156 QVERIFY(client->write(QByteArray("head")));
3157 QVERIFY(client->write(bigblock));
3158 QTRY_COMPARE(server->bytesAvailable(), bigblock.length() + 4);
3159 QCOMPARE(server->read(4), QByteArray("head"));
3160 QCOMPARE(server->peek(bigblock.length()), bigblock);
3161 b.reserve(asize: bigblock.length());
3162 b.resize(size: server->peek(data: b.data(), maxlen: bigblock.length()));
3163 QCOMPARE(b, bigblock);
3164
3165 //check oversized peek
3166 QCOMPARE(server->peek(bigblock.length() * 3), bigblock);
3167 b.reserve(asize: bigblock.length() * 3);
3168 b.resize(size: server->peek(data: b.data(), maxlen: bigblock.length() * 3));
3169 QCOMPARE(b, bigblock);
3170
3171 QCOMPARE(server->readAll(), bigblock);
3172
3173 QVERIFY(client->write("STARTTLS\r\n"));
3174 QTRY_COMPARE(server->bytesAvailable(), 10);
3175 QCOMPARE(server->peek(&c,1), 1);
3176 QCOMPARE(c, 'S');
3177 b = server->peek(maxlen: 3);
3178 QCOMPARE(b, QByteArray("STA"));
3179 QCOMPARE(server->read(5), QByteArray("START"));
3180 QVERIFY(server->peek(a, 3) == 3);
3181 QCOMPARE(a[0], 'T');
3182 QCOMPARE(a[1], 'L');
3183 QCOMPARE(a[2], 'S');
3184 QCOMPARE(server->readAll(), QByteArray("TLS\r\n"));
3185
3186 QFile file(testDataDir + "certs/fluke.key");
3187 QVERIFY(file.open(QIODevice::ReadOnly));
3188 QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
3189 QVERIFY(!key.isNull());
3190 server->setPrivateKey(key);
3191
3192 QList<QSslCertificate> localCert = QSslCertificate::fromPath(path: testDataDir + "certs/fluke.cert");
3193 QVERIFY(!localCert.isEmpty());
3194 QVERIFY(!localCert.first().isNull());
3195 server->setLocalCertificate(localCert.first());
3196
3197 server->setProtocol(QSsl::AnyProtocol);
3198 server->setPeerVerifyMode(QSslSocket::VerifyNone);
3199
3200 server->ignoreSslErrors();
3201 client->ignoreSslErrors();
3202
3203 server->startServerEncryption();
3204 client->startClientEncryption();
3205
3206 QVERIFY(server->write("hello\r\n", 7));
3207 QTRY_COMPARE(client->bytesAvailable(), 7);
3208 QVERIFY(server->mode() == QSslSocket::SslServerMode && client->mode() == QSslSocket::SslClientMode);
3209 QCOMPARE(client->peek(&c,1), 1);
3210 QCOMPARE(c, 'h');
3211 QCOMPARE(client->read(&c,1), 1);
3212 QCOMPARE(c, 'h');
3213 b = client->peek(maxlen: 2);
3214 QCOMPARE(b, QByteArray("el"));
3215 QCOMPARE(client->readAll(), QByteArray("ello\r\n"));
3216
3217 QVERIFY(client->write("goodbye\r\n"));
3218 QTRY_COMPARE(server->bytesAvailable(), 9);
3219 QCOMPARE(server->peek(&c,1), 1);
3220 QCOMPARE(c, 'g');
3221 QCOMPARE(server->readAll(), QByteArray("goodbye\r\n"));
3222 client->disconnectFromHost();
3223 QVERIFY(client->waitForDisconnected(5000));
3224}
3225
3226void tst_QSslSocket::dhServer()
3227{
3228#ifdef Q_OS_WINRT
3229 QSKIP("Server-side encryption is not implemented on WinRT.");
3230#endif
3231 if (!QSslSocket::supportsSsl())
3232 QSKIP("No SSL support");
3233
3234 QFETCH_GLOBAL(bool, setProxy);
3235 if (setProxy)
3236 return;
3237
3238 SslServer server;
3239 server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")};
3240 QVERIFY(server.listen());
3241
3242 QEventLoop loop;
3243 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
3244
3245 QSslSocket client;
3246 socket = &client;
3247 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
3248 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
3249 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
3250
3251 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
3252
3253 loop.exec();
3254 QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
3255}
3256
3257#ifndef QT_NO_OPENSSL
3258void tst_QSslSocket::dhServerCustomParamsNull()
3259{
3260 if (!QSslSocket::supportsSsl())
3261 QSKIP("No SSL support");
3262
3263 QFETCH_GLOBAL(bool, setProxy);
3264 if (setProxy)
3265 return;
3266
3267 SslServer server;
3268 server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")};
3269
3270 QSslConfiguration cfg = server.config;
3271 cfg.setDiffieHellmanParameters(QSslDiffieHellmanParameters());
3272 server.config = cfg;
3273
3274 QVERIFY(server.listen());
3275
3276 QEventLoop loop;
3277 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
3278
3279 QSslSocket client;
3280 socket = &client;
3281 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
3282 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
3283 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
3284
3285 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
3286
3287 loop.exec();
3288
3289 QVERIFY(client.state() != QAbstractSocket::ConnectedState);
3290}
3291#endif // QT_NO_OPENSSL
3292
3293#ifndef QT_NO_OPENSSL
3294void tst_QSslSocket::dhServerCustomParams()
3295{
3296 if (!QSslSocket::supportsSsl())
3297 QSKIP("No SSL support");
3298
3299 QFETCH_GLOBAL(bool, setProxy);
3300 if (setProxy)
3301 return;
3302
3303 SslServer server;
3304 server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")};
3305
3306 QSslConfiguration cfg = server.config;
3307
3308 // Custom 2048-bit DH parameters generated with 'openssl dhparam -outform DER -out out.der -check -2 2048'
3309 const auto dh = QSslDiffieHellmanParameters::fromEncoded(encoded: QByteArray::fromBase64(QByteArrayLiteral(
3310 "MIIBCAKCAQEAvVA7b8keTfjFutCtTJmP/pnQfw/prKa+GMed/pBWjrC4N1YwnI8h/A861d9WE/VWY7XMTjvjX3/0"
3311 "aaU8wEe0EXNpFdlTH+ZMQctQTSJOyQH0RCTwJfDGPCPT9L+c9GKwEKWORH38Earip986HJc0w3UbnfIwXUdsWHiXi"
3312 "Z6r3cpyBmTKlsXTFiDVAOUXSiO8d/zOb6zHZbDfyB/VbtZRmnA7TXVn9oMzC0g9+FXHdrV4K+XfdvNZdCegvoAZiy"
3313 "R6ZQgNG9aZ36/AQekhg060hp55f9HDPgXqYeNeXBiferjUtU7S9b3s83XhOJAr01/0Tf5dENwCfg2gK36TM8cC4wI"
3314 "BAg==")), format: QSsl::Der);
3315 cfg.setDiffieHellmanParameters(dh);
3316
3317 server.config = cfg;
3318
3319 QVERIFY(server.listen());
3320
3321 QEventLoop loop;
3322 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
3323
3324 QSslSocket client;
3325 socket = &client;
3326 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
3327 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
3328 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
3329
3330 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
3331
3332 loop.exec();
3333
3334 QVERIFY(client.state() == QAbstractSocket::ConnectedState);
3335}
3336#endif // QT_NO_OPENSSL
3337
3338void tst_QSslSocket::ecdhServer()
3339{
3340#ifdef Q_OS_WINRT
3341 QSKIP("Server-side encryption is not implemented on WinRT.");
3342#endif
3343 if (!QSslSocket::supportsSsl()) {
3344 qWarning(msg: "SSL not supported, skipping test");
3345 return;
3346 }
3347
3348 QFETCH_GLOBAL(bool, setProxy);
3349 if (setProxy)
3350 return;
3351
3352 SslServer server;
3353 server.ciphers = {QSslCipher("ECDHE-RSA-AES128-SHA")};
3354 QVERIFY(server.listen());
3355
3356 QEventLoop loop;
3357 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
3358
3359 QSslSocket client;
3360 socket = &client;
3361 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &loop, SLOT(quit()));
3362 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
3363 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
3364
3365 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
3366
3367 loop.exec();
3368 QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
3369}
3370
3371void tst_QSslSocket::verifyClientCertificate_data()
3372{
3373 QTest::addColumn<QSslSocket::PeerVerifyMode>(name: "peerVerifyMode");
3374 QTest::addColumn<QList<QSslCertificate> >(name: "clientCerts");
3375 QTest::addColumn<QSslKey>(name: "clientKey");
3376 QTest::addColumn<bool>(name: "works");
3377
3378 // no certificate
3379 QList<QSslCertificate> noCerts;
3380 QSslKey noKey;
3381
3382 QTest::newRow(dataTag: "NoCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << noCerts << noKey << true;
3383 QTest::newRow(dataTag: "NoCert:QueryPeer") << QSslSocket::QueryPeer << noCerts << noKey << true;
3384 QTest::newRow(dataTag: "NoCert:VerifyNone") << QSslSocket::VerifyNone << noCerts << noKey << true;
3385 QTest::newRow(dataTag: "NoCert:VerifyPeer") << QSslSocket::VerifyPeer << noCerts << noKey << false;
3386
3387 // self-signed certificate
3388 QList<QSslCertificate> flukeCerts = QSslCertificate::fromPath(path: testDataDir + "certs/fluke.cert");
3389 QCOMPARE(flukeCerts.size(), 1);
3390
3391 QFile flukeFile(testDataDir + "certs/fluke.key");
3392 QVERIFY(flukeFile.open(QIODevice::ReadOnly));
3393 QSslKey flukeKey(flukeFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
3394 QVERIFY(!flukeKey.isNull());
3395
3396 QTest::newRow(dataTag: "SelfSignedCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << flukeCerts << flukeKey << true;
3397 QTest::newRow(dataTag: "SelfSignedCert:QueryPeer") << QSslSocket::QueryPeer << flukeCerts << flukeKey << true;
3398 QTest::newRow(dataTag: "SelfSignedCert:VerifyNone") << QSslSocket::VerifyNone << flukeCerts << flukeKey << true;
3399 QTest::newRow(dataTag: "SelfSignedCert:VerifyPeer") << QSslSocket::VerifyPeer << flukeCerts << flukeKey << false;
3400
3401 // valid certificate, but wrong usage (server certificate)
3402 QList<QSslCertificate> serverCerts = QSslCertificate::fromPath(path: testDataDir + "certs/bogus-server.crt");
3403 QCOMPARE(serverCerts.size(), 1);
3404
3405 QFile serverFile(testDataDir + "certs/bogus-server.key");
3406 QVERIFY(serverFile.open(QIODevice::ReadOnly));
3407 QSslKey serverKey(serverFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
3408 QVERIFY(!serverKey.isNull());
3409
3410 QTest::newRow(dataTag: "ValidServerCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << serverCerts << serverKey << true;
3411 QTest::newRow(dataTag: "ValidServerCert:QueryPeer") << QSslSocket::QueryPeer << serverCerts << serverKey << true;
3412 QTest::newRow(dataTag: "ValidServerCert:VerifyNone") << QSslSocket::VerifyNone << serverCerts << serverKey << true;
3413 QTest::newRow(dataTag: "ValidServerCert:VerifyPeer") << QSslSocket::VerifyPeer << serverCerts << serverKey << false;
3414
3415 // valid certificate, correct usage (client certificate)
3416 QList<QSslCertificate> validCerts = QSslCertificate::fromPath(path: testDataDir + "certs/bogus-client.crt");
3417 QCOMPARE(validCerts.size(), 1);
3418
3419 QFile validFile(testDataDir + "certs/bogus-client.key");
3420 QVERIFY(validFile.open(QIODevice::ReadOnly));
3421 QSslKey validKey(validFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
3422 QVERIFY(!validKey.isNull());
3423
3424 QTest::newRow(dataTag: "ValidClientCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << validCerts << validKey << true;
3425 QTest::newRow(dataTag: "ValidClientCert:QueryPeer") << QSslSocket::QueryPeer << validCerts << validKey << true;
3426 QTest::newRow(dataTag: "ValidClientCert:VerifyNone") << QSslSocket::VerifyNone << validCerts << validKey << true;
3427 QTest::newRow(dataTag: "ValidClientCert:VerifyPeer") << QSslSocket::VerifyPeer << validCerts << validKey << true;
3428
3429 // valid certificate, correct usage (client certificate), with chain
3430 validCerts += QSslCertificate::fromPath(path: testDataDir + "certs/bogus-ca.crt");
3431 QCOMPARE(validCerts.size(), 2);
3432
3433 QTest::newRow(dataTag: "ValidChainedClientCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << validCerts << validKey << true;
3434 QTest::newRow(dataTag: "ValidChainedClientCert:QueryPeer") << QSslSocket::QueryPeer << validCerts << validKey << true;
3435 QTest::newRow(dataTag: "ValidChainedClientCert:VerifyNone") << QSslSocket::VerifyNone << validCerts << validKey << true;
3436 QTest::newRow(dataTag: "ValidChainedClientCert:VerifyPeer") << QSslSocket::VerifyPeer << validCerts << validKey << true;
3437}
3438
3439void tst_QSslSocket::verifyClientCertificate()
3440{
3441#if QT_CONFIG(securetransport)
3442 // We run both client and server on the same machine,
3443 // this means, client can update keychain with client's certificates,
3444 // and server later will use the same certificates from the same
3445 // keychain thus making tests fail (wrong number of certificates,
3446 // success instead of failure etc.).
3447 QSKIP("This test can not work with Secure Transport");
3448#endif // QT_CONFIG(securetransport)
3449#ifdef Q_OS_WINRT
3450 QSKIP("Server-side encryption is not implemented on WinRT.");
3451#endif
3452 if (!QSslSocket::supportsSsl()) {
3453 qWarning(msg: "SSL not supported, skipping test");
3454 return;
3455 }
3456
3457 QFETCH_GLOBAL(bool, setProxy);
3458 if (setProxy)
3459 return;
3460
3461 QFETCH(QSslSocket::PeerVerifyMode, peerVerifyMode);
3462#if QT_CONFIG(schannel)
3463 if (peerVerifyMode == QSslSocket::QueryPeer || peerVerifyMode == QSslSocket::AutoVerifyPeer)
3464 QSKIP("Schannel doesn't tackle requesting a certificate and not receiving one.");
3465#endif
3466
3467 SslServer server;
3468 server.addCaCertificates = testDataDir + "certs/bogus-ca.crt";
3469 server.ignoreSslErrors = false;
3470 server.peerVerifyMode = peerVerifyMode;
3471 QVERIFY(server.listen());
3472
3473 QEventLoop loop;
3474 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
3475
3476 QFETCH(QList<QSslCertificate>, clientCerts);
3477 QFETCH(QSslKey, clientKey);
3478 QSslSocket client;
3479 client.setLocalCertificateChain(clientCerts);
3480 client.setPrivateKey(clientKey);
3481 socket = &client;
3482
3483 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
3484 connect(sender: socket, SIGNAL(disconnected()), receiver: &loop, SLOT(quit()));
3485 connect(sender: socket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
3486
3487 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
3488
3489 loop.exec();
3490
3491 QFETCH(bool, works);
3492 QAbstractSocket::SocketState expectedState = (works) ? QAbstractSocket::ConnectedState : QAbstractSocket::UnconnectedState;
3493
3494 // check server socket
3495 QVERIFY(server.socket);
3496
3497 QCOMPARE(server.socket->state(), expectedState);
3498 QCOMPARE(server.socket->isEncrypted(), works);
3499
3500 if (peerVerifyMode == QSslSocket::VerifyNone || clientCerts.isEmpty()) {
3501 QVERIFY(server.socket->peerCertificate().isNull());
3502 QVERIFY(server.socket->peerCertificateChain().isEmpty());
3503 } else {
3504 QCOMPARE(server.socket->peerCertificate(), clientCerts.first());
3505#if QT_CONFIG(schannel)
3506 if (clientCerts.count() == 1 && server.socket->peerCertificateChain().count() == 2) {
3507 QEXPECT_FAIL("",
3508 "Schannel includes the entire chain, not just the leaf and intermediates",
3509 Continue);
3510 }
3511#endif
3512 QCOMPARE(server.socket->peerCertificateChain(), clientCerts);
3513 }
3514
3515 // check client socket
3516 QCOMPARE(client.state(), expectedState);
3517 QCOMPARE(client.isEncrypted(), works);
3518}
3519
3520void tst_QSslSocket::readBufferMaxSize()
3521{
3522#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
3523 // QTBUG-55170:
3524 // SecureTransport back-end was ignoring read-buffer
3525 // size limit, resulting (potentially) in a constantly
3526 // growing internal buffer.
3527 // The test's logic is: we set a small read buffer size on a client
3528 // socket (to some ridiculously small value), server sends us
3529 // a bunch of bytes , we ignore readReady signal so
3530 // that socket's internal buffer size stays
3531 // >= readBufferMaxSize, we wait for a quite long time
3532 // (which previously would be enough to read completely)
3533 // and we check socket's bytesAvaiable to be less than sent.
3534 QFETCH_GLOBAL(bool, setProxy);
3535 if (setProxy)
3536 return;
3537
3538 SslServer server;
3539 QVERIFY(server.listen());
3540
3541 QEventLoop loop;
3542
3543 QSslSocketPtr client(new QSslSocket);
3544 socket = client.data();
3545 connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
3546 connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
3547 connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
3548
3549 client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
3550 server.serverPort());
3551
3552 // Wait for 'encrypted' first:
3553 QTimer::singleShot(5000, &loop, SLOT(quit()));
3554 loop.exec();
3555
3556 QCOMPARE(client->state(), QAbstractSocket::ConnectedState);
3557 QCOMPARE(client->mode(), QSslSocket::SslClientMode);
3558
3559 client->setReadBufferSize(10);
3560 const QByteArray message(int(0xffff), 'a');
3561 server.socket->write(message);
3562
3563 QTimer::singleShot(5000, &loop, SLOT(quit()));
3564 loop.exec();
3565
3566 int readSoFar = client->bytesAvailable();
3567 QVERIFY(readSoFar > 0 && readSoFar < message.size());
3568 // Now, let's check that we still can read the rest of it:
3569 QCOMPARE(client->readAll().size(), readSoFar);
3570
3571 client->setReadBufferSize(0);
3572
3573 QTimer::singleShot(1500, &loop, SLOT(quit()));
3574 loop.exec();
3575
3576 QCOMPARE(client->bytesAvailable() + readSoFar, message.size());
3577#else
3578 // Not needed, QSslSocket works correctly with other back-ends.
3579#endif // QT_CONFIG(securetransport) || QT_CONFIG(schannel)
3580}
3581
3582void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, as it has some side effects
3583{
3584 // used to produce a crash in QSslConfigurationPrivate::deepCopyDefaultConfiguration, QTBUG-13265
3585
3586 if (!QSslSocket::supportsSsl())
3587 return;
3588
3589 QSslConfiguration emptyConf;
3590 QSslConfiguration::setDefaultConfiguration(emptyConf);
3591
3592 QSslSocketPtr client = newSocket();
3593 socket = client.data();
3594
3595 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
3596 socket->connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
3597 QFETCH_GLOBAL(bool, setProxy);
3598 if (setProxy && socket->waitForEncrypted(msecs: 4000))
3599 QSKIP("Skipping flaky test - See QTBUG-29941");
3600}
3601
3602void tst_QSslSocket::allowedProtocolNegotiation()
3603{
3604#ifndef ALPN_SUPPORTED
3605 QSKIP("ALPN is unsupported, skipping test");
3606#endif
3607
3608#if QT_CONFIG(schannel)
3609 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
3610 QSKIP("ALPN is not supported on this version of Windows using Schannel.");
3611#endif
3612
3613 QFETCH_GLOBAL(bool, setProxy);
3614 if (setProxy)
3615 return;
3616
3617
3618 const QByteArray expectedNegotiated("cool-protocol");
3619 QList<QByteArray> serverProtos;
3620 serverProtos << expectedNegotiated << "not-so-cool-protocol";
3621 QList<QByteArray> clientProtos;
3622 clientProtos << "uber-cool-protocol" << expectedNegotiated << "not-so-cool-protocol";
3623
3624
3625 SslServer server;
3626 server.config.setAllowedNextProtocols(serverProtos);
3627 QVERIFY(server.listen());
3628
3629 QSslSocket clientSocket;
3630 auto configuration = clientSocket.sslConfiguration();
3631 configuration.setAllowedNextProtocols(clientProtos);
3632 clientSocket.setSslConfiguration(configuration);
3633
3634 clientSocket.connectToHostEncrypted(hostName: "127.0.0.1", port: server.serverPort());
3635 clientSocket.ignoreSslErrors();
3636
3637 QEventLoop loop;
3638 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
3639 connect(sender: &clientSocket, SIGNAL(encrypted()), receiver: &loop, SLOT(quit()));
3640 loop.exec();
3641
3642 QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() ==
3643 clientSocket.sslConfiguration().nextNegotiatedProtocol());
3644 QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() == expectedNegotiated);
3645}
3646
3647#ifndef QT_NO_OPENSSL
3648class PskProvider : public QObject
3649{
3650 Q_OBJECT
3651
3652public:
3653 bool m_server;
3654 QByteArray m_identity;
3655 QByteArray m_psk;
3656
3657 explicit PskProvider(QObject *parent = 0)
3658 : QObject(parent), m_server(false)
3659 {
3660 }
3661
3662 void setIdentity(const QByteArray &identity)
3663 {
3664 m_identity = identity;
3665 }
3666
3667 void setPreSharedKey(const QByteArray &psk)
3668 {
3669 m_psk = psk;
3670 }
3671
3672public slots:
3673 void providePsk(QSslPreSharedKeyAuthenticator *authenticator)
3674 {
3675 QVERIFY(authenticator);
3676 QCOMPARE(authenticator->identityHint(), PSK_SERVER_IDENTITY_HINT);
3677 if (m_server)
3678 QCOMPARE(authenticator->maximumIdentityLength(), 0);
3679 else
3680 QVERIFY(authenticator->maximumIdentityLength() > 0);
3681
3682 QVERIFY(authenticator->maximumPreSharedKeyLength() > 0);
3683
3684 if (!m_identity.isEmpty()) {
3685 authenticator->setIdentity(m_identity);
3686 QCOMPARE(authenticator->identity(), m_identity);
3687 }
3688
3689 if (!m_psk.isEmpty()) {
3690 authenticator->setPreSharedKey(m_psk);
3691 QCOMPARE(authenticator->preSharedKey(), m_psk);
3692 }
3693 }
3694};
3695
3696class PskServer : public QTcpServer
3697{
3698 Q_OBJECT
3699public:
3700 PskServer()
3701 : socket(0),
3702 config(QSslConfiguration::defaultConfiguration()),
3703 ignoreSslErrors(true),
3704 peerVerifyMode(QSslSocket::AutoVerifyPeer),
3705 protocol(QSsl::TlsV1_0),
3706 m_pskProvider()
3707 {
3708 m_pskProvider.m_server = true;
3709 }
3710 QSslSocket *socket;
3711 QSslConfiguration config;
3712 bool ignoreSslErrors;
3713 QSslSocket::PeerVerifyMode peerVerifyMode;
3714 QSsl::SslProtocol protocol;
3715 QList<QSslCipher> ciphers;
3716 PskProvider m_pskProvider;
3717
3718protected:
3719 void incomingConnection(qintptr socketDescriptor)
3720 {
3721 socket = new QSslSocket(this);
3722 socket->setSslConfiguration(config);
3723 socket->setPeerVerifyMode(peerVerifyMode);
3724 socket->setProtocol(protocol);
3725 if (ignoreSslErrors)
3726 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
3727
3728 if (!ciphers.isEmpty()) {
3729 auto sslConfig = socket->sslConfiguration();
3730 sslConfig.setCiphers(ciphers);
3731 socket->setSslConfiguration(sslConfig);
3732 }
3733
3734 QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState));
3735 QVERIFY(!socket->peerAddress().isNull());
3736 QVERIFY(socket->peerPort() != 0);
3737 QVERIFY(!socket->localAddress().isNull());
3738 QVERIFY(socket->localPort() != 0);
3739
3740 connect(sender: socket, signal: &QSslSocket::preSharedKeyAuthenticationRequired, receiver: &m_pskProvider, slot: &PskProvider::providePsk);
3741
3742 socket->startServerEncryption();
3743 }
3744
3745protected slots:
3746 void ignoreErrorSlot()
3747 {
3748 socket->ignoreSslErrors();
3749 }
3750};
3751void tst_QSslSocket::simplePskConnect_data()
3752{
3753 QTest::addColumn<PskConnectTestType>(name: "pskTestType");
3754 QTest::newRow(dataTag: "PskConnectDoNotHandlePsk") << PskConnectDoNotHandlePsk;
3755 QTest::newRow(dataTag: "PskConnectEmptyCredentials") << PskConnectEmptyCredentials;
3756 QTest::newRow(dataTag: "PskConnectWrongCredentials") << PskConnectWrongCredentials;
3757 QTest::newRow(dataTag: "PskConnectWrongIdentity") << PskConnectWrongIdentity;
3758 QTest::newRow(dataTag: "PskConnectWrongPreSharedKey") << PskConnectWrongPreSharedKey;
3759 QTest::newRow(dataTag: "PskConnectRightCredentialsPeerVerifyFailure") << PskConnectRightCredentialsPeerVerifyFailure;
3760 QTest::newRow(dataTag: "PskConnectRightCredentialsVerifyPeer") << PskConnectRightCredentialsVerifyPeer;
3761 QTest::newRow(dataTag: "PskConnectRightCredentialsDoNotVerifyPeer") << PskConnectRightCredentialsDoNotVerifyPeer;
3762}
3763
3764void tst_QSslSocket::simplePskConnect()
3765{
3766 QFETCH(PskConnectTestType, pskTestType);
3767 QSKIP("This test requires change 1f8cab2c3bcd91335684c95afa95ae71e00a94e4 on the network test server, QTQAINFRA-917");
3768
3769 if (!QSslSocket::supportsSsl())
3770 QSKIP("No SSL support");
3771
3772 bool pskCipherFound = false;
3773 const QList<QSslCipher> supportedCiphers = QSslConfiguration::supportedCiphers();
3774 for (const QSslCipher &cipher : supportedCiphers) {
3775 if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) {
3776 pskCipherFound = true;
3777 break;
3778 }
3779 }
3780
3781 if (!pskCipherFound)
3782 QSKIP("SSL implementation does not support the necessary PSK cipher(s)");
3783
3784 QFETCH_GLOBAL(bool, setProxy);
3785 if (setProxy)
3786 QSKIP("This test must not be going through a proxy");
3787
3788 QSslSocket socket;
3789 this->socket = &socket;
3790
3791 QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
3792 QVERIFY(connectedSpy.isValid());
3793
3794 QSignalSpy hostFoundSpy(&socket, SIGNAL(hostFound()));
3795 QVERIFY(hostFoundSpy.isValid());
3796
3797 QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected()));
3798 QVERIFY(disconnectedSpy.isValid());
3799
3800 QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted()));
3801 QVERIFY(connectionEncryptedSpy.isValid());
3802
3803 QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(QList<QSslError>)));
3804 QVERIFY(sslErrorsSpy.isValid());
3805
3806 QSignalSpy socketErrorsSpy(&socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
3807 QVERIFY(socketErrorsSpy.isValid());
3808
3809 QSignalSpy peerVerifyErrorSpy(&socket, SIGNAL(peerVerifyError(QSslError)));
3810 QVERIFY(peerVerifyErrorSpy.isValid());
3811
3812 QSignalSpy pskAuthenticationRequiredSpy(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
3813 QVERIFY(pskAuthenticationRequiredSpy.isValid());
3814
3815 connect(sender: &socket, SIGNAL(connected()), receiver: this, SLOT(exitLoop()));
3816 connect(sender: &socket, SIGNAL(disconnected()), receiver: this, SLOT(exitLoop()));
3817 connect(sender: &socket, SIGNAL(modeChanged(QSslSocket::SslMode)), receiver: this, SLOT(exitLoop()));
3818 connect(sender: &socket, SIGNAL(encrypted()), receiver: this, SLOT(exitLoop()));
3819 connect(sender: &socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(exitLoop()));
3820 connect(sender: &socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: this, SLOT(exitLoop()));
3821 connect(sender: &socket, SIGNAL(peerVerifyError(QSslError)), receiver: this, SLOT(exitLoop()));
3822 connect(sender: &socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), receiver: this, SLOT(exitLoop()));
3823
3824 // force a PSK cipher w/o auth
3825 auto sslConfig = socket.sslConfiguration();
3826 sslConfig.setCiphers({QSslCipher(PSK_CIPHER_WITHOUT_AUTH)});
3827 socket.setSslConfiguration(sslConfig);
3828
3829 PskProvider provider;
3830
3831 switch (pskTestType) {
3832 case PskConnectDoNotHandlePsk:
3833 // don't connect to the provider
3834 break;
3835
3836 case PskConnectEmptyCredentials:
3837 // connect to the psk provider, but don't actually provide any PSK nor identity
3838 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
3839 break;
3840
3841 case PskConnectWrongCredentials:
3842 // provide totally wrong credentials
3843 provider.setIdentity(PSK_CLIENT_IDENTITY.left(len: PSK_CLIENT_IDENTITY.length() - 1));
3844 provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(len: PSK_CLIENT_PRESHAREDKEY.length() - 1));
3845 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
3846 break;
3847
3848 case PskConnectWrongIdentity:
3849 // right PSK, wrong identity
3850 provider.setIdentity(PSK_CLIENT_IDENTITY.left(len: PSK_CLIENT_IDENTITY.length() - 1));
3851 provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
3852 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
3853 break;
3854
3855 case PskConnectWrongPreSharedKey:
3856 // right identity, wrong PSK
3857 provider.setIdentity(PSK_CLIENT_IDENTITY);
3858 provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(len: PSK_CLIENT_PRESHAREDKEY.length() - 1));
3859 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
3860 break;
3861
3862 case PskConnectRightCredentialsPeerVerifyFailure:
3863 // right identity, right PSK, but since we can't verify the other peer, we'll fail
3864 provider.setIdentity(PSK_CLIENT_IDENTITY);
3865 provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
3866 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
3867 break;
3868
3869 case PskConnectRightCredentialsVerifyPeer:
3870 // right identity, right PSK, verify the peer (but ignore the failure) and establish the connection
3871 provider.setIdentity(PSK_CLIENT_IDENTITY);
3872 provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
3873 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
3874 connect(sender: &socket, SIGNAL(peerVerifyError(QSslError)), receiver: this, SLOT(ignoreErrorSlot()));
3875 break;
3876
3877 case PskConnectRightCredentialsDoNotVerifyPeer:
3878 // right identity, right PSK, do not verify the peer and establish the connection
3879 provider.setIdentity(PSK_CLIENT_IDENTITY);
3880 provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
3881 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
3882 socket.setPeerVerifyMode(QSslSocket::VerifyNone);
3883 break;
3884 }
3885
3886 // check the peer verification mode
3887 switch (pskTestType) {
3888 case PskConnectDoNotHandlePsk:
3889 case PskConnectEmptyCredentials:
3890 case PskConnectWrongCredentials:
3891 case PskConnectWrongIdentity:
3892 case PskConnectWrongPreSharedKey:
3893 case PskConnectRightCredentialsPeerVerifyFailure:
3894 case PskConnectRightCredentialsVerifyPeer:
3895 QCOMPARE(socket.peerVerifyMode(), QSslSocket::AutoVerifyPeer);
3896 break;
3897
3898 case PskConnectRightCredentialsDoNotVerifyPeer:
3899 QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyNone);
3900 break;
3901 }
3902
3903 // Start connecting
3904 socket.connectToHost(hostName: QtNetworkSettings::serverName(), port: PSK_SERVER_PORT);
3905 QCOMPARE(socket.state(), QAbstractSocket::HostLookupState);
3906 enterLoop(secs: 10);
3907
3908 // Entered connecting state
3909 QCOMPARE(socket.state(), QAbstractSocket::ConnectingState);
3910 QCOMPARE(connectedSpy.count(), 0);
3911 QCOMPARE(hostFoundSpy.count(), 1);
3912 QCOMPARE(disconnectedSpy.count(), 0);
3913 enterLoop(secs: 10);
3914
3915 // Entered connected state
3916 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
3917 QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
3918 QVERIFY(!socket.isEncrypted());
3919 QCOMPARE(connectedSpy.count(), 1);
3920 QCOMPARE(hostFoundSpy.count(), 1);
3921 QCOMPARE(disconnectedSpy.count(), 0);
3922
3923 // Enter encrypted mode
3924 socket.startClientEncryption();
3925 QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
3926 QVERIFY(!socket.isEncrypted());
3927 QCOMPARE(connectionEncryptedSpy.count(), 0);
3928 QCOMPARE(sslErrorsSpy.count(), 0);
3929 QCOMPARE(peerVerifyErrorSpy.count(), 0);
3930
3931 // Start handshake.
3932 enterLoop(secs: 10);
3933
3934 // We must get the PSK signal in all cases
3935 QCOMPARE(pskAuthenticationRequiredSpy.count(), 1);
3936
3937 switch (pskTestType) {
3938 case PskConnectDoNotHandlePsk:
3939 case PskConnectEmptyCredentials:
3940 case PskConnectWrongCredentials:
3941 case PskConnectWrongIdentity:
3942 case PskConnectWrongPreSharedKey:
3943 // Handshake failure
3944 QCOMPARE(socketErrorsSpy.count(), 1);
3945 QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError);
3946 QCOMPARE(sslErrorsSpy.count(), 0);
3947 QCOMPARE(peerVerifyErrorSpy.count(), 0);
3948 QCOMPARE(connectionEncryptedSpy.count(), 0);
3949 QVERIFY(!socket.isEncrypted());
3950 break;
3951
3952 case PskConnectRightCredentialsPeerVerifyFailure:
3953 // Peer verification failure
3954 QCOMPARE(socketErrorsSpy.count(), 1);
3955 QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError);
3956 QCOMPARE(sslErrorsSpy.count(), 1);
3957 QCOMPARE(peerVerifyErrorSpy.count(), 1);
3958 QCOMPARE(connectionEncryptedSpy.count(), 0);
3959 QVERIFY(!socket.isEncrypted());
3960 break;
3961
3962 case PskConnectRightCredentialsVerifyPeer:
3963 // Peer verification failure, but ignore it and keep connecting
3964 QCOMPARE(socketErrorsSpy.count(), 0);
3965 QCOMPARE(sslErrorsSpy.count(), 1);
3966 QCOMPARE(peerVerifyErrorSpy.count(), 1);
3967 QCOMPARE(connectionEncryptedSpy.count(), 1);
3968 QVERIFY(socket.isEncrypted());
3969 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
3970 break;
3971
3972 case PskConnectRightCredentialsDoNotVerifyPeer:
3973 // No peer verification => no failure
3974 QCOMPARE(socketErrorsSpy.count(), 0);
3975 QCOMPARE(sslErrorsSpy.count(), 0);
3976 QCOMPARE(peerVerifyErrorSpy.count(), 0);
3977 QCOMPARE(connectionEncryptedSpy.count(), 1);
3978 QVERIFY(socket.isEncrypted());
3979 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
3980 break;
3981 }
3982
3983 // check writing
3984 switch (pskTestType) {
3985 case PskConnectDoNotHandlePsk:
3986 case PskConnectEmptyCredentials:
3987 case PskConnectWrongCredentials:
3988 case PskConnectWrongIdentity:
3989 case PskConnectWrongPreSharedKey:
3990 case PskConnectRightCredentialsPeerVerifyFailure:
3991 break;
3992
3993 case PskConnectRightCredentialsVerifyPeer:
3994 case PskConnectRightCredentialsDoNotVerifyPeer:
3995 socket.write(data: "Hello from Qt TLS/PSK!");
3996 QVERIFY(socket.waitForBytesWritten());
3997 break;
3998 }
3999
4000 // disconnect
4001 switch (pskTestType) {
4002 case PskConnectDoNotHandlePsk:
4003 case PskConnectEmptyCredentials:
4004 case PskConnectWrongCredentials:
4005 case PskConnectWrongIdentity:
4006 case PskConnectWrongPreSharedKey:
4007 case PskConnectRightCredentialsPeerVerifyFailure:
4008 break;
4009
4010 case PskConnectRightCredentialsVerifyPeer:
4011 case PskConnectRightCredentialsDoNotVerifyPeer:
4012 socket.disconnectFromHost();
4013 enterLoop(secs: 10);
4014 break;
4015 }
4016
4017 QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
4018 QCOMPARE(disconnectedSpy.count(), 1);
4019}
4020
4021void tst_QSslSocket::ephemeralServerKey_data()
4022{
4023#ifdef Q_OS_WINRT
4024 QSKIP("Server-side encryption is not implemented on WinRT.");
4025#endif
4026 QTest::addColumn<QString>(name: "cipher");
4027 QTest::addColumn<bool>(name: "emptyKey");
4028
4029 QTest::newRow(dataTag: "ForwardSecrecyCipher") << "ECDHE-RSA-AES256-SHA" << (QSslSocket::sslLibraryVersionNumber() < 0x10002000L);
4030}
4031
4032void tst_QSslSocket::ephemeralServerKey()
4033{
4034 QFETCH_GLOBAL(bool, setProxy);
4035 if (!QSslSocket::supportsSsl() || setProxy)
4036 return;
4037
4038 QFETCH(QString, cipher);
4039 QFETCH(bool, emptyKey);
4040 SslServer server;
4041 server.config.setCiphers(QList<QSslCipher>() << QSslCipher(cipher));
4042 QVERIFY(server.listen());
4043 QSslSocketPtr client = newSocket();
4044 socket = client.data();
4045 connect(sender: socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(ignoreErrorSlot()));
4046 QSignalSpy spy(client.data(), &QSslSocket::encrypted);
4047
4048 client->connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
4049 spy.wait();
4050
4051 QCOMPARE(spy.count(), 1);
4052 QVERIFY(server.config.ephemeralServerKey().isNull());
4053 QCOMPARE(client->sslConfiguration().ephemeralServerKey().isNull(), emptyKey);
4054}
4055
4056void tst_QSslSocket::pskServer()
4057{
4058#ifdef Q_OS_WINRT
4059 QSKIP("Server-side encryption is not implemented on WinRT.");
4060#endif
4061#if QT_CONFIG(schannel)
4062 QSKIP("Schannel does not have PSK support implemented.");
4063#endif
4064 QFETCH_GLOBAL(bool, setProxy);
4065 if (!QSslSocket::supportsSsl() || setProxy)
4066 return;
4067
4068 QSslSocket socket;
4069 this->socket = &socket;
4070
4071 QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
4072 QVERIFY(connectedSpy.isValid());
4073
4074 QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected()));
4075 QVERIFY(disconnectedSpy.isValid());
4076
4077 QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted()));
4078 QVERIFY(connectionEncryptedSpy.isValid());
4079
4080 QSignalSpy pskAuthenticationRequiredSpy(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
4081 QVERIFY(pskAuthenticationRequiredSpy.isValid());
4082
4083 connect(sender: &socket, SIGNAL(connected()), receiver: this, SLOT(exitLoop()));
4084 connect(sender: &socket, SIGNAL(disconnected()), receiver: this, SLOT(exitLoop()));
4085 connect(sender: &socket, SIGNAL(modeChanged(QSslSocket::SslMode)), receiver: this, SLOT(exitLoop()));
4086 connect(sender: &socket, SIGNAL(encrypted()), receiver: this, SLOT(exitLoop()));
4087 connect(sender: &socket, SIGNAL(sslErrors(QList<QSslError>)), receiver: this, SLOT(exitLoop()));
4088 connect(sender: &socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: this, SLOT(exitLoop()));
4089 connect(sender: &socket, SIGNAL(peerVerifyError(QSslError)), receiver: this, SLOT(exitLoop()));
4090 connect(sender: &socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), receiver: this, SLOT(exitLoop()));
4091
4092 // force a PSK cipher w/o auth
4093 auto sslConfig = socket.sslConfiguration();
4094 sslConfig.setCiphers({QSslCipher(PSK_CIPHER_WITHOUT_AUTH)});
4095 socket.setSslConfiguration(sslConfig);
4096
4097 PskProvider provider;
4098 provider.setIdentity(PSK_CLIENT_IDENTITY);
4099 provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
4100 connect(sender: &socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), receiver: &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
4101 socket.setPeerVerifyMode(QSslSocket::VerifyNone);
4102
4103 PskServer server;
4104 server.m_pskProvider.setIdentity(provider.m_identity);
4105 server.m_pskProvider.setPreSharedKey(provider.m_psk);
4106 server.config.setPreSharedKeyIdentityHint(PSK_SERVER_IDENTITY_HINT);
4107 QVERIFY(server.listen());
4108
4109 // Start connecting
4110 socket.connectToHost(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
4111 enterLoop(secs: 5);
4112
4113 // Entered connected state
4114 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
4115 QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
4116 QVERIFY(!socket.isEncrypted());
4117 QCOMPARE(connectedSpy.count(), 1);
4118 QCOMPARE(disconnectedSpy.count(), 0);
4119
4120 // Enter encrypted mode
4121 socket.startClientEncryption();
4122 QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
4123 QVERIFY(!socket.isEncrypted());
4124 QCOMPARE(connectionEncryptedSpy.count(), 0);
4125
4126 // Start handshake.
4127 enterLoop(secs: 10);
4128
4129 // We must get the PSK signal in all cases
4130 QCOMPARE(pskAuthenticationRequiredSpy.count(), 1);
4131
4132 QCOMPARE(connectionEncryptedSpy.count(), 1);
4133 QVERIFY(socket.isEncrypted());
4134 QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
4135
4136 // check writing
4137 socket.write(data: "Hello from Qt TLS/PSK!");
4138 QVERIFY(socket.waitForBytesWritten());
4139
4140 // disconnect
4141 socket.disconnectFromHost();
4142 enterLoop(secs: 10);
4143
4144 QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
4145 QCOMPARE(disconnectedSpy.count(), 1);
4146}
4147
4148void tst_QSslSocket::signatureAlgorithm_data()
4149{
4150 if (!QSslSocket::supportsSsl())
4151 QSKIP("Signature algorithms cannot be tested without SSL support");
4152
4153 if (QSslSocket::sslLibraryVersionNumber() >= 0x10101000L) {
4154 // FIXME: investigate if this test makes any sense with TLS 1.3.
4155 QSKIP("Test is not valid for TLS 1.3/OpenSSL 1.1.1");
4156 }
4157
4158 QTest::addColumn<QByteArrayList>(name: "serverSigAlgPairs");
4159 QTest::addColumn<QSsl::SslProtocol>(name: "serverProtocol");
4160 QTest::addColumn<QByteArrayList>(name: "clientSigAlgPairs");
4161 QTest::addColumn<QSsl::SslProtocol>(name: "clientProtocol");
4162 QTest::addColumn<QAbstractSocket::SocketState>(name: "state");
4163
4164 const QByteArray dsaSha1("DSA+SHA1");
4165 const QByteArray ecdsaSha1("ECDSA+SHA1");
4166 const QByteArray ecdsaSha512("ECDSA+SHA512");
4167 const QByteArray rsaSha256("RSA+SHA256");
4168 const QByteArray rsaSha384("RSA+SHA384");
4169 const QByteArray rsaSha512("RSA+SHA512");
4170
4171 QTest::newRow(dataTag: "match_TlsV1_2")
4172 << QByteArrayList({rsaSha256})
4173 << QSsl::TlsV1_2
4174 << QByteArrayList({rsaSha256})
4175 << QSsl::AnyProtocol
4176 << QAbstractSocket::ConnectedState;
4177 QTest::newRow(dataTag: "no_hashalg_match_TlsV1_2")
4178 << QByteArrayList({rsaSha256})
4179 << QSsl::TlsV1_2
4180 << QByteArrayList({rsaSha512})
4181 << QSsl::AnyProtocol
4182 << QAbstractSocket::UnconnectedState;
4183 QTest::newRow(dataTag: "no_sigalg_match_TlsV1_2")
4184 << QByteArrayList({ecdsaSha512})
4185 << QSsl::TlsV1_2
4186 << QByteArrayList({rsaSha512})
4187 << QSsl::AnyProtocol
4188 << QAbstractSocket::UnconnectedState;
4189 QTest::newRow(dataTag: "no_cipher_match_AnyProtocol")
4190 << QByteArrayList({rsaSha512})
4191 << QSsl::AnyProtocol
4192 << QByteArrayList({ecdsaSha512})
4193 << QSsl::AnyProtocol
4194 << QAbstractSocket::UnconnectedState;
4195 QTest::newRow(dataTag: "match_multiple-choice")
4196 << QByteArrayList({dsaSha1, rsaSha256, rsaSha384, rsaSha512})
4197 << QSsl::AnyProtocol
4198 << QByteArrayList({ecdsaSha1, rsaSha384, rsaSha512, ecdsaSha512})
4199 << QSsl::AnyProtocol
4200 << QAbstractSocket::ConnectedState;
4201 QTest::newRow(dataTag: "match_client_longer")
4202 << QByteArrayList({dsaSha1, rsaSha256})
4203 << QSsl::AnyProtocol
4204 << QByteArrayList({ecdsaSha1, ecdsaSha512, rsaSha256})
4205 << QSsl::AnyProtocol
4206 << QAbstractSocket::ConnectedState;
4207 QTest::newRow(dataTag: "match_server_longer")
4208 << QByteArrayList({ecdsaSha1, ecdsaSha512, rsaSha256})
4209 << QSsl::AnyProtocol
4210 << QByteArrayList({dsaSha1, rsaSha256})
4211 << QSsl::AnyProtocol
4212 << QAbstractSocket::ConnectedState;
4213
4214 // signature algorithms do not match, but are ignored because the tls version is not v1.2
4215 QTest::newRow(dataTag: "client_ignore_TlsV1_1")
4216 << QByteArrayList({rsaSha256})
4217 << QSsl::TlsV1_1
4218 << QByteArrayList({rsaSha512})
4219 << QSsl::AnyProtocol
4220 << QAbstractSocket::ConnectedState;
4221 QTest::newRow(dataTag: "server_ignore_TlsV1_1")
4222 << QByteArrayList({rsaSha256})
4223 << QSsl::AnyProtocol
4224 << QByteArrayList({rsaSha512})
4225 << QSsl::TlsV1_1
4226 << QAbstractSocket::ConnectedState;
4227 QTest::newRow(dataTag: "client_ignore_TlsV1_0")
4228 << QByteArrayList({rsaSha256})
4229 << QSsl::TlsV1_0
4230 << QByteArrayList({rsaSha512})
4231 << QSsl::AnyProtocol
4232 << QAbstractSocket::ConnectedState;
4233 QTest::newRow(dataTag: "server_ignore_TlsV1_0")
4234 << QByteArrayList({rsaSha256})
4235 << QSsl::AnyProtocol
4236 << QByteArrayList({rsaSha512})
4237 << QSsl::TlsV1_0
4238 << QAbstractSocket::ConnectedState;
4239}
4240
4241void tst_QSslSocket::signatureAlgorithm()
4242{
4243 QFETCH_GLOBAL(bool, setProxy);
4244 if (setProxy)
4245 QSKIP("Test not adapted for use with proxying");
4246
4247 QFETCH(QByteArrayList, serverSigAlgPairs);
4248 QFETCH(QSsl::SslProtocol, serverProtocol);
4249 QFETCH(QByteArrayList, clientSigAlgPairs);
4250 QFETCH(QSsl::SslProtocol, clientProtocol);
4251 QFETCH(QAbstractSocket::SocketState, state);
4252
4253 SslServer server;
4254 server.protocol = serverProtocol;
4255 server.config.setCiphers({QSslCipher("ECDHE-RSA-AES256-SHA")});
4256 server.config.setBackendConfigurationOption(QByteArrayLiteral("SignatureAlgorithms"), value: serverSigAlgPairs.join(sep: ':'));
4257 QVERIFY(server.listen());
4258
4259 QSslConfiguration clientConfig = QSslConfiguration::defaultConfiguration();
4260 clientConfig.setProtocol(clientProtocol);
4261 clientConfig.setBackendConfigurationOption(QByteArrayLiteral("SignatureAlgorithms"), value: clientSigAlgPairs.join(sep: ':'));
4262 QSslSocket client;
4263 client.setSslConfiguration(clientConfig);
4264 socket = &client;
4265
4266 QEventLoop loop;
4267 QTimer::singleShot(interval: 5000, receiver: &loop, slot: &QEventLoop::quit);
4268 connect(sender: socket, signal: &QAbstractSocket::errorOccurred, receiver: &loop, slot: &QEventLoop::quit);
4269 connect(sender: socket, signal: QOverload<const QList<QSslError> &>::of(ptr: &QSslSocket::sslErrors), receiver: this, slot: &tst_QSslSocket::ignoreErrorSlot);
4270 connect(sender: socket, signal: &QSslSocket::encrypted, receiver: &loop, slot: &QEventLoop::quit);
4271
4272 client.connectToHostEncrypted(hostName: QHostAddress(QHostAddress::LocalHost).toString(), port: server.serverPort());
4273 loop.exec();
4274 socket = nullptr;
4275 QCOMPARE(client.state(), state);
4276}
4277
4278void tst_QSslSocket::forwardReadChannelFinished()
4279{
4280 if (!QSslSocket::supportsSsl())
4281 QSKIP("Needs SSL");
4282 QFETCH_GLOBAL(bool, setProxy);
4283 if (setProxy)
4284 QSKIP("This test doesn't work via a proxy");
4285
4286 QSslSocket socket;
4287 QSignalSpy readChannelFinishedSpy(&socket, &QAbstractSocket::readChannelFinished);
4288 connect(sender: &socket, signal: &QSslSocket::encrypted, slot: [&socket]() {
4289 const auto data = QString("GET /ip HTTP/1.0\r\nHost: %1\r\n\r\nAccept: */*\r\n\r\n")
4290 .arg(a: QtNetworkSettings::serverLocalName()).toUtf8();
4291 socket.write(data);
4292 });
4293 connect(sender: &socket, signal: &QSslSocket::readChannelFinished,
4294 receiver: &QTestEventLoop::instance(), slot: &QTestEventLoop::exitLoop);
4295 socket.connectToHostEncrypted(hostName: QtNetworkSettings::httpServerName(), port: 443);
4296 enterLoop(secs: 10);
4297 QVERIFY(readChannelFinishedSpy.count());
4298}
4299
4300#endif // QT_NO_OPENSSL
4301
4302void tst_QSslSocket::disabledProtocols_data()
4303{
4304 QTest::addColumn<QSsl::SslProtocol>(name: "disabledProtocol");
4305 QTest::newRow(dataTag: "SslV2") << QSsl::SslV2;
4306 QTest::newRow(dataTag: "SslV3") << QSsl::SslV3;
4307}
4308
4309void tst_QSslSocket::disabledProtocols()
4310{
4311 QFETCH_GLOBAL(const bool, setProxy);
4312 if (setProxy)
4313 return;
4314
4315 QFETCH(const QSsl::SslProtocol, disabledProtocol);
4316 const int timeoutMS = 500;
4317 // Test a client socket.
4318 {
4319 // 0. connectToHostEncrypted: client-side, non-blocking API, error is discovered
4320 // early, preventing any real connection from ever starting.
4321 QSslSocket socket;
4322 socket.setProtocol(disabledProtocol);
4323 QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
4324 socket.connectToHostEncrypted(QStringLiteral("doesnotmatter.org"), port: 1010);
4325 QCOMPARE(socket.error(), QAbstractSocket::SslInvalidUserDataError);
4326 QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
4327 }
4328 {
4329 // 1. startClientEncryption: client-side, non blocking API, but wants a socket in
4330 // the 'connected' state (otherwise just returns false not setting any error code).
4331 SslServer server;
4332 QVERIFY(server.listen());
4333
4334 QSslSocket socket;
4335 QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
4336
4337 socket.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
4338 QVERIFY(socket.waitForConnected(timeoutMS));
4339
4340 socket.setProtocol(disabledProtocol);
4341 socket.startClientEncryption();
4342 QCOMPARE(socket.error(), QAbstractSocket::SslInvalidUserDataError);
4343 }
4344 {
4345 // 2. waitForEncrypted: client-side, blocking API plus requires from us
4346 // to call ... connectToHostEncrypted(), which will notice an error and
4347 // will prevent any connect at all. Nothing to test.
4348 }
4349
4350 // Test a server side, relatively simple: server does not connect, it listens/accepts
4351 // and then calls startServerEncryption() (which must fall).
4352 {
4353 SslServer server;
4354 server.protocol = disabledProtocol;
4355 QVERIFY(server.listen());
4356
4357 QTestEventLoop loop;
4358 connect(sender: &server, signal: &SslServer::socketError, slot: [&loop](QAbstractSocket::SocketError)
4359 {loop.exitLoop();});
4360
4361 QTcpSocket client;
4362 client.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
4363 loop.enterLoopMSecs(ms: timeoutMS);
4364 QVERIFY(!loop.timeout());
4365 QVERIFY(server.socket);
4366 QCOMPARE(server.socket->error(), QAbstractSocket::SslInvalidUserDataError);
4367 }
4368}
4369
4370void tst_QSslSocket::oldErrorsOnSocketReuse()
4371{
4372 QFETCH_GLOBAL(bool, setProxy);
4373 if (setProxy)
4374 return; // not relevant
4375 SslServer server;
4376 server.protocol = QSsl::TlsV1_1;
4377 server.m_certFile = testDataDir + "certs/fluke.cert";
4378 server.m_keyFile = testDataDir + "certs/fluke.key";
4379 QVERIFY(server.listen(QHostAddress::SpecialAddress::LocalHost));
4380
4381 QSslSocket socket;
4382 socket.setProtocol(QSsl::TlsV1_1);
4383 QList<QSslError> errorList;
4384 auto connection = connect(sender: &socket, signal: QOverload<const QList<QSslError> &>::of(ptr: &QSslSocket::sslErrors),
4385 slot: [&socket, &errorList](const QList<QSslError> &errors) {
4386 errorList += errors;
4387 socket.ignoreSslErrors(errors);
4388 socket.resume();
4389 });
4390
4391 socket.connectToHostEncrypted(hostName: QString::fromLatin1(str: "localhost"), port: server.serverPort());
4392 QVERIFY(QTest::qWaitFor([&socket](){ return socket.isEncrypted(); }));
4393 socket.disconnectFromHost();
4394 if (socket.state() != QAbstractSocket::UnconnectedState) {
4395 QVERIFY(QTest::qWaitFor(
4396 [&socket](){
4397 return socket.state() == QAbstractSocket::UnconnectedState;
4398 }));
4399 }
4400
4401 auto oldList = errorList;
4402 errorList.clear();
4403 server.close();
4404 server.m_certFile = testDataDir + "certs/bogus-client.crt";
4405 server.m_keyFile = testDataDir + "certs/bogus-client.key";
4406 QVERIFY(server.listen(QHostAddress::SpecialAddress::LocalHost));
4407
4408 socket.connectToHostEncrypted(hostName: QString::fromLatin1(str: "localhost"), port: server.serverPort());
4409 QVERIFY(QTest::qWaitFor([&socket](){ return socket.isEncrypted(); }));
4410
4411 for (const auto &error : oldList) {
4412 QVERIFY2(!errorList.contains(error),
4413 "The new errors should not contain any of the old ones");
4414 }
4415}
4416
4417#endif // QT_NO_SSL
4418
4419QTEST_MAIN(tst_QSslSocket)
4420
4421#include "tst_qsslsocket.moc"
4422

source code of qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp