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>bb10
parent
061fbceb77
commit
30978dc1a5
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ namespace QSsl {
|
|||
TlsV1_1OrLater,
|
||||
TlsV1_2OrLater,
|
||||
|
||||
DtlsV1_0,
|
||||
DtlsV1_2,
|
||||
DtlsV1_2OrLater,
|
||||
|
||||
UnknownProtocol = -1
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -997,6 +997,27 @@ QSslConfiguration::NextProtocolNegotiationStatus QSslConfiguration::nextProtocol
|
|||
return d->nextProtocolNegotiationStatus;
|
||||
}
|
||||
|
||||
/*!
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -2125,6 +2131,26 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
|
|||
globalData()->supportedCiphers = ciphers;
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
*/
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -2260,6 +2295,30 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
|
|||
ptr->backendConfig = global->backendConfig;
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue