summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKalle Viironen <kalle.viironen@digia.com>2012-01-26 12:33:47 +0200
committerQt by Nokia <qt-info@nokia.com>2012-03-19 15:16:36 +0100
commit68b1d5c17aa38d5921bdade2b0e0cb67c6c90513 (patch)
treeb759f8421f23876b85c97536bf5277c75593e868
parentc0b782e8c516245bd534542f3682e7e25a33c414 (diff)
Fix bug in qsslsocket peek()
Calling peek() for qsslsocket caused socket data to be copied into qiodevices buffer and therefore make it unaccessible in qsslsocket. Task-number: QTBUG-18498 Change-Id: Ie27a90a468be8158bd8afcd259dbb34483623c36 Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
-rw-r--r--src/network/ssl/qsslsocket.cpp35
-rw-r--r--src/network/ssl/qsslsocket_p.h3
-rw-r--r--tests/auto/qsslsocket/tst_qsslsocket.cpp127
3 files changed, 165 insertions, 0 deletions
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index f89b9b3545..7fc36c8523 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -2246,6 +2246,41 @@ void QSslSocketPrivate::_q_flushReadBuffer()
/*!
\internal
*/
+qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize)
+{
+ if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) {
+ if (plainSocket)
+ return plainSocket->peek(data, maxSize);
+ else
+ return -1;
+ } else {
+ QByteArray tmp;
+ tmp = readBuffer.peek(maxSize);
+ memcpy(data, tmp.data(), tmp.length());
+ return tmp.length();
+ }
+}
+
+/*!
+ \internal
+*/
+QByteArray QSslSocketPrivate::peek(qint64 maxSize)
+{
+ if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) {
+ if (plainSocket)
+ return plainSocket->peek(maxSize);
+ else
+ return QByteArray();
+ } else {
+ QByteArray tmp;
+ tmp = readBuffer.peek(maxSize);
+ return tmp;
+ }
+}
+
+/*!
+ \internal
+*/
QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
{
return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva, MeeGo ...
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 606352b0ba..58515c9f04 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -159,6 +159,9 @@ public:
void _q_flushWriteBuffer();
void _q_flushReadBuffer();
+ virtual qint64 peek(char *data, qint64 maxSize);
+ virtual QByteArray peek(qint64 maxSize);
+
// Platform specific functions
virtual void startClientEncryption() = 0;
virtual void startServerEncryption() = 0;
diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp
index 961e4da306..cf4d04e07c 100644
--- a/tests/auto/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp
@@ -190,6 +190,7 @@ private slots:
void readFromClosedSocket();
void writeBigChunk();
void blacklistedCertificates();
+ void qtbug18498_peek();
void setEmptyDefaultConfiguration();
static void exitLoop()
@@ -2032,6 +2033,132 @@ void tst_QSslSocket::blacklistedCertificates()
QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted);
}
+class WebSocket : public QSslSocket
+{
+ Q_OBJECT
+public:
+ explicit WebSocket(int socketDescriptor,
+ const QString &keyFile = SRCDIR "certs/fluke.key",
+ const QString &certFile = SRCDIR "certs/fluke.cert");
+
+protected slots:
+ void onReadyReadFirstBytes(void);
+
+private:
+ void _startServerEncryption(void);
+
+ QString m_keyFile;
+ QString m_certFile;
+
+private:
+ Q_DISABLE_COPY(WebSocket)
+};
+
+WebSocket::WebSocket (int socketDescriptor, const QString &keyFile, const QString &certFile)
+ : m_keyFile(keyFile),
+ m_certFile(certFile)
+{
+ QVERIFY(setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState, QIODevice::ReadWrite | QIODevice::Unbuffered));
+ connect (this, SIGNAL(readyRead()), this, SLOT(onReadyReadFirstBytes()));
+}
+
+void WebSocket::_startServerEncryption (void)
+{
+ QFile file(m_keyFile);
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
+ QVERIFY(!key.isNull());
+ setPrivateKey(key);
+
+ QList<QSslCertificate> localCert = QSslCertificate::fromPath(m_certFile);
+ QVERIFY(!localCert.isEmpty());
+ QVERIFY(localCert.first().handle());
+ setLocalCertificate(localCert.first());
+
+ QVERIFY(!peerAddress().isNull());
+ QVERIFY(peerPort() != 0);
+ QVERIFY(!localAddress().isNull());
+ QVERIFY(localPort() != 0);
+
+ setProtocol(QSsl::AnyProtocol);
+ setPeerVerifyMode(QSslSocket::VerifyNone);
+ ignoreSslErrors();
+ startServerEncryption();
+}
+
+void WebSocket::onReadyReadFirstBytes (void)
+{
+ peek(1);
+ disconnect(this,SIGNAL(readyRead()), this, SLOT(onReadyReadFirstBytes()));
+ _startServerEncryption();
+}
+
+class SslServer4 : public QTcpServer
+{
+ Q_OBJECT
+public:
+ SslServer4() : socket(0) {}
+ WebSocket *socket;
+
+protected:
+ void incomingConnection(int socketDescriptor)
+ {
+ socket = new WebSocket(socketDescriptor);
+ }
+};
+
+void tst_QSslSocket::qtbug18498_peek()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ SslServer4 server;
+ QSslSocket *client = new QSslSocket(this);
+
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+ client->connectToHost("127.0.0.1", server.serverPort());
+ QVERIFY(client->waitForConnected(5000));
+ QVERIFY(server.waitForNewConnection(0));
+ client->setObjectName("client");
+ client->ignoreSslErrors();
+
+ connect(client, SIGNAL(encrypted()), this, SLOT(exitLoop()));
+ connect(client, SIGNAL(disconnected()), this, SLOT(exitLoop()));
+
+ client->startClientEncryption();
+ WebSocket *serversocket = server.socket;
+ QVERIFY(serversocket);
+ serversocket->setObjectName("server");
+
+ enterLoop(1);
+ QVERIFY(!timeout());
+ QVERIFY(serversocket->isEncrypted());
+ QVERIFY(client->isEncrypted());
+
+ QByteArray data("abc123");
+ client->write(data.data());
+
+ connect(serversocket, SIGNAL(readyRead()), this, SLOT(exitLoop()));
+ enterLoop(1);
+ QVERIFY(!timeout());
+
+ QByteArray peek1_data;
+ peek1_data.reserve(data.size());
+ QByteArray peek2_data;
+ QByteArray read_data;
+
+ int lngth = serversocket->peek(peek1_data.data(), 10);
+ peek1_data.resize(lngth);
+
+ peek2_data = serversocket->peek(10);
+ read_data = serversocket->readAll();
+
+ QCOMPARE(peek1_data, data);
+ QCOMPARE(peek2_data, data);
+ QCOMPARE(read_data, data);
+}
+
void tst_QSslSocket::setEmptyDefaultConfiguration()
{
// used to produce a crash in QSslConfigurationPrivate::deepCopyDefaultConfiguration, QTBUG-13265