diff options
Diffstat (limited to 'src/network')
-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 |