Add the ability to prefer the cipher preferences specified by the server.
Currently the cipher preferred by the client will always be used for SSL connections. This change makes it so that by default the ciphers specified by the server will be used (like the Apache SSLHonorCipherOrder option). This behavior can be disabled using a new SslOption. [ChangeLog][QtNetwork][QSslSocket] QSslSocket will now default to using the cipher preferences of the server socket when used as an SSL server. This can be disabled using the QSslConfiguration. Change-Id: I2d16d10145cf88a7412f30ef960d87024777de1c Reviewed-by: Peter Hartmann <peter-qt@hartmann.tk>
This commit is contained in:
parent
7b97f53e71
commit
00f0a4119c
@ -166,6 +166,10 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
|
||||
in ASN.1 format as returned by QSslConfiguration::sessionTicket(). Enabling
|
||||
this feature adds memory overhead of approximately 1K per used session
|
||||
ticket.
|
||||
\value SslOptionDisableServerCipherPreference Disables selecting the cipher
|
||||
chosen based on the servers preferences rather than the order ciphers were
|
||||
sent by the client. This option is only relevant to server sockets, and is
|
||||
only honored by the OpenSSL backend.
|
||||
|
||||
By default, SslOptionDisableEmptyFragments is turned on since this causes
|
||||
problems with a large number of servers. SslOptionDisableLegacyRenegotiation
|
||||
|
@ -95,7 +95,8 @@ namespace QSsl {
|
||||
SslOptionDisableServerNameIndication = 0x08,
|
||||
SslOptionDisableLegacyRenegotiation = 0x10,
|
||||
SslOptionDisableSessionSharing = 0x20,
|
||||
SslOptionDisableSessionPersistence = 0x40
|
||||
SslOptionDisableSessionPersistence = 0x40,
|
||||
SslOptionDisableServerCipherPreference = 0x80
|
||||
};
|
||||
Q_DECLARE_FLAGS(SslOptions, SslOption)
|
||||
}
|
||||
|
@ -344,6 +344,9 @@ long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, Q
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
|
||||
if (!(sslOptions & QSsl::SslOptionDisableServerCipherPreference))
|
||||
options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
@ -170,6 +170,9 @@ private slots:
|
||||
void protocol();
|
||||
void protocolServerSide_data();
|
||||
void protocolServerSide();
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void serverCipherPreferences();
|
||||
#endif // QT_NO_OPENSSL
|
||||
void setCaCertificates();
|
||||
void setLocalCertificate();
|
||||
void localCertificateChain();
|
||||
@ -1063,6 +1066,7 @@ public:
|
||||
const QString &certFile = SRCDIR "certs/fluke.cert",
|
||||
const QString &interFile = QString())
|
||||
: socket(0),
|
||||
config(QSslConfiguration::defaultConfiguration()),
|
||||
ignoreSslErrors(true),
|
||||
peerVerifyMode(QSslSocket::AutoVerifyPeer),
|
||||
protocol(QSsl::TlsV1_0),
|
||||
@ -1071,6 +1075,7 @@ public:
|
||||
m_interFile(interFile)
|
||||
{ }
|
||||
QSslSocket *socket;
|
||||
QSslConfiguration config;
|
||||
QString addCaCertificates;
|
||||
bool ignoreSslErrors;
|
||||
QSslSocket::PeerVerifyMode peerVerifyMode;
|
||||
@ -1084,6 +1089,7 @@ protected:
|
||||
void incomingConnection(qintptr socketDescriptor)
|
||||
{
|
||||
socket = new QSslSocket(this);
|
||||
socket->setSslConfiguration(config);
|
||||
socket->setPeerVerifyMode(peerVerifyMode);
|
||||
socket->setProtocol(protocol);
|
||||
if (ignoreSslErrors)
|
||||
@ -1254,6 +1260,78 @@ void tst_QSslSocket::protocolServerSide()
|
||||
QCOMPARE(client->isEncrypted(), works);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
|
||||
void tst_QSslSocket::serverCipherPreferences()
|
||||
{
|
||||
if (!QSslSocket::supportsSsl()) {
|
||||
qWarning("SSL not supported, skipping test");
|
||||
return;
|
||||
}
|
||||
|
||||
QFETCH_GLOBAL(bool, setProxy);
|
||||
if (setProxy)
|
||||
return;
|
||||
|
||||
// First using the default (server preference)
|
||||
{
|
||||
SslServer server;
|
||||
server.ciphers = QString("AES128-SHA:AES256-SHA");
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(5000, &loop, SLOT(quit()));
|
||||
|
||||
QSslSocketPtr client(new QSslSocket);
|
||||
socket = client.data();
|
||||
socket->setCiphers("AES256-SHA:AES128-SHA");
|
||||
|
||||
// upon SSL wrong version error, error will be triggered, not sslErrors
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
|
||||
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
|
||||
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
|
||||
|
||||
client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
|
||||
|
||||
loop.exec();
|
||||
|
||||
QVERIFY(client->isEncrypted());
|
||||
QCOMPARE(client->sessionCipher().name(), QString("AES128-SHA"));
|
||||
}
|
||||
|
||||
{
|
||||
// Now using the client preferences
|
||||
SslServer server;
|
||||
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
|
||||
config.setSslOption(QSsl::SslOptionDisableServerCipherPreference, true);
|
||||
server.config = config;
|
||||
server.ciphers = QString("AES128-SHA:AES256-SHA");
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(5000, &loop, SLOT(quit()));
|
||||
|
||||
QSslSocketPtr client(new QSslSocket);
|
||||
socket = client.data();
|
||||
socket->setCiphers("AES256-SHA:AES128-SHA");
|
||||
|
||||
// upon SSL wrong version error, error will be triggered, not sslErrors
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
|
||||
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
|
||||
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
|
||||
|
||||
client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
|
||||
|
||||
loop.exec();
|
||||
|
||||
QVERIFY(client->isEncrypted());
|
||||
QCOMPARE(client->sessionCipher().name(), QString("AES256-SHA"));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QT_NO_OPENSSL
|
||||
|
||||
|
||||
void tst_QSslSocket::setCaCertificates()
|
||||
{
|
||||
if (!QSslSocket::supportsSsl())
|
||||
@ -2354,28 +2432,28 @@ void tst_QSslSocket::sslOptions()
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSslConfigurationPrivate::defaultSslOptions),
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION));
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE));
|
||||
#else
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSslConfigurationPrivate::defaultSslOptions),
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3));
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
|
||||
#endif
|
||||
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableEmptyFragments
|
||||
|QSsl::SslOptionDisableLegacyRenegotiation),
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3));
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
|
||||
|
||||
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableEmptyFragments),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)));
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableLegacyRenegotiation),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS));
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS));
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
@ -2383,7 +2461,7 @@ void tst_QSslSocket::sslOptions()
|
||||
QSsl::SslOptionDisableEmptyFragments
|
||||
|QSsl::SslOptionDisableLegacyRenegotiation
|
||||
|QSsl::SslOptionDisableSessionTickets),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET)));
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_CIPHER_SERVER_PREFERENCE)));
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
@ -2393,7 +2471,7 @@ void tst_QSslSocket::sslOptions()
|
||||
|QSsl::SslOptionDisableLegacyRenegotiation
|
||||
|QSsl::SslOptionDisableSessionTickets
|
||||
|QSsl::SslOptionDisableCompression),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_NO_COMPRESSION)));
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user