diff options
author | Richard Moore <rich@kde.org> | 2011-10-19 09:40:57 (GMT) |
---|---|---|
committer | Peter Hartmann <peter.hartmann@nokia.com> | 2011-10-21 10:27:56 (GMT) |
commit | 19bd31fc84cc4916aef4835429fc4a55e85d0c28 (patch) | |
tree | b68a0f30916d62b83ef95adb283c4a0c83a613bb /src/network/ssl | |
parent | 0375fff2b077ddd20a97c1b1c8d34f22553abe0c (diff) | |
download | Qt-19bd31fc84cc4916aef4835429fc4a55e85d0c28.zip Qt-19bd31fc84cc4916aef4835429fc4a55e85d0c28.tar.gz Qt-19bd31fc84cc4916aef4835429fc4a55e85d0c28.tar.bz2 |
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>
(cherry picked from commit 78d02e93aca5325fc5be9bfd275862795207abaa)
(commit was cherry-picked from Qt 5 to 4.8 after agreeing with the
author because the merge request was filed against Qt 5.)
Diffstat (limited to 'src/network/ssl')
-rw-r--r-- | src/network/ssl/qssl.cpp | 30 | ||||
-rw-r--r-- | src/network/ssl/qssl.h | 11 | ||||
-rw-r--r-- | src/network/ssl/qsslconfiguration.cpp | 29 | ||||
-rw-r--r-- | src/network/ssl/qsslconfiguration.h | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslconfiguration_p.h | 2 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 2 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 33 |
7 files changed, 102 insertions, 9 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index 586c894..08a05ff 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 2ecd1c3..453d4da 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 @@ -81,8 +82,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 69d3b66..e24076e 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 258b454..ff8c8fc 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 af80e4c..b83edb9 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 df61fb6..3ac8f18 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -896,6 +896,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; } @@ -2027,6 +2028,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 8e53974..3942209 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; @@ -419,7 +436,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 |