summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moore <rich@kde.org>2011-10-19 11:40:57 +0200
committerQt by Nokia <qt-info@nokia.com>2011-10-20 18:20:12 +0200
commit78d02e93aca5325fc5be9bfd275862795207abaa (patch)
tree71be722032f646957beb3c683923d37f20314346
parent5b6894de8771caffdcf27e79412e03a64e103d4a (diff)
Add the ability to enable various SSL bug workarounds.
There are lots of buggy SSL servers around and to connect to them you need to disable various features. This commit adds the ability to disable the SSL ticket extension, the ability to disable the insertion of empty fragments, and the ability to disable compression. Task-number: QTBUG-21906 Change-Id: I3e1d0347a46e9030b889bbf15b2aad19b8513b73 Merge-request: 68 Reviewed-by: Peter Hartmann <peter.hartmann@nokia.com>
-rw-r--r--src/network/ssl/qssl.cpp30
-rw-r--r--src/network/ssl/qssl.h11
-rw-r--r--src/network/ssl/qsslconfiguration.cpp29
-rw-r--r--src/network/ssl/qsslconfiguration.h4
-rw-r--r--src/network/ssl/qsslconfiguration_p.h2
-rw-r--r--src/network/ssl/qsslsocket.cpp2
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp33
-rw-r--r--tests/manual/qssloptions/main.cpp92
-rw-r--r--tests/manual/qssloptions/qssloptions.pro12
9 files changed, 206 insertions, 9 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index 17f8014e52..d342a779f6 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -120,4 +120,34 @@ QT_BEGIN_NAMESPACE
the correct setting for your protocol.
*/
+/*!
+ \enum QSsl::SslOption
+
+ Describes the options that can be used to control the details of
+ SSL behaviour. These options are generally used to turn features off
+ to work around buggy servers.
+
+ \value SslOptionDisableEmptyFragments Disables the insertion of empty
+ fragments into the data when using block ciphers. When enabled, this
+ prevents some attacks (such as the BEAST attack), however it is
+ incompatible with some servers.
+ \value SslOptionDisableTickets Disables the SSL session ticket
+ extension. This can cause slower connection setup, however some servers
+ are not compatible with the extension.
+ \value SslOptionDisableCompression Disables the SSL compression
+ extension. When enabled, this allows the data being passed over SSL to
+ be compressed, however some servers are not compatible with this
+ extension.
+ \value SslOptionDisableServerNameIndication Disables the SSL server
+ name indication extension. When enabled, this tells the server the virtual
+ host being accessed allowing it to respond with the correct certificate.
+
+ By default, SslOptionDisableEmptyFragments is turned on since this causes
+ problems with a large number of servers, but the other options are disabled.
+
+ Note: Availability of above options depends on the version of the SSL
+ backend in use.
+*/
+
+
QT_END_NAMESPACE
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index c8af346800..4c6739c1f7 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -44,6 +44,7 @@
#define QSSL_H
#include <QtCore/qglobal.h>
+#include <QtCore/QFlags>
QT_BEGIN_HEADER
@@ -86,8 +87,18 @@ namespace QSsl {
SecureProtocols,
UnknownProtocol = -1
};
+
+ enum SslOption {
+ SslOptionDisableEmptyFragments = 0x01,
+ SslOptionDisableSessionTickets = 0x02,
+ SslOptionDisableCompression = 0x04,
+ SslOptionDisableServerNameIndication = 0x08
+ };
+ Q_DECLARE_FLAGS(SslOptions, SslOption)
}
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions)
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 69d3b6687e..e24076e7d1 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -167,7 +167,8 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->caCertificates == other.d->caCertificates &&
d->protocol == other.d->protocol &&
d->peerVerifyMode == other.d->peerVerifyMode &&
- d->peerVerifyDepth == other.d->peerVerifyDepth;
+ d->peerVerifyDepth == other.d->peerVerifyDepth &&
+ d->sslOptions == other.d->sslOptions;
}
/*!
@@ -199,7 +200,8 @@ bool QSslConfiguration::isNull() const
d->localCertificate.isNull() &&
d->privateKey.isNull() &&
d->peerCertificate.isNull() &&
- d->peerCertificateChain.count() == 0);
+ d->peerCertificateChain.count() == 0 &&
+ d->sslOptions == 0);
}
/*!
@@ -507,6 +509,29 @@ void QSslConfiguration::setCaCertificates(const QList<QSslCertificate> &certific
}
/*!
+ Enables or disables an SSL compatibility option.
+
+ \sa testSSlOption()
+*/
+void QSslConfiguration::setSslOption(QSsl::SslOption option, bool on)
+{
+ if (on)
+ d->sslOptions |= option;
+ else
+ d->sslOptions &= ~option;
+}
+
+/*!
+ Returns true if the specified SSL compatibility option is enabled.
+
+ \sa testSSlOption()
+*/
+bool QSslConfiguration::testSslOption(QSsl::SslOption option) const
+{
+ return d->sslOptions & option;
+}
+
+/*!
Returns the default SSL configuration to be used in new SSL
connections.
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index 258b454431..ff8c8fc4b4 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -59,6 +59,7 @@
#include <QtCore/qshareddata.h>
#include <QtNetwork/qsslsocket.h>
+#include <QtNetwork/qssl.h>
QT_BEGIN_HEADER
@@ -118,6 +119,9 @@ public:
QList<QSslCertificate> caCertificates() const;
void setCaCertificates(const QList<QSslCertificate> &certificates);
+ void setSslOption(QSsl::SslOption option, bool on);
+ bool testSslOption(QSsl::SslOption option) const;
+
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index af80e4cb9d..b83edb9eb8 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -98,6 +98,8 @@ public:
QSslSocket::PeerVerifyMode peerVerifyMode;
int peerVerifyDepth;
+ QSsl::SslOptions sslOptions;
+
// in qsslsocket.cpp:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 294e2508d8..2fb04077d4 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -897,6 +897,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
d->configuration.peerVerifyMode = configuration.peerVerifyMode();
d->configuration.protocol = configuration.protocol();
+ d->configuration.sslOptions = configuration.d->sslOptions;
d->allowRootCertOnDemandLoading = false;
}
@@ -2049,6 +2050,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
ptr->protocol = global->protocol;
ptr->peerVerifyMode = global->peerVerifyMode;
ptr->peerVerifyDepth = global->peerVerifyDepth;
+ ptr->sslOptions = global->sslOptions;
}
/*!
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 14a3899bfd..2175f7f78f 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -285,12 +285,29 @@ init_context:
return false;
}
- // Enable all bug workarounds.
- if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) {
- q_SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
- } else {
- q_SSL_CTX_set_options(ctx, SSL_OP_ALL);
- }
+ // Enable bug workarounds.
+ long options;
+ if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols)
+ options = SSL_OP_ALL|SSL_OP_NO_SSLv2;
+ else
+ options = SSL_OP_ALL;
+
+ // This option is disabled by default, so we need to be able to clear it
+ if (configuration.sslOptions & QSsl::SslOptionDisableEmptyFragments)
+ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+ else
+ options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+
+#ifdef SSL_OP_NO_TICKET
+ if (configuration.sslOptions & QSsl::SslOptionDisableSessionTickets)
+ options |= SSL_OP_NO_TICKET;
+#endif
+#ifdef SSL_OP_NO_COMPRESSION
+ if (configuration.sslOptions & QSsl::SslOptionDisableCompression)
+ options |= SSL_OP_NO_COMPRESSION;
+#endif
+
+ q_SSL_CTX_set_options(ctx, options);
// Initialize ciphers
QByteArray cipherString;
@@ -426,7 +443,9 @@ init_context:
tlsHostName = hostName;
QByteArray ace = QUrl::toAce(tlsHostName);
// only send the SNI header if the URL is valid and not an IP
- if (!ace.isEmpty() && !QHostAddress().setAddress(tlsHostName)) {
+ if (!ace.isEmpty()
+ && !QHostAddress().setAddress(tlsHostName)
+ && !(configuration.sslOptions & QSsl::SslOptionDisableServerNameIndication)) {
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.data()))
#else
diff --git a/tests/manual/qssloptions/main.cpp b/tests/manual/qssloptions/main.cpp
new file mode 100644
index 0000000000..7ee3f9ce0c
--- /dev/null
+++ b/tests/manual/qssloptions/main.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtNetwork/qsslconfiguration.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTextStream>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ if (argc < 3) {
+ QTextStream out(stdout);
+ out << "Usage: " << argv[0] << " host port [options]" << endl;
+ out << "The options can be one or more of the following:" << endl;
+ out << "enable_empty_fragments" << endl;
+ out << "disable_session_tickets" << endl;
+ out << "disable_compression" << endl;
+ out << "disable_sni" << endl;
+ return 1;
+ }
+
+ QString host = QString::fromLocal8Bit(argv[1]);
+ int port = QString::fromLocal8Bit(argv[2]).toInt();
+
+ QSslConfiguration config = QSslConfiguration::defaultConfiguration();
+
+ for (int i=3; i < argc; i++) {
+ QString option = QString::fromLocal8Bit(argv[i]);
+
+ if (option == QStringLiteral("enable_empty_fragments"))
+ config.setSslOption(QSsl::SslOptionDisableEmptyFragments, false);
+ else if (option == QStringLiteral("disable_session_tickets"))
+ config.setSslOption(QSsl::SslOptionDisableSessionTickets, true);
+ else if (option == QStringLiteral("disable_compression"))
+ config.setSslOption(QSsl::SslOptionDisableCompression, true);
+ else if (option == QStringLiteral("disable_sni"))
+ config.setSslOption(QSsl::SslOptionDisableServerNameIndication, true);
+ }
+
+ QSslConfiguration::setDefaultConfiguration(config);
+
+ QSslSocket socket;
+ //socket.setSslConfiguration(config);
+ socket.connectToHostEncrypted(host, port);
+
+ if ( !socket.waitForEncrypted() ) {
+ qDebug() << socket.errorString();
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/tests/manual/qssloptions/qssloptions.pro b/tests/manual/qssloptions/qssloptions.pro
new file mode 100644
index 0000000000..c1c8446e0f
--- /dev/null
+++ b/tests/manual/qssloptions/qssloptions.pro
@@ -0,0 +1,12 @@
+load(qttest_p4)
+TEMPLATE = app
+TARGET = tst_qssloptions
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT -= gui
+QT += network
+
+#CONFIG += release
+
+SOURCES += main.cpp