summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2018-02-19 13:46:21 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2018-04-06 05:13:37 +0000
commit30978dc1a50368e45c3764d7efc283c4e660a9b9 (patch)
treede5385a867c326f574f33db6dc7a5262dbc6a52b /src/network
parent061fbceb777c41b23bc2b8180b2af85d9b35b246 (diff)
Add a new (D)TLS configuration
Namespace QSsl: introduce DtlsV1_0/DtlsV1_2/DtlsV1_2OrLater enumerators into SslProtocol. Implement QSslConfiguration::defaultDtlsConfiguration. Make some functions shared - now not only QSslSocket needs them, but also DTLS-related code. This patch-set also enables protocol-specific set of ciphers (so for DTLS we are using the correct method - 'DTLS_method'). Change-Id: I828fc898674aa3c0a471e8e5b94575bb50538601 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/network')
-rw-r--r--src/network/ssl/qssl.cpp3
-rw-r--r--src/network/ssl/qssl.h4
-rw-r--r--src/network/ssl/qsslconfiguration.cpp56
-rw-r--r--src/network/ssl/qsslconfiguration.h6
-rw-r--r--src/network/ssl/qsslconfiguration_p.h5
-rw-r--r--src/network/ssl/qsslsocket.cpp61
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp62
7 files changed, 177 insertions, 20 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index 85d1a99c45..0102956097 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -125,6 +125,9 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value TlsV1_1OrLater TLSv1.1 and later versions. This option is not available when using the WinRT backend due to platform limitations.
\value TlsV1_2 TLSv1.2. When using the WinRT backend this option will also enable TLSv1.0 and TLSv1.1.
\value TlsV1_2OrLater TLSv1.2 and later versions. This option is not available when using the WinRT backend due to platform limitations.
+ \value DtlsV1_0 DTLSv1.0
+ \value DtlsV1_2 DTLSv1.2
+ \value DtlsV1_2OrLater DTLSv1.2 and later versions.
\value UnknownProtocol The cipher's protocol cannot be determined.
\value AnyProtocol The socket understands SSLv2, SSLv3, and TLSv1.0. This
value is used by QSslSocket only.
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index c2a468c97c..7d688e27fc 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -91,6 +91,10 @@ namespace QSsl {
TlsV1_1OrLater,
TlsV1_2OrLater,
+ DtlsV1_0,
+ DtlsV1_2,
+ DtlsV1_2OrLater,
+
UnknownProtocol = -1
};
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 116a6693c4..8c9fa5d4f2 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -998,6 +998,27 @@ QSslConfiguration::NextProtocolNegotiationStatus QSslConfiguration::nextProtocol
}
/*!
+ This function returns true if DTLS cookie verification was enabled on a
+ server-side socket.
+
+ \sa setDtlsCookieVerificationEnabled()
+ */
+bool QSslConfiguration::dtlsCookieVerificationEnabled() const
+{
+ return d->dtlsCookieEnabled;
+}
+
+/*!
+ This function enables DTLS cookie verification when \a enable is true.
+
+ \sa dtlsCookieVerificationEnabled()
+ */
+void QSslConfiguration::setDtlsCookieVerificationEnabled(bool enable)
+{
+ d->dtlsCookieEnabled = enable;
+}
+
+/*!
Returns the default SSL configuration to be used in new SSL
connections.
@@ -1030,6 +1051,41 @@ void QSslConfiguration::setDefaultConfiguration(const QSslConfiguration &configu
QSslConfigurationPrivate::setDefaultConfiguration(configuration);
}
+/*!
+ Returns the default DTLS configuration to be used in new DTLS
+ connections.
+
+ The default DTLS configuration consists of:
+
+ \list
+ \li no local certificate and no private key
+ \li protocol DtlsV1_2OrLater
+ \li the system's default CA certificate list
+ \li the cipher list equal to the list of the SSL libraries'
+ supported TLS 1.2 ciphers that use 128 or more secret bits
+ for the cipher.
+ \endlist
+
+ \sa setDefaultDtlsConfiguration()
+*/
+QSslConfiguration QSslConfiguration::defaultDtlsConfiguration()
+{
+ return QSslConfigurationPrivate::defaultDtlsConfiguration();
+}
+
+/*!
+ Sets the default DTLS configuration to be used in new DTLS
+ connections to be \a configuration. Existing connections are not
+ affected by this call.
+
+ \sa defaultDtlsConfiguration()
+*/
+void QSslConfiguration::setDefaultDtlsConfiguration(const QSslConfiguration &configuration)
+{
+ QSslConfigurationPrivate::setDefaultDtlsConfiguration(configuration);
+}
+
+
/*! \internal
*/
bool QSslConfigurationPrivate::peerSessionWasShared(const QSslConfiguration &configuration) {
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index a5561d9828..520504ff4c 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -154,9 +154,15 @@ public:
void setBackendConfigurationOption(const QByteArray &name, const QVariant &value);
void setBackendConfiguration(const QMap<QByteArray, QVariant> &backendConfig = QMap<QByteArray, QVariant>());
+ bool dtlsCookieVerificationEnabled() const;
+ void setDtlsCookieVerificationEnabled(bool enable);
+
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
+ static QSslConfiguration defaultDtlsConfiguration();
+ static void setDefaultDtlsConfiguration(const QSslConfiguration &configuration);
+
enum NextProtocolNegotiationStatus {
NextProtocolNegotiationNone,
NextProtocolNegotiationNegotiated,
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 38a98239db..f44485d51a 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -137,10 +137,15 @@ public:
QByteArray nextNegotiatedProtocol;
QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
+ bool dtlsCookieEnabled = true;
+
// in qsslsocket.cpp:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
static void deepCopyDefaultConfiguration(QSslConfigurationPrivate *config);
+
+ static QSslConfiguration defaultDtlsConfiguration();
+ static void setDefaultDtlsConfiguration(const QSslConfiguration &configuration);
};
// implemented here for inlining purposes
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 4273904c12..2a415ace44 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -336,12 +336,18 @@ QT_BEGIN_NAMESPACE
class QSslSocketGlobalData
{
public:
- QSslSocketGlobalData() : config(new QSslConfigurationPrivate) {}
+ QSslSocketGlobalData()
+ : config(new QSslConfigurationPrivate),
+ dtlsConfig(new QSslConfigurationPrivate)
+ {
+ dtlsConfig->protocol = QSsl::DtlsV1_2OrLater;
+ }
QMutex mutex;
QList<QSslCipher> supportedCiphers;
QVector<QSslEllipticCurve> supportedEllipticCurves;
QExplicitlySharedDataPointer<QSslConfigurationPrivate> config;
+ QExplicitlySharedDataPointer<QSslConfigurationPrivate> dtlsConfig;
};
Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
@@ -2128,6 +2134,26 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
/*!
\internal
*/
+void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
+{
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->ciphers = ciphers;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCipher> q_getDefaultDtlsCiphers()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->dtlsConfig->ciphers;
+}
+
+/*!
+ \internal
+*/
QVector<QSslEllipticCurve> QSslSocketPrivate::supportedEllipticCurves()
{
QSslSocketPrivate::ensureInitialized();
@@ -2142,6 +2168,7 @@ void QSslSocketPrivate::setDefaultSupportedEllipticCurves(const QVector<QSslElli
{
const QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
+ globalData()->dtlsConfig.detach();
globalData()->supportedEllipticCurves = curves;
}
@@ -2164,6 +2191,8 @@ void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &c
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates = certs;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates = certs;
// when the certificates are set explicitly, we do not want to
// load the system certificates on demand
s_loadRootCertsOnDemand = false;
@@ -2183,6 +2212,8 @@ bool QSslSocketPrivate::addDefaultCaCertificates(const QString &path, QSsl::Enco
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates += certs;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates += certs;
return true;
}
@@ -2195,6 +2226,8 @@ void QSslSocketPrivate::addDefaultCaCertificate(const QSslCertificate &cert)
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates += cert;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates += cert;
}
/*!
@@ -2206,6 +2239,8 @@ void QSslSocketPrivate::addDefaultCaCertificates(const QList<QSslCertificate> &c
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates += certs;
+ globalData()->dtlsConfig.detach();
+ globalData()->dtlsConfig->caCertificates += certs;
}
/*!
@@ -2263,6 +2298,30 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
/*!
\internal
*/
+QSslConfiguration QSslConfigurationPrivate::defaultDtlsConfiguration()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+
+ return QSslConfiguration(globalData()->dtlsConfig.data());
+}
+
+/*!
+ \internal
+*/
+void QSslConfigurationPrivate::setDefaultDtlsConfiguration(const QSslConfiguration &configuration)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ if (globalData()->dtlsConfig == configuration.d)
+ return; // nothing to do
+
+ globalData()->dtlsConfig = const_cast<QSslConfigurationPrivate*>(configuration.d.constData());
+}
+
+/*!
+ \internal
+*/
void QSslSocketPrivate::createPlainSocket(QIODevice::OpenMode openMode)
{
Q_Q(QSslSocket);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index e269a1f8ea..3858b4b21f 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -193,8 +193,7 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER
return ciph;
}
-// static
-inline QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
+QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
{
return {
q_X509_STORE_CTX_get_error(ctx),
@@ -247,6 +246,33 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx)
return 1;
}
+static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphers,
+ QList<QSslCipher> &defaultCiphers)
+{
+ Q_ASSERT(connection);
+
+ STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
+ for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
+ if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
+ QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);
+ if (!ciph.isNull()) {
+ // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
+ if (!ciph.name().toLower().startsWith(QLatin1String("adh")) &&
+ !ciph.name().toLower().startsWith(QLatin1String("exp-adh")) &&
+ !ciph.name().toLower().startsWith(QLatin1String("aecdh"))) {
+ ciphers << ciph;
+
+ if (ciph.usedBits() >= 128)
+ defaultCiphers << ciph;
+ }
+ }
+ }
+ }
+}
+
+// Defined in qsslsocket.cpp
+void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
+
long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
{
long options;
@@ -452,29 +478,27 @@ void QSslSocketPrivate::resetDefaultCiphers()
QList<QSslCipher> ciphers;
QList<QSslCipher> defaultCiphers;
- STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(mySsl);
- for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
- if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
- QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);
- if (!ciph.isNull()) {
- // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
- if (!ciph.name().toLower().startsWith(QLatin1String("adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("exp-adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("aecdh"))) {
- ciphers << ciph;
-
- if (ciph.usedBits() >= 128)
- defaultCiphers << ciph;
- }
- }
- }
- }
+ q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
q_SSL_CTX_free(myCtx);
q_SSL_free(mySsl);
setDefaultSupportedCiphers(ciphers);
setDefaultCiphers(defaultCiphers);
+
+ ciphers.clear();
+ defaultCiphers.clear();
+
+ myCtx = q_SSL_CTX_new(q_DTLS_client_method());
+ if (myCtx) {
+ mySsl = q_SSL_new(myCtx);
+ if (mySsl) {
+ q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
+ q_setDefaultDtlsCiphers(defaultCiphers);
+ q_SSL_free(mySsl);
+ }
+ q_SSL_CTX_free(myCtx);
+ }
}
void QSslSocketPrivate::resetDefaultEllipticCurves()