summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hartmann <peter.hartmann@nokia.com>2011-03-14 13:28:34 (GMT)
committerPeter Hartmann <peter.hartmann@nokia.com>2011-03-14 16:47:40 (GMT)
commitb2c8421ff95ad62cbd67843ad5cd3edf72ecda31 (patch)
treee919c4f9c5b13ee32be1ada6cedcd52c2e3c3256
parentd0e46f9221b614007cc4dea25e0f83d10f1c2f11 (diff)
downloadQt-b2c8421ff95ad62cbd67843ad5cd3edf72ecda31.zip
Qt-b2c8421ff95ad62cbd67843ad5cd3edf72ecda31.tar.gz
Qt-b2c8421ff95ad62cbd67843ad5cd3edf72ecda31.tar.bz2
SSL: introduce new option TlsV1SslV3 for SSL communication
currently there are 3 supported protocols: SSL2, SSL3 and TLS1. SSL2 is considered insecure and should not be used anymore. This commit offers an option to use both TLS1 and SSL3, leaving SSL2 out. Part-of-the-patch-by: Darren Lissimore Reviewed-by: Markus Goetz Task-number: QTBUG-12338
-rw-r--r--src/network/ssl/qssl.cpp3
-rw-r--r--src/network/ssl/qssl.h1
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp7
-rw-r--r--tests/auto/qsslsocket/tst_qsslsocket.cpp150
4 files changed, 130 insertions, 31 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index 8a450b9..241eb12 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -107,6 +107,9 @@ QT_BEGIN_NAMESPACE
\value UnknownProtocol The cipher's protocol cannot be determined.
\value AnyProtocol The socket understands SSLv2, SSLv3, and TLSv1. This
value is used by QSslSocket only.
+ \value TlsV1SslV3 On the client side, this will send
+ a TLS 1.0 Client Hello, enabling TLSv1 and SSLv3 connections.
+ On the server side, this will enable both SSLv3 and TLSv1 connections.
Note: most servers using SSL understand both versions (2 and 3),
but it is recommended to use the latest version only for security
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index 4c035fd..e13ee78 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -77,6 +77,7 @@ namespace QSsl {
SslV2,
TlsV1,
AnyProtocol,
+ TlsV1SslV3,
UnknownProtocol = -1
};
}
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 646889c..8da3bb7 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -259,6 +259,7 @@ init_context:
case QSsl::SslV3:
ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method());
break;
+ case QSsl::TlsV1SslV3: // TlsV1SslV3 will be disabled below
case QSsl::AnyProtocol:
default:
ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
@@ -284,7 +285,11 @@ init_context:
}
// Enable all bug workarounds.
- q_SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ if (configuration.protocol == QSsl::TlsV1SslV3) {
+ q_SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
+ } else {
+ q_SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ }
// Initialize ciphers
QByteArray cipherString;
diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp
index 4beddad..b420b1d 100644
--- a/tests/auto/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp
@@ -66,6 +66,7 @@ Q_DECLARE_METATYPE(QSslSocket::SslMode)
typedef QList<QSslError::SslError> SslErrorList;
Q_DECLARE_METATYPE(SslErrorList)
Q_DECLARE_METATYPE(QSslError)
+Q_DECLARE_METATYPE(QSsl::SslProtocol)
#endif
#if defined Q_OS_HPUX && defined Q_CC_GNU
@@ -145,10 +146,11 @@ private slots:
void peerCertificateChain();
void privateKey();
void protocol();
+ void protocolServerSide_data();
+ void protocolServerSide();
void setCaCertificates();
void setLocalCertificate();
void setPrivateKey();
- void setProtocol();
void setSocketDescriptor();
void waitForEncrypted();
void waitForConnectedEncryptedReadyRead();
@@ -763,14 +765,12 @@ void tst_QSslSocket::protocol()
this->socket = socket;
QList<QSslCertificate> certs = QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem");
-// qDebug() << "certs:" << certs.at(0).issuerInfo(QSslCertificate::CommonName);
socket->setCaCertificates(certs);
#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND
connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(untrustedWorkaroundSlot(QList<QSslError>)));
#endif
-// qDebug() << "socket cert:" << socket->caCertificates().at(0).issuerInfo(QSslCertificate::CommonName);
QCOMPARE(socket->protocol(), QSsl::TlsV1);
{
// Fluke allows SSLv3.
@@ -835,44 +835,36 @@ void tst_QSslSocket::protocol()
QCOMPARE(socket->protocol(), QSsl::AnyProtocol);
socket->abort();
}
-}
-
-void tst_QSslSocket::setCaCertificates()
-{
- if (!QSslSocket::supportsSsl())
- return;
-
- QSslSocket socket;
- QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates());
- socket.setCaCertificates(QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem"));
- QCOMPARE(socket.caCertificates().size(), 1);
- socket.setCaCertificates(socket.defaultCaCertificates());
- QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates());
-}
-
-void tst_QSslSocket::setLocalCertificate()
-{
-}
-
-void tst_QSslSocket::setPrivateKey()
-{
-}
-
-void tst_QSslSocket::setProtocol()
-{
+ {
+ // Fluke allows SSLV3, so it allows NoSslV2
+ socket->setProtocol(QSsl::TlsV1SslV3);
+ QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
+ socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
+ QVERIFY(socket->waitForEncrypted());
+ QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
+ socket->abort();
+ QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
+ socket->connectToHost(QtNetworkSettings::serverName(), 443);
+ QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
+ socket->startClientEncryption();
+ QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString()));
+ QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
+ socket->abort();
+ }
}
class SslServer : public QTcpServer
{
Q_OBJECT
public:
- SslServer() : socket(0) { }
+ SslServer() : socket(0), protocol(QSsl::TlsV1) { }
QSslSocket *socket;
-
+ QSsl::SslProtocol protocol;
protected:
void incomingConnection(int socketDescriptor)
{
socket = new QSslSocket(this);
+ socket->setProtocol(protocol);
connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot()));
QFile file(SRCDIR "certs/fluke.key");
@@ -902,6 +894,104 @@ protected slots:
}
};
+void tst_QSslSocket::protocolServerSide_data()
+{
+
+ QTest::addColumn<QSsl::SslProtocol>("serverProtocol");
+ QTest::addColumn<QSsl::SslProtocol>("clientProtocol");
+ QTest::addColumn<bool>("works");
+
+ QTest::newRow("ssl2-ssl2") << QSsl::SslV2 << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2
+ QTest::newRow("ssl3-ssl3") << QSsl::SslV3 << QSsl::SslV3 << true;
+ QTest::newRow("tls1-tls1") << QSsl::TlsV1 << QSsl::TlsV1 << true;
+ QTest::newRow("tls1ssl3-tls1ssl3") << QSsl::TlsV1SslV3 << QSsl::TlsV1SslV3 << true;
+ QTest::newRow("any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true;
+
+ QTest::newRow("ssl2-ssl3") << QSsl::SslV2 << QSsl::SslV3 << false;
+ QTest::newRow("ssl2-tls1") << QSsl::SslV2 << QSsl::TlsV1 << false;
+ QTest::newRow("ssl2-tls1ssl3") << QSsl::SslV2 << QSsl::TlsV1SslV3 << false;
+ QTest::newRow("ssl2-any") << QSsl::SslV2 << QSsl::AnyProtocol << false; // no idea why it does not work, but we don't care about SSL 2
+
+ QTest::newRow("ssl3-ssl2") << QSsl::SslV3 << QSsl::SslV2 << false;
+ QTest::newRow("ssl3-tls1") << QSsl::SslV3 << QSsl::TlsV1 << false;
+ QTest::newRow("ssl3-tls1ssl3") << QSsl::SslV3 << QSsl::TlsV1SslV3 << true;
+ QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << true;
+
+ QTest::newRow("tls1-ssl2") << QSsl::TlsV1 << QSsl::SslV2 << false;
+ QTest::newRow("tls1-ssl3") << QSsl::TlsV1 << QSsl::SslV3 << false;
+ QTest::newRow("tls1-tls1ssl3") << QSsl::TlsV1 << QSsl::TlsV1SslV3 << true;
+ QTest::newRow("tls1-any") << QSsl::TlsV1 << QSsl::AnyProtocol << true;
+
+ QTest::newRow("tls1ssl3-ssl2") << QSsl::TlsV1SslV3 << QSsl::SslV2 << false;
+ QTest::newRow("tls1ssl3-ssl3") << QSsl::TlsV1SslV3 << QSsl::SslV3 << true;
+ QTest::newRow("tls1ssl3-tls1") << QSsl::TlsV1SslV3 << QSsl::TlsV1 << true;
+ QTest::newRow("tls1ssl3-tls1") << QSsl::TlsV1SslV3 << QSsl::AnyProtocol << true;
+
+ QTest::newRow("any-ssl2") << QSsl::AnyProtocol << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2
+ QTest::newRow("any-ssl3") << QSsl::AnyProtocol << QSsl::SslV3 << true;
+ QTest::newRow("any-tls1") << QSsl::AnyProtocol << QSsl::TlsV1 << true;
+ QTest::newRow("any-tls1ssl3") << QSsl::AnyProtocol << QSsl::TlsV1SslV3 << true;
+}
+
+void tst_QSslSocket::protocolServerSide()
+{
+ if (!QSslSocket::supportsSsl()) {
+ qWarning("SSL not supported, skipping test");
+ return;
+ }
+
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QFETCH(QSsl::SslProtocol, serverProtocol);
+ SslServer server;
+ server.protocol = serverProtocol;
+ QVERIFY(server.listen());
+
+ QEventLoop loop;
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+
+ QSslSocketPtr client = new QSslSocket;
+ socket = client;
+ QFETCH(QSsl::SslProtocol, clientProtocol);
+ socket->setProtocol(clientProtocol);
+ // upon SSL wrong version error, error will be triggered, not sslErrors
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
+ connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot()));
+ connect(client, SIGNAL(encrypted()), &loop, SLOT(quit()));
+
+ client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+
+ loop.exec();
+
+ QFETCH(bool, works);
+ QAbstractSocket::SocketState expectedState = (works) ? QAbstractSocket::ConnectedState : QAbstractSocket::UnconnectedState;
+ QCOMPARE(client->state(), expectedState);
+ QCOMPARE(client->isEncrypted(), works);
+}
+
+void tst_QSslSocket::setCaCertificates()
+{
+ if (!QSslSocket::supportsSsl())
+ return;
+
+ QSslSocket socket;
+ QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates());
+ socket.setCaCertificates(QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem"));
+ QCOMPARE(socket.caCertificates().size(), 1);
+ socket.setCaCertificates(socket.defaultCaCertificates());
+ QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates());
+}
+
+void tst_QSslSocket::setLocalCertificate()
+{
+}
+
+void tst_QSslSocket::setPrivateKey()
+{
+}
+
void tst_QSslSocket::setSocketDescriptor()
{
if (!QSslSocket::supportsSsl())