summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-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
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